diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5b00fb6f3..933bd0195 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,7 +19,7 @@ jobs: contents: read # for actions/checkout to fetch code security-events: write # for github/codeql-action/autobuild to send a status report name: Analyse - runs-on: ubuntu-latest + runs-on: self-hosted steps: - name: Harden Runner diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c1209291a..5ba8bb381 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -14,7 +14,7 @@ permissions: jobs: dependency-review: - runs-on: ubuntu-latest + runs-on: self-hosted steps: - name: Harden Runner uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 19275d2c2..be387804b 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -15,7 +15,7 @@ jobs: permissions: contents: read # for actions/checkout to fetch code pull-requests: read # for sonarsource/sonarcloud-github-action to determine which PR to decorate - runs-on: ubuntu-22.04 + runs-on: self-hosted steps: - name: Harden Runner @@ -29,14 +29,14 @@ jobs: uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2 with: php-version: '8.1' - extensions: ldap, xdebug, gd, json, xml, curl, zip, mbstring + extensions: ldap, xdebug, gd, json, xml, curl, zip, mbstring, imagick, pdo_sqlite - name: Validate composer.json and composer.lock run: composer validate --strict - name: Cache Composer packages id: composer-cache - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} @@ -56,4 +56,4 @@ jobs: uses: sonarsource/sonarcloud-github-action@eb211723266fe8e83102bac7361f0a05c3ac1d1b # master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 20b8ee4c0..38f2c0e58 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -12,7 +12,7 @@ permissions: jobs: build: - runs-on: ubuntu-22.04 + runs-on: self-hosted steps: - name: Harden Runner @@ -26,28 +26,28 @@ jobs: uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2 with: php-version: '8.1' - extensions: ldap, xdebug, gd, json, xml, curl, zip, mbstring + extensions: ldap, xdebug, gd, json, xml, curl, zip, mbstring, imagick, pdo_sqlite - name: Validate composer.json and composer.lock run: composer validate --strict - name: Cache Composer packages id: composer-cache - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + key: ${{ runner.os }}-quality-${{ hashFiles('**/composer.lock') }} restore-keys: | - ${{ runner.os }}-php- + ${{ runner.os }}-quality- - name: PHP Version run: php --version - name: Install dependencies - run: composer install --prefer-dist --no-progress + run: composer install --no-progress - name: Install CodeSpell - run: pip install --user codespell + run: pipx install codespell - name: CodeSpell run: ./codespell.sh @@ -56,7 +56,7 @@ jobs: run: ./vendor/bin/phpstan -V - name: PHPStan - run: ./vendor/bin/phpstan --xdebug + run: ./vendor/bin/phpstan - name: Rector run: ./vendor/bin/rector process --dry-run diff --git a/Readme.md b/Readme.md index 09f95edc3..f9e57cade 100644 --- a/Readme.md +++ b/Readme.md @@ -25,4 +25,4 @@ There are two modules. Usually, you only need the files inside "lam". LAM is published under the GNU General Public License. The complete list of licenses can be found in the copyright file. -Copyright (C) 2003 - 2024 Roland Gruber \ No newline at end of file +Copyright (C) 2003 - 2025 Roland Gruber diff --git a/codespell.sh b/codespell.sh index ff9a894b2..434fb5934 100755 --- a/codespell.sh +++ b/codespell.sh @@ -1,3 +1,3 @@ #!/bin/bash -~/.local/bin/codespell --skip '*3rdParty*,*/jodit/*,*/po/*,*/locale/*,tmp,sess,config,graphics,*/style/images/*,*/style/*.gif,*/style/*.png,*/docs/manual-onePage/*,*/docs/manual-sources/images/*,*/templates/lib/*jquery*,*/templates/lib/*popper*,*/templates/lib/*tippy*,*/templates/lib/*flatpickr*,*/templates/lib/*Sortable*,*/templates/lib/*cropper*,*~,*/docs/phpdoc/*,*/docs/manual/*,*/docs/devel/images/*,*/docs/manual-pdf/*,*.sh,*/cropper.js,*/lib/extra/*,lam/.phpdoc,lam/composer.*' --ignore-words-list "tim,te,pres,files'" lam +~/.local/bin/codespell --skip '*3rdParty*,*/jodit/*,*/po/*,*/locale/*,tmp,sess,config,graphics,*/style/images/*,*/style/*.gif,*/style/*.png,*/docs/manual-onePage/*,*/docs/manual-sources/images/*,*/templates/lib/*jquery*,*/templates/lib/*popper*,*/templates/lib/*tippy*,*/templates/lib/*flatpickr*,*/templates/lib/*Sortable*,*/templates/lib/*cropper*,*~,*/docs/phpdoc/*,*/docs/manual/*,*/docs/devel/images/*,*/docs/manual-pdf/*,*.sh,*/cropper.js,*/templates/lib/*sweetalert*,*/lib/extra/*,lam/.phpdoc,lam/composer.*' --ignore-words-list "tim,te,pres,files'" lam diff --git a/composer.json b/composer.json index 07a2f89c7..54eb755a5 100644 --- a/composer.json +++ b/composer.json @@ -3,9 +3,8 @@ "description": "LDAP Account Manager", "require-dev" : { "phpunit/phpunit" : "9.5.21", - "squizlabs/php_codesniffer" : "3.4.0", - "phpstan/phpstan": "^1.10", - "rector/rector": "^1", + "phpstan/phpstan": "^2", + "rector/rector": "^2", "cyclonedx/cyclonedx-php-composer": "^5.0" }, "require": { @@ -13,7 +12,14 @@ "ext-json": "*", "ext-pdo": "*", "ext-xmlreader": "*", - "ext-zip": "*" + "ext-zip": "*", + "ext-gd": "*", + "ext-imagick": "*", + "ext-gettext": "*", + "ext-curl": "*", + "ext-openssl": "*", + "ext-xmlwriter": "*", + "ext-iconv": "*" }, "scripts": { "test": "vendor/bin/phpunit" diff --git a/lam-packaging/RPM/ldap-account-manager.spec b/lam-packaging/RPM/ldap-account-manager.spec index 9e7959e8c..4b5bee2dc 100644 --- a/lam-packaging/RPM/ldap-account-manager.spec +++ b/lam-packaging/RPM/ldap-account-manager.spec @@ -112,11 +112,6 @@ if [ ! -f /var/lib/%{lam_dir}/config/config.cfg ]; then cp /var/lib/%{lam_dir}/config/config.cfg.sample /var/lib/%{lam_dir}/config/config.cfg chmod 600 /var/lib/%{lam_dir}/config/config.cfg chown %{lam_uid}:%{lam_gid} /var/lib/%{lam_dir}/config/config.cfg - if [ ! -f /var/lib/%{lam_dir}/config/lam.conf ]; then - cp /var/lib/%{lam_dir}/config/unix.sample.conf /var/lib/%{lam_dir}/config/lam.conf - chmod 600 /var/lib/%{lam_dir}/config/lam.conf - chown %{lam_uid}:%{lam_gid} /var/lib/%{lam_dir}/config/lam.conf - fi fi for server in apache2 httpd nginx; do if [ `which systemctl 2< /dev/null` ]; then diff --git a/lam-packaging/buildPackages b/lam-packaging/buildPackages index 53fee059c..377223641 100755 --- a/lam-packaging/buildPackages +++ b/lam-packaging/buildPackages @@ -30,7 +30,7 @@ function minify { for file in $files; do jsFiles="$jsFiles $file" done - uglifyjs -o $outFile $jsFiles + terser $jsFiles -o $outFile rm $files # add final new line to supress Debian warnings echo "" >> $outFile diff --git a/lam-packaging/debian/README.Debian b/lam-packaging/debian/README.Debian index dbc34a966..c21c0a565 100644 --- a/lam-packaging/debian/README.Debian +++ b/lam-packaging/debian/README.Debian @@ -14,10 +14,16 @@ Configuration: All settings can be edited via the webfrontend. Please point your browser to the LAM start page and then select "LAM configuration". - The default password for the configuration is "lam". Lamdaemon: If you want to use the lamdaemon you need to install the package ldap-account-manager-lamdaemon on the target machine. + + +Packaging: + +The Debian's orig.tar.bz2 file differs from the tar.bz2 files that are provided upstream. +While the upstream files contain minified CSS and JS files, the Debian orig.tar.bz2 file +contains the sources and minifies during Debian package build. diff --git a/lam-packaging/debian/changelog b/lam-packaging/debian/changelog index 2a67f03d0..964bc604c 100644 --- a/lam-packaging/debian/changelog +++ b/lam-packaging/debian/changelog @@ -1,8 +1,32 @@ -ldap-account-manager (9.0.RC1-1) unstable; urgency=medium +ldap-account-manager (9.3-1) unstable; urgency=medium * new upstream release - -- Roland Gruber Wed, 04 Dec 2024 07:23:11 +0200 + -- Roland Gruber Mon, 15 Sep 2025 07:11:26 +0200 + +ldap-account-manager (9.2-1) unstable; urgency=medium + + * new upstream release + * Fix "Please upgrade to upstream release >= 9.1" by packaging + new version (Closes: #1100719) + + -- Roland Gruber Fri, 06 Jun 2025 07:41:13 +0200 + +ldap-account-manager (9.1-1) unstable; urgency=medium + + * new upstream release + + -- Roland Gruber Thu, 13 Mar 2025 07:36:27 +0200 + +ldap-account-manager (9.0-1) unstable; urgency=medium + + * new upstream release + * Fix "ldap-account-manager: CVE-2024-52792" by using + new file format (Closes: #1090934) + * Fix "Please allow recent php-monolog (>= 3)" by using + different dependencies (Closes: #1076835) + + -- Roland Gruber Tue, 17 Dec 2024 19:23:11 +0200 ldap-account-manager (8.9-1) unstable; urgency=medium diff --git a/lam-packaging/debian/control b/lam-packaging/debian/control index 69cbfc5fd..37c2b3eda 100644 --- a/lam-packaging/debian/control +++ b/lam-packaging/debian/control @@ -2,8 +2,8 @@ Source: ldap-account-manager Maintainer: Roland Gruber Section: web Priority: optional -Standards-Version: 4.7.0 -Build-Depends: debhelper (>= 12), debhelper-compat (= 12), po-debconf, cleancss (>= 5.2), uglifyjs (>= 3.12) +Standards-Version: 4.7.2 +Build-Depends: debhelper (>= 12), debhelper-compat (= 12), po-debconf, cleancss (>= 5.2), terser (>= 5.0) Homepage: https://www.ldap-account-manager.org/ Rules-Requires-Root: binary-targets @@ -11,16 +11,15 @@ Package: ldap-account-manager Architecture: all Depends: php (>= 8.1), php-ldap, php-gd | php-imagick, - php-json, php-curl, + php-json, php-curl, php-sqlite3, php-mysql, php-zip, php-xml, php-gmp, php-mbstring, libapache2-mod-php | libapache2-mod-fcgid | php-fpm, apache2 (>= 2.4.0) | httpd, gettext, fonts-dejavu, - libjs-jquery-jstree (>= 3.3.0), php-phpseclib3, php-monolog, - php-voku-portable-ascii (<< 3.0), libphp-phpmailer (<< 7.0), + libphp-phpmailer (<< 7.0), debconf (>= 0.2.26) | debconf-2.0, ${misc:Depends} -Recommends: php-opcache +Recommends: php-opcache, php-apcu Suggests: ldap-server, php-mcrypt, ldap-account-manager-lamdaemon, perl Conflicts: libapache2-mod-php5, php5, php5-fpm Description: webfrontend for managing accounts in an LDAP directory diff --git a/lam-packaging/debian/copyright b/lam-packaging/debian/copyright index 5bc904a14..f901e1f24 100644 --- a/lam-packaging/debian/copyright +++ b/lam-packaging/debian/copyright @@ -1,4 +1,4 @@ -This software is copyright (c) 2003 - 2024 by Roland Gruber +This software is copyright (c) 2003 - 2025 by Roland Gruber If you purchased a copy of LDAP Account Manager Pro then the following files are licensed under the conditions which you accepted at purchase @@ -17,6 +17,8 @@ time. * lib/modules/automount.inc * lib/modules/bindDLZ.inc * lib/modules/bindDLZXfr.inc +* lib/modules/bindDyndbRecord.inc +* lib/modules/bindDyndbZone.inc * lib/modules/customBaseType.inc * lib/modules/customFields.inc * lib/modules/customScripts.inc @@ -56,6 +58,7 @@ time. * lib/modules/rfc2307bisAutomount.inc * lib/modules/rfc2307bisPosixGroup.inc * lib/modules/selfRegistration.inc +* lib/modules/simpleSecurityObject.inc * lib/modules/sudoRole.inc * lib/modules/uidObject.inc * lib/modules/webauthn.inc @@ -64,6 +67,7 @@ time. * lib/types/alias.inc * lib/types/automountType.inc * lib/types/bind.inc +* lib/types/bindDyndbType.inc * lib/types/customType.inc * lib/types/gon.inc * lib/types/kopanoAddressListType.inc @@ -94,7 +98,7 @@ All other files are licensed under the conditions below. The complete license can be found in the file COPYING or in -/usr/share/common-licenses/GPL-3. +/usr/share/common-licenses/GPL-3 (Debian/Ubuntu). Some parts of this package have other, compatible licences. These are: @@ -408,33 +412,6 @@ D: E: - Duo - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -F: 3-Clause BSD License Redistribution and use in source and binary forms, with or without @@ -463,7 +440,7 @@ F: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -G: +F: 2-Clause BSD License Redistribution and use in source and binary forms, with or without modification, @@ -487,38 +464,8 @@ G: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -H: - 3-Clause BSD License -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -I: +G: GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 @@ -973,217 +920,199 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -J: -Apache 2.0 +H: + Apache License 2.0 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1. Definitions. +## 1. Definitions. -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 +through 9 of this document. -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the +License. -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled +by, or are under common control with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract +or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. -You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and -configuration files. +"Source" form shall mean the preferred form for making modifications, including but not limited to software +source code, documentation source, and configuration files. -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object -code, generated documentation, and conversions to other media types. +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, +including but not limited to compiled object code, generated documentation, and conversions to other media +types. -"Work" shall mean the work of authorship, whether in Source or Object form, -made available under the License, as indicated by a copyright notice that is -included in or attached to the work (an example is provided in the Appendix -below). +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, +as indicated by a copyright notice that is included in or attached to the work (an example is provided in the +Appendix below). -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) +the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not +include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work +and Derivative Works thereof. -"Contribution" shall mean any work of authorship, including the original -version of the Work and any modifications or additions to that Work or -Derivative Works thereof, that is intentionally submitted to Licensor for -inclusion in the Work by the copyright owner or by an individual or Legal -Entity authorized to submit on behalf of the copyright owner. For the purposes -of this definition, "submitted" means any form of electronic, verbal, or -written communication sent to the Licensor or its representatives, including -but not limited to communication on electronic mailing lists, source code -control systems, and issue tracking systems that are managed by, or on behalf -of, the Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise designated in -writing by the copyright owner as "Not a Contribution." +"Contribution" shall mean any work of authorship, including the original version of the Work and any +modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to +Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to +submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control systems, and issue tracking systems +that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been +received by Licensor and subsequently incorporated within the Work. -3. Grant of Patent License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this -section) patent license to make, have made, use, offer to sell, sell, import, -and otherwise transfer the Work, where such license applies only to those -patent claims licensable by such Contributor that are necessarily infringed by -their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent -litigation against any entity (including a cross-claim or counterclaim in a -lawsuit) alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent -licenses granted to You under this License for that Work shall terminate as of -the date such litigation is filed. +## 2. Grant of Copyright License. -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. -(a) You must give any other recipients of the Work or Derivative Works a copy -of this License; and +## 3. Grant of Patent License. -(b) You must cause any modified files to carry prominent notices stating that -You changed the files; and +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim +or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent licenses granted to You under this +License for that Work shall terminate as of the date such litigation is filed. -(c) You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any -part of the Derivative Works; and +## 4. Redistribution. -(d) If the Work includes a "NOTICE" text file as part of its distribution, then -any Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following conditions: -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise -complies with the conditions stated in this License. + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, + trademark, and attribution notices from the Source form of the Work, excluding those notices that do + not pertain to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that + You distribute must include a readable copy of the attribution notices contained within such NOTICE + file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the Derivative Works; or, within a display + generated by the Derivative Works, if and wherever such third-party notices normally appear. The + contents of the NOTICE file are for informational purposes only and do not modify the License. You may + add Your own attribution notices within Derivative Works that You distribute, alongside or as an + addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be + construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license +terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative +Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the +conditions stated in this License. + +## 5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by +You to the Licensor shall be under the terms and conditions of this License, without any additional terms or +conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate +license agreement you may have executed with Licensor regarding such Contributions. + +## 6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of +the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. +## 7. Disclaimer of Warranty. -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any -character arising as a result of this License or out of the use or inability to -use the Work (including but not limited to damages for loss of goodwill, work -stoppage, computer failure or malfunction, or any and all other commercial -damages or losses), even if such Contributor has been advised of the -possibility of such damages. +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor +provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree -to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. +## 8. Limitation of Liability. +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless +required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any +Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential +damages of any character arising as a result of this License or out of the use or inability to use the Work +(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has been advised of the possibility +of such damages. +## 9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold +each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS Programs and licenses with other licenses and/or authors than the main license and authors: -graphics/webauthn.svg F 2017 Duo Security, Inc. -lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei -lib/3rdParty/composer/brick B Benjamin Morel -lib/3rdParty/composer/carbonphp B 2023 Carbon -lib/3rdParty/composer/christian-riesen B Christian Riesen -lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano -lib/3rdParty/composer/doctrine B Doctrine Project -lib/3rdParty/composer/duo E Cisco Systems, Inc. and/or its affiliates -lib/3rdParty/composer/facile-it B Thomas Vargiu -lib/3rdParty/composer/fgrosse B 2015 Friedrich Große -lib/3rdParty/composer/firebase F 2011 Neuman Vong -lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling -lib/3rdParty/composer/http-interop B 2016 Woody Gilk -lib/3rdParty/composer/illuminate B Taylor Otwell -lib/3rdParty/composer/nesbot B Brian Nesbitt -lib/3rdParty/composer/monolog B 2011 Jordi Boggiano -lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises -lib/3rdParty/composer/php-http B 2015 PHP HTTP Team -lib/3rdParty/composer/phpmailer I -lib/3rdParty/composer/phpseclib B 2019 TerraFrost and other contributors -lib/3rdParty/composer/psr B PHP Framework Interoperability Group -lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar -lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs -lib/3rdParty/composer/symfony B 2022 Fabien Potencier -lib/3rdParty/composer/thecodingmachine B TheCodingMachine -lib/3rdParty/composer/voku B 2019 Lars Moelleken -lib/3rdParty/composer/web-auth B 2018 Spomky-Labs -lib/3rdParty/composer/web-token B Florent Morselli -lib/3rdParty/composer/webklex B 2016 Webklex -lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD -lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah -lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB -style/010_normalize.css B Nicolas Gallagher and Jonathan Neal -style/050_grid.css B -templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors -templates/lib/*popper*.js B -templates/lib/*tippy*.js B 2021 atomiks -templates/lib/*flatpickr*.js B 2017 Gregory Petrosyan -style/600_flatpickr.css B 2017 Gregory Petrosyan -templates/lib/*sweetalert2*.js B -style/*sweetalert2*.css B -templates/lib/cropper*.js B 2018 Chen Fengyuan -style/600_cropper*.css B 2018 Chen Fengyuan -templates/lib/extra/jodit B Chupurnov -templates/lib/extra/friendlyCaptcha B -templates/lib/400_Sortable*.js B RubaXa, owenm -templates/lib/extra/jstree/* B 2014 Ivan Bozhanov -style/jstree/* B 2014 Ivan Bozhanov -templates/lib/extra/qrcode/* B 2009 Kazuhiko Arase -templates/lib/extra/tabulator/* B 2024 Oliver Folkerd -style/tabulator/* B 2024 Oliver Folkerd +graphics/webauthn.svg E 2017 Duo Security, Inc. https://github.com/duo-labs/webauthn.io +lib/3rdParty/composer/aws H Amazon Web Services https://github.com/aws/aws-sdk-php, https://github.com/awslabs/aws-crt-php +lib/3rdParty/composer/brick B Benjamin Morel https://github.com/brick/math +lib/3rdParty/composer/carbonphp B 2023 Carbon https://github.com/CarbonPHP/carbon-doctrine-types +lib/3rdParty/composer/christian-riesen B Christian Riesen https://github.com/ChristianRiesen/base32 +lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano https://github.com/composer/composer +lib/3rdParty/composer/doctrine B Doctrine Project https://github.com/doctrine +lib/3rdParty/composer/duosecurity E Cisco Systems, Inc. and/or its affiliates https://github.com/duosecurity/duo_universal_php +lib/3rdParty/composer/facile-it B Thomas Vargiu https://github.com/facile-it +lib/3rdParty/composer/firebase E 2011 Neuman Vong https://github.com/firebase/php-jwt +lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling https://github.com/guzzle/psr7 +lib/3rdParty/composer/http-interop B 2016 Woody Gilk https://github.com/http-interop/http-factory-guzzle +lib/3rdParty/composer/illuminate B Taylor Otwell https://github.com/illuminate +lib/3rdParty/composer/lcobucci B 2017 Luís Cobucci https://github.com/lcobucci/clock +lib/3rdParty/composer/monolog B 2011 Jordi Boggiano https://github.com/Seldaek/monolog +lib/3rdParty/composer/mtdowling B 2014 Michael Dowling https://github.com/jmespath/jmespath.php +lib/3rdParty/composer/nesbot B Brian Nesbitt https://github.com/CarbonPHP/carbon +lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises https://github.com/paragonie +lib/3rdParty/composer/php-http B 2015 PHP HTTP Team https://github.com/php-http/discovery +lib/3rdParty/composer/phpmailer G https://github.com/PHPMailer/PHPMailer +lib/3rdParty/composer/phpseclib B 2019 TerraFrost and other contributors https://github.com/phpseclib/phpseclib +lib/3rdParty/composer/psr B PHP Framework Interoperability Group https://github.com/php-fig +lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar https://github.com/ralouphie/getallheaders +lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs https://github.com/Spomky-Labs +lib/3rdParty/composer/symfony B 2022 Fabien Potencier https://github.com/symfony +lib/3rdParty/composer/web-auth B 2018 Spomky-Labs https://github.com/web-auth +lib/3rdParty/composer/web-token B Florent Morselli https://github.com/web-token +lib/3rdParty/composer/webklex B 2016 Webklex https://github.com/Webklex/php-imap +lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD https://github.com/tecnickcom/TCPDF +lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah https://github.com/dejavu-fonts/dejavu-fonts +lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB https://github.com/Yubico/php-yubico +style/010_normalize.css B Nicolas Gallagher and Jonathan Neal https://github.com/csstools/normalize.css +style/050_grid.css B https://foundation.zurb.com/sites/docs/v/5.5.3/components/grid.html +templates/lib/*popper*.js B https://github.com/floating-ui/floating-ui +templates/lib/*tippy*.js B 2021 atomiks https://github.com/atomiks/tippyjs +templates/lib/*flatpickr*.js B 2017 Gregory Petrosyan https://github.com/flatpickr/flatpickr +style/600_flatpickr.css B 2017 Gregory Petrosyan https://github.com/flatpickr/flatpickr +templates/lib/*sweetalert2*.js B https://github.com/sweetalert2/sweetalert2 +style/*sweetalert2*.css B https://github.com/sweetalert2/sweetalert2 +templates/lib/410_cropper*.js B 2018 Chen Fengyuan https://github.com/fengyuanchen/cropperjs +style/600_cropper*.css B 2018 Chen Fengyuan https://github.com/fengyuanchen/cropperjs +templates/lib/extra/jodit B Chupurnov https://github.com/xdan/jodit/ +templates/lib/extra/friendlyCaptcha B https://github.com/FriendlyCaptcha/friendly-challenge +templates/lib/400_Sortable*.js B RubaXa, owenm https://github.com/SortableJS/Sortable +templates/lib/extra/qrcode/* B 2009 Kazuhiko Arase https://github.com/kazuhikoarase/qrcode-generator +templates/lib/extra/tabulator/* B 2024 Oliver Folkerd https://github.com/olifolkerd/tabulator/ +style/tabulator/* B 2024 Oliver Folkerd https://github.com/olifolkerd/tabulator/ +templates/lib/extra/wunderbaum/* B 2024 Martin Wendt https://github.com/mar10/wunderbaum +style/wunderbaum/* B 2024 Martin Wendt https://github.com/mar10/wunderbaum +style/bootstrap-icons/* B 2024 The Bootstrap Authors https://icons.getbootstrap.com/ diff --git a/lam-packaging/debian/ldap-account-manager.links b/lam-packaging/debian/ldap-account-manager.links new file mode 100644 index 000000000..79de59455 --- /dev/null +++ b/lam-packaging/debian/ldap-account-manager.links @@ -0,0 +1,8 @@ +/usr/share/doc/ldap-account-manager/docs /usr/share/ldap-account-manager/docs +/etc/ldap-account-manager/config.cfg /var/lib/ldap-account-manager/config/config.cfg +/usr/share/php/phpseclib3 /usr/share/ldap-account-manager/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib +/usr/share/php/Monolog /usr/share/ldap-account-manager/lib/3rdParty/composer/monolog/monolog/src/Monolog +/usr/share/php/libphp-phpmailer /usr/share/ldap-account-manager/lib/3rdParty/composer/phpmailer/phpmailer +/var/lib/ldap-account-manager/config /usr/share/ldap-account-manager/config +/var/lib/ldap-account-manager/sess /usr/share/ldap-account-manager/sess +/var/lib/ldap-account-manager/tmp /usr/share/ldap-account-manager/tmp diff --git a/lam-packaging/debian/minify b/lam-packaging/debian/minify index 7fea7296b..bd1df62bb 100755 --- a/lam-packaging/debian/minify +++ b/lam-packaging/debian/minify @@ -8,7 +8,7 @@ if [ ! -e $outFile ]; then for file in $files; do jsFiles="$jsFiles $file" done - uglifyjs -o $outFile $jsFiles + terser $jsFiles -o $outFile rm $files # add final new line to supress Debian warnings echo "" >> $outFile diff --git a/lam-packaging/debian/postinst b/lam-packaging/debian/postinst index b9dde9f97..2c70ba11e 100755 --- a/lam-packaging/debian/postinst +++ b/lam-packaging/debian/postinst @@ -9,26 +9,6 @@ fi . /usr/share/debconf/confmodule db_version 2.0 || [ $? -lt 30 ] -# 3rd party libs -jsThirdPartyLibs='jstree' -for jsThirdPartyLib in $jsThirdPartyLibs; do - if [ ! -L /usr/share/ldap-account-manager/templates/lib/extra/${jsThirdPartyLib} ] ; then - ln -s /usr/share/javascript/${jsThirdPartyLib} /usr/share/ldap-account-manager/templates/lib/extra/${jsThirdPartyLib} - fi -done -if [ ! -L /usr/share/ldap-account-manager/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib ] ; then - ln -s /usr/share/php/phpseclib3 /usr/share/ldap-account-manager/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib -fi -if [ ! -L /usr/share/ldap-account-manager/lib/3rdParty/composer/monolog/monolog/src/Monolog ] ; then - ln -s /usr/share/php/Monolog /usr/share/ldap-account-manager/lib/3rdParty/composer/monolog/monolog/src/Monolog -fi -if [ ! -L /usr/share/ldap-account-manager/lib/3rdParty/composer/voku/portable-ascii/src/voku ] ; then - ln -s /usr/share/php/voku /usr/share/ldap-account-manager/lib/3rdParty/composer/voku/portable-ascii/src/voku -fi -if [ ! -L /usr/share/ldap-account-manager/lib/3rdParty/composer/phpmailer/phpmailer ] ; then - ln -s /usr/share/php/libphp-phpmailer /usr/share/ldap-account-manager/lib/3rdParty/composer/phpmailer/phpmailer -fi - cd /usr/share/ldap-account-manager/config-samples/profiles files=`ls -a default.*` for file in $files; do @@ -51,15 +31,7 @@ for file in $files; do cp $file /var/lib/ldap-account-manager/config/templates/pdf/logos/$file chown www-data /var/lib/ldap-account-manager/config/templates/pdf/logos/$file done -if [ ! -h /usr/share/ldap-account-manager/config ]; then - ln -s /var/lib/ldap-account-manager/config /usr/share/ldap-account-manager/config -fi -if [ ! -h /usr/share/ldap-account-manager/sess ]; then - ln -s /var/lib/ldap-account-manager/sess /usr/share/ldap-account-manager/sess -fi -if [ ! -h /usr/share/ldap-account-manager/tmp ]; then - ln -s /var/lib/ldap-account-manager/tmp /usr/share/ldap-account-manager/tmp -fi + chmod 700 /var/lib/ldap-account-manager/config chmod 700 /var/lib/ldap-account-manager/tmp chmod 700 /var/lib/ldap-account-manager/sess diff --git a/lam-packaging/debian/rules b/lam-packaging/debian/rules index b71120b4d..d9f7ee47d 100755 --- a/lam-packaging/debian/rules +++ b/lam-packaging/debian/rules @@ -51,7 +51,6 @@ install: cp -r lib/3rdParty/composer debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/ rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/composer/monolog/monolog/src/Monolog - rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/composer/voku/portable-ascii/src/voku rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/composer/phpmailer/phpmailer cp -r lib/3rdParty/yubico debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/ cp -r lib/3rdParty/tcpdf debian/ldap-account-manager/usr/share/ldap-account-manager/lib/3rdParty/ @@ -60,7 +59,6 @@ install: install -D --mode=644 sess/.htaccess debian/ldap-account-manager/var/lib/ldap-account-manager/sess/.htaccess cp -r style debian/ldap-account-manager/usr/share/ldap-account-manager/ cp -r templates debian/ldap-account-manager/usr/share/ldap-account-manager/ - rm -r debian/ldap-account-manager/usr/share/ldap-account-manager/templates/lib/extra/jstree install -D --mode=755 lib/lamdaemon.pl debian/ldap-account-manager-lamdaemon/usr/share/ldap-account-manager/lib/lamdaemon.pl install -D --mode=755 debian/README-lamdaemon.Debian debian/ldap-account-manager-lamdaemon/usr/share/doc/ldap-account-manager-lamdaemon/README.Debian @@ -77,12 +75,11 @@ binary-indep: build install dh_install dh_compress dh_fixperms - dh_link /usr/share/doc/ldap-account-manager/docs /usr/share/ldap-account-manager/docs install -D --mode=644 debian/lam.apache.conf debian/ldap-account-manager/etc/ldap-account-manager/apache.conf install -D --mode=644 debian/lam.nginx.conf debian/ldap-account-manager/etc/ldap-account-manager/nginx.conf install -D --mode=644 config/config.cfg.sample debian/ldap-account-manager/etc/ldap-account-manager/config.cfg + dh_link chown www-data debian/ldap-account-manager/etc/ldap-account-manager/config.cfg - dh_link /etc/ldap-account-manager/config.cfg /var/lib/ldap-account-manager/config/config.cfg chown www-data debian/ldap-account-manager/etc/ldap-account-manager/config.cfg chown -R www-data debian/ldap-account-manager/var/lib/ldap-account-manager/config chown www-data debian/ldap-account-manager/var/lib/ldap-account-manager/tmp diff --git a/lam-packaging/docker/.env b/lam-packaging/docker/.env index f9e002dd4..f32188645 100644 --- a/lam-packaging/docker/.env +++ b/lam-packaging/docker/.env @@ -15,10 +15,12 @@ LDAP_GROUPS_DN=ou=groups,dc=my-domain,dc=com # LDAP server URL LDAP_SERVER=ldap://ldap:389 # LDAP admin user (set as login user for LAM) +# Use LDAP_USER_FILE to read the value from a file (e.g. for Docker swarm: docker service create --secret LDAP_USER -e LDAP_USER_FILE=/run/secrets/LDAP_USER ...) LDAP_USER=cn=admin,dc=my-domain,dc=com # default language, e.g. en_US, de_DE, fr_FR, ... LAM_LANG=en_US # LAM configuration master password and password for server profile "lam" +# Use LAM_PASSWORD_FILE to read the value from a file (e.g. for Docker swarm: docker service create --secret LAM_PASSWORD -e LAM_PASSWORD_FILE=/run/secrets/LAM_PASSWORD ...) LAM_PASSWORD=lam # run cron jobs (LAM Pro) LAM_CONFIGURE_CRON=false @@ -32,11 +34,13 @@ LAM_CONFIGURATION_PORT= # MySQL user name if database is mysql LAM_CONFIGURATION_USER= # MySQL password if database is mysql +# Use LAM_CONFIGURATION_PASSWORD_FILE to read the value from a file (e.g. for Docker swarm: docker service create --secret LAM_CONFIGURATION_PASSWORD -e LAM_CONFIGURATION_PASSWORD_FILE=/run/secrets/LAM_CONFIGURATION_PASSWORD ...) LAM_CONFIGURATION_PASSWORD= # MySQL database name if database is mysql LAM_CONFIGURATION_DATABASE_NAME= # LAM Pro license (line breaks can be removed) +# Use LAM_LICENSE_FILE to read the value from a file (e.g. for Docker swarm: docker service create --secret LAM_LICENSE -e LAM_LICENSE_FILE=/run/secrets/LAM_LICENSE ...) LAM_LICENSE= # deactivate TLS certificate checks, activate for development only diff --git a/lam-packaging/docker/Dockerfile b/lam-packaging/docker/Dockerfile index ef944fa57..807b7ff82 100644 --- a/lam-packaging/docker/Dockerfile +++ b/lam-packaging/docker/Dockerfile @@ -2,7 +2,7 @@ # Docker image for LDAP Account Manager # This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) -# Copyright (C) 2019 - 2024 Roland Gruber +# Copyright (C) 2019 - 2025 Roland Gruber # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ FROM debian:bookworm-slim LABEL maintainer="Roland Gruber " -ARG LAM_RELEASE=9.0.RC1 +ARG LAM_RELEASE=9.3 EXPOSE 80 ENV \ @@ -44,6 +44,7 @@ RUN apt-get install -y locales RUN sed -i 's/^# *\(ca_ES.UTF-8\)/\1/' /etc/locale.gen && \ sed -i 's/^# *\(cz_CZ.UTF-8\)/\1/' /etc/locale.gen && \ sed -i 's/^# *\(de_DE.UTF-8\)/\1/' /etc/locale.gen && \ + sed -i 's/^# *\(el_GR.UTF-8\)/\1/' /etc/locale.gen && \ sed -i 's/^# *\(en_GB.UTF-8\)/\1/' /etc/locale.gen && \ sed -i 's/^# *\(en_US.UTF-8\)/\1/' /etc/locale.gen && \ sed -i 's/^# *\(es_ES.UTF-8\)/\1/' /etc/locale.gen && \ @@ -82,12 +83,12 @@ RUN apt-get install --no-install-recommends -y \ php-mysql \ php-sqlite3 \ php-mbstring \ + php-opcache \ + php-apcu \ wget \ libldap-common \ gettext \ - libjs-jquery-jstree \ php-phpseclib3 \ - php-voku-portable-ascii \ libphp-phpmailer \ cron \ && \ diff --git a/lam-packaging/docker/docker-compose.yml b/lam-packaging/docker/docker-compose.yml index ef89ebe1a..9f3365b7c 100644 --- a/lam-packaging/docker/docker-compose.yml +++ b/lam-packaging/docker/docker-compose.yml @@ -3,7 +3,7 @@ services: ldap-account-manager: build: context: . - image: ldapaccountmanager/lam:9.0.RC1 + image: ldapaccountmanager/lam:9.3 restart: unless-stopped ports: - "8080:80" diff --git a/lam-packaging/docker/start.sh b/lam-packaging/docker/start.sh index bf5db8d9d..3cbd04b98 100755 --- a/lam-packaging/docker/start.sh +++ b/lam-packaging/docker/start.sh @@ -4,7 +4,7 @@ # This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) # Copyright (C) 2019 Felix Bartels -# 2019 - 2024 Roland Gruber +# 2019 - 2025 Roland Gruber # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -42,14 +42,13 @@ if [ "$LAM_SKIP_PRECONFIGURE" != "true" ]; then echo "Configuring LAM" LAM_LANG="${LAM_LANG:-en_US}" - export LAM_PASSWORD="${LAM_PASSWORD:-lam}" - LAM_PASSWORD_SSHA=$(php -r '$password = getenv("LAM_PASSWORD"); $rand = abs(hexdec(bin2hex(openssl_random_pseudo_bytes(5)))); $salt0 = substr(pack("h*", md5($rand)), 0, 8); $salt = substr(pack("H*", sha1($salt0 . $password)), 0, 4); print "{SSHA}" . base64_encode(pack("H*", sha1($password . $salt))) . " " . base64_encode($salt) . "\n";') + LAM_PASSWORD="${LAM_PASSWORD:-lam}" LDAP_SERVER="${LDAP_SERVER:-ldap://ldap:389}" LDAP_DOMAIN="${LDAP_DOMAIN:-my-domain.com}" LDAP_BASE_DN="${LDAP_BASE_DN:-dc=${LDAP_DOMAIN//\./,dc=}}" LDAP_USERS_DN="${LDAP_USERS_DN:-${LDAP_BASE_DN}}" LDAP_GROUPS_DN="${LDAP_GROUPS_DN:-${LDAP_BASE_DN}}" - LDAP_ADMIN_USER="${LDAP_USER:-cn=admin,${LDAP_BASE_DN}}" + LDAP_USER="${LDAP_USER:-cn=admin,${LDAP_BASE_DN}}" LAM_LICENSE="${LAM_LICENSE:-}" LAM_CONFIGURATION_DATABASE="${LAM_CONFIGURATION_DATABASE:-files}" LAM_CONFIGURATION_HOST="${LAM_CONFIGURATION_HOST:-}" @@ -58,8 +57,32 @@ if [ "$LAM_SKIP_PRECONFIGURE" != "true" ]; then LAM_CONFIGURATION_USER="${LAM_CONFIGURATION_USER:-}" LAM_CONFIGURATION_PASSWORD="${LAM_CONFIGURATION_PASSWORD:-}" + # Set an environment variable with the _FILE suffix to override the non-suffixed environment variable with the contents of the specified file + fileVariables=( + LDAP_USER + LAM_PASSWORD + LAM_CONFIGURATION_PASSWORD + LAM_LICENSE + ) + + for envVar in "${fileVariables[@]}"; do + fileEnvVar="${envVar}_FILE" + if [[ -n "${!fileEnvVar:-}" ]]; then + if [[ -r "${!fileEnvVar:-}" ]]; then + export "${envVar}=$(< "${!fileEnvVar}")" + unset "${fileEnvVar}" + else + warn "Skipping export of '${envVar}'. '${!fileEnvVar:-}' is not readable." + fi + fi + done + unset fileVariables + + export LAM_PASSWORD + LAM_PASSWORD_SSHA=$(php -r '$password = getenv("LAM_PASSWORD"); $rand = abs(hexdec(bin2hex(openssl_random_pseudo_bytes(5)))); $salt0 = substr(pack("h*", md5($rand)), 0, 8); $salt = substr(pack("H*", sha1($salt0 . $password)), 0, 4); print "{SSHA}" . base64_encode(pack("H*", sha1($password . $salt))) . " " . base64_encode($salt) . "\n";') + unset LAM_PASSWORD + sed -i -f- /etc/ldap-account-manager/config.cfg <<- EOF - s|"password": "[^"]*"|"password": "${LAM_PASSWORD_SSHA}"|; s|"license": "[^"]*"|"license": "${LAM_LICENSE}"|; s|"configDatabaseType": "[^"]*"|"configDatabaseType": "${LAM_CONFIGURATION_DATABASE}"|; s|"configDatabaseServer": "[^"]*"|"configDatabaseServer": "${LAM_CONFIGURATION_HOST}"|; @@ -68,7 +91,11 @@ if [ "$LAM_SKIP_PRECONFIGURE" != "true" ]; then s|"configDatabaseUser": "[^"]*"|"configDatabaseUser": "${LAM_CONFIGURATION_USER}"|; s|"configDatabasePassword": "[^"]*"|"configDatabasePassword": "${LAM_CONFIGURATION_PASSWORD}"|; EOF - unset LAM_PASSWORD + if ! grep -e '"password":' /etc/ldap-account-manager/config.cfg > /dev/null; then + sed -i "2i\ \ \"password\": \"${LAM_PASSWORD_SSHA}\"," /etc/ldap-account-manager/config.cfg + else + sed -i "s|\"password\": .*|\"password\": \"${LAM_PASSWORD_SSHA}\",|" /etc/ldap-account-manager/config.cfg + fi set +e ls -l /var/lib/ldap-account-manager/config/lam.conf @@ -81,13 +108,17 @@ EOF sed -i -f- /var/lib/ldap-account-manager/config/lam.conf <<- EOF s|"ServerURL": "[^"]*"|"ServerURL": "${LDAP_SERVER}"|; - s|"Admins": "[^"]*"|"Admins": "${LDAP_ADMIN_USER}"|; - s|"Passwd": "[^"]*"|"Passwd": "${LAM_PASSWORD_SSHA}"|; + s|"Admins": "[^"]*"|"Admins": "${LDAP_USER}"|; s|"treeViewSuffix": "[^"]*"|"treeViewSuffix": "${LDAP_BASE_DN}"|; s|"defaultLanguage": "[^"]*"|"defaultLanguage": "${LAM_LANG}.utf8"|; s|"suffix_user": "[^"]*"|"suffix_user": "${LDAP_USERS_DN}"|; s|"suffix_group": "[^"]*"|"suffix_group": "${LDAP_GROUPS_DN}"|; EOF + if ! grep -e '"Passwd":' /var/lib/ldap-account-manager/config/lam.conf > /dev/null; then + sed -i "2i\ \ \"Passwd\": \"${LAM_PASSWORD_SSHA}\"," /var/lib/ldap-account-manager/config/lam.conf + else + sed -i "s|\"Passwd\": .*|\"Passwd\": \"${LAM_PASSWORD_SSHA}\",|" /var/lib/ldap-account-manager/config/lam.conf + fi fi diff --git a/lam/HISTORY b/lam/HISTORY index 02bc7b542..f64845d5e 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,6 +1,56 @@ -December 2024 9.0 +December 2025 9.4 + - Main configuration and server profiles require latest file format (introduced in 9.0) (389) + - LAM Pro: + -> SMS sending can be done with email2SMS providers (465) + + +16.09.2025 9.3 + - New translation: Greek + - Tree view: added comparison feature (440) + - Windows: added logon hours (457) + - Lamdaemon: run /usr/sbin/userdel.local before (and no longer after) home directory is deleted (443) + - LAM Pro: + -> SMS support for password sending and password self-reset (441) + -> Self-Service: clear PPolicy "pwdReset" on password change if needed (448) + - Fixed bugs: + -> WebAuthn: 2-factor verification failed: Unable to load the data (453) + -> Random password generator does not respect server profile rules (458) + -> XSS in profile editor (low, CVE-2025-58174) + + +06.06.2025 9.2 + - PHP 8.4 compatibility + - TAK support added + - Active Directory: allow to restore deleted entries in tree view (415) + - Multi-edit tool: change operations are combined by DN to allow e.g. adding object classes with required attributes (408) + - Windows users: support thumbnail images (needs to be activated in server profile) (431) + - Tree view: better editing of olcAccess (420) + - LAM Pro: + -> Custom scripts: split config by account type (409) + - Fixed bugs: + -> Unix: profile editor for users not working (418) + -> Custom fields: problems with deleting facsimileTelephoneNumber (419) + -> Cannot add user (windowsUser) to group (windowsGroup) (444) + + +13.03.2025 9.1 + - Usability improvements (347, 348, 360, 403) + - Active Directory: deleted entries in "CN=Deleted Objects" can be shown (option in server profile, advanced settings) + - Security: LAM no longer ships with any default passwords, main configuration password is requested on login if not yet set (390) + - Docker: support to read e.g. configuration password from file to support Docker swarm + - LAM Pro: + -> Added support to manage DNS entries of bind-dyndb-ldap (361) + -> Unix users: support to create a group with same name for rfc2307bis (404) + - Fixed bugs: + -> Ambiguous tooltip on profile editor for Shadow users (394) + -> Self service photo file enhancements (396) + -> Tree view: delete does not work in French (406) + -> Cron job mails: show all values for multi-value attribute wildcards (411) + + +17.12.2024 9.0 - New configuration file format for main configuration and server profiles (applied on save, old format can still be read) - - Unix users: allow to create group with same name via account profile (#332) + - Unix users: allow to create group with same name via account profile (332) - Group of (unique) names, organisational roles: added member/owner count to PDF fields - Windows: display password expiration date - Usability improvements (342, 350, 372) @@ -13,6 +63,7 @@ December 2024 9.0 -> Docker: added option to run cron jobs (346) -> Windows: use msDS-UserPasswordExpiryTimeComputed for password expiration job (387) - Fixed bugs: + -> Security fix: Set arbitrary config values due to improper input validation for config values (GHSA-6cp9-j5r7-xhcc, CVE-2024-52792) -> Windows: show more than 1000 LDAP entries when paged results is activated in server profile -> WebAuthn: support DNs larger than 64 bytes (358) -> Wildcard replacements do not work without switching to the module tab (379) @@ -26,7 +77,7 @@ December 2024 9.0 -> Self registration: added option to generate password -> Request access: allow to define an expiration time for memberships/ownerships (284) -> Request access: support additional group next to owners (300) - -> Request access: auto-refresh views (#324) + -> Request access: auto-refresh views (324) - Fixed bugs: -> Unix users: error log messages on file upload @@ -247,8 +298,8 @@ December 2024 9.0 - PHP 8.0 compatibility (except tree view) - Support copying LDAP entries from account list - Account/PDF profiles: management of global templates and logos - - Group of names: allow filter by member/owner (#151) - - General information: link to groups (#152) + - Group of names: allow filter by member/owner (151) + - General information: link to groups (152) - LAM Pro: -> Self registration: support binary attributes (e.g. for jpegPhoto) -> Self registration: support custom mail attributes and mail from constant value (149) @@ -260,7 +311,7 @@ December 2024 9.0 06.12.2020 7.4 - - Argond2id support for password hashes (requires PHP 7.3) (#113) + - Argond2id support for password hashes (requires PHP 7.3) (113) - 2-factor authentication: -> Support for Okta -> WebAuthn devices can be named in Self Service and WebAuthn tool @@ -386,7 +437,7 @@ December 2024 9.0 - LAM Pro: -> Auto deletion of entries with dynamic directory services support (requires PHP 7.2) - Fixed bugs: - -> Issue when changing key case of uid (#197) + -> Issue when changing key case of uid (197) 20.06.2018 6.4 diff --git a/lam/README b/lam/README index 53812faed..a7bd58eb9 100644 --- a/lam/README +++ b/lam/README @@ -15,9 +15,6 @@ LAM - Readme Installation and documentation: Please see the LAM manual in docs/manual/index.html. - Default password: - The default password to edit the configuration options is "lam". - Download: You can get the newest version at https://www.ldap-account-manager.org/. @@ -25,4 +22,4 @@ LAM - Readme LAM is published under the GNU General Public License. The complete list of licenses can be found in the copyright file. - Copyright (C) 2003 - 2024 Roland Gruber + Copyright (C) 2003 - 2025 Roland Gruber diff --git a/lam/VERSION b/lam/VERSION index 57a831718..c3cae12bc 100644 --- a/lam/VERSION +++ b/lam/VERSION @@ -1 +1 @@ -9.0.RC1 +9.3 diff --git a/lam/composer.json b/lam/composer.json index 2cb20efc3..140bb004c 100644 --- a/lam/composer.json +++ b/lam/composer.json @@ -1,6 +1,6 @@ { "name": "ldap-account-manager/ldap-account-manager", - "version": "9.0", + "version": "9.3", "config": { "vendor-dir": "lib/3rdParty/composer", "platform": { @@ -10,22 +10,34 @@ "php-http/discovery": false } }, - "require" : { - "web-auth/webauthn-lib" : "^4", + "require": { + "web-auth/webauthn-lib": "^4", "web-auth/cose-lib": "^v4", - "web-auth/metadata-service": "^4", - "symfony/psr-http-message-bridge" : "^6", - "symfony/http-foundation" : "^6.0", + "symfony/psr-http-message-bridge": "^6", + "symfony/http-foundation": "^6.0", "symfony/http-client": "^6", "http-interop/http-factory-guzzle": "^1.2", - "webklex/php-imap" : "^5.5", + "webklex/php-imap": "^6", "phpmailer/phpmailer": "~6.5", "guzzlehttp/psr7": "^2", "paragonie/random_compat": "^2.0", "phpseclib/phpseclib": "^3.0", "christian-riesen/base32": "^1.6", + "facile-it/php-openid-client": "^0", + "spomky-labs/aes-key-wrap": "^7", + "monolog/monolog": "^3", - "duosecurity/duo_universal_php": "^1.0" + "duosecurity/duo_universal_php": "^1.0", + + "aws/aws-sdk-php": "^3" + }, + "scripts": { + "pre-autoload-dump": "Aws\\Script\\Composer\\Composer::removeUnusedServices" + }, + "extra": { + "aws/aws-sdk-php": [ + "Sns" + ] } } diff --git a/lam/composer.lock b/lam/composer.lock index b5c76bc14..826d80567 100644 --- a/lam/composer.lock +++ b/lam/composer.lock @@ -4,97 +4,180 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e65b6b4acb9ae7806399f8439e4c9004", + "content-hash": "84529a49d7eba6207d716b7bc9726826", "packages": [ { - "name": "beberlei/assert", - "version": "v3.3.3", + "name": "aws/aws-crt-php", + "version": "v1.2.7", "source": { "type": "git", - "url": "https://github.com/beberlei/assert.git", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd" + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/b5fd8eacd8915a1b627b8bfc027803f1939734dd", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-simplexml": "*", - "php": "^7.1 || ^8.0" + "php": ">=5.5" }, "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": ">=6.0.0", - "yoast/phpunit-polyfills": "^0.1.0" + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." }, "type": "library", "autoload": { - "files": [ - "lib/Assert/functions.php" - ], - "psr-4": { - "Assert\\": "lib/Assert" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "Apache-2.0" ], "authors": [ { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de", - "role": "Lead Developer" - }, - { - "name": "Richard Quadling", - "email": "rquadling@gmail.com", - "role": "Collaborator" + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" } ], - "description": "Thin assertion library for input validation in business models.", + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", "keywords": [ - "assert", - "assertion", - "validation" + "amazon", + "aws", + "crt", + "sdk" ], "support": { - "issues": "https://github.com/beberlei/assert/issues", - "source": "https://github.com/beberlei/assert/tree/v3.3.3" + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" }, - "time": "2024-07-15T13:18:35+00:00" + "time": "2024-10-18T22:15:13+00:00" }, { - "name": "brick/math", - "version": "0.9.3", + "name": "aws/aws-sdk-php", + "version": "3.356.8", "source": { "type": "git", - "url": "https://github.com/brick/math.git", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3efa8c62c11fedb17b90f60b2d3a9f815b406e63", + "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63", "shasum": "" }, "require": { + "aws/aws-crt-php": "^1.2.3", "ext-json": "*", - "php": "^7.1 || ^8.0" + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "symfony/filesystem": "^v6.4.0 || ^v7.1.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.356.8" + }, + "time": "2025-08-29T18:06:18+00:00" + }, + { + "name": "brick/math", + "version": "0.12.3", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", + "shasum": "" + }, + "require": { + "php": "^8.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.9.2" + "phpunit/phpunit": "^10.1", + "vimeo/psalm": "6.8.8" }, "type": "library", "autoload": { @@ -114,24 +197,25 @@ "arithmetic", "bigdecimal", "bignum", + "bignumber", "brick", - "math" + "decimal", + "integer", + "math", + "mathematics", + "rational" ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.3" + "source": "https://github.com/brick/math/tree/0.12.3" }, "funding": [ { "url": "https://github.com/BenMorel", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" } ], - "time": "2021-08-15T20:50:18+00:00" + "time": "2025-02-28T13:11:00+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -263,33 +347,38 @@ }, { "name": "doctrine/inflector", - "version": "2.0.10", + "version": "1.4.4", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector", + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -334,7 +423,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/1.4.4" }, "funding": [ { @@ -350,27 +439,27 @@ "type": "tidelift" } ], - "time": "2024-02-18T20:23:39+00:00" + "time": "2021-04-16T17:34:40+00:00" }, { "name": "duosecurity/duo_universal_php", - "version": "1.0.2", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/duosecurity/duo_universal_php.git", - "reference": "8734a47480d2d2f0539e8ee782675e052025d026" + "reference": "4ee7253863d84653a60a8cad4b03aa3b66fcfd35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/duosecurity/duo_universal_php/zipball/8734a47480d2d2f0539e8ee782675e052025d026", - "reference": "8734a47480d2d2f0539e8ee782675e052025d026", + "url": "https://api.github.com/repos/duosecurity/duo_universal_php/zipball/4ee7253863d84653a60a8cad4b03aa3b66fcfd35", + "reference": "4ee7253863d84653a60a8cad4b03aa3b66fcfd35", "shasum": "" }, "require": { "ext-curl": "*", "ext-json": "*", "firebase/php-jwt": "^6.0", - "php": ">=7.3" + "php": ">=7.4" }, "require-dev": { "phpunit/phpunit": "^9.0", @@ -383,69 +472,73 @@ } }, "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], "description": "A PHP implementation of the Duo Universal SDK.", "homepage": "https://duo.com/", "support": { "email": "support@duosecurity.com", "issues": "https://github.com/duosecurity/duo_universal_php/issues", - "source": "https://github.com/duosecurity/duo_universal_php/tree/1.0.2" + "source": "https://github.com/duosecurity/duo_universal_php/tree/1.1.1" }, - "time": "2023-01-13T18:47:58+00:00" + "time": "2025-08-13T14:05:56+00:00" }, { "name": "facile-it/php-jose-verifier", - "version": "0.3.0", + "version": "0.4.5", "source": { "type": "git", "url": "https://github.com/facile-it/php-jose-verifier.git", - "reference": "b6a3d17896dec0c3e383c0ae83b7be855b8fd247" + "reference": "fe7e092f90ad2a624e69ae989a781258805d9ed0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facile-it/php-jose-verifier/zipball/b6a3d17896dec0c3e383c0ae83b7be855b8fd247", - "reference": "b6a3d17896dec0c3e383c0ae83b7be855b8fd247", + "url": "https://api.github.com/repos/facile-it/php-jose-verifier/zipball/fe7e092f90ad2a624e69ae989a781258805d9ed0", + "reference": "fe7e092f90ad2a624e69ae989a781258805d9ed0", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.2 || ^8.0", "php-http/discovery": "^1.7", + "psr/clock": "^1.0", "psr/http-client": "^1.0", - "psr/http-message": "^1.0", - "psr/simple-cache": "^1.0", + "psr/http-message": "^1.0 || 2.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "spomky-labs/base64url": "^2.0.1", "symfony/polyfill-mbstring": "^1.15", - "web-token/jwt-checker": "^2.2.0", - "web-token/jwt-core": "^2.2.0", - "web-token/jwt-easy": "^2.2.0", - "web-token/jwt-key-mgmt": "^2.2.0", - "web-token/jwt-signature": "^2.2.0", - "web-token/jwt-signature-algorithm-rsa": "^2.2.0" + "web-token/jwt-checker": "^2.2.0 || ^3.0", + "web-token/jwt-core": "^2.2.0 || ^3.0", + "web-token/jwt-key-mgmt": "^2.2.0 || ^3.0", + "web-token/jwt-signature": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-rsa": "^2.2.0 || ^3.0" }, "require-dev": { - "facile-it/facile-coding-standard": "^0.4.1", - "friendsofphp/php-cs-fixer": "^2.16.1", - "laminas/laminas-diactoros": "^2.2", + "facile-it/facile-coding-standard": "^0.5", + "friendsofphp/php-cs-fixer": "^3.0", + "laminas/laminas-diactoros": "^2.2 || ^3.0.0", "php-http/curl-client": "^2.1", "phpspec/prophecy-phpunit": "^1.1 || ^2.0", "phpunit/phpunit": "^8.5.14 || ^9.3", - "vimeo/psalm": "^4.4.1", - "web-token/jwt-encryption": "^2.2.0", - "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0", - "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0", - "web-token/jwt-encryption-algorithm-dir": "^2.2.0", - "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0", - "web-token/jwt-encryption-algorithm-experimental": "^2.2.0", - "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0", - "web-token/jwt-encryption-algorithm-rsa": "^2.2.0", - "web-token/jwt-nested-token": "^2.2.0", - "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0", - "web-token/jwt-signature-algorithm-experimental": "^2.2.0", - "web-token/jwt-signature-algorithm-hmac": "^2.2.0", - "web-token/jwt-signature-algorithm-none": "^2.2.0", - "web-token/jwt-util-ecc": "^2.2.0" + "vimeo/psalm": "^4.30.0 || ^5.13.1", + "web-token/jwt-checker": "^2.2.0 || ^3.2.0", + "web-token/jwt-encryption": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-dir": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-rsa": "^2.2.0 || ^3.0", + "web-token/jwt-nested-token": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-hmac": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-none": "^2.2.0 || ^3.0", + "web-token/jwt-util-ecc": "^2.2.0 || ^3.0" }, "type": "library", "autoload": { @@ -484,9 +577,9 @@ ], "support": { "issues": "https://github.com/facile-it/php-jose-verifier/issues", - "source": "https://github.com/facile-it/php-jose-verifier/tree/0.3.0" + "source": "https://github.com/facile-it/php-jose-verifier/tree/0.4.5" }, - "time": "2021-05-05T11:57:42+00:00" + "time": "2024-04-27T09:47:19+00:00" }, { "name": "facile-it/php-openid-client", @@ -600,94 +693,18 @@ }, "time": "2023-11-21T10:07:21+00:00" }, - { - "name": "fgrosse/phpasn1", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/fgrosse/PHPASN1.git", - "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b", - "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "~2.0", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "suggest": { - "ext-bcmath": "BCmath is the fallback extension for big integer calculations", - "ext-curl": "For loading OID information from the web if they have not bee defined statically", - "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" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "FG\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Friedrich Große", - "email": "friedrich.grosse@gmail.com", - "homepage": "https://github.com/FGrosse", - "role": "Author" - }, - { - "name": "All contributors", - "homepage": "https://github.com/FGrosse/PHPASN1/contributors" - } - ], - "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", - "homepage": "https://github.com/FGrosse/PHPASN1", - "keywords": [ - "DER", - "asn.1", - "asn1", - "ber", - "binary", - "decoding", - "encoding", - "x.509", - "x.690", - "x509", - "x690" - ], - "support": { - "issues": "https://github.com/fgrosse/PHPASN1/issues", - "source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0" - }, - "abandoned": true, - "time": "2022-12-19T11:08:26+00:00" - }, { "name": "firebase/php-jwt", - "version": "v6.10.2", + "version": "v6.11.1", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b" + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/30c19ed0f3264cb660ea496895cfb6ef7ee3653b", - "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", "shasum": "" }, "require": { @@ -735,22 +752,231 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v6.10.2" + "source": "https://github.com/firebase/php-jwt/tree/v6.11.1" }, - "time": "2024-11-24T11:22:49+00:00" + "time": "2025-04-09T20:32:01+00:00" }, { - "name": "guzzlehttp/psr7", - "version": "2.7.0", + "name": "guzzlehttp/guzzle", + "version": "7.10.0", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -766,7 +992,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -837,7 +1063,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -853,7 +1079,7 @@ "type": "tidelift" } ], - "time": "2024-07-18T11:15:46+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "http-interop/http-factory-guzzle", @@ -913,130 +1139,27 @@ }, "time": "2021-07-21T13:50:14+00:00" }, - { - "name": "illuminate/collections", - "version": "v10.48.25", - "source": { - "type": "git", - "url": "https://github.com/illuminate/collections.git", - "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/48de3d6bc6aa779112ddcb608a3a96fc975d89d8", - "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8", - "shasum": "" - }, - "require": { - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "php": "^8.1" - }, - "suggest": { - "symfony/var-dumper": "Required to use the dump method (^6.2)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "autoload": { - "files": [ - "helpers.php" - ], - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Collections package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "time": "2024-11-21T14:02:44+00:00" - }, - { - "name": "illuminate/conditionable", - "version": "v10.48.25", - "source": { - "type": "git", - "url": "https://github.com/illuminate/conditionable.git", - "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", - "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", - "shasum": "" - }, - "require": { - "php": "^8.0.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Conditionable package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "time": "2024-11-21T14:02:44+00:00" - }, { "name": "illuminate/contracts", - "version": "v10.48.25", + "version": "v5.4.36", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74" + "reference": "67f642e018f3e95fb0b2ebffc206c3200391b1ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/f90663a69f926105a70b78060a31f3c64e2d1c74", - "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/67f642e018f3e95fb0b2ebffc206c3200391b1ab", + "reference": "67f642e018f3e95fb0b2ebffc206c3200391b1ab", "shasum": "" }, "require": { - "php": "^8.1", - "psr/container": "^1.1.1|^2.0.1", - "psr/simple-cache": "^1.0|^2.0|^3.0" + "php": ">=5.6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "autoload": { @@ -1060,79 +1183,31 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-11-21T14:02:44+00:00" - }, - { - "name": "illuminate/macroable", - "version": "v10.48.25", - "source": { - "type": "git", - "url": "https://github.com/illuminate/macroable.git", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Macroable package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "time": "2023-06-05T12:46:42+00:00" + "time": "2017-08-26T23:56:53+00:00" }, { "name": "illuminate/pagination", - "version": "v10.48.25", + "version": "v5.4.36", "source": { "type": "git", "url": "https://github.com/illuminate/pagination.git", - "reference": "616874b9607ff35925347e1710a8b5151858cdf2" + "reference": "ae1540acf02c8b642666d6901c18d2deb5606b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/pagination/zipball/616874b9607ff35925347e1710a8b5151858cdf2", - "reference": "616874b9607ff35925347e1710a8b5151858cdf2", + "url": "https://api.github.com/repos/illuminate/pagination/zipball/ae1540acf02c8b642666d6901c18d2deb5606b47", + "reference": "ae1540acf02c8b642666d6901c18d2deb5606b47", "shasum": "" }, "require": { - "ext-filter": "*", - "illuminate/collections": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0", - "php": "^8.1" + "illuminate/contracts": "5.4.*", + "illuminate/support": "5.4.*", + "php": ">=5.6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "autoload": { @@ -1156,51 +1231,41 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-04-11T14:31:05+00:00" + "time": "2017-07-24T13:37:02+00:00" }, { "name": "illuminate/support", - "version": "v10.48.25", + "version": "v5.4.36", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c" + "reference": "feab1d1495fd6d38970bd6c83586ba2ace8f299a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/64b258f80175c658aef9e22dd3f2ba18c99b243c", - "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c", + "url": "https://api.github.com/repos/illuminate/support/zipball/feab1d1495fd6d38970bd6c83586ba2ace8f299a", + "reference": "feab1d1495fd6d38970bd6c83586ba2ace8f299a", "shasum": "" }, "require": { - "doctrine/inflector": "^2.0", - "ext-ctype": "*", - "ext-filter": "*", + "doctrine/inflector": "~1.1", "ext-mbstring": "*", - "illuminate/collections": "^10.0", - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "nesbot/carbon": "^2.67", - "php": "^8.1", - "voku/portable-ascii": "^2.0" + "illuminate/contracts": "5.4.*", + "paragonie/random_compat": "~1.4|~2.0", + "php": ">=5.6.4" }, - "conflict": { - "tightenco/collect": "<5.5.33" + "replace": { + "tightenco/collect": "self.version" }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (^10.0).", - "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", - "ramsey/uuid": "Required to use Str::uuid() (^4.7).", - "symfony/process": "Required to use the composer class (^6.2).", - "symfony/uid": "Required to use Str::ulid() (^6.2).", - "symfony/var-dumper": "Required to use the dd function (^6.2).", - "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." + "illuminate/filesystem": "Required to use the composer class (5.2.*).", + "symfony/process": "Required to use the composer class (~3.2).", + "symfony/var-dumper": "Required to use the dd function (~3.2)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "autoload": { @@ -1227,20 +1292,84 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-11-21T14:02:44+00:00" + "time": "2017-08-15T13:25:41+00:00" }, { - "name": "monolog/monolog", - "version": "3.8.0", + "name": "lcobucci/clock", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" + "url": "https://github.com/lcobucci/clock.git", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "infection/infection": "^0.26", + "lcobucci/coding-standard": "^9.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-deprecation-rules": "^1.1.1", + "phpstan/phpstan-phpunit": "^1.3.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.27" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2022-12-19T15:00:24+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -1318,7 +1447,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.8.0" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -1330,56 +1459,116 @@ "type": "tidelift" } ], - "time": "2024-11-12T13:57:08+00:00" + "time": "2025-03-24T10:02:05+00:00" }, { - "name": "nesbot/carbon", - "version": "2.72.5", + "name": "mtdowling/jmespath.php", + "version": "2.8.0", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed" + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed", - "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", "shasum": "" }, "require": { - "carbonphp/carbon-doctrine-types": "*", + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.10.2", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", "ext-json": "*", - "php": "^7.1.8 || ^8.0", + "php": "^8.1", "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "provide": { "psr/clock-implementation": "1.0" }, "require-dev": { - "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", - "doctrine/orm": "^2.7 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.0", - "kylekatarnls/multi-tester": "^2.0", - "ondrejmirtes/better-reflection": "*", - "phpmd/phpmd": "^2.9", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.99 || ^1.7.14", - "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", - "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", - "squizlabs/php_codesniffer": "^3.4" + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.75.0", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, "bin": [ "bin/carbon" ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.x-dev", - "dev-2.x": "2.x-dev" - }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -1389,6 +1578,10 @@ "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" } }, "autoload": { @@ -1420,8 +1613,8 @@ ], "support": { "docs": "https://carbon.nesbot.com/docs", - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" }, "funding": [ { @@ -1437,28 +1630,28 @@ "type": "tidelift" } ], - "time": "2024-06-03T19:18:41+00:00" + "time": "2025-08-02T09:36:06+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.7.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" }, "type": "library", "autoload": { @@ -1504,7 +1697,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2024-05-08T12:18:48+00:00" + "time": "2024-05-08T12:36:18+00:00" }, { "name": "paragonie/random_compat", @@ -1560,6 +1753,97 @@ }, "time": "2022-02-16T17:07:03+00:00" }, + { + "name": "paragonie/sodium_compat", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/sodium_compat.git", + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb", + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb", + "shasum": "" + }, + "require": { + "php": "^8.1", + "php-64bit": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9", + "vimeo/psalm": "^4|^5" + }, + "suggest": { + "ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com" + }, + { + "name": "Frank Denis", + "email": "jedisct1@pureftpd.org" + } + ], + "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists", + "keywords": [ + "Authentication", + "BLAKE2b", + "ChaCha20", + "ChaCha20-Poly1305", + "Chapoly", + "Curve25519", + "Ed25519", + "EdDSA", + "Edwards-curve Digital Signature Algorithm", + "Elliptic Curve Diffie-Hellman", + "Poly1305", + "Pure-PHP cryptography", + "RFC 7748", + "RFC 8032", + "Salpoly", + "Salsa20", + "X25519", + "XChaCha20-Poly1305", + "XSalsa20-Poly1305", + "Xchacha20", + "Xsalsa20", + "aead", + "cryptography", + "ecdh", + "elliptic curve", + "elliptic curve cryptography", + "encryption", + "libsodium", + "php", + "public-key cryptography", + "secret-key cryptography", + "side-channel resistant" + ], + "support": { + "issues": "https://github.com/paragonie/sodium_compat/issues", + "source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0" + }, + "time": "2024-09-04T12:51:01+00:00" + }, { "name": "php-http/discovery", "version": "1.20.0", @@ -1641,16 +1925,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.3", + "version": "v6.10.0", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", - "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", "shasum": "" }, "require": { @@ -1710,7 +1994,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0" }, "funding": [ { @@ -1718,20 +2002,20 @@ "type": "github" } ], - "time": "2024-11-24T18:04:13+00:00" + "time": "2025-04-24T15:19:31+00:00" }, { "name": "phpseclib/phpseclib", - "version": "3.0.42", + "version": "3.0.46", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98" + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db92f1b1987b12b13f248fe76c3a52cadb67bb98", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", "shasum": "" }, "require": { @@ -1812,7 +2096,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.42" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" }, "funding": [ { @@ -1828,7 +2112,56 @@ "type": "tidelift" } ], - "time": "2024-09-16T03:06:04+00:00" + "time": "2025-06-26T16:29:55+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/clock", @@ -1931,6 +2264,56 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "psr/http-client", "version": "1.0.3", @@ -2040,16 +2423,16 @@ }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -2058,7 +2441,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2073,7 +2456,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -2087,9 +2470,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/http-server-handler", @@ -2256,25 +2639,25 @@ }, { "name": "psr/simple-cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -2289,7 +2672,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for simple caching", @@ -2301,9 +2684,9 @@ "simple-cache" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" }, - "time": "2017-10-23T01:57:42+00:00" + "time": "2021-10-29T13:26:27+00:00" }, { "name": "ralouphie/getallheaders", @@ -2349,6 +2732,82 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "spomky-labs/aes-key-wrap", + "version": "v7.0.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/aes-key-wrap.git", + "reference": "fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/aes-key-wrap/zipball/fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae", + "reference": "fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "php": ">=8.0" + }, + "require-dev": { + "infection/infection": "^0.25.4", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-beberlei-assert": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.0", + "rector/rector": "^0.12.5", + "symplify/easy-coding-standard": "^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AESKW\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap/contributors" + } + ], + "description": "AES Key Wrap for PHP.", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap", + "keywords": [ + "A128KW", + "A192KW", + "A256KW", + "RFC3394", + "RFC5649", + "aes", + "key", + "padding", + "wrap" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/aes-key-wrap/issues", + "source": "https://github.com/Spomky-Labs/aes-key-wrap/tree/v7.0.0" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2021-12-08T20:36:59+00:00" + }, { "name": "spomky-labs/base64url", "version": "v2.0.4", @@ -2416,37 +2875,37 @@ }, { "name": "spomky-labs/cbor-php", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/cbor-php.git", - "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4" + "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", - "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", + "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11|^0.12", + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", "ext-mbstring": "*", "php": ">=8.0" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0", + "deptrac/deptrac": "^3.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", "ext-json": "*", "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^10.1|^11.0", - "qossmic/deptrac": "^2.0", - "rector/rector": "^1.0", + "phpstan/phpstan": "^1.0|^2.0", + "phpstan/phpstan-beberlei-assert": "^1.0|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.0|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", "roave/security-advisories": "dev-latest", "symfony/var-dumper": "^6.0|^7.0", "symplify/easy-coding-standard": "^12.0" @@ -2483,7 +2942,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/cbor-php/issues", - "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.0" + "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.1" }, "funding": [ { @@ -2495,20 +2954,305 @@ "type": "patreon" } ], - "time": "2024-07-18T08:37:03+00:00" + "time": "2025-06-13T11:57:55+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "name": "spomky-labs/pki-framework", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "url": "https://github.com/Spomky-Labs/pki-framework.git", + "reference": "eced5b5ce70518b983ff2be486e902bbd15135ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/eced5b5ce70518b983ff2be486e902bbd15135ae", + "reference": "eced5b5ce70518b983ff2be486e902bbd15135ae", + "shasum": "" + }, + "require": { + "brick/math": "^0.10|^0.11|^0.12|^0.13", + "ext-mbstring": "*", + "php": ">=8.1" + }, + "require-dev": { + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "ext-gmp": "*", + "ext-openssl": "*", + "infection/infection": "^0.28|^0.29", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "^1.3|^2.0", + "phpstan/phpstan": "^1.8|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.3|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", + "roave/security-advisories": "dev-latest", + "symfony/string": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0" + }, + "suggest": { + "ext-bcmath": "For better performance (or GMP)", + "ext-gmp": "For better performance (or BCMath)", + "ext-openssl": "For OpenSSL based cyphering" + }, + "type": "library", + "autoload": { + "psr-4": { + "SpomkyLabs\\Pki\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joni Eskelinen", + "email": "jonieske@gmail.com", + "role": "Original developer" + }, + { + "name": "Florent Morselli", + "email": "florent.morselli@spomky-labs.com", + "role": "Spomky-Labs PKI Framework developer" + } + ], + "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", + "homepage": "https://github.com/spomky-labs/pki-framework", + "keywords": [ + "DER", + "Private Key", + "ac", + "algorithm identifier", + "asn.1", + "asn1", + "attribute certificate", + "certificate", + "certification request", + "cryptography", + "csr", + "decrypt", + "ec", + "encrypt", + "pem", + "pkcs", + "public key", + "rsa", + "sign", + "signature", + "verify", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/pki-framework/issues", + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "time": "2025-06-13T08:35:04+00:00" + }, + { + "name": "symfony/clock", + "version": "v6.4.24", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v6.4.24" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-10T08:14:14+00:00" + }, + { + "name": "symfony/console", + "version": "v6.4.25", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.25" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-08-22T10:21:53+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -2516,12 +3260,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -2546,7 +3290,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -2562,27 +3306,28 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.16", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "60a113666fa67e598abace38e5f46a0954d8833d" + "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/60a113666fa67e598abace38e5f46a0954d8833d", - "reference": "60a113666fa67e598abace38e5f46a0954d8833d", + "url": "https://api.github.com/repos/symfony/http-client/zipball/b8e9dce2d8acba3c32af467bb58e0c3656886181", + "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.3|^3.5.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -2639,7 +3384,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.16" + "source": "https://github.com/symfony/http-client/tree/v6.4.25" }, "funding": [ { @@ -2650,25 +3395,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-27T11:52:33+00:00" + "time": "2025-08-27T07:01:16+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9" + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/c2f3ad828596624ca39ea40f83617ef51ca8bbf9", - "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { @@ -2676,12 +3425,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -2717,7 +3466,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { @@ -2733,20 +3482,20 @@ "type": "tidelift" } ], - "time": "2024-11-25T12:02:18+00:00" + "time": "2025-04-29T11:18:49+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.16", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57" + "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57", - "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6bc974c0035b643aa497c58d46d9e25185e4b272", + "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272", "shasum": "" }, "require": { @@ -2794,7 +3543,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.16" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.25" }, "funding": [ { @@ -2805,30 +3554,285 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-13T18:58:10+00:00" + "time": "2025-08-20T06:48:20+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { "php": ">=7.2" }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, "provide": { "ext-mbstring": "*" }, @@ -2838,8 +3842,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2874,7 +3878,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -2886,83 +3890,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -2970,20 +3898,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -2992,8 +3920,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3030,7 +3958,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -3041,16 +3969,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -3074,8 +4006,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3109,7 +4041,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -3120,6 +4052,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3129,16 +4065,16 @@ }, { "name": "symfony/psr-http-message-bridge", - "version": "v6.4.13", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec" + "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/c9cf83326a1074f83a738fc5320945abf7fb7fec", - "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/6954b4e8aef0e5d46f8558c90edcf27bb01b4724", + "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724", "shasum": "" }, "require": { @@ -3192,7 +4128,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.13" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.24" }, "funding": [ { @@ -3203,25 +4139,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -3234,12 +4174,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -3275,7 +4215,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -3291,20 +4231,110 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { - "name": "symfony/translation", - "version": "v6.4.13", + "name": "symfony/string", + "version": "v6.4.25", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" + "url": "https://github.com/symfony/string.git", + "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", + "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.4.25" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-08-22T12:33:20+00:00" + }, + { + "name": "symfony/translation", + "version": "v6.4.24", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "300b72643e89de0734d99a9e3f8494a3ef6936e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/300b72643e89de0734d99a9e3f8494a3ef6936e1", + "reference": "300b72643e89de0734d99a9e3f8494a3ef6936e1", "shasum": "" }, "require": { @@ -3370,7 +4400,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.13" + "source": "https://github.com/symfony/translation/tree/v6.4.24" }, "funding": [ { @@ -3381,25 +4411,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T18:14:25+00:00" + "time": "2025-07-30T17:30:48+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", "shasum": "" }, "require": { @@ -3407,12 +4441,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -3448,7 +4482,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" }, "funding": [ { @@ -3464,20 +4498,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-27T08:32:26+00:00" }, { "name": "symfony/uid", - "version": "v6.4.13", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007" + "reference": "17da16a750541a42cf2183935e0f6008316c23f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007", - "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007", + "url": "https://api.github.com/repos/symfony/uid/zipball/17da16a750541a42cf2183935e0f6008316c23f7", + "reference": "17da16a750541a42cf2183935e0f6008316c23f7", "shasum": "" }, "require": { @@ -3522,7 +4556,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.4.13" + "source": "https://github.com/symfony/uid/tree/v6.4.24" }, "funding": [ { @@ -3533,261 +4567,52 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" - }, - { - "name": "thecodingmachine/safe", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/thecodingmachine/safe.git", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.2", - "thecodingmachine/phpstan-strict-rules": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "files": [ - "deprecated/apc.php", - "deprecated/array.php", - "deprecated/datetime.php", - "deprecated/libevent.php", - "deprecated/misc.php", - "deprecated/password.php", - "deprecated/mssql.php", - "deprecated/stats.php", - "deprecated/strings.php", - "lib/special_cases.php", - "deprecated/mysqli.php", - "generated/apache.php", - "generated/apcu.php", - "generated/array.php", - "generated/bzip2.php", - "generated/calendar.php", - "generated/classobj.php", - "generated/com.php", - "generated/cubrid.php", - "generated/curl.php", - "generated/datetime.php", - "generated/dir.php", - "generated/eio.php", - "generated/errorfunc.php", - "generated/exec.php", - "generated/fileinfo.php", - "generated/filesystem.php", - "generated/filter.php", - "generated/fpm.php", - "generated/ftp.php", - "generated/funchand.php", - "generated/gettext.php", - "generated/gmp.php", - "generated/gnupg.php", - "generated/hash.php", - "generated/ibase.php", - "generated/ibmDb2.php", - "generated/iconv.php", - "generated/image.php", - "generated/imap.php", - "generated/info.php", - "generated/inotify.php", - "generated/json.php", - "generated/ldap.php", - "generated/libxml.php", - "generated/lzf.php", - "generated/mailparse.php", - "generated/mbstring.php", - "generated/misc.php", - "generated/mysql.php", - "generated/network.php", - "generated/oci8.php", - "generated/opcache.php", - "generated/openssl.php", - "generated/outcontrol.php", - "generated/pcntl.php", - "generated/pcre.php", - "generated/pgsql.php", - "generated/posix.php", - "generated/ps.php", - "generated/pspell.php", - "generated/readline.php", - "generated/rpminfo.php", - "generated/rrd.php", - "generated/sem.php", - "generated/session.php", - "generated/shmop.php", - "generated/sockets.php", - "generated/sodium.php", - "generated/solr.php", - "generated/spl.php", - "generated/sqlsrv.php", - "generated/ssdeep.php", - "generated/ssh2.php", - "generated/stream.php", - "generated/strings.php", - "generated/swoole.php", - "generated/uodbc.php", - "generated/uopz.php", - "generated/url.php", - "generated/var.php", - "generated/xdiff.php", - "generated/xml.php", - "generated/xmlrpc.php", - "generated/yaml.php", - "generated/yaz.php", - "generated/zip.php", - "generated/zlib.php" - ], - "classmap": [ - "lib/DateTime.php", - "lib/DateTimeImmutable.php", - "lib/Exceptions/", - "deprecated/Exceptions/", - "generated/Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "support": { - "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v2.5.0" - }, - "time": "2023-04-05T11:54:14+00:00" - }, - { - "name": "voku/portable-ascii", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/voku/portable-ascii.git", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "shasum": "" - }, - "require": { - "php": ">=7.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" - }, - "suggest": { - "ext-intl": "Use Intl for transliterator_transliterate() support" - }, - "type": "library", - "autoload": { - "psr-4": { - "voku\\": "src/voku/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Lars Moelleken", - "homepage": "https://www.moelleken.org/" - } - ], - "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", - "homepage": "https://github.com/voku/portable-ascii", - "keywords": [ - "ascii", - "clean", - "php" - ], - "support": { - "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.3" - }, - "funding": [ - { - "url": "https://www.paypal.me/moelleken", - "type": "custom" - }, - { - "url": "https://github.com/voku", - "type": "github" - }, - { - "url": "https://opencollective.com/portable-ascii", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", - "type": "tidelift" - } - ], - "time": "2024-11-21T01:49:47+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "web-auth/cose-lib", - "version": "4.0.13", + "version": "4.4.2", "source": { "type": "git", "url": "https://github.com/web-auth/cose-lib.git", - "reference": "fc733974fe12b550b54a94a08e4e184aca0015e5" + "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/fc733974fe12b550b54a94a08e4e184aca0015e5", - "reference": "fc733974fe12b550b54a94a08e4e184aca0015e5", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/a93b61c48fb587855f64a9ec11ad7b60e867cb15", + "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10", + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", - "fgrosse/phpasn1": "^2.1", - "php": ">=8.1" + "php": ">=8.1", + "spomky-labs/pki-framework": "^1.0" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0", - "infection/infection": "^0.26.12", + "deptrac/deptrac": "^3.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "^9.5", - "qossmic/deptrac-shim": "^0.24.0", - "rector/rector": "^0.14", - "symfony/phpunit-bridge": "^6.1", - "symplify/easy-coding-standard": "^11.0" + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.7|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0" }, "suggest": { "ext-bcmath": "For better performance, please install either GMP (recommended) or BCMath extension", @@ -3821,7 +4646,7 @@ ], "support": { "issues": "https://github.com/web-auth/cose-lib/issues", - "source": "https://github.com/web-auth/cose-lib/tree/4.0.13" + "source": "https://github.com/web-auth/cose-lib/tree/4.4.2" }, "funding": [ { @@ -3833,119 +4658,57 @@ "type": "patreon" } ], - "time": "2022-09-17T08:34:42+00:00" - }, - { - "name": "web-auth/metadata-service", - "version": "v4.0.5", - "source": { - "type": "git", - "url": "https://github.com/web-auth/webauthn-metadata-service.git", - "reference": "2bc26efc09d280f87777c736f404a2d875d6e7c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/2bc26efc09d280f87777c736f404a2d875d6e7c4", - "reference": "2bc26efc09d280f87777c736f404a2d875d6e7c4", - "shasum": "" - }, - "require": { - "beberlei/assert": "^3.2", - "ext-json": "*", - "paragonie/constant_time_encoding": "^2.4", - "php": ">=8.1", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/log": "^2.0|^3.0" - }, - "suggest": { - "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for fetching Metadata Statement from distant sources", - "web-token/jwt-signature-algorithm-ecdsa": "Mandatory for fetching Metadata Statement from distant sources" - }, - "type": "library", - "autoload": { - "psr-4": { - "Webauthn\\MetadataService\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-auth/metadata-service/contributors" - } - ], - "description": "Metadata Service for FIDO2/Webauthn", - "homepage": "https://github.com/web-auth", - "keywords": [ - "FIDO2", - "fido", - "webauthn" - ], - "support": { - "source": "https://github.com/web-auth/webauthn-metadata-service/tree/v4.0.5" - }, - "funding": [ - { - "url": "https://github.com/Spomky", - "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "abandoned": "web-auth/webauthn-lib", - "time": "2022-06-22T11:14:44+00:00" + "time": "2025-08-14T20:33:29+00:00" }, { "name": "web-auth/webauthn-lib", - "version": "v4.0.5", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "1b02740ab8539f025419380c9e4c41b090c6cf47" + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/1b02740ab8539f025419380c9e4c41b090c6cf47", - "reference": "1b02740ab8539f025419380c9e4c41b090c6cf47", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/008b25171c27cf4813420d0de31cc059bcc71f1a", + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a", "shasum": "" }, "require": { - "beberlei/assert": "^3.2", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "fgrosse/phpasn1": "^2.1", - "paragonie/constant_time_encoding": "^2.4", + "lcobucci/clock": "^2.2|^3.0", + "paragonie/constant_time_encoding": "^2.6|^3.0", "php": ">=8.1", + "psr/clock": "^1.0", + "psr/event-dispatcher": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "psr/log": "^2.0|^3.0", + "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", - "symfony/uid": "^6.0", - "thecodingmachine/safe": "^2.0", - "web-auth/cose-lib": "^4.0", - "web-auth/metadata-service": "self.version" + "spomky-labs/pki-framework": "^1.0", + "symfony/deprecation-contracts": "^3.2", + "symfony/uid": "^6.1|^7.0", + "web-auth/cose-lib": "^4.2.3" }, "suggest": { + "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", + "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-ecdsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-eddsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-rsa": "Mandatory for the AndroidSafetyNet Attestation Statement support" + "symfony/event-dispatcher": "Recommended to use dispatched events", + "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/web-auth/webauthn-framework", + "name": "web-auth/webauthn-framework" + } + }, "autoload": { "psr-4": { "Webauthn\\": "src/" @@ -3973,7 +4736,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/v4.0.5" + "source": "https://github.com/web-auth/webauthn-lib/tree/4.9.2" }, "funding": [ { @@ -3985,31 +4748,28 @@ "type": "patreon" } ], - "time": "2022-06-23T16:25:36+00:00" + "time": "2025-01-04T09:47:58+00:00" }, { "name": "web-token/jwt-checker", - "version": "v2.2.11", + "version": "3.4.8", "source": { "type": "git", "url": "https://github.com/web-token/jwt-checker.git", - "reference": "5f31d98155951739e2fae7455e8466ccddd08f50" + "reference": "973ab960dd1761b00fce24a7cf2ec2a328499a58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-checker/zipball/5f31d98155951739e2fae7455e8466ccddd08f50", - "reference": "5f31d98155951739e2fae7455e8466ccddd08f50", + "url": "https://api.github.com/repos/web-token/jwt-checker/zipball/973ab960dd1761b00fce24a7cf2ec2a328499a58", + "reference": "973ab960dd1761b00fce24a7cf2ec2a328499a58", "shasum": "" }, "require": { - "web-token/jwt-core": "^2.1" + "php": ">=8.1", + "psr/clock": "^1.0", + "web-token/jwt-library": "^3.3" }, "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Checker\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4021,10 +4781,10 @@ }, { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-checker/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Checker component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4045,7 +4805,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-checker/tree/v2.2.11" + "source": "https://github.com/web-token/jwt-checker/tree/3.4.8" }, "funding": [ { @@ -4054,281 +4814,257 @@ } ], "abandoned": "web-token/jwt-library", - "time": "2021-03-17T14:55:52+00:00" + "time": "2024-02-22T07:19:34+00:00" }, { "name": "web-token/jwt-core", - "version": "v2.2.11", + "version": "3.4.8", "source": { "type": "git", "url": "https://github.com/web-token/jwt-core.git", - "reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678" + "reference": "0a47aa6096024af3bff8082e47e27219b9889542" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-core/zipball/53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678", - "reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678", + "url": "https://api.github.com/repos/web-token/jwt-core/zipball/0a47aa6096024af3bff8082e47e27219b9889542", + "reference": "0a47aa6096024af3bff8082e47e27219b9889542", "shasum": "" }, "require": { - "brick/math": "^0.8.17|^0.9", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-json": "*", "ext-mbstring": "*", - "fgrosse/phpasn1": "^2.0", - "php": ">=7.2", - "spomky-labs/base64url": "^1.0|^2.0" + "paragonie/constant_time_encoding": "^2.6|^3.0", + "php": ">=8.1", + "spomky-labs/pki-framework": "^1.2.1", + "web-token/jwt-library": "^3.3" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-core/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", + "time": "2024-06-24T16:31:57+00:00" + }, + { + "name": "web-token/jwt-encryption", + "version": "3.4.8", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-encryption.git", + "reference": "3e4b1c4080a77a6e97b62b33562805c1fc552b5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-encryption/zipball/3e4b1c4080a77a6e97b62b33562805c1fc552b5e", + "reference": "3e4b1c4080a77a6e97b62b33562805c1fc552b5e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "web-token/jwt-library": "^3.3" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-encryption/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", + "time": "2024-02-22T07:19:34+00:00" + }, + { + "name": "web-token/jwt-key-mgmt", + "version": "3.4.8", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-key-mgmt.git", + "reference": "4d2a5a1a86477dd50b89aff76962816ddbd64590" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/4d2a5a1a86477dd50b89aff76962816ddbd64590", + "reference": "4d2a5a1a86477dd50b89aff76962816ddbd64590", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=8.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "web-token/jwt-library": "^3.3" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-key-mgmt/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", + "time": "2024-02-22T07:19:34+00:00" + }, + { + "name": "web-token/jwt-library", + "version": "3.4.8", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-library.git", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-library/zipball/92445671cc788fa5f639898a67c06f9fd0bf491f", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f", + "shasum": "" + }, + "require": { + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "ext-json": "*", + "ext-mbstring": "*", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/clock": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "spomky-labs/pki-framework": "^1.2.1", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.12" }, "conflict": { "spomky-labs/jose": "*" }, - "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Core\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-framework/contributors" - } - ], - "description": "Core component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "support": { - "source": "https://github.com/web-token/jwt-core/tree/v2.2.11" - }, - "funding": [ - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "abandoned": "web-token/jwt-library", - "time": "2021-03-17T14:55:52+00:00" - }, - { - "name": "web-token/jwt-easy", - "version": "v2.2.11", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-easy.git", - "reference": "01db23252bb53d4fd36975b55dd58466bab1bb30" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-easy/zipball/01db23252bb53d4fd36975b55dd58466bab1bb30", - "reference": "01db23252bb53d4fd36975b55dd58466bab1bb30", - "shasum": "" - }, - "require": { - "web-token/jwt-checker": "^2.1", - "web-token/jwt-encryption": "^2.1", - "web-token/jwt-signature": "^2.1" - }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "Adds AES-CBC based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "Adds AES-GCM based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "Adds AES-GCM Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "Adds AES Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-dir": "Adds Direct encryption algorithm", - "web-token/jwt-encryption-algorithm-ecdh-es": "Adds ECDH-ES based encryption algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "Adds PBES2 based encryption algorithms", - "web-token/jwt-encryption-algorithm-rsa": "Adds RSA based encryption algorithms", - "web-token/jwt-signature-algorithm-ecdsa": "Adds ECDSA based signature algorithms", - "web-token/jwt-signature-algorithm-eddsa": "Adds EdDSA based signature algorithms", - "web-token/jwt-signature-algorithm-hmac": "Adds HMAC based signature algorithms", - "web-token/jwt-signature-algorithm-none": "Adds none signature algorithms", - "web-token/jwt-signature-algorithm-rsa": "Adds RSA based signature algorithms" - }, - "type": "library", - "autoload": { - "psr-4": { - "Jose\\Easy\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-framework/contributors" - } - ], - "description": "Easy toolset to use the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "support": { - "source": "https://github.com/web-token/jwt-easy/tree/v2.2.11" - }, - "funding": [ - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "abandoned": true, - "time": "2021-03-17T14:55:52+00:00" - }, - { - "name": "web-token/jwt-encryption", - "version": "v2.2.11", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-encryption.git", - "reference": "3b8d67d7c5c013750703e7c27f1001544407bbb2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-encryption/zipball/3b8d67d7c5c013750703e7c27f1001544407bbb2", - "reference": "3b8d67d7c5c013750703e7c27f1001544407bbb2", - "shasum": "" - }, - "require": { - "web-token/jwt-core": "^2.1" - }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "AES CBC Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "AES GCM Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "AES GCM Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "AES Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-dir": "Direct Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-ecdh-es": "ECDH-ES Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-experimental": "Experimental Key and Signature Algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "PBES2 Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-rsa": "RSA Based Key Encryption Algorithms" - }, - "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Encryption\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-encryption/contributors" - } - ], - "description": "Encryption component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "support": { - "source": "https://github.com/web-token/jwt-encryption/tree/v2.2.11" - }, - "funding": [ - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "abandoned": "web-token/jwt-library", - "time": "2021-03-17T14:55:52+00:00" - }, - { - "name": "web-token/jwt-key-mgmt", - "version": "v2.2.11", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-key-mgmt.git", - "reference": "0b116379515700d237b4e5de86879078ccb09d8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/0b116379515700d237b4e5de86879078ccb09d8a", - "reference": "0b116379515700d237b4e5de86879078ccb09d8a", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "web-token/jwt-core": "^2.0" - }, "suggest": { + "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", + "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance", + "ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)", "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", - "php-http/httplug": "To enable JKU/X5U support.", - "php-http/message-factory": "To enable JKU/X5U support.", - "web-token/jwt-util-ecc": "To use EC key analyzers." + "paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW...)", + "symfony/http-client": "To enable JKU/X5U support." }, "type": "library", "autoload": { "psr-4": { - "Jose\\Component\\KeyManagement\\": "" + "Jose\\Component\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -4342,10 +5078,10 @@ }, { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-key-mgmt/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Key Management component of the JWT Framework.", + "description": "JWT library", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4366,123 +5102,40 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-key-mgmt/tree/v2.2.11" + "issues": "https://github.com/web-token/jwt-library/issues", + "source": "https://github.com/web-token/jwt-library/tree/3.4.8" }, "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, { "url": "https://www.patreon.com/FlorentMorselli", "type": "patreon" } ], - "abandoned": "web-token/jwt-library", - "time": "2021-03-17T14:55:52+00:00" + "time": "2025-05-07T09:11:18+00:00" }, { "name": "web-token/jwt-signature", - "version": "v2.2.11", + "version": "3.4.8", "source": { "type": "git", "url": "https://github.com/web-token/jwt-signature.git", - "reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103" + "reference": "eccfd59e658d4118414cf6d14229aa52eec387e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/015b59aaf3b6e8fb9f5bd1338845b7464c7d8103", - "reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103", + "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/eccfd59e658d4118414cf6d14229aa52eec387e7", + "reference": "eccfd59e658d4118414cf6d14229aa52eec387e7", "shasum": "" }, "require": { - "web-token/jwt-core": "^2.1" - }, - "suggest": { - "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms", - "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", - "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", - "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms" + "php": ">=8.1", + "web-token/jwt-library": "^3.3" }, "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-signature/contributors" - } - ], - "description": "Signature component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "support": { - "source": "https://github.com/web-token/jwt-signature/tree/v2.2.11" - }, - "funding": [ - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "abandoned": "web-token/jwt-library", - "time": "2021-03-01T19:55:28+00:00" - }, - { - "name": "web-token/jwt-signature-algorithm-rsa", - "version": "v2.2.11", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-signature-algorithm-rsa.git", - "reference": "513ad90eb5ef1886ff176727a769bda4618141b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-rsa/zipball/513ad90eb5ef1886ff176727a769bda4618141b0", - "reference": "513ad90eb5ef1886ff176727a769bda4618141b0", - "shasum": "" - }, - "require": { - "brick/math": "^0.8.17|^0.9", - "ext-openssl": "*", - "web-token/jwt-signature": "^2.1" - }, - "suggest": { - "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", - "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance" - }, - "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\Algorithm\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4497,7 +5150,7 @@ "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "RSA Based Signature Algorithms the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4518,7 +5171,7 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-signature-algorithm-rsa/tree/v2.2.11" + "source": "https://github.com/web-token/jwt-signature/tree/3.4.8" }, "funding": [ { @@ -4527,20 +5180,87 @@ } ], "abandoned": "web-token/jwt-library", - "time": "2021-01-21T19:18:03+00:00" + "time": "2024-02-22T07:19:34+00:00" }, { - "name": "webklex/php-imap", - "version": "5.5.0", + "name": "web-token/jwt-signature-algorithm-rsa", + "version": "3.4.8", "source": { "type": "git", - "url": "https://github.com/Webklex/php-imap.git", - "reference": "3c23c8f66b772ce8597772816e068326559e7e4b" + "url": "https://github.com/web-token/jwt-signature-algorithm-rsa.git", + "reference": "4408e41671294f0390731e2f84065a03a8089ace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Webklex/php-imap/zipball/3c23c8f66b772ce8597772816e068326559e7e4b", - "reference": "3c23c8f66b772ce8597772816e068326559e7e4b", + "url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-rsa/zipball/4408e41671294f0390731e2f84065a03a8089ace", + "reference": "4408e41671294f0390731e2f84065a03a8089ace", + "shasum": "" + }, + "require": { + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "ext-openssl": "*", + "php": ">=8.1", + "web-token/jwt-library": "^3.3" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-signature-algorithm-rsa/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", + "time": "2024-02-22T07:19:34+00:00" + }, + { + "name": "webklex/php-imap", + "version": "6.2.0", + "source": { + "type": "git", + "url": "https://github.com/Webklex/php-imap.git", + "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Webklex/php-imap/zipball/6b8ef85d621bbbaf52741b00cca8e9237e2b2e05", + "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05", "shasum": "" }, "require": { @@ -4552,7 +5272,7 @@ "ext-openssl": "*", "ext-zip": "*", "illuminate/pagination": ">=5.0.0", - "nesbot/carbon": "^2.62.1", + "nesbot/carbon": "^2.62.1|^3.2.4", "php": "^8.0.2", "symfony/http-foundation": ">=2.8.0" }, @@ -4566,7 +5286,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -4596,7 +5316,7 @@ ], "support": { "issues": "https://github.com/Webklex/php-imap/issues", - "source": "https://github.com/Webklex/php-imap/tree/5.5.0" + "source": "https://github.com/Webklex/php-imap/tree/6.2.0" }, "funding": [ { @@ -4608,7 +5328,7 @@ "type": "ko_fi" } ], - "time": "2023-06-28T01:57:03+00:00" + "time": "2025-04-25T06:02:37+00:00" } ], "packages-dev": [], diff --git a/lam/config/addressbook.sample.conf b/lam/config/addressbook.sample.conf index ba6fa60d4..3b46d4538 100644 --- a/lam/config/addressbook.sample.conf +++ b/lam/config/addressbook.sample.conf @@ -3,7 +3,6 @@ "useTLS": "yes", "followReferrals": "false", "pagedResults": "false", - "Passwd": "{CRYPT-SHA512}$6$ZJcXwaxHP0GQH0Rd$Ggkn8Wz\/8ntCM9v0TywomjkgSvV.3BoayFwnc9QP3MV.b7HWaqLOA8urP2e7HyEmU\/JmC8xR7jTqrXCHC4kFr. WkpjWHdheEhQMEdRSDBSZA==", "Admins": "cn=Manager,dc=my-domain,dc=com", "defaultLanguage": "en_GB.utf8", "scriptPath": "", diff --git a/lam/config/config.cfg.sample b/lam/config/config.cfg.sample index 046734c5e..f1ed0d05d 100644 --- a/lam/config/config.cfg.sample +++ b/lam/config/config.cfg.sample @@ -1,5 +1,4 @@ { - "password": "{CRYPT-SHA512}$6$WheNHdlVwDoL4s.x$DrZ10TpIGQa5wd0jbvtm8eaTleJCf1nec3ihOaNwMdPUKVFCphXwtnTSmFFXjhGa45RlrSEWhDVyjLCMiV\/.c. V2hlTkhkbFZ3RG9MNHMueA==", "default": "lam", "sessionTimeout": "30", "hideLoginErrorDetails": "false", diff --git a/lam/config/language b/lam/config/language index c690b357e..826cf4660 100644 --- a/lam/config/language +++ b/lam/config/language @@ -26,6 +26,9 @@ es_ES.utf8:UTF-8:Español (España) # French fr_FR.utf8:UTF-8:Français (France) +# Greek +el_GR.utf8:UTF-8:Ελληνικά (Ελλάδα) + # Italian it_IT.utf8:UTF-8:Italiano (Italia) diff --git a/lam/config/samba3.sample.conf b/lam/config/samba3.sample.conf index 66c7864f4..4bfddb42e 100644 --- a/lam/config/samba3.sample.conf +++ b/lam/config/samba3.sample.conf @@ -3,7 +3,6 @@ "useTLS": "yes", "followReferrals": "false", "pagedResults": "false", - "Passwd": "{CRYPT-SHA512}$6$MUWJEkvtUY7G5sFA$QS6voQCksH9gNbbbQpjDKt65iez9bgKQI2x60DAffCK5.LO\/\/QfYTetQ6V2PlUR32CTkuhlSXSGXnH9scD\/zb0 TVVXSkVrdnRVWTdHNXNGQQ==", "Admins": "cn=Manager,dc=my-domain,dc=com", "defaultLanguage": "en_GB.utf8", "scriptPath": "", diff --git a/lam/config/templates/pdf/default.bindDyndbType.xml b/lam/config/templates/pdf/default.bindDyndbType.xml new file mode 100644 index 000000000..61d269448 --- /dev/null +++ b/lam/config/templates/pdf/default.bindDyndbType.xml @@ -0,0 +1,18 @@ + +
+ + + + + + + + + + + + + + +
+
diff --git a/lam/config/templates/profiles/default.bindDyndbType b/lam/config/templates/profiles/default.bindDyndbType new file mode 100644 index 000000000..05739b8cd --- /dev/null +++ b/lam/config/templates/profiles/default.bindDyndbType @@ -0,0 +1,6 @@ +ldap_suffix: - +ldap_rdn: idnsname +bindDyndbZone_idnssoaexpire: 604800 +bindDyndbZone_idnssoaminimum: 86400 +bindDyndbZone_idnssoarefresh: 2800 +bindDyndbZone_idnssoaretry: 7200 diff --git a/lam/config/unix.sample.conf b/lam/config/unix.sample.conf index 53aedf331..865c24cd5 100644 --- a/lam/config/unix.sample.conf +++ b/lam/config/unix.sample.conf @@ -3,7 +3,6 @@ "useTLS": "no", "followReferrals": "false", "pagedResults": "false", - "Passwd": "{CRYPT-SHA512}$6$zvb8WVEHSAKEGtGO$573kA9Us8LtGLLm5Gu87P\/vIiF\/2Ol\/DauzPmUpvC4eCL\/t0WWiwBaY19Rx5G3wzbeZWWlE1kp2fikrpZTZ51\/ enZiOFdWRUhTQUtFR3RHTw==", "Admins": "cn=Manager,dc=my-domain,dc=com", "defaultLanguage": "en_GB.utf8", "scriptPath": "", diff --git a/lam/config/windows_samba4.sample.conf b/lam/config/windows_samba4.sample.conf index e521c78a7..f2ab63f47 100644 --- a/lam/config/windows_samba4.sample.conf +++ b/lam/config/windows_samba4.sample.conf @@ -3,7 +3,6 @@ "useTLS": "no", "followReferrals": "false", "pagedResults": "false", - "Passwd": "{CRYPT-SHA512}$6$9IWWua4lbp7uiLCC$AHPgST1YAm3yUAWKGeNZ5f9GCo1wBGyVo3MGvAt6.UOtQ9dYxs4WeQ4mlzjR30rD6cRayMNRBWqYFuBLvzn9T0 OUlXV3VhNGxicDd1aUxDQw==", "Admins": "cn=Administrator,cn=users,dc=my-domain,dc=com", "defaultLanguage": "en_GB.utf8", "scriptPath": "", diff --git a/lam/copyright b/lam/copyright index 594651a9c..f901e1f24 100644 --- a/lam/copyright +++ b/lam/copyright @@ -1,4 +1,4 @@ -This software is copyright (c) 2003 - 2024 by Roland Gruber +This software is copyright (c) 2003 - 2025 by Roland Gruber If you purchased a copy of LDAP Account Manager Pro then the following files are licensed under the conditions which you accepted at purchase @@ -17,6 +17,8 @@ time. * lib/modules/automount.inc * lib/modules/bindDLZ.inc * lib/modules/bindDLZXfr.inc +* lib/modules/bindDyndbRecord.inc +* lib/modules/bindDyndbZone.inc * lib/modules/customBaseType.inc * lib/modules/customFields.inc * lib/modules/customScripts.inc @@ -56,6 +58,7 @@ time. * lib/modules/rfc2307bisAutomount.inc * lib/modules/rfc2307bisPosixGroup.inc * lib/modules/selfRegistration.inc +* lib/modules/simpleSecurityObject.inc * lib/modules/sudoRole.inc * lib/modules/uidObject.inc * lib/modules/webauthn.inc @@ -64,6 +67,7 @@ time. * lib/types/alias.inc * lib/types/automountType.inc * lib/types/bind.inc +* lib/types/bindDyndbType.inc * lib/types/customType.inc * lib/types/gon.inc * lib/types/kopanoAddressListType.inc @@ -93,7 +97,8 @@ All other files are licensed under the conditions below. along with this program. If not, see . -The complete license can be found in the file COPYING. +The complete license can be found in the file COPYING or in +/usr/share/common-licenses/GPL-3 (Debian/Ubuntu). Some parts of this package have other, compatible licences. These are: @@ -407,33 +412,6 @@ D: E: - Duo - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -F: 3-Clause BSD License Redistribution and use in source and binary forms, with or without @@ -462,7 +440,7 @@ F: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -G: +F: 2-Clause BSD License Redistribution and use in source and binary forms, with or without modification, @@ -486,38 +464,8 @@ G: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -H: - 3-Clause BSD License -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -I: +G: GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 @@ -972,217 +920,199 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -J: -Apache 2.0 +H: + Apache License 2.0 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1. Definitions. +## 1. Definitions. -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 +through 9 of this document. -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the +License. -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled +by, or are under common control with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract +or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. -You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and -configuration files. +"Source" form shall mean the preferred form for making modifications, including but not limited to software +source code, documentation source, and configuration files. -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object -code, generated documentation, and conversions to other media types. +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, +including but not limited to compiled object code, generated documentation, and conversions to other media +types. -"Work" shall mean the work of authorship, whether in Source or Object form, -made available under the License, as indicated by a copyright notice that is -included in or attached to the work (an example is provided in the Appendix -below). +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, +as indicated by a copyright notice that is included in or attached to the work (an example is provided in the +Appendix below). -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) +the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not +include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work +and Derivative Works thereof. -"Contribution" shall mean any work of authorship, including the original -version of the Work and any modifications or additions to that Work or -Derivative Works thereof, that is intentionally submitted to Licensor for -inclusion in the Work by the copyright owner or by an individual or Legal -Entity authorized to submit on behalf of the copyright owner. For the purposes -of this definition, "submitted" means any form of electronic, verbal, or -written communication sent to the Licensor or its representatives, including -but not limited to communication on electronic mailing lists, source code -control systems, and issue tracking systems that are managed by, or on behalf -of, the Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise designated in -writing by the copyright owner as "Not a Contribution." +"Contribution" shall mean any work of authorship, including the original version of the Work and any +modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to +Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to +submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control systems, and issue tracking systems +that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable copyright license to -reproduce, prepare Derivative Works of, publicly display, publicly perform, -sublicense, and distribute the Work and such Derivative Works in Source or -Object form. +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been +received by Licensor and subsequently incorporated within the Work. -3. Grant of Patent License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, -non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this -section) patent license to make, have made, use, offer to sell, sell, import, -and otherwise transfer the Work, where such license applies only to those -patent claims licensable by such Contributor that are necessarily infringed by -their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent -litigation against any entity (including a cross-claim or counterclaim in a -lawsuit) alleging that the Work or a Contribution incorporated within the Work -constitutes direct or contributory patent infringement, then any patent -licenses granted to You under this License for that Work shall terminate as of -the date such litigation is filed. +## 2. Grant of Copyright License. -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and in -Source or Object form, provided that You meet the following conditions: +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. -(a) You must give any other recipients of the Work or Derivative Works a copy -of this License; and +## 3. Grant of Patent License. -(b) You must cause any modified files to carry prominent notices stating that -You changed the files; and +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim +or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent licenses granted to You under this +License for that Work shall terminate as of the date such litigation is filed. -(c) You must retain, in the Source form of any Derivative Works that You -distribute, all copyright, patent, trademark, and attribution notices from the -Source form of the Work, excluding those notices that do not pertain to any -part of the Derivative Works; and +## 4. Redistribution. -(d) If the Work includes a "NOTICE" text file as part of its distribution, then -any Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following conditions: -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise -complies with the conditions stated in this License. + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without any -additional terms or conditions. Notwithstanding the above, nothing herein shall -supersede or modify the terms of any separate license agreement you may have -executed with Licensor regarding such Contributions. + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, + trademark, and attribution notices from the Source form of the Work, excluding those notices that do + not pertain to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that + You distribute must include a readable copy of the attribution notices contained within such NOTICE + file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the Derivative Works; or, within a display + generated by the Derivative Works, if and wherever such third-party notices normally appear. The + contents of the NOTICE file are for informational purposes only and do not modify the License. You may + add Your own attribution notices within Derivative Works that You distribute, alongside or as an + addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be + construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license +terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative +Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the +conditions stated in this License. + +## 5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by +You to the Licensor shall be under the terms and conditions of this License, without any additional terms or +conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate +license agreement you may have executed with Licensor regarding such Contributions. + +## 6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of +the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in -writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. +## 7. Disclaimer of Warranty. -8. Limitation of Liability. In no event and under no legal theory, whether in -tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to in -writing, shall any Contributor be liable to You for damages, including any -direct, indirect, special, incidental, or consequential damages of any -character arising as a result of this License or out of the use or inability to -use the Work (including but not limited to damages for loss of goodwill, work -stoppage, computer failure or malfunction, or any and all other commercial -damages or losses), even if such Contributor has been advised of the -possibility of such damages. +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor +provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. -9. Accepting Warranty or Additional Liability. While redistributing the Work or -Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such -obligations, You may act only on Your own behalf and on Your sole -responsibility, not on behalf of any other Contributor, and only if You agree -to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. +## 8. Limitation of Liability. +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless +required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any +Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential +damages of any character arising as a result of this License or out of the use or inability to use the Work +(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has been advised of the possibility +of such damages. +## 9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold +each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS Programs and licenses with other licenses and/or authors than the main license and authors: -graphics/webauthn.svg F 2017 Duo Security, Inc. -lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei -lib/3rdParty/composer/brick B Benjamin Morel -lib/3rdParty/composer/carbonphp B 2023 Carbon -lib/3rdParty/composer/christian-riesen B Christian Riesen -lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano -lib/3rdParty/composer/doctrine B Doctrine Project -lib/3rdParty/composer/duo E Cisco Systems, Inc. and/or its affiliates -lib/3rdParty/composer/facile-it B Thomas Vargiu -lib/3rdParty/composer/fgrosse B 2015 Friedrich Große -lib/3rdParty/composer/firebase F 2011 Neuman Vong -lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling -lib/3rdParty/composer/http-interop B 2016 Woody Gilk -lib/3rdParty/composer/illuminate B Taylor Otwell -lib/3rdParty/composer/nesbot B Brian Nesbitt -lib/3rdParty/composer/monolog B 2011 Jordi Boggiano -lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises -lib/3rdParty/composer/php-http B 2015 PHP HTTP Team -lib/3rdParty/composer/phpmailer I -lib/3rdParty/composer/phpseclib B 2019 TerraFrost and other contributors -lib/3rdParty/composer/psr B PHP Framework Interoperability Group -lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar -lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs -lib/3rdParty/composer/symfony B 2022 Fabien Potencier -lib/3rdParty/composer/thecodingmachine B TheCodingMachine -lib/3rdParty/composer/voku B 2019 Lars Moelleken -lib/3rdParty/composer/web-auth B 2018 Spomky-Labs -lib/3rdParty/composer/web-token B Florent Morselli -lib/3rdParty/composer/webklex B 2016 Webklex -lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD -lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah -lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB -style/010_normalize.css B Nicolas Gallagher and Jonathan Neal -style/050_grid.css B -templates/lib/*jquery*.js B 2018 jQuery Foundation and other contributors -templates/lib/*popper*.js B -templates/lib/*tippy*.js B 2021 atomiks -templates/lib/*flatpickr*.js B 2017 Gregory Petrosyan -style/600_flatpickr.css B 2017 Gregory Petrosyan -templates/lib/*sweetalert2*.js B -style/*sweetalert2*.css B -templates/lib/cropper*.js B 2018 Chen Fengyuan -style/600_cropper*.css B 2018 Chen Fengyuan -templates/lib/extra/jodit B Chupurnov -templates/lib/extra/friendlyCaptcha B -templates/lib/400_Sortable*.js B RubaXa, owenm -templates/lib/extra/jstree/* B 2014 Ivan Bozhanov -style/jstree/* B 2014 Ivan Bozhanov -templates/lib/extra/qrcode/* B 2009 Kazuhiko Arase -templates/lib/extra/tabulator/* B 2024 Oliver Folkerd -style/tabulator/* B 2024 Oliver Folkerd +graphics/webauthn.svg E 2017 Duo Security, Inc. https://github.com/duo-labs/webauthn.io +lib/3rdParty/composer/aws H Amazon Web Services https://github.com/aws/aws-sdk-php, https://github.com/awslabs/aws-crt-php +lib/3rdParty/composer/brick B Benjamin Morel https://github.com/brick/math +lib/3rdParty/composer/carbonphp B 2023 Carbon https://github.com/CarbonPHP/carbon-doctrine-types +lib/3rdParty/composer/christian-riesen B Christian Riesen https://github.com/ChristianRiesen/base32 +lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano https://github.com/composer/composer +lib/3rdParty/composer/doctrine B Doctrine Project https://github.com/doctrine +lib/3rdParty/composer/duosecurity E Cisco Systems, Inc. and/or its affiliates https://github.com/duosecurity/duo_universal_php +lib/3rdParty/composer/facile-it B Thomas Vargiu https://github.com/facile-it +lib/3rdParty/composer/firebase E 2011 Neuman Vong https://github.com/firebase/php-jwt +lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling https://github.com/guzzle/psr7 +lib/3rdParty/composer/http-interop B 2016 Woody Gilk https://github.com/http-interop/http-factory-guzzle +lib/3rdParty/composer/illuminate B Taylor Otwell https://github.com/illuminate +lib/3rdParty/composer/lcobucci B 2017 Luís Cobucci https://github.com/lcobucci/clock +lib/3rdParty/composer/monolog B 2011 Jordi Boggiano https://github.com/Seldaek/monolog +lib/3rdParty/composer/mtdowling B 2014 Michael Dowling https://github.com/jmespath/jmespath.php +lib/3rdParty/composer/nesbot B Brian Nesbitt https://github.com/CarbonPHP/carbon +lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises https://github.com/paragonie +lib/3rdParty/composer/php-http B 2015 PHP HTTP Team https://github.com/php-http/discovery +lib/3rdParty/composer/phpmailer G https://github.com/PHPMailer/PHPMailer +lib/3rdParty/composer/phpseclib B 2019 TerraFrost and other contributors https://github.com/phpseclib/phpseclib +lib/3rdParty/composer/psr B PHP Framework Interoperability Group https://github.com/php-fig +lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar https://github.com/ralouphie/getallheaders +lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs https://github.com/Spomky-Labs +lib/3rdParty/composer/symfony B 2022 Fabien Potencier https://github.com/symfony +lib/3rdParty/composer/web-auth B 2018 Spomky-Labs https://github.com/web-auth +lib/3rdParty/composer/web-token B Florent Morselli https://github.com/web-token +lib/3rdParty/composer/webklex B 2016 Webklex https://github.com/Webklex/php-imap +lib/3rdParty/tcpdf D 2022 Nicola Asuni - Tecnick.com LTD https://github.com/tecnickcom/TCPDF +lib/3rdParty/tcpdf/fonts/dejavu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah https://github.com/dejavu-fonts/dejavu-fonts +lib/3rdParty/yubico/Yubico.php C 2015 Yubico AB https://github.com/Yubico/php-yubico +style/010_normalize.css B Nicolas Gallagher and Jonathan Neal https://github.com/csstools/normalize.css +style/050_grid.css B https://foundation.zurb.com/sites/docs/v/5.5.3/components/grid.html +templates/lib/*popper*.js B https://github.com/floating-ui/floating-ui +templates/lib/*tippy*.js B 2021 atomiks https://github.com/atomiks/tippyjs +templates/lib/*flatpickr*.js B 2017 Gregory Petrosyan https://github.com/flatpickr/flatpickr +style/600_flatpickr.css B 2017 Gregory Petrosyan https://github.com/flatpickr/flatpickr +templates/lib/*sweetalert2*.js B https://github.com/sweetalert2/sweetalert2 +style/*sweetalert2*.css B https://github.com/sweetalert2/sweetalert2 +templates/lib/410_cropper*.js B 2018 Chen Fengyuan https://github.com/fengyuanchen/cropperjs +style/600_cropper*.css B 2018 Chen Fengyuan https://github.com/fengyuanchen/cropperjs +templates/lib/extra/jodit B Chupurnov https://github.com/xdan/jodit/ +templates/lib/extra/friendlyCaptcha B https://github.com/FriendlyCaptcha/friendly-challenge +templates/lib/400_Sortable*.js B RubaXa, owenm https://github.com/SortableJS/Sortable +templates/lib/extra/qrcode/* B 2009 Kazuhiko Arase https://github.com/kazuhikoarase/qrcode-generator +templates/lib/extra/tabulator/* B 2024 Oliver Folkerd https://github.com/olifolkerd/tabulator/ +style/tabulator/* B 2024 Oliver Folkerd https://github.com/olifolkerd/tabulator/ +templates/lib/extra/wunderbaum/* B 2024 Martin Wendt https://github.com/mar10/wunderbaum +style/wunderbaum/* B 2024 Martin Wendt https://github.com/mar10/wunderbaum +style/bootstrap-icons/* B 2024 The Bootstrap Authors https://icons.getbootstrap.com/ diff --git a/lam/docs/devel/upgrade.htm b/lam/docs/devel/upgrade.htm index ed8d6730b..bd9465f5e 100644 --- a/lam/docs/devel/upgrade.htm +++ b/lam/docs/devel/upgrade.htm @@ -60,6 +60,23 @@ This is a list of API changes for all LAM releases.
+

9.2 -> 9.3

+
    +
  • Module/Type API +
      +
    • Added defined parameter and return types to some methods (e.g. "getTitleBarSubtitle")
    • +
    • getPasswordQuickChangeOptions(): new parameter $forcePasswordChangeByDefault
    • +
    +
  • +
+

9.0 -> 9.1

+
    +
  • JavaScript +
      +
    • jQuery was removed from the project
    • +
    +
  • +

8.4 -> 8.5

  • Files in "tmp" directory must be managed via class LamTemporaryFilesManager
  • diff --git a/lam/docs/manual-sources/appendix-lamdaemon.xml b/lam/docs/manual-sources/appendix-lamdaemon.xml index f2f300a83..7c94aca51 100644 --- a/lam/docs/manual-sources/appendix-lamdaemon.xml +++ b/lam/docs/manual-sources/appendix-lamdaemon.xml @@ -1,205 +1,204 @@ - - Setup for home directory and quota management + + Setup lamdaemon for home directory and quota management - Lamdaemon.pl is used to modify quota and home directories on a - remote or local host via SSH (even if homedirs are located on - localhost). + Lamdaemon.pl is used to modify quota and home directories on a remote + or local host via SSH (even if homedirs are located on localhost). - If you want wo use it you have to set up the following things to get - it to work: + If you want to use it you have to set up the following things to get + it to work: -
    - Installation + Installation - First of all, you need to install lamdaemon.pl on your remote - server where LAM should manage homedirs and/or quota. This is usually a - different server than the one where LAM is installed. But there is no - problem if it is the same. + First of all, you need to install lamdaemon.pl on your remote server + where LAM should manage homedirs and/or quota. This is usually a different + server than the one where LAM is installed. But there is no problem if it is + the same. - - - - - - - + + + + + + + - + - Debian based (e.g. also - Ubuntu) + + + Debian based (e.g. also Ubuntu): Please install the lamdaemon DEB + package on your quota/homedir server. + - Please install the lamdaemon DEB package on your quota/homedir - server. + + RPM based (Fedora, CentOS, Suse, ...): Please install the + lamdaemon RPM package on your quota/homedir server. + - RPM based (Fedora, CentOS, Suse, - ...) - - Please install the lamdaemon RPM package on your quota/homedir - server. - - Other - - Please copy lib/lamdaemon.pl from the LAM tar.bz2 package to your - quota/homedir server. The location may be anywhere (e.g. use + + Other: Please copy lib/lamdaemon.pl from the LAM tar.bz2 package + to your quota/homedir server. The location may be anywhere (e.g. use /opt/lamdaemon). Please make the lamdaemon.pl script executable. -
    + + -
    - LDAP Account Manager configuration + LAM server profile + configuration - - - Set the remote or local host in the configuration (e.g. - 127.0.0.1) - + + + Set the remote or local host in the configuration (e.g. + 127.0.0.1) + - - Path to lamdaemon.pl, e.g. - /srv/www/htdocs/lam/lib/lamdaemon.pl If you installed a DEB or - RPM package then the script will be located at - /usr/share/ldap-account-manager/lib/lamdaemon.pl. - + + Path to lamdaemon.pl, e.g. /srv/www/htdocs/lam/lib/lamdaemon.pl If + you installed a DEB or RPM package then the script will be located at + /usr/share/ldap-account-manager/lib/lamdaemon.pl. + - - Your LAM admin user must be a valid Unix account. It needs to - have the object class "posixAccount" and an attribute "uid". This - account must be accepted by the SSH daemon of your home directory - server. Do not create a second local account but change your system - to accept LDAP users. You can use LAM to add the Unix account part - to your admin user or create a new account. Please do not forget to - setup LDAP write access (ACLs) - if you create a new account. - - + + Your LAM admin user must be a valid Unix + account. It needs to have the object class "posixAccount" and an + attribute "uid". This account must be accepted by the SSH daemon of your + home directory server. Do not create a second local account but change + your system to accept LDAP users. You can use LAM to add the Unix + account part to your admin user or create a new account. Please do not + forget to setup LDAP write access (ACLs) + if you create a new account. + + - + - - - - - - - + + + + + + + - Note that the builtin admin/manager entries do not work for - lamdaemon. You need to login with a Unix account. + Note that the builtin admin/manager entries do not work for lamdaemon. + You need to login with a Unix account. - - - - - - - + + + + + + + - OpenLDAP ACL location: + OpenLDAP ACL location - The access rights for OpenLDAP are configured in - /etc/ldap/slapd.conf or - /etc/ldap/slapd.d/cn=config/olcDatabase={1}bdb.ldif. -
    + The access rights for OpenLDAP are configured in /etc/ldap/slapd.conf + or /etc/ldap/slapd.d/cn=config/olcDatabase={1}bdb.ldif. -
    - Setup sudo + Setup sudo - The perl script has to run as root. Therefore we need a wrapper, - sudo. Edit /etc/sudoers on host where homedirs or quotas should be used - and add the following line: + The perl script has to run as root. Therefore we need a wrapper, sudo. + Edit /etc/sudoers on host where homedirs or quotas should be used and add + the following line: - $admin All= NOPASSWD: $path_to_lamdaemon * + $admin All= NOPASSWD: $path_to_lamdaemon * - $admin is the admin user from - LAM (must be a valid Unix account) and - $path_to_lamdaemon is the path to - lamdaemon.pl. + $admin is the admin user from LAM + (must be a valid Unix account) and $path_to_lamdaemon + is the path to lamdaemon.pl. - Example: + Example: - myAdmin ALL= NOPASSWD: /srv/www/htdocs/lam/lib/lamdaemon.pl - * + myAdmin ALL= NOPASSWD: /srv/www/htdocs/lam/lib/lamdaemon.pl * - You might need to run the sudo command once manually to init sudo. - The command "sudo -l" will show all possible sudo commands of the - current user. + You might need to run the sudo command once manually to init sudo. The + command "sudo -l" will show all possible sudo commands of the current + user. - Attention: Please do not use the - options "Defaults requiretty" and "Defaults env_reset" in /etc/sudoers. - Otherwise you might get errors like "you must have a tty to run sudo" or - "no tty present and no askpass program specified". -
    + Attention: Please do not use the + options "Defaults requiretty" and "Defaults env_reset" in /etc/sudoers. + Otherwise you might get errors like "you must have a tty to run sudo" or "no + tty present and no askpass program specified". -
    - Setup Perl + Setup Perl - We need an extra Perl module - Quota. To install it, run: + We need an extra Perl module - Quota. To install it, run: + + + perl -MCPAN -e shell + + install Quota + + + If your Perl executable is not located in /usr/bin/perl you will have + to edit the path in the first line of lamdaemon.pl. If you have problems + compiling the Perl modules try installing a newer release of your GCC + compiler and the "make" application. + + Several Linux distributions already include a quota package for + Perl. + + Set up SSH + + Your SSH daemon must offer the password authentication method. To + activate it just use this configuration option in + /etc/ssh/sshd_config: + + PasswordAuthentication yes + + Calling of external scripts + + The following extra scripts are called if they exist: + + + + Create home directory: /usr/sbin/useradd.local <USER NAME> + (after directory was created) + + + + Delete home directory: /usr/sbin/userdel.local <USER NAME> + (before directory is removed) + + + + Troubleshooting + + If you have problems managing quotas and home directories then these + points might help: + + + + There is a test page for lamdaemon: Login to LAM and open Tools + -> Tests -> Lamdaemon test + + + + Check /var/log/auth.log or its equivalent on your system. This + file contains messages about all logins. If the ssh login failed then + you will find a description about the reason here. + + + + Set sshd in debug mode. In /etc/ssh/sshd_conf add these + lines: - perl -MCPAN -e shell + SyslogFacility AUTH - install Quota + LogLevel DEBUG3 - If your Perl executable is not located in /usr/bin/perl you will - have to edit the path in the first line of lamdaemon.pl. If you have - problems compiling the Perl modules try installing a newer release of - your GCC compiler and the "make" application. + Now check /var/log/syslog for messages from sshd. + + - Several Linux distributions already include a quota package for - Perl. -
    - -
    - Set up SSH - - Your SSH daemon must offer the password authentication method. To - activate it just use this configuration option in - /etc/ssh/sshd_config: - - PasswordAuthentication yes -
    - -
    - Troubleshooting - - If you have problems managing quotas and home directories then - these points might help: - - - - There is a test page for lamdaemon: Login to LAM and open - Tools -> Tests -> Lamdaemon test - - - - Check /var/log/auth.log or its equivalent on your system. This - file contains messages about all logins. If the ssh login failed - then you will find a description about the reason here. - - - - Set sshd in debug mode. In /etc/ssh/sshd_conf add these - lines: - - - SyslogFacility AUTH - - LogLevel DEBUG3 - - - Now check /var/log/syslog for messages from sshd. - - - - Error message "Your LAM admin user (...) - must be a valid Unix account to work with lamdaemon!": This - happens if you use the default LDAP admin/manager user to login to LAM. - Please see here and setup a Unix - account. -
    -
    + Error message "Your LAM admin user (...) must be + a valid Unix account to work with lamdaemon!": This happens if + you use the default LDAP admin/manager user to login to LAM. Please see + here and setup a Unix account. +
    diff --git a/lam/docs/manual-sources/appendix-schema.xml b/lam/docs/manual-sources/appendix-schema.xml index cc027a3bb..c369ed91e 100644 --- a/lam/docs/manual-sources/appendix-schema.xml +++ b/lam/docs/manual-sources/appendix-schema.xml @@ -467,12 +467,30 @@ dhcp.schema - docs/schema/dhcp.schema + Part of LAM installation: docs/schema/dhcp.schema The LDAP suffix should be set to your dhcpServer entry. + + + + + + + + Bind dyndb-ldap + + idnsZone, idnsRecord + + schema.ldif + + Part of bind-dyndb-ldap + + LAM Pro only + + @@ -487,7 +505,7 @@ dlz.schema - part of Bind + Part of Bind DLZ patch LAM Pro only @@ -803,6 +821,24 @@ LAM Pro only, requires DDS extension on LDAP server side + + + + + + + + + TAK + + takUser + + tak-*.ldif + + Part of LAM installation: docs/schema/tak-*.ldif + + + diff --git a/lam/docs/manual-sources/appendix-troubleshooting.xml b/lam/docs/manual-sources/appendix-troubleshooting.xml index 97e6763b5..eaf6cfa62 100644 --- a/lam/docs/manual-sources/appendix-troubleshooting.xml +++ b/lam/docs/manual-sources/appendix-troubleshooting.xml @@ -28,27 +28,23 @@ Locate config.cfg: On DEB/RPM installations it is in - /usr/share/ldap-account-manager/config and for tar.bz2 in config + /usr/share/ldap-account-manager/config and + for tar.bz2 in config folder. - Locate the "password" entry in the file + Locate the "password" line in the file - Replace the password hash after "password: " with your new - clear-text password (e.g. "secret") + Remove the password line in the configuration file - After the change the line should look like this: - - password: secret - - You can now login using your new password. Set the password once - again via GUI in main configuration settings. This will then put again - a hash value in the config.cfg file. + When you open LAM's start page you will now be asked to set a + new password.
    diff --git a/lam/docs/manual-sources/chapter-accessLevel.xml b/lam/docs/manual-sources/chapter-accessLevel.xml index e69f01369..4b1f3cc7d 100644 --- a/lam/docs/manual-sources/chapter-accessLevel.xml +++ b/lam/docs/manual-sources/chapter-accessLevel.xml @@ -1,184 +1,179 @@ - - Access levels and password reset page (LAM Pro) +"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> + + Access levels and password reset page (LAM Pro) - You can define different access levels for each profile to allow or - disallow write access. The password reset page helps your deskside support - staff to reset user passwords. + You can define different access levels for each profile to allow or + disallow write access. The password reset page helps your deskside support + staff to reset user passwords. -
    - Access levels +
    + Access levels - There are three access levels: + There are three access levels: - - - Write access (default) + + + Write access (default) - There are no restrictions. LAM admin users can manage account, - create profiles and set passwords. - + There are no restrictions. LAM admin users can manage account, + create profiles and set passwords. + - - Change passwords + + Change passwords - Similar to "Read only" except that the password reset page is available. - + Similar to "Read only" except that the password reset page is available. + - - Read only + + Read only - No write access to the LDAP database is allowed. It is also - impossible to manage account and PDF profiles. + No write access to the LDAP database is allowed. It is also + impossible to manage account and PDF profiles. - Accounts may be viewed but no changes can be saved. - - + Accounts may be viewed but no changes can be saved. + + - The access level can be set on the server configuration - page: + The access level can be set on the server configuration page: - - - - - - - -
    - -
    - Password reset page - - This special page allows your deskside support staff to reset the - Unix and Samba passwords of your users. Account may also be (un)locked - If you set the access level to - "Change passwords" then LAM will not allow any changes to the LDAP - database except password changes via this page. The account pages will - be still available in read-only mode. - - You can open the password reset page by clicking on the key symbol - on each user account: - - - - - - - - There are three different options to set a new password. - You can further restrict these options in server profile - settings. - - - - set random password and display it on - screen - - This will set the user's password to a random value. The - password will be 11 characters long with a random combination of - letters, digits and ".-_". - - You may want to use this method to tell users their new - passwords via phone. - - - - set random password and mail it to - user - - If the user account has set the mail attribute then LAM can - send your user a mail with the new password. You can change the mail - template to fit your needs. Please configure your LAM server profile - to setup the sender address, subject and mail body. See here for setting up your - SMTP server. - - Using this method will prevent that your support staff knows - the new password. - - - - set specific password - - Here you can specify your own password. - - - - + - + - + +
    - LAM will display contact information about the user like the - user's name, email address and telephone number. This will help your - deskside support to easily contact your users. +
    + Password reset page - Options: + This special page allows your deskside support staff to reset the + Unix and Samba passwords of your users. Account may also be (un)locked If + you set the access level to "Change + passwords" then LAM will not allow any changes to the LDAP database except + password changes via this page. The account pages will be still available + in read-only mode. - Depending on the account there may be additional options - available. + You can open the password reset page by clicking on the key symbol + on each user account: - - - Sync Samba NT/LM password with Unix - password: If a user account has Samba passwords set then - LAM will offer to synchronize the passwords. - + + + + + + + There are different options to set a new password - either + set a random password or specify the new password. You can further + restrict these options in server profile settings. - - Unlock Samba account: Locked - Samba accounts can be unlocked with the password change. - + + + Generate random password - - Update Samba password - timestamps: This will set the timestamps when the - password was changed (sambaPwdLastSet). Only existing attributes are - updated. No new attributes are added. - + This will set the user's password to a random value. The + password will be 14 characters long with a random combination of + letters, digits and ".-_". - - Sync Kerberos password with Unix - password: This will also update the Heimdal Kerberos - password. - + You can send the password via email or SMS if the user account has set the + mail/mobile phone attribute. You can change the email template to fit + your needs. Please configure your LAM server profile to setup the + sender address, subject and mail body. See here for setting up your SMTP server. Using + this method will prevent that your support staff knows the new + password. - - Sync Asterisk (voicemail) password with - Unix password: Changes also the Asterisk - passwords. - + The password can be shown on screen, too. You may want to use + this method to tell users their new password via phone. + - - Force password change: This - will force the user to change his password at next login. This - option supports Shadow, Samba 3 and PPolicy (automatically - detected). - - + + Set specific password - + Here you can specify your own password. It can also be sent via + email or SMS if the user account has set the + mail/mobile phone attribute. + + + + + + + + + + + + LAM will display contact information about the user like the user's + name, email address and telephone number. This will help your deskside + support to easily contact your users. + + Options: + + Depending on the account there may be additional options + available. + + + + Sync Samba NT/LM password with Unix + password: If a user account has Samba passwords set then + LAM will offer to synchronize the passwords. + + + + Unlock Samba account: Locked + Samba accounts can be unlocked with the password change. + + + + Update Samba password + timestamps: This will set the timestamps when the password + was changed (sambaPwdLastSet). Only existing attributes are updated. + No new attributes are added. + + + + Sync Kerberos password with Unix + password: This will also update the Heimdal Kerberos + password. + + + + Sync Asterisk (voicemail) password with + Unix password: Changes also the Asterisk passwords. + + + + Force password change: This + will force the user to change his password at next login. This option + supports Shadow, Samba 3 and PPolicy (automatically detected). + + + + - Account (un)locking: + Account (un)locking: - Depending if the account includes a Unix/Samba extension and - PPolicy is activated the page will show options to (un)lock the account. - E.g. if the account is fully unlocked then there will be no unlocking - options printed. + Depending if the account includes a Unix/Samba extension and PPolicy + is activated the page will show options to (un)lock the account. E.g. if + the account is fully unlocked then there will be no unlocking options + printed. - - - - - - - -
    - + + + + + + + +
    +
    diff --git a/lam/docs/manual-sources/chapter-configuration.xml b/lam/docs/manual-sources/chapter-configuration.xml index 4cdf0a059..524140324 100644 --- a/lam/docs/manual-sources/chapter-configuration.xml +++ b/lam/docs/manual-sources/chapter-configuration.xml @@ -44,11 +44,6 @@
    General settings - After selecting "Edit general settings" you will need to enter the - master configuration password. - The default password for new installations is "lam". Now you can edit the - general settings. -
    Configuration Database @@ -301,6 +296,124 @@
    +
    + SMS options (LAM Pro) + + You can send SMS messages to your users for password resets. To + activate this feature you need to have an account at one of the + supported SMS providers. + + After all options are filled you can test your settings and check + if you get an SMS delivered to the entered mobile number. + + + + + + Common options + + + + Default country prefix: please enter your country prefix for + telephone numbers. It will be applied whenever no country prefix is + part of the user's telephone number. + + + + Mobile phone attributes: LAM will check these attributes to + find the user's mobile telephone number. The first number that is + found will be used. + + + + AWS + SNS + + + + Region: this is your AWS region (e.g. eu-central-1) + + + + Account id: please enter the access key id of your IMS user + that is allowed to send SMS (e.g. AKIAIOSFODNN7EXAMPLE) + + + + Token: this is the secret value of your access key (e.g. + wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY) + + + + Email2SMS + + This service can be used for all SMS gateways that allow to send + SMS via email. This means LAM sends out an email to the gateway and they + convert it to an SMS. + + + + Account id: please enter the receiving email address at your + email2SMS gateway. The address must contain the wildcard "$number" + for the user's phone number. E.g. "$number@sms.clicksend.com". + "$number" will be replaced with the actual mobile phone + number. + + + + From: this is the email FROM address. Typically, email2SMS + gateways require that the email comes from a specific email + address. + + + + GatewayAPI + + + + Token: please enter your API token (not key/secret) + + + + SMSAPI + + + + Token: please enter your API token + + + + SMSBOX + + + + API key: please enter your API key (pub-...) + + + + Twilio + + + + Account id: this is your account SID (e.g. AC...) + + + + Token: please enter your API token (not API SID/secret) + + + + From: this can be a mobile number (needs to be registered in + Twilio) or the ID of a messaging service (MG...). The messaging + service allows to define a textual sender name. + + +
    +
    WebAuthn/FIDO2 devices @@ -546,6 +659,10 @@ will then query LDAP to return results in chunks of 999 entries. + Show deleted entries: This is for Active Directory and Samba 4 + only. It will unhide LDAP entries in "CN=Deleted Objects,DC=...". You + can use this to browse and restore these entries in tree view. + Referential integrity overlay: Activate this checkbox if you have any server side extension for referential integrity in place. In this case the server will cleanup references to LDAP entries that are diff --git a/lam/docs/manual-sources/chapter-installation.xml b/lam/docs/manual-sources/chapter-installation.xml index 35ebe9c48..9c761534e 100644 --- a/lam/docs/manual-sources/chapter-installation.xml +++ b/lam/docs/manual-sources/chapter-installation.xml @@ -608,6 +608,62 @@ version. Unless explicitly noticed there is no need to install an intermediate release. +
    + 9.3 -> 9.4 + + New configuration format for main + configuration and server profiles is enforced. Please save your main + configuration and all server profiles with LAM 9.0 - 9.3 before + upgrading. You can also export your configuration and import all + server profiles and main configuration. This format change does not + apply if you use MySQL for configuration + storage. +
    + +
    + 9.2 -> 9.3 + + No actions required. +
    + +
    + 9.1 -> 9.2 + + LAM Pro: + + + + Custom scripts: The settings in server profile were split by + account type. If you use custom scripts then you need to perform + these steps for each server profile that uses them (no scripts + will be executed till migration was done): + + + + Open server profile and switch to tab "Module + settings" + + + + Review the automated migration of the custom scripts + settings (complex configurations will need manual + adaptions) + + + + Save the server profile + + + + +
    + +
    + 9.0 -> 9.1 + + No actions required. +
    +
    8.9 -> 9.0 diff --git a/lam/docs/manual-sources/chapter-modules.xml b/lam/docs/manual-sources/chapter-modules.xml index 621f83d9f..1377ff177 100644 --- a/lam/docs/manual-sources/chapter-modules.xml +++ b/lam/docs/manual-sources/chapter-modules.xml @@ -293,8 +293,9 @@ If a module supports to enforce a password change then you will see the appropriate checkbox. LAM Pro also offers to send the password via - email after the account is saved. Email options are specified in your - LAM server profile. + email/SMS after the account is saved. Email options are specified in your + LAM server profile and SMS options in + main configuration. @@ -2510,6 +2511,56 @@ AuthorizedKeysCommandUser root
    + +
    + TAK + + The TAK module + supports the Team Awareness Kit or Tactical Assault Kit (TAK) with the + Android Team Awareness Kit (ATAK). + + You can define callsigns, team roles and colors for users. + + LDAP schema + + The module expects that TAK users use the object class "takUser" + and the attributes "takCallsign", "takRole" and "takColor". You can find + matching schema files in /usr/share/ldap-account-manager/docs/schema + (DEB/RPM) or docs/schema (tar.bz2). Please see the beginning of the + files for installation instructions. + + + + OpenLDAP: tak-OpenLDAP.ldif + + + + Samba 4: tak-Samba4-attributes.ldif and + tak-Samba4-objectClass.ldif + + + + Windows (AD): tak-Windows.ldif + + + + Configuration + + Add the TAK module for users in your server profile: + + + + + + Now you can manage the TAK attributes for users. + + LAM Pro users can add these attributes to the self-service profile + if needed. + + + + +
    @@ -4324,6 +4375,289 @@ Run slapindex to rebuild the index.
    +
    + Bind dyndb-ldap (LAM Pro) + + The bind-dyndb-ldap plugin for + Bind allows you to manage + DNS entries in LDAP. Please install the bind-dyndb-ldap schema file on + your LDAP server. It is part of the bind-dyndb-ldap download. LAM Pro can + manage DNS zones and the following record types: + + A/AAAA: IP addresses + + + + CNAME: alias names + + + + DNAME: delegation name + + + + MX: mail servers + + + + NS: name servers + + + + PTR: reverse DNS entries + + + + SRV: service entries + + + + TXT: text records + + + +
    + Configuration + + Please open your LAM server profile configuration and add two + instances of the "Bind dyndb" account type. One for records and one for + zones. + + + + + + The recommended settings are as follows. Please adapt if + needed. + + DNS records: + + + + LDAP suffix: if you manage a single domain then use the DN of + the zone entry. If you manage multiple domains then use the DN under + which they are stored (e.g. the "nsContainer"). + + + + List attributes: + #idnsName;#aRecord;#aAAARecord;#cNAMERecord;#dNameRecord;#tXTRecord;#mxrecord;#srvrecord;#ptrrecord;#dnsttl + + + + Custom label: DNS records + + + + DNS zones: + + + + LDAP suffix: use the DN under which the domains are stored + (e.g. the "nsContainer"). + + + + List attributes: + #idnsName;#aRecord;#aAAARecord;#cNAMERecord;#dNameRecord;#tXTRecord;#idnssoaserial + + + + Custom label: DNS zones + + + + + + + + Next, switch to the modules tab. Here, select DNS records for your + record type and DNS zone for your zone type. Then you can save the + server profile and login to LAM. + + + + +
    + +
    + DNS zones + + This allows you to manage your DNS zones (SOA+NS records). You can + e.g. specify timeouts and name servers. + + + + +
    + +
    + DNS entries + + LAM supports the following DNS record types: + + + + A/AAAA: IP addresses + + + + CNAME: alias names + + + + DNAME: delegation name + + + + MX: mail servers + + + + PTR: reverse DNS entries + + + + SRV: service entries + + + + TXT: text records + + + + + + + IP addresses (A/AAAA) + + Here you can enter IPv4 (A) or IPv6 (AAAA) addresses for a DNS + name. + + + + + + + + + + + + + Alias names (CNAME) + + Sometimes a DNS entry should simply point to a different DNS entry + (e.g. for migrations). This can be done by adding an alias name. + + + + + + + + + + + + + Alias names (DNAME) + + You can delegate a DNS zone to a different server. + + + + + + + + + + + + + Mail servers (MX) + + The mail server entries define where mails to a domain should be + delivered. The server with the lowest preference has the highest + priority. + + + + + + + + + + + + + Reverse DNS entries (PTR) + + Reverse DNS entries are important when you need to find the DNS + name that is associated with a given IP address. Reverse DNS entries are + stored in a separate DNS zone. + + + + + + + + + + + + + Services (SRV) + + Service records can be used to specify which servers provide + common services such as LDAP. Please note that the host name must be + _SERVICE._PROTOCOL (e.g. _ldap._tcp). + + + + + Priority: The priority of the target host, lower value means more + preferred. + + Weight: A relative weight for records with the same priority. E.g. + weights 20 and 80 for a service will result in 20% queries to the one + server and 80% to the other. + + Port: The port number that is used for your service. + + Server: DNS name where service can be reached (relative without or + absolute with dot at the end). + + + + + + + + + + + + + Text records (TXT) + + Text records can be added to store a description or other data + (e.g. SPF information). + + + + + + + + +
    +
    +
    Bind DLZ (LAM Pro) @@ -6033,13 +6367,15 @@ OK (10 msec) In "Module settings" you can specify multiple scripts for each - action type (e.g. modify) and account type (e.g. user). The scripts need - to be located on the filesystem of your webserver and will be executed in - its user environment. E.g. if you webserver runs as user www-data with the - group www-data then the custom scripts will be run under this user with - his rights. The output of the scripts will be shown in LAM. + action type (e.g. preModify) and account type (e.g. user). The scripts + need to be located on the filesystem of your webserver and will be + executed in its user environment. E.g. if you webserver runs as user + www-data with the group www-data then the custom scripts will be run under + this user with his rights. The output of the scripts will be shown in + LAM. - You can specify the scripts on the LAM configuration pages. + You can specify the scripts on the LAM configuration pages. Please + note that the syntax changed with version 9.2 (see below). @@ -6057,15 +6393,21 @@ OK (10 msec) Syntax: Please enter one script per line. Each line has the following - format: <account type> <action> <script> + format: <action> <script> + + E.g.: preModify /usr/bin/myCustomScript -u $uid$ + + Syntax (pre 9.2): + + Please enter one script per line. Each line has the following + format: <account type> + <action> <script> E.g.: user preModify /usr/bin/myCustomScript -u $uid$ - Account types: - - You can setup scripts for all available account types (e.g. user, - group, host, ...). Please see the help on the configuration page about - your current active account types. + Account types: You can setup scripts for all available account types + (e.g. user, group, host, ...). Please see the help on the configuration + page about your current active account types. Actions: @@ -6242,6 +6584,11 @@ OK (10 msec) send password via email (yes|no) + + $INFO.sendPasswordViaSms$: send + password via SMS (yes|no) + + $INFO.sendPasswordAlternateAddress$: alternate @@ -6282,14 +6629,10 @@ OK (10 msec) Example: - user preModify /opt/myapp/preModify.sh -u $uid$ -group postDelete /opt/myapp/postDelete.sh -g $gid$ + preModify /opt/myapp/preModify.sh -u $uid$ LAM_GROUP: Mail actions -user manual LAMLABEL="Clean" /bin/myscripts/cleanMailbox -u $uid$ -user manual LAMLABEL="Extend" /bin/myscripts/extendMailbox -u $uid$ -LAM_GROUP: Sync actions -user manual /bin/myscripts/syncWithCRM -u $uid$ -user manual LAMLABEL="Some app" /bin/myscripts/syncWithSomeApp -u $uid$ +manual LAMLABEL="Clean" /bin/myscripts/cleanMailbox -u $uid$ +manual LAMLABEL="Extend" /bin/myscripts/extendMailbox -u $uid$ @@ -6350,10 +6693,10 @@ user manual LAMLABEL="Some app" /bin/myscripts/syncWithSomeApp -u $uid$ LAM_SELECTION_TENANT: Tenant=foo;bar LAM_TEXT_COMMENT: Comment=no comment LAM_TEXT_AMOUNT: Amount -user manual LAMLABEL="Clean" /bin/myscripts/cleanMailbox -u $uid$ -e $LAM_SELECTION_ENV$ -user manual LAMLABEL="Extend" /bin/myscripts/extendMailbox -u $uid$ -e $LAM_SELECTION_TENANT$ -user manual /bin/myscripts/syncWithCRM -u $uid$ -c $LAM_TEXT_COMMENT$ -user manual LAMLABEL="Some app" /bin/myscripts/syncWithSomeApp -u $uid$ -a $LAM_TEXT_AMOUNT$ +manual LAMLABEL="Clean" /bin/myscripts/cleanMailbox -u $uid$ -e $LAM_SELECTION_ENV$ +manual LAMLABEL="Extend" /bin/myscripts/extendMailbox -u $uid$ -e $LAM_SELECTION_TENANT$ +manual /bin/myscripts/syncWithCRM -u $uid$ -c $LAM_TEXT_COMMENT$ +manual LAMLABEL="Some app" /bin/myscripts/syncWithSomeApp -u $uid$ -a $LAM_TEXT_AMOUNT$ diff --git a/lam/docs/manual-sources/chapter-selfService.xml b/lam/docs/manual-sources/chapter-selfService.xml index 0e7e281d4..cdae7a558 100644 --- a/lam/docs/manual-sources/chapter-selfService.xml +++ b/lam/docs/manual-sources/chapter-selfService.xml @@ -1457,20 +1457,25 @@ - LAM Pro can send your users an email with a confirmation link to - validate their email address. Of course, this should only be used if the - email account is independent from the user password (e.g. at external - provider) or you use the backup email address feature. The mail body - must include the confirmation link by using the special wildcard - "@@resetLink@@". Additionally, you may want to insert other wildcards - that are replaced by the corresponding LDAP attributes. E.g. "@@uid@@" - will be replaced by the user name. + LAM Pro can send your users an SMS/email with a confirmation link + to validate their SMS/email address. If you select to send an SMS then + the email mechanism will only be used if no mobile phone number was + found for this user. You also need to setup the SMS settings. + + Confirmation mails should only be used if the email account is + independent from the user password (e.g. at external provider) or you + use the backup email address feature. The mail body must include the + confirmation link by using the special wildcard "@@resetLink@@". + Additionally, you may want to insert other wildcards that are replaced + by the corresponding LDAP attributes. E.g. "@@uid@@" will be replaced by + the user name. There is also an option to skip the security question at all if email verification is enabled. In this case the password can be reset directly after clicking on the confirmation link. Please handle with - care since anybody with access to the user's mail account can reset the - password. + care since anybody with access to the user's SMS/mail account can reset + the password. Captcha support @@ -1703,11 +1708,12 @@ Label that is displayed on page - optional regular expression for validation (e.g. - "/^[0-9a-zA-Z]+$/") + Optional regular expression for validation (e.g. + "/^[0-9a-zA-Z]+$/"). For binary fields the file name will be + checked. - validation message if value does not match validation - expression + Validation message if value does not match validation + expression. @@ -1721,11 +1727,12 @@ Label that is displayed on page - optional regular expression for validation (e.g. - "/^[0-9a-zA-Z]+$/") + Optional regular expression for validation (e.g. + "/^[0-9a-zA-Z]+$/"). For binary fields the file name will be + checked. - validation message if value does not match validation - expression + Validation message if value does not match validation + expression. @@ -1800,6 +1807,14 @@ constant::userAccountControl::512 + + + + Binary file: + + required::jpegPhoto;binary::Photo::/.jp(e)?g$/i::Please select a + JPG file + diff --git a/lam/docs/manual-sources/images/configGeneral12.png b/lam/docs/manual-sources/images/configGeneral12.png new file mode 100644 index 000000000..918879f76 Binary files /dev/null and b/lam/docs/manual-sources/images/configGeneral12.png differ diff --git a/lam/docs/manual-sources/images/configProfiles4.png b/lam/docs/manual-sources/images/configProfiles4.png index 79c1edeeb..349af554b 100644 Binary files a/lam/docs/manual-sources/images/configProfiles4.png and b/lam/docs/manual-sources/images/configProfiles4.png differ diff --git a/lam/docs/manual-sources/images/customScripts.png b/lam/docs/manual-sources/images/customScripts.png index f97a06409..8eefbb4a8 100644 Binary files a/lam/docs/manual-sources/images/customScripts.png and b/lam/docs/manual-sources/images/customScripts.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-1.png b/lam/docs/manual-sources/images/mod_bind-dyndb-1.png new file mode 100644 index 000000000..f00fa2474 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-1.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-10.png b/lam/docs/manual-sources/images/mod_bind-dyndb-10.png new file mode 100644 index 000000000..89760fe69 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-10.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-11.png b/lam/docs/manual-sources/images/mod_bind-dyndb-11.png new file mode 100644 index 000000000..5422ace5c Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-11.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-2.png b/lam/docs/manual-sources/images/mod_bind-dyndb-2.png new file mode 100644 index 000000000..18ed478a7 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-2.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-3.png b/lam/docs/manual-sources/images/mod_bind-dyndb-3.png new file mode 100644 index 000000000..dc0409598 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-3.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-4.png b/lam/docs/manual-sources/images/mod_bind-dyndb-4.png new file mode 100644 index 000000000..a6374a9c7 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-4.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-5.png b/lam/docs/manual-sources/images/mod_bind-dyndb-5.png new file mode 100644 index 000000000..c2401f479 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-5.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-6.png b/lam/docs/manual-sources/images/mod_bind-dyndb-6.png new file mode 100644 index 000000000..65a7c363f Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-6.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-7.png b/lam/docs/manual-sources/images/mod_bind-dyndb-7.png new file mode 100644 index 000000000..fa0926d31 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-7.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-8.png b/lam/docs/manual-sources/images/mod_bind-dyndb-8.png new file mode 100644 index 000000000..a14fea67f Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-8.png differ diff --git a/lam/docs/manual-sources/images/mod_bind-dyndb-9.png b/lam/docs/manual-sources/images/mod_bind-dyndb-9.png new file mode 100644 index 000000000..5128c71e2 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_bind-dyndb-9.png differ diff --git a/lam/docs/manual-sources/images/mod_tak1.png b/lam/docs/manual-sources/images/mod_tak1.png new file mode 100644 index 000000000..5caf6d0a4 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_tak1.png differ diff --git a/lam/docs/manual-sources/images/mod_tak2.png b/lam/docs/manual-sources/images/mod_tak2.png new file mode 100644 index 000000000..a5e97b7c0 Binary files /dev/null and b/lam/docs/manual-sources/images/mod_tak2.png differ diff --git a/lam/docs/manual-sources/images/password1.png b/lam/docs/manual-sources/images/password1.png index 9db9f7133..bfc7c13a3 100644 Binary files a/lam/docs/manual-sources/images/password1.png and b/lam/docs/manual-sources/images/password1.png differ diff --git a/lam/docs/manual-sources/images/passwordReset2.png b/lam/docs/manual-sources/images/passwordReset2.png index a59fa8aa8..59b7ecb99 100644 Binary files a/lam/docs/manual-sources/images/passwordReset2.png and b/lam/docs/manual-sources/images/passwordReset2.png differ diff --git a/lam/docs/manual-sources/images/passwordSelfReset1.png b/lam/docs/manual-sources/images/passwordSelfReset1.png index 07e7e5166..24ef7b6a1 100644 Binary files a/lam/docs/manual-sources/images/passwordSelfReset1.png and b/lam/docs/manual-sources/images/passwordSelfReset1.png differ diff --git a/lam/docs/manual-sources/images/schema_bind9.png b/lam/docs/manual-sources/images/schema_bind9.png new file mode 100644 index 000000000..b62da561d Binary files /dev/null and b/lam/docs/manual-sources/images/schema_bind9.png differ diff --git a/lam/docs/manual-sources/images/schema_tak.png b/lam/docs/manual-sources/images/schema_tak.png new file mode 100644 index 000000000..0bb41fb6b Binary files /dev/null and b/lam/docs/manual-sources/images/schema_tak.png differ diff --git a/lam/docs/manual-sources/images/tree1.png b/lam/docs/manual-sources/images/tree1.png index f95815e1c..5336faa47 100644 Binary files a/lam/docs/manual-sources/images/tree1.png and b/lam/docs/manual-sources/images/tree1.png differ diff --git a/lam/docs/manual-sources/overview.xml b/lam/docs/manual-sources/overview.xml index 8bfb1a50f..f9c57580f 100644 --- a/lam/docs/manual-sources/overview.xml +++ b/lam/docs/manual-sources/overview.xml @@ -16,7 +16,7 @@ https://www.ldap-account-manager.org/ - Copyright (C) 2003 - 2024 Roland Gruber + Copyright (C) 2003 - 2025 Roland Gruber <post@rolandgruber.de> Key features: @@ -87,26 +87,15 @@ Edge (max. 2 years old) - - - Opera (max. 2 years old) - - The default password to edit the configuration options is - "lam". - License: LAM is published under the GNU General Public License. The complete list of licenses can be found in the copyright file. - Default password: - - The default password for the LAM configuration is "lam". - Have fun! The LAM development team diff --git a/lam/docs/schema/tak-OpenLDAP.ldif b/lam/docs/schema/tak-OpenLDAP.ldif new file mode 100644 index 000000000..a9d69372c --- /dev/null +++ b/lam/docs/schema/tak-OpenLDAP.ldif @@ -0,0 +1,33 @@ +# +# LDAP schema for LAM TAK functionality +# +# This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) +# Copyright (C) 2025 Roland Gruber +# +# +# OID bases: +# 1.3.6.1.4.1.34955 Roland Gruber Softwareentwicklung +# 1.3.6.1.4.1.34955.1 attributes +# 1.3.6.1.4.1.34955.2 object classes +# +# Installation: +# ldapadd -x -W -H ldap://localhost -D "cn=admin,dc=company,dc=com" -f tak-OpenLDAP.ldif +# +# Please replace "localhost" with your LDAP server and "cn=admin,dc=company,dc=com" with your LDAP admin user (usually starts with cn=admin or cn=manager). +# +# In some cases you might need to import directly on the OpenLDAP server as root: +# ldapadd -Y EXTERNAL -H ldapi:/// -f tak-OpenLDAP.ldif +# +# Version: 1 +# +# Changelog: +# 1: initial release (LAM 9.2) +# + +dn: cn=tak,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: tak +olcAttributeTypes: ( 1.3.6.1.4.1.34955.1.100 NAME 'takCallsign' DESC 'TAK callsign' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.34955.1.101 NAME 'takRole' DESC 'TAK team role' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.34955.1.102 NAME 'takColor' DESC 'TAK team color' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcObjectClasses: ( 1.3.6.1.4.1.34955.2.10 NAME 'takUser' DESC 'TAK user' SUP top AUXILIARY MAY ( takCallsign $ takRole $ takColor ) MUST ( cn ) ) diff --git a/lam/docs/schema/tak-Samba4-attributes.ldif b/lam/docs/schema/tak-Samba4-attributes.ldif new file mode 100644 index 000000000..38b93523a --- /dev/null +++ b/lam/docs/schema/tak-Samba4-attributes.ldif @@ -0,0 +1,58 @@ +# +# LDAP schema for LAM TAK functionality +# +# This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) +# Copyright (C) 2025 Roland Gruber +# +# +# OID bases: +# 1.3.6.1.4.1.34955 Roland Gruber Softwareentwicklung +# 1.3.6.1.4.1.34955.1 attributes +# 1.3.6.1.4.1.34955.2 object classes +# +# Please replace DOMAIN_TOP_DN with your LDAP suffix (e.g. dc=samba4,dc=test). +# This file must be installed first. +# +# Installation: ldbmodify -H /var/lib/samba/private/sam.ldb tak-Samba4-attributes.ldif --option="dsdb:schema update allowed"=true +# +# +# Version: 1 +# 1: initial release (LAM 9.2) +# + +dn: CN=takCallsign,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.100 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +rangeLower: 4 +cn: takCallsign +name: takCallsign +lDAPDisplayName: takCallsign +description: TAK callsign + +dn: CN=takRole,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.101 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +cn: takRole +name: takRole +lDAPDisplayName: takRole +description: TAK team role + +dn: CN=takColor,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.102 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +cn: takColor +name: takColor +LDAPDisplayName: takColor +Description: TAK team color diff --git a/lam/docs/schema/tak-Samba4-objectClass.ldif b/lam/docs/schema/tak-Samba4-objectClass.ldif new file mode 100644 index 000000000..25d165988 --- /dev/null +++ b/lam/docs/schema/tak-Samba4-objectClass.ldif @@ -0,0 +1,36 @@ +# +# LDAP schema for LAM TAK functionality +# +# This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) +# Copyright (C) 2025 Roland Gruber +# +# +# OID bases: +# 1.3.6.1.4.1.34955 Roland Gruber Softwareentwicklung +# 1.3.6.1.4.1.34955.1 attributes +# 1.3.6.1.4.1.34955.2 object classes +# +# Please replace DOMAIN_TOP_DN with your LDAP suffix (e.g. dc=samba4,dc=test). +# This file must be installed second. +# +# Installation: ldbmodify -H /var/lib/samba/private/sam.ldb tak-Samba4-objectClass.ldif --option="dsdb:schema update allowed"=true +# +# +# Version: 1 +# 1: initial release (LAM 9.2) +# + +dn: CN=takUser,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +objectClass: top +objectClass: classSchema +governsID: 1.3.6.1.4.1.34955.2.10 +cn: takUser +lDAPDisplayName: takUser +subClassOf: top +objectClassCategory: 3 +mustContain: cn +mayContain: takCallsign +mayContain: takRole +mayContain: takColor +description: TAK user +possSuperiors: top diff --git a/lam/docs/schema/tak-Windows.ldif b/lam/docs/schema/tak-Windows.ldif new file mode 100644 index 000000000..0fba52bed --- /dev/null +++ b/lam/docs/schema/tak-Windows.ldif @@ -0,0 +1,100 @@ +# +# LDAP schema for LAM TAK functionality +# +# This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) +# Copyright (C) 2025 Roland Gruber +# +# +# OID bases: +# 1.3.6.1.4.1.34955 Roland Gruber Softwareentwicklung +# 1.3.6.1.4.1.34955.1 attributes +# 1.3.6.1.4.1.34955.2 object classes +# +# Please replace DOMAIN_TOP_DN with your LDAP suffix (e.g. dc=windows,dc=test). +# +# Installation: ldifde -v -i -f tak-Windows.ldif +# +# +# Version: 1 +# 1: initial release (LAM 9.2) +# + +dn: CN=takCallsign,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +changetype: add +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.100 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +rangeLower: 4 +cn: takCallsign +name: takCallsign +lDAPDisplayName: takCallsign +description: TAK callsign + +dn: CN=takRole,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +changetype: add +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.101 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +cn: takRole +name: takRole +lDAPDisplayName: takRole +description: TAK team role + +dn: CN=takColor,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +changetype: add +objectClass: top +objectClass: attributeSchema +attributeID: 1.3.6.1.4.1.34955.1.102 +attributeSyntax: 2.5.5.12 +oMSyntax: 64 +isSingleValued: TRUE +cn: takColor +name: takColor +LDAPDisplayName: takColor +Description: TAK team color + +dn: +changetype: modify +add: schemaUpdateNow +schemaUpdateNow: 1 +- + +dn: CN=takUser,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +changetype: add +objectClass: top +objectClass: classSchema +governsID: 1.3.6.1.4.1.34955.2.10 +cn: takUser +lDAPDisplayName: takUser +subClassOf: top +objectClassCategory: 3 +mustContain: cn +mayContain: takCallsign +mayContain: takRole +mayContain: takColor +description: TAK user +possSuperiors: top + +dn: +changetype: modify +add: schemaUpdateNow +schemaUpdateNow: 1 +- + +dn: CN=User,CN=Schema,CN=Configuration,DOMAIN_TOP_DN +changetype: modify +add: auxiliaryClass +auxiliaryClass: takUser +- + +dn: +changetype: modify +add: schemaUpdateNow +schemaUpdateNow: 1 +- diff --git a/lam/graphics/bind9.png b/lam/graphics/bind9.png new file mode 100644 index 000000000..b62da561d Binary files /dev/null and b/lam/graphics/bind9.png differ diff --git a/lam/graphics/compare.svg b/lam/graphics/compare.svg new file mode 100644 index 000000000..6170ab5c8 --- /dev/null +++ b/lam/graphics/compare.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/lam/graphics/list-add.svg b/lam/graphics/list-add.svg new file mode 100644 index 000000000..348b00d5f --- /dev/null +++ b/lam/graphics/list-add.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/lam/graphics/list-remove.svg b/lam/graphics/list-remove.svg new file mode 100644 index 000000000..c35f7e19d --- /dev/null +++ b/lam/graphics/list-remove.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/lam/help/help.inc b/lam/help/help.inc index e1f80e89f..1a79ce4ad 100644 --- a/lam/help/help.inc +++ b/lam/help/help.inc @@ -5,7 +5,7 @@ use \LAM\TYPES\TypeManager; This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) Copyright (C) 2003 - 2006 Michael Duergner - 2003 - 2024 Roland Gruber + 2003 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,9 +42,9 @@ if (isset($_SESSION['conf_config'])) { $entry206Example .= "" . $type->getAlias() . ":
    \n"; $descriptions = $type->getBaseType()->getListAttributeDescriptions(); $attributes = array_keys($descriptions); - for ($a = 0; $a < sizeof($attributes); $a++) { + for ($a = 0; $a < count($attributes); $a++) { $entry206Example .= "#" . $attributes[$a] . ": " . $descriptions[$attributes[$a]]; - if ($a < (sizeof($attributes) - 1)) { + if ($a < (count($attributes) - 1)) { $entry206Example .= ", "; } } @@ -239,7 +239,7 @@ $helpArray = [ "Text" => _("Please select if the connection should be encrypted via TLS, SSL or not at all.") ], "257" => ["Headline" => _("Hide LDAP details on failed login"), - "Text" => _("If activated, LAM will not display and details why the login to LAM failed. Use this if you have high security requirements and want to prevent e.g. user name guessing.") + "Text" => _("If activated, LAM will not display any details why the login to LAM failed. Use this if you have high security requirements and want to prevent e.g. user name guessing.") ], "258" => ["Headline" => _("Mail attribute"), "Text" => _("This LDAP attribute contains the account's primary mail address.") @@ -300,6 +300,9 @@ $helpArray = [ "276" => ["Headline" => _('Database name'), "Text" => _('This is the database name on the server.') ], + "277" => ["Headline" => _('CA certificate path'), + "Text" => _('For SSL-secured connections please enter the path to your CA certificate file.') + ], '280' => ["Headline" => _('Allow setting specific passwords'), "Text" => _('Allows to set a specific password via input field.') ], @@ -333,7 +336,7 @@ $helpArray = [ '289' => ["Headline" => _('From address'), "Text" => _('This email address will be set as sender address of the mails.') ], - '290' => ["Headline" => _('TO address'), + '290' => ["Headline" => _('To address'), "Text" => _('This email address will be set as TO address for the mails.') . ' ' . _("Multiple values are separated by semicolon.") ], @@ -349,6 +352,33 @@ $helpArray = [ "294" => ["Headline" => _('Cron command'), "Text" => _('Run this for global cleanup tasks. See manual for details.') ], + "295" => ["Headline" => _("Show deleted entries"), + "Text" => _("This enables to show deleted entries in \"CN=Deleted Objects\" for Active Directory.") + ], + "296" => ["Headline" => _("SMS provider"), + "Text" => _("Please select the SMS provider that should be used for password and reset link sending.") + ], + "297" => ["Headline" => _("API key"), + "Text" => _("Please enter the API key of your SMS provider.") + ], + "298" => ["Headline" => _("Token"), + "Text" => _("Please enter the API token of your SMS provider.") + ], + "298a" => ["Headline" => _("Account id"), + "Text" => _("Please enter the account id of your SMS provider.") + ], + "299" => ["Headline" => _("Mobile phone attributes"), + "Text" => _("Please enter the LDAP attributes that should be checked to identify the user's mobile phone number.") . ' ' . _("Multiple values are separated by semicolon.") + ], + "299a" => ["Headline" => _("Default country prefix"), + "Text" => _("Please enter the default country prefix for your phone numbers (e.g. '+49').") + ], + "299b" => ["Headline" => _("From"), + "Text" => _("Please enter the phone number or messaging service ID that acts as the source of the message.") + ], + "299c" => ["Headline" => _("Region"), + "Text" => _("Please enter the region ID for the SMS service.") + ], // 300 - 399 // profile/PDF editor, file upload "301" => ["Headline" => _("RDN identifier"), @@ -408,6 +438,9 @@ $helpArray = [ "411" => ["Headline" => _("Font"), "Text" => _("Please select the font for the PDF file. Dejavu will work on all systems but does not support e.g. Chinese and Japanese. The other fonts require that an appropriate font is installed on the system where the PDF is opened.") ], + "412" => ["Headline" => _("Send via SMS"), + "Text" => _("Sends the password to the user via SMS.") + ], // 500 - 599 // LAM Pro "501" => ["Headline" => _("LDAP suffix"), @@ -539,6 +572,9 @@ $helpArray = [ "Text" => _('This email address will be set as To address of all mails.') . ' ' . _('Multiple values are separated by comma.') ], + "558" => ["Headline" => _("Send SMS"), + "Text" => _('Sends the confirmation link by SMS. If no phone number is found then an email will be sent.') + ], "560" => ["Headline" => _("Remember device"), "Text" => _('This will remember your current device. You will not need to provide your 2nd factor for a configured period of time.') ], diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index 2c14fec1a..3918ada22 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -7,8 +7,14 @@ use DateTime; use Duo\DuoUniversal\Client; use Duo\DuoUniversal\DuoException; use Exception; +use Facile\OpenIDClient\Client\ClientBuilder; +use Facile\OpenIDClient\Client\ClientInterface; +use Facile\OpenIDClient\Client\Metadata\ClientMetadata; +use Facile\OpenIDClient\Issuer\IssuerBuilder; +use GuzzleHttp\Psr7\ServerRequest; use htmlResponsiveRow; use LAM\LOGIN\WEBAUTHN\WebauthnManager; +use LAM_INTERFACE; use SelfServiceLoginHandler; use selfServiceProfile; use LAMConfig; @@ -23,7 +29,7 @@ use Webauthn\PublicKeyCredentialCreationOptions; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2017 - 2024 Roland Gruber + Copyright (C) 2017 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -65,7 +71,7 @@ interface TwoFactorProvider { * @param string $password password * @param string $serial serial number of token * @param string $twoFactorInput input for 2nd factor - * @return boolean true if verified and false if verification failed + * @return bool true if verified and false if verification failed * @throws Exception error during check */ public function verify2ndFactor($user, $password, $serial, $twoFactorInput); @@ -74,7 +80,7 @@ interface TwoFactorProvider { * Returns if the service has a custom input form. * In this case the token field is not displayed. * - * @return has custom input form + * @return bool has custom input form */ public function hasCustomInputForm(); @@ -130,7 +136,7 @@ abstract class BaseProvider implements TwoFactorProvider { * Returns the value of the user attribute in LDAP. * * @param string $userDn user DN - * @return string user name + * @return string|null user name */ protected function getLoginAttributeValue($userDn) { $attrName = $this->config->twoFactorAuthenticationSerialAttributeName; @@ -456,7 +462,7 @@ class DuoProvider extends BaseProvider { * @see BaseProvider::addCustomInput */ public function addCustomInput(&$row, $userDn) { - $pathPrefix = $this->config->isSelfService ? '../' : ''; + $pathPrefix = ($this->config->interface === LAM_INTERFACE::SELF_SERVICE) ? '../' : ''; $row->add(new htmlImage($pathPrefix . '../graphics/duo.png')); if (!empty($_GET['duo_code'])) { // authentication is verified @@ -607,7 +613,7 @@ class OktaProvider extends BaseProvider { return; } - $pathPrefix = $this->config->isSelfService ? '../' : ''; + $pathPrefix = ($this->config->interface === LAM_INTERFACE::SELF_SERVICE) ? '../' : ''; $row->add(new htmlImage($pathPrefix . '../graphics/okta.png')); $_SESSION['okta_state'] = bin2hex(random_bytes(10)); $_SESSION['okta_code_verifier'] = bin2hex(random_bytes(50)); @@ -792,7 +798,7 @@ class OpenIdProvider extends BaseProvider { return; } $content = new htmlResponsiveRow(); - $pathPrefix = $this->config->isSelfService ? '../' : ''; + $pathPrefix = ($this->config->interface === LAM_INTERFACE::SELF_SERVICE) ? '../' : ''; $row->add(new htmlImage($pathPrefix . '../graphics/openid.png')); include_once __DIR__ . '/3rdParty/composer/autoload.php'; try { @@ -831,10 +837,10 @@ class OpenIdProvider extends BaseProvider { /** * Returns the client object. * - * @return \Facile\OpenIDClient\Client\Client client + * @return ClientInterface client */ - private function getOpenIdClient(): \Facile\OpenIDClient\Client\Client { - $issuer = (new \Facile\OpenIDClient\Issuer\IssuerBuilder())->build($this->config->twoFactorAuthenticationURL . '/.well-known/openid-configuration'); + private function getOpenIdClient(): ClientInterface { + $issuer = (new IssuerBuilder())->build($this->config->twoFactorAuthenticationURL . '/.well-known/openid-configuration'); $meta = [ 'client_id' => $this->config->twoFactorAuthenticationClientId, 'client_secret' => $this->config->twoFactorAuthenticationSecretKey, @@ -843,8 +849,8 @@ class OpenIdProvider extends BaseProvider { if (!empty($_GET['redirect_uri'])) { $meta['redirect_uri'] = $_GET['redirect_uri']; } - $clientMetadata = \Facile\OpenIDClient\Client\Metadata\ClientMetadata::fromArray($meta); - return (new \Facile\OpenIDClient\Client\ClientBuilder()) + $clientMetadata = ClientMetadata::fromArray($meta); + return (new ClientBuilder()) ->setIssuer($issuer) ->setClientMetadata($clientMetadata) ->build(); @@ -874,7 +880,7 @@ class OpenIdProvider extends BaseProvider { include_once __DIR__ . '/3rdParty/composer/autoload.php'; $client = $this->getOpenIdClient(); $authorizationService = $this->getAuthorizationService(); - $serverRequest = \GuzzleHttp\Psr7\ServerRequest::fromGlobals(); + $serverRequest = ServerRequest::fromGlobals(); try { $callbackParams = $authorizationService->getCallbackParams($serverRequest, $client); $tokenSet = $authorizationService->callback($client, $callbackParams, $_GET['redirect_uri']); @@ -971,8 +977,8 @@ class WebauthnProvider extends BaseProvider { $row->add(new htmlStatusMessage('INFO', _('Please register a security device.'))); } $row->addVerticalSpacer('2rem'); - $pathPrefix = $this->config->isSelfService ? '../' : ''; - $selfServiceParam = $this->config->isSelfService ? 'true' : 'false'; + $pathPrefix = ($this->config->interface === LAM_INTERFACE::SELF_SERVICE) ? '../' : ''; + $selfServiceParam = ($this->config->interface === LAM_INTERFACE::SELF_SERVICE) ? 'selfservice=true' : ''; $row->add(new htmlImage($pathPrefix . '../graphics/webauthn.svg', '50%')); $row->addVerticalSpacer('1rem'); $errorMessage = new htmlStatusMessage('ERROR', '', _('This service requires a browser with "WebAuthn" support.')); @@ -990,7 +996,9 @@ class WebauthnProvider extends BaseProvider { $errorMessageDiv->addDataAttribute('button', _('Ok')); $errorMessageDiv->addDataAttribute('title', _('WebAuthn failed')); $row->add($errorMessageDiv); - $row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', ' . $selfServiceParam . ');'), 0); + $row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', \'' . $selfServiceParam . '\',' . + ' \'' . _('Do you want to set a name for this device?') . '\', \'' . _('Name') . '\',' . + ' \'' . _('Ok') . '\', \'' . _('Cancel') . '\');'), 0); } /** @@ -1024,7 +1032,14 @@ class WebauthnProvider extends BaseProvider { } $response = base64_decode($_POST['sig_response']); $registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']); - return $webauthnManager->storeNewRegistration($registrationObject, $response); + if (!$webauthnManager->storeNewRegistration($registrationObject, $response)) { + return false; + } + if (!empty($_POST['newName'])) { + $deviceList = $webauthnManager->getDatabase()->findAllForUserDn($userDn); + $webauthnManager->getDatabase()->updateDeviceName($userDn, base64_encode($deviceList[0]->getPublicKeyCredentialId()), $_POST['newName']); + } + return true; } else { logNewMessage(LOG_DEBUG, 'Checking WebAuthn response of ' . $userDn); @@ -1072,7 +1087,7 @@ class TwoFactorProviderService { * * @param selfServiceProfile|LAMConfig $configObj profile */ - public function __construct(&$configObj) { + public function __construct(selfServiceProfile|LAMConfig $configObj) { if ($configObj instanceof selfServiceProfile) { $this->config = $this->getConfigSelfService($configObj); } @@ -1084,7 +1099,6 @@ class TwoFactorProviderService { /** * Returns the provider for the given type. * - * @param string $type authentication type * @return TwoFactorProvider provider * @throws Exception unable to get provider */ @@ -1231,7 +1245,7 @@ class TwoFactorProviderService { */ private function getConfigSelfService(&$profile): TwoFactorConfiguration { $tfConfig = new TwoFactorConfiguration(); - $tfConfig->isSelfService = true; + $tfConfig->interface = LAM_INTERFACE::SELF_SERVICE; $tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication; $tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure; $tfConfig->twoFactorAuthenticationOptional = $profile->twoFactorAuthenticationOptional; @@ -1281,7 +1295,7 @@ class TwoFactorProviderService { */ private function getConfigAdmin($conf): TwoFactorConfiguration { $tfConfig = new TwoFactorConfiguration(); - $tfConfig->isSelfService = false; + $tfConfig->interface = LAM_INTERFACE::ADMIN; $tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication(); $tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure(); $tfConfig->twoFactorAuthenticationOptional = $conf->getTwoFactorAuthenticationOptional(); @@ -1327,10 +1341,8 @@ class TwoFactorProviderService { */ class TwoFactorConfiguration { - /** - * @var bool is self service - */ - public bool $isSelfService = false; + /** LAM UI */ + public LAM_INTERFACE $interface = LAM_INTERFACE::ADMIN; /** * @var ?string provider id diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/CODE_OF_CONDUCT.md b/lam/lib/3rdParty/composer/aws/aws-crt-php/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..5b627cfa6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/LICENSE b/lam/lib/3rdParty/composer/aws/aws-crt-php/LICENSE new file mode 100644 index 000000000..67db85882 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/NOTICE b/lam/lib/3rdParty/composer/aws/aws-crt-php/NOTICE new file mode 100644 index 000000000..616fc5889 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/NOTICE @@ -0,0 +1 @@ +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/README.md b/lam/lib/3rdParty/composer/aws/aws-crt-php/README.md new file mode 100644 index 000000000..6cb323dbf --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/README.md @@ -0,0 +1,117 @@ +# AWS Common Runtime PHP bindings + +## Requirements + +* PHP 5.5+ on UNIX platforms, 7.2+ on Windows +* CMake 3.x +* GCC 4.4+, clang 3.8+ on UNIX, Visual Studio build tools on Windows +* Tests require [Composer](https://getcomposer.org) + +## Installing with Composer and PECL + +The package has two different package published to [composer](https://packagist.org/packages/aws/aws-crt-php) and [PECL](https://pecl.php.net/package/awscrt). + +On UNIX, you can get the package from package manager or build from source: + +``` +pecl install awscrt +composer require aws/aws-crt-php +``` + +On Windows, you need to build from source as instruction written below for the native extension `php_awscrt.dll` . And, follow https://www.php.net/manual/en/install.pecl.windows.php#install.pecl.windows.loading to load extension. After that: + +``` +composer require aws/aws-crt-php +``` + +## Building from Github source + +```sh +$ git clone --recursive https://github.com/awslabs/aws-crt-php.git +$ cd aws-crt-php +$ phpize +$ ./configure +$ make +$ ./dev-scripts/run_tests.sh +``` + +## Building on Windows + +### Requirements for Windows + +* Ensure you have the [windows PHP SDK](https://github.com/microsoft/php-sdk-binary-tools) (this example assumes installation of the SDK to C:\php-sdk and that you've checked out the PHP source to php-src within the build directory) and it works well on your machine. + +* Ensure you have "Development package (SDK to develop PHP extensions)" and PHP available from your system path. You can download them from https://windows.php.net/download/. You can check if they are available by running `phpize -v` and `php -v` + +### Instructions + +From Command Prompt (not powershell). The instruction is based on Visual Studio 2019 on 64bit Windows. + +```bat +> git clone --recursive https://github.com/awslabs/aws-crt-php.git +> git clone https://github.com/microsoft/php-sdk-binary-tools.git C:\php-sdk +> C:\php-sdk\phpsdk-vs16-x64.bat + +C:\php-sdk\ +$ cd + +\ +$ phpize + +# --with-prefix only required when your php runtime in system path is different than the runtime you wish to use. +\ +$ configure --enable-awscrt=shared --with-prefix= + +\ +$ nmake + +\ +$ nmake generate-php-ini + +# check .\php-win.ini, it now has the full path to php_awscrt.dll that you can manually load to your php runtime, or you can run the following command to run tests and load the required native extension for awscrt. +\ +$ .\dev-scripts\run_tests.bat +``` + +Note: for VS2017, Cmake will default to build for Win32, refer to [here](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2015%202017.html). If you are building for x64 php, you can set environment variable as follow to let cmake pick x64 compiler. + +```bat +set CMAKE_GENERATOR=Visual Studio 15 2017 +set CMAKE_GENERATOR_PLATFORM=x64 +``` + +## Debugging + +Using [PHPBrew](https://github.com/phpbrew/phpbrew) to build/manage multiple versions of PHP is helpful. + +Note: You must use a debug build of PHP to debug native extensions. +See the [PHP Internals Book](https://www.phpinternalsbook.com/php7/build_system/building_php.html) for more info + +```shell +# PHP 8 example +$ phpbrew install --stdout -j 8 8.0 +default -- CFLAGS=-Wno-error --disable-cgi --enable-debug +# PHP 5.5 example +$ phpbrew install --stdout -j 8 5.5 +default -openssl -mbstring -- CFLAGS="-w -Wno-error" --enable-debug --with-zlib=/usr/local/opt/zlib +$ phpbrew switch php-8.0.6 # or whatever version is current, it'll be at the end of the build output +$ phpize +$ ./configure +$ make CMAKE_BUILD_TYPE=Debug +``` + +Ensure that the php you launch from your debugger is the result of `which php` , not just +the system default php. + +## Security + +See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. + +## Known OpenSSL related issue (Unix only) + +* When your php loads a different version of openssl than your system openssl version, awscrt may fail to load or weirdly crash. You can find the openssl version php linked via: `php -i | grep 'OpenSSL'`, and awscrt linked from the build log, which will be `Found OpenSSL: * (found version *)` + +The easiest workaround to those issue is to build from source and get aws-lc for awscrt to depend on instead. +TO do that, same instructions as [here](#building-from-github-source), but use `USE_OPENSSL=OFF make` instead of `make` + +## License + +This project is licensed under the Apache-2.0 License. diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/composer.json b/lam/lib/3rdParty/composer/aws/aws-crt-php/composer.json new file mode 100644 index 000000000..13e7ac65e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/composer.json @@ -0,0 +1,35 @@ +{ + "name": "aws/aws-crt-php", + "homepage": "https://github.com/awslabs/aws-crt-php", + "description": "AWS Common Runtime for PHP", + "keywords": ["aws","amazon","sdk","crt"], + "type": "library", + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "minimum-stability": "alpha", + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit":"^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "scripts": { + "test": "./dev-scripts/run_tests.sh", + "test-extension": "@test", + "test-win": ".\\dev-scripts\\run_tests.bat" + }, + "license": "Apache-2.0" +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/format-check.py b/lam/lib/3rdParty/composer/aws/aws-crt-php/format-check.py new file mode 100755 index 000000000..35ac46e8c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/format-check.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path +import re +from subprocess import list2cmdline, run +from tempfile import NamedTemporaryFile + +CLANG_FORMAT_VERSION = '18.1.6' + +INCLUDE_REGEX = re.compile(r'^ext/.*\.(c|h|inl)$') +EXCLUDE_REGEX = re.compile(r'^$') + +arg_parser = argparse.ArgumentParser(description="Check with clang-format") +arg_parser.add_argument('-i', '--inplace-edit', action='store_true', + help="Edit files inplace") +args = arg_parser.parse_args() + +os.chdir(Path(__file__).parent) + +# create file containing list of all files to format +filepaths_file = NamedTemporaryFile(delete=False) +for dirpath, dirnames, filenames in os.walk('.'): + for filename in filenames: + # our regexes expect filepath to use forward slash + filepath = Path(dirpath, filename).as_posix() + if not INCLUDE_REGEX.match(filepath): + continue + if EXCLUDE_REGEX.match(filepath): + continue + + filepaths_file.write(f"{filepath}\n".encode()) +filepaths_file.close() + +# use pipx to run clang-format from PyPI +# this is a simple way to run the same clang-format version regardless of OS +cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}', + f'--files={filepaths_file.name}'] +if args.inplace_edit: + cmd += ['-i'] +else: + cmd += ['--Werror', '--dry-run'] + +print(f"{Path.cwd()}$ {list2cmdline(cmd)}") +if run(cmd).returncode: + exit(1) diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php new file mode 100644 index 000000000..6f6acee2c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php @@ -0,0 +1,69 @@ + '', + 'secret_access_key' => '', + 'session_token' => '', + 'expiration_timepoint_seconds' => 0, + ]; + } + + private $access_key_id; + private $secret_access_key; + private $session_token; + private $expiration_timepoint_seconds = 0; + + public function __get($name) { + return $this->$name; + } + + function __construct(array $options = []) { + parent::__construct(); + + $options = new Options($options, self::defaults()); + $this->access_key_id = $options->access_key_id->asString(); + $this->secret_access_key = $options->secret_access_key->asString(); + $this->session_token = $options->session_token ? $options->session_token->asString() : null; + $this->expiration_timepoint_seconds = $options->expiration_timepoint_seconds->asInt(); + + if (strlen($this->access_key_id) == 0) { + throw new \InvalidArgumentException("access_key_id must be provided"); + } + if (strlen($this->secret_access_key) == 0) { + throw new \InvalidArgumentException("secret_access_key must be provided"); + } + + $creds_options = self::$crt->aws_credentials_options_new(); + self::$crt->aws_credentials_options_set_access_key_id($creds_options, $this->access_key_id); + self::$crt->aws_credentials_options_set_secret_access_key($creds_options, $this->secret_access_key); + self::$crt->aws_credentials_options_set_session_token($creds_options, $this->session_token); + self::$crt->aws_credentials_options_set_expiration_timepoint_seconds($creds_options, $this->expiration_timepoint_seconds); + $this->acquire(self::$crt->aws_credentials_new($creds_options)); + self::$crt->aws_credentials_options_release($creds_options); + } + + function __destruct() { + self::$crt->aws_credentials_release($this->release()); + parent::__destruct(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php new file mode 100644 index 000000000..e9d358867 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php @@ -0,0 +1,23 @@ +credentials_provider_release($this->release()); + parent::__destruct(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php new file mode 100644 index 000000000..100b56ad5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php @@ -0,0 +1,43 @@ +signable_new_from_http_request($http_message->native); + }); + } + + public static function fromChunk($chunk_stream, $previous_signature="") { + if (!($chunk_stream instanceof InputStream)) { + $chunk_stream = new InputStream($chunk_stream); + } + return new Signable(function() use($chunk_stream, $previous_signature) { + return self::$crt->signable_new_from_chunk($chunk_stream->native, $previous_signature); + }); + } + + public static function fromCanonicalRequest($canonical_request) { + return new Signable(function() use($canonical_request) { + return self::$crt->signable_new_from_canonical_request($canonical_request); + }); + } + + protected function __construct($ctor) { + parent::__construct(); + $this->acquire($ctor()); + } + + function __destruct() { + self::$crt->signable_release($this->release()); + parent::__destruct(); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php new file mode 100644 index 000000000..3d3b99f08 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php @@ -0,0 +1,15 @@ +sign_request_aws($signable->native, $signing_config->native, + function($result, $error_code) use ($on_complete) { + $signing_result = SigningResult::fromNative($result); + $on_complete($signing_result, $error_code); + }, null); + } + + static function testVerifySigV4ASigning($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) { + return self::$crt->test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php new file mode 100644 index 000000000..dd1105989 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php @@ -0,0 +1,11 @@ + SigningAlgorithm::SIGv4, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => null, + 'region' => null, + 'service' => null, + 'use_double_uri_encode' => false, + 'should_normalize_uri_path' => false, + 'omit_session_token' => false, + 'signed_body_value' => null, + 'signed_body_header_type' => SignedBodyHeaderType::NONE, + 'expiration_in_seconds' => 0, + 'date' => time(), + 'should_sign_header' => null, + ]; + } + + private $options; + + public function __construct(array $options = []) { + parent::__construct(); + $this->options = $options = new Options($options, self::defaults()); + $sc = $this->acquire(self::$crt->signing_config_aws_new()); + self::$crt->signing_config_aws_set_algorithm($sc, $options->algorithm->asInt()); + self::$crt->signing_config_aws_set_signature_type($sc, $options->signature_type->asInt()); + if ($credentials_provider = $options->credentials_provider->asObject()) { + self::$crt->signing_config_aws_set_credentials_provider( + $sc, + $credentials_provider->native); + } + self::$crt->signing_config_aws_set_region( + $sc, $options->region->asString()); + self::$crt->signing_config_aws_set_service( + $sc, $options->service->asString()); + self::$crt->signing_config_aws_set_use_double_uri_encode( + $sc, $options->use_double_uri_encode->asBool()); + self::$crt->signing_config_aws_set_should_normalize_uri_path( + $sc, $options->should_normalize_uri_path->asBool()); + self::$crt->signing_config_aws_set_omit_session_token( + $sc, $options->omit_session_token->asBool()); + self::$crt->signing_config_aws_set_signed_body_value( + $sc, $options->signed_body_value->asString()); + self::$crt->signing_config_aws_set_signed_body_header_type( + $sc, $options->signed_body_header_type->asInt()); + self::$crt->signing_config_aws_set_expiration_in_seconds( + $sc, $options->expiration_in_seconds->asInt()); + self::$crt->signing_config_aws_set_date($sc, $options->date->asInt()); + if ($should_sign_header = $options->should_sign_header->asCallable()) { + self::$crt->signing_config_aws_set_should_sign_header_fn($sc, $should_sign_header); + } + } + + function __destruct() + { + self::$crt->signing_config_aws_release($this->release()); + parent::__destruct(); + } + + public function __get($name) { + return $this->options->get($name); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php new file mode 100644 index 000000000..b8a4ab566 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php @@ -0,0 +1,33 @@ +acquire($native); + } + + function __destruct() { + // No destruction necessary, SigningResults are transient, just release + $this->release(); + parent::__destruct(); + } + + public static function fromNative($ptr) { + return new SigningResult($ptr); + } + + public function applyToHttpRequest(&$http_request) { + self::$crt->signing_result_apply_to_http_request($this->native, $http_request->native); + // Update http_request from native + $http_request = Request::unmarshall($http_request->toBlob()); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php new file mode 100644 index 000000000..8dc624944 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php @@ -0,0 +1,35 @@ +$name; + } + + function __construct(array $options = []) { + parent::__construct(); + $this->credentials = new AwsCredentials($options); + + $provider_options = self::$crt->credentials_provider_static_options_new(); + self::$crt->credentials_provider_static_options_set_access_key_id($provider_options, $this->credentials->access_key_id); + self::$crt->credentials_provider_static_options_set_secret_access_key($provider_options, $this->credentials->secret_access_key); + self::$crt->credentials_provider_static_options_set_session_token($provider_options, $this->credentials->session_token); + $this->acquire(self::$crt->credentials_provider_static_new($provider_options)); + self::$crt->credentials_provider_static_options_release($provider_options); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/CRT.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/CRT.php new file mode 100644 index 000000000..d196a4737 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/CRT.php @@ -0,0 +1,358 @@ +aws_crt_last_error(); + } + + /** + * @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error} + * @return string Human-readable description of the provided error code + */ + public static function error_str($error) { + return self::$impl->aws_crt_error_str((int) $error); + } + + /** + * @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error} + * @return string Name/enum identifier for the provided error code + */ + public static function error_name($error) { + return self::$impl->aws_crt_error_name((int) $error); + } + + public static function log_to_stdout() { + return self::$impl->aws_crt_log_to_stdout(); + } + + public static function log_to_stderr() { + return self::$impl->aws_crt_log_to_stderr(); + } + + public static function log_to_file($filename) { + return self::$impl->aws_crt_log_to_file($filename); + } + + public static function log_to_stream($stream) { + return self::$impl->aws_crt_log_to_stream($stream); + } + + public static function log_set_level($level) { + return self::$impl->aws_crt_log_set_level($level); + } + + public static function log_stop() { + return self::$impl->aws_crt_log_stop(); + } + + public static function log_message($level, $message) { + return self::$impl->aws_crt_log_message($level, $message); + } + + /** + * @return object Pointer to native event_loop_group_options + */ + function event_loop_group_options_new() { + return self::$impl->aws_crt_event_loop_group_options_new(); + } + + /** + * @param object $elg_options Pointer to native event_loop_group_options + */ + function event_loop_group_options_release($elg_options) { + self::$impl->aws_crt_event_loop_group_options_release($elg_options); + } + + /** + * @param object $elg_options Pointer to native event_loop_group_options + * @param integer $max_threads Maximum number of threads to allow the event loop group to use, default: 0/1 per CPU core + */ + function event_loop_group_options_set_max_threads($elg_options, $max_threads) { + self::$impl->aws_crt_event_loop_group_options_set_max_threads($elg_options, (int)$max_threads); + } + + /** + * @param object Pointer to event_loop_group_options, {@see event_loop_group_options_new} + * @return object Pointer to the new event loop group + */ + function event_loop_group_new($options) { + return self::$impl->aws_crt_event_loop_group_new($options); + } + + /** + * @param object $elg Pointer to the event loop group to release + */ + function event_loop_group_release($elg) { + self::$impl->aws_crt_event_loop_group_release($elg); + } + + /** + * return object Pointer to native AWS credentials options + */ + function aws_credentials_options_new() { + return self::$impl->aws_crt_credentials_options_new(); + } + + function aws_credentials_options_release($options) { + self::$impl->aws_crt_credentials_options_release($options); + } + + function aws_credentials_options_set_access_key_id($options, $access_key_id) { + self::$impl->aws_crt_credentials_options_set_access_key_id($options, $access_key_id); + } + + function aws_credentials_options_set_secret_access_key($options, $secret_access_key) { + self::$impl->aws_crt_credentials_options_set_secret_access_key($options, $secret_access_key); + } + + function aws_credentials_options_set_session_token($options, $session_token) { + self::$impl->aws_crt_credentials_options_set_session_token($options, $session_token); + } + + function aws_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds) { + self::$impl->aws_crt_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds); + } + + function aws_credentials_new($options) { + return self::$impl->aws_crt_credentials_new($options); + } + + function aws_credentials_release($credentials) { + self::$impl->aws_crt_credentials_release($credentials); + } + + function credentials_provider_release($provider) { + self::$impl->aws_crt_credentials_provider_release($provider); + } + + function credentials_provider_static_options_new() { + return self::$impl->aws_crt_credentials_provider_static_options_new(); + } + + function credentials_provider_static_options_release($options) { + self::$impl->aws_crt_credentials_provider_static_options_release($options); + } + + function credentials_provider_static_options_set_access_key_id($options, $access_key_id) { + self::$impl->aws_crt_credentials_provider_static_options_set_access_key_id($options, $access_key_id); + } + + function credentials_provider_static_options_set_secret_access_key($options, $secret_access_key) { + self::$impl->aws_crt_credentials_provider_static_options_set_secret_access_key($options, $secret_access_key); + } + + function credentials_provider_static_options_set_session_token($options, $session_token) { + self::$impl->aws_crt_credentials_provider_static_options_set_session_token($options, $session_token); + } + + function credentials_provider_static_new($options) { + return self::$impl->aws_crt_credentials_provider_static_new($options); + } + + function input_stream_options_new() { + return self::$impl->aws_crt_input_stream_options_new(); + } + + function input_stream_options_release($options) { + self::$impl->aws_crt_input_stream_options_release($options); + } + + function input_stream_options_set_user_data($options, $user_data) { + self::$impl->aws_crt_input_stream_options_set_user_data($options, $user_data); + } + + function input_stream_new($options) { + return self::$impl->aws_crt_input_stream_new($options); + } + + function input_stream_release($stream) { + self::$impl->aws_crt_input_stream_release($stream); + } + + function input_stream_seek($stream, $offset, $basis) { + return self::$impl->aws_crt_input_stream_seek($stream, $offset, $basis); + } + + function input_stream_read($stream, $length) { + return self::$impl->aws_crt_input_stream_read($stream, $length); + } + + function input_stream_eof($stream) { + return self::$impl->aws_crt_input_stream_eof($stream); + } + + function input_stream_get_length($stream) { + return self::$impl->aws_crt_input_stream_get_length($stream); + } + + function http_message_new_from_blob($blob) { + return self::$impl->aws_crt_http_message_new_from_blob($blob); + } + + function http_message_to_blob($message) { + return self::$impl->aws_crt_http_message_to_blob($message); + } + + function http_message_release($message) { + self::$impl->aws_crt_http_message_release($message); + } + + function signing_config_aws_new() { + return self::$impl->aws_crt_signing_config_aws_new(); + } + + function signing_config_aws_release($signing_config) { + return self::$impl->aws_crt_signing_config_aws_release($signing_config); + } + + function signing_config_aws_set_algorithm($signing_config, $algorithm) { + self::$impl->aws_crt_signing_config_aws_set_algorithm($signing_config, (int)$algorithm); + } + + function signing_config_aws_set_signature_type($signing_config, $signature_type) { + self::$impl->aws_crt_signing_config_aws_set_signature_type($signing_config, (int)$signature_type); + } + + function signing_config_aws_set_credentials_provider($signing_config, $credentials_provider) { + self::$impl->aws_crt_signing_config_aws_set_credentials_provider($signing_config, $credentials_provider); + } + + function signing_config_aws_set_region($signing_config, $region) { + self::$impl->aws_crt_signing_config_aws_set_region($signing_config, $region); + } + + function signing_config_aws_set_service($signing_config, $service) { + self::$impl->aws_crt_signing_config_aws_set_service($signing_config, $service); + } + + function signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode) { + self::$impl->aws_crt_signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode); + } + + function signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path) { + self::$impl->aws_crt_signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path); + } + + function signing_config_aws_set_omit_session_token($signing_config, $omit_session_token) { + self::$impl->aws_crt_signing_config_aws_set_omit_session_token($signing_config, $omit_session_token); + } + + function signing_config_aws_set_signed_body_value($signing_config, $signed_body_value) { + self::$impl->aws_crt_signing_config_aws_set_signed_body_value($signing_config, $signed_body_value); + } + + function signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type) { + self::$impl->aws_crt_signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type); + } + + function signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds) { + self::$impl->aws_crt_signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds); + } + + function signing_config_aws_set_date($signing_config, $timestamp) { + self::$impl->aws_crt_signing_config_aws_set_date($signing_config, $timestamp); + } + + function signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn) { + self::$impl->aws_crt_signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn); + } + + function signable_new_from_http_request($http_message) { + return self::$impl->aws_crt_signable_new_from_http_request($http_message); + } + + function signable_new_from_chunk($chunk_stream, $previous_signature) { + return self::$impl->aws_crt_signable_new_from_chunk($chunk_stream, $previous_signature); + } + + function signable_new_from_canonical_request($canonical_request) { + return self::$impl->aws_crt_signable_new_from_canonical_request($canonical_request); + } + + function signable_release($signable) { + self::$impl->aws_crt_signable_release($signable); + } + + function signing_result_release($signing_result) { + self::$impl->aws_crt_signing_result_release($signing_result); + } + + function signing_result_apply_to_http_request($signing_result, $http_message) { + return self::$impl->aws_crt_signing_result_apply_to_http_request( + $signing_result, $http_message); + } + + function sign_request_aws($signable, $signing_config, $on_complete, $user_data) { + return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete, $user_data); + } + + function test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) { + return self::$impl->aws_crt_test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y); + } + + public static function crc32($input, $previous = 0) { + return self::$impl->aws_crt_crc32($input, $previous); + } + + public static function crc32c($input, $previous = 0) { + return self::$impl->aws_crt_crc32c($input, $previous); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php new file mode 100644 index 000000000..8d1457cf7 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php @@ -0,0 +1,50 @@ +headers = $headers; + } + + public static function marshall($headers) { + $buf = ""; + foreach ($headers->headers as $header => $value) { + $buf .= Encoding::encodeString($header); + $buf .= Encoding::encodeString($value); + } + return $buf; + } + + public static function unmarshall($buf) { + $strings = Encoding::readStrings($buf); + $headers = []; + for ($idx = 0; $idx < count($strings);) { + $headers[$strings[$idx++]] = $strings[$idx++]; + } + return new Headers($headers); + } + + public function count() { + return count($this->headers); + } + + public function get($header) { + return isset($this->headers[$header]) ? $this->headers[$header] : null; + } + + public function set($header, $value) { + $this->headers[$header] = $value; + } + + public function toArray() { + return $this->headers; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php new file mode 100644 index 000000000..a8c151fe2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php @@ -0,0 +1,95 @@ +method = $method; + $this->path = $path; + $this->query = $query; + $this->headers = new Headers($headers); + $this->acquire(self::$crt->http_message_new_from_blob(self::marshall($this))); + } + + public function __destruct() { + self::$crt->http_message_release($this->release()); + parent::__destruct(); + } + + public function toBlob() { + return self::$crt->http_message_to_blob($this->native); + } + + protected static function marshall($msg) { + $buf = ""; + $buf .= Encoding::encodeString($msg->method); + $buf .= Encoding::encodeString($msg->pathAndQuery()); + $buf .= Headers::marshall($msg->headers); + return $buf; + } + + protected static function _unmarshall($buf, $class=Message::class) { + $method = Encoding::readString($buf); + $path_and_query = Encoding::readString($buf); + $parts = explode("?", $path_and_query, 2); + $path = isset($parts[0]) ? $parts[0] : ""; + $query = isset($parts[1]) ? $parts[1] : ""; + $headers = Headers::unmarshall($buf); + + // Turn query params back into a dictionary + if (strlen($query)) { + $query = rawurldecode($query); + $query = explode("&", $query); + $query = array_reduce($query, function($params, $pair) { + list($param, $value) = explode("=", $pair, 2); + $params[$param] = $value; + return $params; + }, []); + } else { + $query = []; + } + + return new $class($method, $path, $query, $headers->toArray()); + } + + public function pathAndQuery() { + $path = $this->path; + $queries = []; + foreach ($this->query as $param => $value) { + $queries []= urlencode($param) . "=" . urlencode($value); + } + $query = implode("&", $queries); + if (strlen($query)) { + $path = implode("?", [$path, $query]); + } + return $path; + } + + public function method() { + return $this->method; + } + + public function path() { + return $this->path; + } + + public function query() { + return $this->query; + } + + public function headers() { + return $this->headers; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php new file mode 100644 index 000000000..bec4ac1a1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php @@ -0,0 +1,32 @@ +body_stream = $body_stream; + } + + public static function marshall($request) { + return parent::marshall($request); + } + + public static function unmarshall($buf) { + return parent::_unmarshall($buf, Request::class); + } + + public function body_stream() { + return $this->body_stream; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php new file mode 100644 index 000000000..526edc3a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php @@ -0,0 +1,27 @@ +status_code = $status_code; + } + + public static function marshall($response) { + return parent::marshall($response); + } + + public static function unmarshall($buf) { + return parent::_unmarshall($buf, Response::class); + } + + public function status_code() { + return $this->status_code; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php new file mode 100644 index 000000000..7e989e768 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php @@ -0,0 +1,39 @@ + 0, + ]; + } + + function __construct(array $options = []) { + parent::__construct(); + $options = new Options($options, self::defaults()); + $elg_options = self::$crt->event_loop_group_options_new(); + self::$crt->event_loop_group_options_set_max_threads($elg_options, $options->getInt('max_threads')); + $this->acquire(self::$crt->event_loop_group_new($elg_options)); + self::$crt->event_loop_group_options_release($elg_options); + } + + function __destruct() { + self::$crt->event_loop_group_release($this->release()); + parent::__destruct(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php new file mode 100644 index 000000000..6aef70927 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php @@ -0,0 +1,50 @@ +stream = $stream; + $options = self::$crt->input_stream_options_new(); + // The stream implementation in native just converts the PHP stream into + // a native php_stream* and executes operations entirely in native + self::$crt->input_stream_options_set_user_data($options, $stream); + $this->acquire(self::$crt->input_stream_new($options)); + self::$crt->input_stream_options_release($options); + } + + public function __destruct() { + $this->release(); + parent::__destruct(); + } + + public function eof() { + return self::$crt->input_stream_eof($this->native); + } + + public function length() { + return self::$crt->input_stream_get_length($this->native); + } + + public function read($length = 0) { + if ($length == 0) { + $length = $this->length(); + } + return self::$crt->input_stream_read($this->native, $length); + } + + public function seek($offset, $basis) { + return self::$crt->input_stream_seek($this->native, $offset, $basis); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php new file mode 100644 index 000000000..7c625592d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php @@ -0,0 +1,37 @@ += self::NONE && $level <= self::TRACE); + CRT::log_set_level($level); + } + + public static function log($level, $message) { + CRT::log_message($level, $message); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/NativeResource.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/NativeResource.php new file mode 100644 index 000000000..528df759f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/NativeResource.php @@ -0,0 +1,42 @@ +native = $handle; + } + + protected function release() { + $native = $this->native; + $this->native = null; + return $native; + } + + function __destruct() { + // Should have been destroyed and released by derived resource + assert($this->native == null); + unset(self::$resources[spl_object_hash($this)]); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Options.php b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Options.php new file mode 100644 index 000000000..363a396c4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-crt-php/src/AWS/CRT/Options.php @@ -0,0 +1,77 @@ +value = $value; + } + + public function asObject() { + return $this->value; + } + + public function asMixed() { + return $this->value; + } + + public function asInt() { + return empty($this->value) ? 0 : (int)$this->value; + } + + public function asBool() { + return boolval($this->value); + } + + public function asString() { + return !empty($this->value) ? strval($this->value) : ""; + } + + public function asArray() { + return is_array($this->value) ? $this->value : (!empty($this->value) ? [$this->value] : []); + } + + public function asCallable() { + return is_callable($this->value) ? $this->value : null; + } +} + +final class Options { + private $options; + + public function __construct($opts = [], $defaults = []) { + $this->options = array_replace($defaults, empty($opts) ? [] : $opts); + } + + public function __get($name) { + return $this->get($name); + } + + public function asArray() { + return $this->options; + } + + public function toArray() { + return array_merge_recursive([], $this->options); + } + + public function get($name) { + return new OptionValue($this->options[$name]); + } + + public function getInt($name) { + return $this->get($name)->asInt(); + } + + public function getString($name) { + return $this->get($name)->asString(); + } + + public function getBool($name) { + return $this->get($name)->asBool(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/CODE_OF_CONDUCT.md b/lam/lib/3rdParty/composer/aws/aws-sdk-php/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..5dccd4cfb --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/CRT_INSTRUCTIONS.md b/lam/lib/3rdParty/composer/aws/aws-sdk-php/CRT_INSTRUCTIONS.md new file mode 100644 index 000000000..047b4b087 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/CRT_INSTRUCTIONS.md @@ -0,0 +1,4 @@ +## Building and enabling the Common Run Time + +1. **Follow instructions on crt repo** – Clone and build the repo as shown [here][https://github.com/awslabs/aws-crt-php]. +1. **Enable the CRT** – add the following line to your php.ini file `extension=path/to/aws-crt-php/modules/awscrt.so` \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/LICENSE b/lam/lib/3rdParty/composer/aws/aws-sdk-php/LICENSE new file mode 100644 index 000000000..8d53e9f5e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/LICENSE @@ -0,0 +1,141 @@ +# Apache License +Version 2.0, January 2004 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +## 1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 +through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the +License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled +by, or are under common control with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract +or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software +source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, +including but not limited to compiled object code, generated documentation, and conversions to other media +types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, +as indicated by a copyright notice that is included in or attached to the work (an example is provided in the +Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) +the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not +include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work +and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any +modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to +Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to +submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control systems, and issue tracking systems +that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been +received by Licensor and subsequently incorporated within the Work. + +## 2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +## 3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim +or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent licenses granted to You under this +License for that Work shall terminate as of the date such litigation is filed. + +## 4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, + trademark, and attribution notices from the Source form of the Work, excluding those notices that do + not pertain to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that + You distribute must include a readable copy of the attribution notices contained within such NOTICE + file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the Derivative Works; or, within a display + generated by the Derivative Works, if and wherever such third-party notices normally appear. The + contents of the NOTICE file are for informational purposes only and do not modify the License. You may + add Your own attribution notices within Derivative Works that You distribute, alongside or as an + addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be + construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license +terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative +Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the +conditions stated in this License. + +## 5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by +You to the Licensor shall be under the terms and conditions of this License, without any additional terms or +conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate +license agreement you may have executed with Licensor regarding such Contributions. + +## 6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of +the Licensor, except as required for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +## 7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor +provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +## 8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless +required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any +Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential +damages of any character arising as a result of this License or out of the use or inability to use the Work +(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has been advised of the possibility +of such damages. + +## 9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold +each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/NOTICE b/lam/lib/3rdParty/composer/aws/aws-sdk-php/NOTICE new file mode 100644 index 000000000..e231afd7a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/NOTICE @@ -0,0 +1,17 @@ +# AWS SDK for PHP + + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"). +You may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/THIRD-PARTY-LICENSES b/lam/lib/3rdParty/composer/aws/aws-sdk-php/THIRD-PARTY-LICENSES new file mode 100644 index 000000000..6f7dc6252 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/THIRD-PARTY-LICENSES @@ -0,0 +1,84 @@ +The AWS SDK for PHP includes the following third-party software/licensing: + + +** Guzzle - https://github.com/guzzle/guzzle + +Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------- + +** jmespath.php - https://github.com/mtdowling/jmespath.php + +Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------- + +** phpunit-mock-objects -- https://github.com/sebastianbergmann/phpunit-mock-objects + +Copyright (c) 2002-2018, Sebastian Bergmann . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Sebastian Bergmann nor the names of his + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/composer.json b/lam/lib/3rdParty/composer/aws/aws-sdk-php/composer.json new file mode 100644 index 000000000..55f22f05c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/composer.json @@ -0,0 +1,73 @@ +{ + "name": "aws/aws-sdk-php", + "homepage": "http://aws.amazon.com/sdkforphp", + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "keywords": ["aws","amazon","sdk","s3","ec2","dynamodb","cloud","glacier"], + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues" + }, + "require": { + "php": ">=8.1", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.4.5", + "guzzlehttp/promises": "^2.0", + "mtdowling/jmespath.php": "^2.8.0", + "ext-pcre": "*", + "ext-json": "*", + "ext-simplexml": "*", + "aws/aws-crt-php": "^1.2.3", + "psr/http-message": "^2.0" + }, + "require-dev": { + "composer/composer" : "^2.7.8", + "ext-openssl": "*", + "ext-dom": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "andrewsville/php-token-reflection": "^1.4", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "symfony/filesystem": "^v6.4.0 || ^v7.1.0", + "yoast/phpunit-polyfills": "^2.0", + "dms/phpunit-arraysubset-asserts": "^0.4.0" + }, + "suggest": { + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-curl": "To send requests using cURL", + "ext-sockets": "To use client-side monitoring", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications" + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": ["src/functions.php"], + "exclude-from-classmap": ["src/data/"] + }, + "autoload-dev": { + "psr-4": { + "Aws\\Test\\": "tests/" + }, + "classmap": ["build/"] + }, + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AbstractConfigurationProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AbstractConfigurationProvider.php new file mode 100644 index 000000000..78a5cdada --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AbstractConfigurationProvider.php @@ -0,0 +1,157 @@ +get($cacheKey); + if ($found instanceof static::$interfaceClass) { + return Promise\Create::promiseFor($found); + } + + return $provider() + ->then(function ($config) use ( + $cache, + $cacheKey + ) { + $cache->set($cacheKey, $config); + return $config; + }); + }; + } + + /** + * Creates an aggregate configuration provider that invokes the provided + * variadic providers one after the other until a provider returns + * configuration. + * + * @return callable + */ + public static function chain() + { + $links = func_get_args(); + if (empty($links)) { + throw new \InvalidArgumentException('No providers in chain'); + } + + return function () use ($links) { + /** @var callable $parent */ + $parent = array_shift($links); + $promise = $parent(); + while ($next = array_shift($links)) { + $promise = $promise->otherwise($next); + } + return $promise; + }; + } + + /** + * Gets the environment's HOME directory if available. + * + * @return null|string + */ + protected static function getHomeDir() + { + // On Linux/Unix-like systems, use the HOME environment variable + if ($homeDir = getenv('HOME')) { + return $homeDir; + } + + // Get the HOMEDRIVE and HOMEPATH values for Windows hosts + $homeDrive = getenv('HOMEDRIVE'); + $homePath = getenv('HOMEPATH'); + + return ($homeDrive && $homePath) ? $homeDrive . $homePath : null; + } + + /** + * Gets default config file location from environment, falling back to aws + * default location + * + * @return string + */ + protected static function getDefaultConfigFilename() + { + if ($filename = getenv(self::ENV_CONFIG_FILE)) { + return $filename; + } + return self::getHomeDir() . '/.aws/config'; + } + + /** + * Wraps a config provider and caches previously provided configuration. + * + * @param callable $provider Config provider function to wrap. + * + * @return callable + */ + public static function memoize(callable $provider) + { + return function () use ($provider) { + static $result; + static $isConstant; + + // Constant config will be returned constantly. + if ($isConstant) { + return $result; + } + + // Create the initial promise that will be used as the cached value + if (null === $result) { + $result = $provider(); + } + + // Return config and set flag that provider is already set + return $result + ->then(function ($config) use (&$isConstant) { + $isConstant = true; + return $config; + }); + }; + } + + /** + * Reject promise with standardized exception. + * + * @param $msg + * @return Promise\RejectedPromise + */ + protected static function reject($msg) + { + $exceptionClass = static::$exceptionClass; + return new Promise\RejectedPromise(new $exceptionClass($msg)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/AbstractModel.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/AbstractModel.php new file mode 100644 index 000000000..2c9b412d0 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/AbstractModel.php @@ -0,0 +1,89 @@ +definition = $definition; + $this->shapeMap = $shapeMap; + if (isset($definition['contextParam'])) { + $this->contextParam = $definition['contextParam']; + } + } + + public function toArray() + { + return $this->definition; + } + + /** + * @return mixed|null + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return isset($this->definition[$offset]) + ? $this->definition[$offset] : null; + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + $this->definition[$offset] = $value; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->definition[$offset]); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + unset($this->definition[$offset]); + } + + protected function shapeAt($key) + { + if (!isset($this->definition[$key])) { + throw new \InvalidArgumentException('Expected shape definition at ' + . $key); + } + + return $this->shapeFor($this->definition[$key]); + } + + protected function shapeFor(array $definition) + { + return isset($definition['shape']) + ? $this->shapeMap->resolve($definition) + : Shape::create($definition, $this->shapeMap); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ApiProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ApiProvider.php new file mode 100644 index 000000000..818ff5daf --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ApiProvider.php @@ -0,0 +1,244 @@ + 'api-2', + 'paginator' => 'paginators-1', + 'waiter' => 'waiters-2', + 'docs' => 'docs-2', + ]; + + /** @var array API manifest */ + private $manifest; + + /** @var string The directory containing service models. */ + private $modelsDir; + + /** + * Resolves an API provider and ensures a non-null return value. + * + * @param callable $provider Provider function to invoke. + * @param string $type Type of data ('api', 'waiter', 'paginator'). + * @param string $service Service name. + * @param string $version API version. + * + * @return array + * @throws UnresolvedApiException + */ + public static function resolve(callable $provider, $type, $service, $version) + { + // Execute the provider and return the result, if there is one. + $result = $provider($type, $service, $version); + if (is_array($result)) { + if (!isset($result['metadata']['serviceIdentifier'])) { + $result['metadata']['serviceIdentifier'] = $service; + } + return $result; + } + + // Throw an exception with a message depending on the inputs. + if (!isset(self::$typeMap[$type])) { + $msg = "The type must be one of: " . implode(', ', self::$typeMap); + } elseif ($service) { + $msg = "The {$service} service does not have version: {$version}."; + } else { + $msg = "You must specify a service name to retrieve its API data."; + } + + throw new UnresolvedApiException($msg); + } + + /** + * Default SDK API provider. + * + * This provider loads pre-built manifest data from the `data` directory. + * + * @return self + */ + public static function defaultProvider() + { + return new self(__DIR__ . '/../data', \Aws\manifest()); + } + + /** + * Loads API data after resolving the version to the latest, compatible, + * available version based on the provided manifest data. + * + * Manifest data is essentially an associative array of service names to + * associative arrays of API version aliases. + * + * [ + * ... + * 'ec2' => [ + * 'latest' => '2014-10-01', + * '2014-10-01' => '2014-10-01', + * '2014-09-01' => '2014-10-01', + * '2014-06-15' => '2014-10-01', + * ... + * ], + * 'ecs' => [...], + * 'elasticache' => [...], + * ... + * ] + * + * @param string $dir Directory containing service models. + * @param array $manifest The API version manifest data. + * + * @return self + */ + public static function manifest($dir, array $manifest) + { + return new self($dir, $manifest); + } + + /** + * Loads API data from the specified directory. + * + * If "latest" is specified as the version, this provider must glob the + * directory to find which is the latest available version. + * + * @param string $dir Directory containing service models. + * + * @return self + * @throws \InvalidArgumentException if the provided `$dir` is invalid. + */ + public static function filesystem($dir) + { + return new self($dir); + } + + /** + * Retrieves a list of valid versions for the specified service. + * + * @param string $service Service name + * + * @return array + */ + public function getVersions($service) + { + if (!isset($this->manifest)) { + $this->buildVersionsList($service); + } + + if (!isset($this->manifest[$service]['versions'])) { + return []; + } + + return array_values(array_unique($this->manifest[$service]['versions'])); + } + + /** + * Execute the provider. + * + * @param string $type Type of data ('api', 'waiter', 'paginator'). + * @param string $service Service name. + * @param string $version API version. + * + * @return array|null + */ + public function __invoke($type, $service, $version) + { + // Resolve the type or return null. + if (isset(self::$typeMap[$type])) { + $type = self::$typeMap[$type]; + } else { + return null; + } + + // Resolve the version or return null. + if (!isset($this->manifest)) { + $this->buildVersionsList($service); + } + + if (!isset($this->manifest[$service]['versions'][$version])) { + return null; + } + + $version = $this->manifest[$service]['versions'][$version]; + $path = "{$this->modelsDir}/{$service}/{$version}/{$type}.json"; + + try { + return \Aws\load_compiled_json($path); + } catch (\InvalidArgumentException $e) { + return null; + } + } + + /** + * @param string $modelsDir Directory containing service models. + * @param array $manifest The API version manifest data. + */ + private function __construct($modelsDir, ?array $manifest = null) + { + $this->manifest = $manifest; + $this->modelsDir = rtrim($modelsDir, '/'); + if (!is_dir($this->modelsDir)) { + throw new \InvalidArgumentException( + "The specified models directory, {$modelsDir}, was not found." + ); + } + } + + /** + * Build the versions list for the specified service by globbing the dir. + */ + private function buildVersionsList($service) + { + $dir = "{$this->modelsDir}/{$service}/"; + + if (!is_dir($dir)) { + return; + } + + // Get versions, remove . and .., and sort in descending order. + $results = array_diff(scandir($dir, SCANDIR_SORT_DESCENDING), ['..', '.']); + + if (!$results) { + $this->manifest[$service] = ['versions' => []]; + } else { + $this->manifest[$service] = [ + 'versions' => [ + 'latest' => $results[0] + ] + ]; + $this->manifest[$service]['versions'] += array_combine($results, $results); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DateTimeResult.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DateTimeResult.php new file mode 100644 index 000000000..b296abc49 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DateTimeResult.php @@ -0,0 +1,134 @@ +format('Y-m-d H:i:s.u'), + new DateTimeZone('UTC') + ); + } + + /** + * @return DateTimeResult + */ + public static function fromISO8601($iso8601Timestamp) + { + if (is_numeric($iso8601Timestamp) || !is_string($iso8601Timestamp)) { + throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromISO8601'); + } + + // Prior to 8.0.10, nanosecond precision is not supported + // Reduces to microsecond precision if nanosecond precision is detected + if (PHP_VERSION_ID < 80010 + && preg_match(self::ISO8601_NANOSECOND_REGEX, $iso8601Timestamp, $matches) + ) { + $iso8601Timestamp = $matches[1] . ($matches[3] ?? ''); + } + + return new DateTimeResult($iso8601Timestamp); + } + + /** + * Create a new DateTimeResult from an unknown timestamp. + * + * @return DateTimeResult + * @throws Exception + */ + public static function fromTimestamp($timestamp, $expectedFormat = null) + { + if (empty($timestamp)) { + return self::fromEpoch(0); + } + + if (!(is_string($timestamp) || is_numeric($timestamp))) { + throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp'); + } + + try { + if ($expectedFormat == 'iso8601') { + try { + return self::fromISO8601($timestamp); + } catch (Exception $exception) { + return self::fromEpoch($timestamp); + } + } else if ($expectedFormat == 'unixTimestamp') { + try { + return self::fromEpoch($timestamp); + } catch (Exception $exception) { + return self::fromISO8601($timestamp); + } + } else if (\Aws\is_valid_epoch($timestamp)) { + return self::fromEpoch($timestamp); + } + return self::fromISO8601($timestamp); + } catch (Exception $exception) { + throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp'); + } + } + + /** + * Serialize the DateTimeResult as an ISO 8601 date string. + * + * @return string + */ + public function __toString() + { + return $this->format('c'); + } + + /** + * Serialize the date as an ISO 8601 date when serializing as JSON. + * + * @return string + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return (string) $this; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DocModel.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DocModel.php new file mode 100644 index 000000000..1a0ecf95f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/DocModel.php @@ -0,0 +1,139 @@ +docs = $docs; + } + + /** + * Convert the doc model to an array. + * + * @return array + */ + public function toArray() + { + return $this->docs; + } + + /** + * Retrieves documentation about the service. + * + * @return null|string + */ + public function getServiceDocs() + { + return isset($this->docs['service']) ? $this->docs['service'] : null; + } + + /** + * Retrieves documentation about an operation. + * + * @param string $operation Name of the operation + * + * @return null|string + */ + public function getOperationDocs($operation) + { + return isset($this->docs['operations'][$operation]) + ? $this->docs['operations'][$operation] + : null; + } + + /** + * Retrieves documentation about an error. + * + * @param string $error Name of the error + * + * @return null|string + */ + public function getErrorDocs($error) + { + return isset($this->docs['shapes'][$error]['base']) + ? $this->docs['shapes'][$error]['base'] + : null; + } + + /** + * Retrieves documentation about a shape, specific to the context. + * + * @param string $shapeName Name of the shape. + * @param string $parentName Name of the parent/context shape. + * @param string $ref Name used by the context to reference the shape. + * + * @return null|string + */ + public function getShapeDocs($shapeName, $parentName, $ref) + { + if (!isset($this->docs['shapes'][$shapeName])) { + return ''; + } + + $result = ''; + $d = $this->docs['shapes'][$shapeName]; + if (isset($d['refs']["{$parentName}\${$ref}"])) { + $result = $d['refs']["{$parentName}\${$ref}"]; + } elseif (isset($d['base'])) { + $result = $d['base']; + } + + if (isset($d['append'])) { + if (!isset($d['excludeAppend']) + || !in_array($parentName, $d['excludeAppend']) + ) { + $result .= $d['append']; + } + } + + if (isset($d['appendOnly']) + && in_array($parentName, $d['appendOnly']['shapes']) + ) { + $result .= $d['appendOnly']['message']; + } + + return $this->clean($result); + } + + + private function clean($content) + { + if (!$content) { + return ''; + } + + $tidy = new \tidy(); + $tidy->parseString($content, [ + 'indent' => true, + 'doctype' => 'omit', + 'output-html' => true, + 'show-body-only' => true, + 'drop-empty-paras' => true, + 'clean' => true, + 'drop-proprietary-attributes' => true, + 'hide-comments' => true, + 'logical-emphasis' => true + ]); + $tidy->cleanRepair(); + + return (string) $content; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/AbstractErrorParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/AbstractErrorParser.php new file mode 100644 index 000000000..c72f03f64 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/AbstractErrorParser.php @@ -0,0 +1,99 @@ +api = $api; + } + + abstract protected function payload( + ResponseInterface $response, + StructureShape $member + ); + + protected function extractPayload( + StructureShape $member, + ResponseInterface $response + ) { + if ($member instanceof StructureShape) { + // Structure members parse top-level data into a specific key. + return $this->payload($response, $member); + } else { + // Streaming data is just the stream from the response body. + return $response->getBody(); + } + } + + protected function populateShape( + array &$data, + ResponseInterface $response, + ?CommandInterface $command = null + ) { + $data['body'] = []; + + if (!empty($command) && !empty($this->api)) { + + // If modeled error code is indicated, check for known error shape + if (!empty($data['code'])) { + + $errors = $this->api->getOperation($command->getName())->getErrors(); + foreach ($errors as $key => $error) { + + // If error code matches a known error shape, populate the body + if ($this->errorCodeMatches($data, $error)) { + $modeledError = $error; + $data['body'] = $this->extractPayload( + $modeledError, + $response + ); + $data['error_shape'] = $modeledError; + + foreach ($error->getMembers() as $name => $member) { + switch ($member['location']) { + case 'header': + $this->extractHeader($name, $member, $response, $data['body']); + break; + case 'headers': + $this->extractHeaders($name, $member, $response, $data['body']); + break; + case 'statusCode': + $this->extractStatus($name, $response, $data['body']); + break; + } + } + + break; + } + } + } + } + + return $data; + } + + private function errorCodeMatches(array $data, $error): bool + { + return $data['code'] == $error['name'] + || (isset($error['error']['code']) && $data['code'] === $error['error']['code']); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonParserTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonParserTrait.php new file mode 100644 index 000000000..67afb1645 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonParserTrait.php @@ -0,0 +1,144 @@ +getStatusCode(); + $error_code = null; + $error_type = null; + + // Parse error code and type for query compatible services + if ($this->api + && !is_null($this->api->getMetadata('awsQueryCompatible')) + && $response->hasHeader('x-amzn-query-error') + ) { + $awsQueryError = $this->parseAwsQueryCompatibleHeader($response); + if ($awsQueryError) { + $error_code = $awsQueryError['code']; + $error_type = $awsQueryError['type']; + } + } + + // Parse error code from X-Amzn-Errortype header + if (!$error_code && $response->hasHeader('X-Amzn-Errortype')) { + $error_code = $this->extractErrorCode( + $response->getHeaderLine('X-Amzn-Errortype') + ); + } + + $parsedBody = null; + $body = $response->getBody(); + if (!$body->isSeekable() || $body->getSize()) { + $parsedBody = $this->parseJson((string) $body, $response); + } + + // Parse error code from response body + if (!$error_code && $parsedBody) { + $error_code = $this->parseErrorFromBody($parsedBody); + } + + if (!isset($error_type)) { + $error_type = $code[0] == '4' ? 'client' : 'server'; + } + + return [ + 'request_id' => $response->getHeaderLine('x-amzn-requestid'), + 'code' => $error_code ?? null, + 'message' => null, + 'type' => $error_type, + 'parsed' => $parsedBody + ]; + } + + /** + * Parse AWS Query Compatible error from header + * + * @param ResponseInterface $response + * @return array|null Returns ['code' => string, 'type' => string] or null + */ + private function parseAwsQueryCompatibleHeader(ResponseInterface $response): ?array + { + $queryError = $response->getHeaderLine('x-amzn-query-error'); + $parts = explode(';', $queryError); + + if (count($parts) === 2 && $parts[0] && $parts[1]) { + return [ + 'code' => $parts[0], + 'type' => $parts[1] + ]; + } + + return null; + } + + /** + * Parse error code from response body + * + * @param array|null $parsedBody + * @return string|null + */ + private function parseErrorFromBody(?array $parsedBody): ?string + { + if (!$parsedBody + || (!isset($parsedBody['code']) && !isset($parsedBody['__type'])) + ) { + return null; + } + + $error_code = $parsedBody['code'] ?? $parsedBody['__type']; + return $this->extractErrorCode($error_code); + } + + /** + * Extract error code from raw error string containing # and/or : delimiters + * + * @param string $rawErrorCode + * @return string + */ + private function extractErrorCode(string $rawErrorCode): string + { + // Handle format with both # and uri (e.g., "namespace#http://foo-bar") + if (str_contains($rawErrorCode, ':') && str_contains($rawErrorCode, '#')) { + $start = strpos($rawErrorCode, '#') + 1; + $end = strpos($rawErrorCode, ':', $start); + return substr($rawErrorCode, $start, $end - $start); + } + + // Handle format with uri only : (e.g., "ErrorCode:http://foo-bar.com/baz") + if (str_contains($rawErrorCode, ':')) { + return substr($rawErrorCode, 0, strpos($rawErrorCode, ':')); + } + + // Handle format with only # (e.g., "namespace#ErrorCode") + if (str_contains($rawErrorCode, '#')) { + return substr($rawErrorCode, strpos($rawErrorCode, '#') + 1); + } + + return $rawErrorCode; + } + + protected function payload( + ResponseInterface $response, + StructureShape $member + ) { + $body = $response->getBody(); + if (!$body->isSeekable() || $body->getSize()) { + $jsonBody = $this->parseJson($body, $response); + } else { + $jsonBody = (string) $body; + } + + return $this->parser->parse($member, $jsonBody); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonRpcErrorParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonRpcErrorParser.php new file mode 100644 index 000000000..35e8ebe0e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/JsonRpcErrorParser.php @@ -0,0 +1,47 @@ +parser = $parser ?: new JsonParser(); + } + + public function __invoke( + ResponseInterface $response, + ?CommandInterface $command = null + ) { + $data = $this->genericHandler($response); + + // Make the casing consistent across services. + if ($data['parsed']) { + $data['parsed'] = array_change_key_case($data['parsed']); + } + + if (isset($data['parsed']['__type'])) { + if (!isset($data['code'])) { + $parts = explode('#', $data['parsed']['__type']); + $data['code'] = isset($parts[1]) ? $parts[1] : $parts[0]; + } + $data['message'] = $data['parsed']['message'] ?? null; + } + + $this->populateShape($data, $response, $command); + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/RestJsonErrorParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/RestJsonErrorParser.php new file mode 100644 index 000000000..3d50a73ca --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/RestJsonErrorParser.php @@ -0,0 +1,49 @@ +parser = $parser ?: new JsonParser(); + } + + public function __invoke( + ResponseInterface $response, + ?CommandInterface $command = null + ) { + $data = $this->genericHandler($response); + + // Merge in error data from the JSON body + if ($json = $data['parsed']) { + $data = array_replace($json, $data); + } + + // Correct error type from services like Amazon Glacier + if (!empty($data['type'])) { + $data['type'] = strtolower($data['type']); + } + + // Retrieve error message directly + $data['message'] = $data['parsed']['message'] + ?? ($data['parsed']['Message'] ?? null); + + $this->populateShape($data, $response, $command); + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/XmlErrorParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/XmlErrorParser.php new file mode 100644 index 000000000..86f5d0be5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ErrorParser/XmlErrorParser.php @@ -0,0 +1,111 @@ +parser = $parser ?: new XmlParser(); + } + + public function __invoke( + ResponseInterface $response, + ?CommandInterface $command = null + ) { + $code = (string) $response->getStatusCode(); + + $data = [ + 'type' => $code[0] == '4' ? 'client' : 'server', + 'request_id' => null, + 'code' => null, + 'message' => null, + 'parsed' => null + ]; + + $body = $response->getBody(); + if ($body->getSize() > 0) { + $this->parseBody($this->parseXml($body, $response), $data); + } else { + $this->parseHeaders($response, $data); + } + + $this->populateShape($data, $response, $command); + + return $data; + } + + private function parseHeaders(ResponseInterface $response, array &$data) + { + if ($response->getStatusCode() == '404') { + $data['code'] = 'NotFound'; + } + + $data['message'] = $response->getStatusCode() . ' ' + . $response->getReasonPhrase(); + + if ($requestId = $response->getHeaderLine('x-amz-request-id')) { + $data['request_id'] = $requestId; + $data['message'] .= " (Request-ID: $requestId)"; + } + } + + private function parseBody(\SimpleXMLElement $body, array &$data) + { + $data['parsed'] = $body; + $prefix = $this->registerNamespacePrefix($body); + + if ($tempXml = $body->xpath("//{$prefix}Code[1]")) { + $data['code'] = (string) $tempXml[0]; + } + + if ($tempXml = $body->xpath("//{$prefix}Message[1]")) { + $data['message'] = (string) $tempXml[0]; + } + + $tempXml = $body->xpath("//{$prefix}RequestId[1]"); + if (isset($tempXml[0])) { + $data['request_id'] = (string)$tempXml[0]; + } + } + + protected function registerNamespacePrefix(\SimpleXMLElement $element) + { + $namespaces = $element->getDocNamespaces(); + if (!isset($namespaces[''])) { + return ''; + } + + // Account for the default namespace being defined and PHP not + // being able to handle it :(. + $element->registerXPathNamespace('ns', $namespaces['']); + return 'ns:'; + } + + protected function payload( + ResponseInterface $response, + StructureShape $member + ) { + $xmlBody = $this->parseXml($response->getBody(), $response); + $prefix = $this->registerNamespacePrefix($xmlBody); + $errorBody = $xmlBody->xpath("//{$prefix}Error"); + + if (is_array($errorBody) && !empty($errorBody[0])) { + return $this->parser->parse($member, $errorBody[0]); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ListShape.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ListShape.php new file mode 100644 index 000000000..a425efa72 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ListShape.php @@ -0,0 +1,35 @@ +member) { + if (!isset($this->definition['member'])) { + throw new \RuntimeException('No member attribute specified'); + } + $this->member = Shape::create( + $this->definition['member'], + $this->shapeMap + ); + } + + return $this->member; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/MapShape.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/MapShape.php new file mode 100644 index 000000000..f180f9a68 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/MapShape.php @@ -0,0 +1,54 @@ +value) { + if (!isset($this->definition['value'])) { + throw new \RuntimeException('No value specified'); + } + + $this->value = Shape::create( + $this->definition['value'], + $this->shapeMap + ); + } + + return $this->value; + } + + /** + * @return Shape + */ + public function getKey() + { + if (!$this->key) { + $this->key = isset($this->definition['key']) + ? Shape::create($this->definition['key'], $this->shapeMap) + : new Shape(['type' => 'string'], $this->shapeMap); + } + + return $this->key; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Operation.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Operation.php new file mode 100644 index 000000000..36ba3950c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Operation.php @@ -0,0 +1,158 @@ +staticContextParams = $definition['staticContextParams']; + } + + if (isset($definition['operationContextParams'])) { + $this->operationContextParams = $definition['operationContextParams']; + } + + parent::__construct($definition, $shapeMap); + $this->contextParams = $this->setContextParams(); + } + + /** + * Returns an associative array of the HTTP attribute of the operation: + * + * - method: HTTP method of the operation + * - requestUri: URI of the request (can include URI template placeholders) + * + * @return array + */ + public function getHttp() + { + return $this->definition['http']; + } + + /** + * Get the input shape of the operation. + * + * @return StructureShape + */ + public function getInput() + { + if (!$this->input) { + if ($input = $this['input']) { + $this->input = $this->shapeFor($input); + } else { + $this->input = new StructureShape([], $this->shapeMap); + } + } + + return $this->input; + } + + /** + * Get the output shape of the operation. + * + * @return StructureShape + */ + public function getOutput() + { + if (!$this->output) { + if ($output = $this['output']) { + $this->output = $this->shapeFor($output); + } else { + $this->output = new StructureShape([], $this->shapeMap); + } + } + + return $this->output; + } + + /** + * Get an array of operation error shapes. + * + * @return Shape[] + */ + public function getErrors() + { + if ($this->errors === null) { + if ($errors = $this['errors']) { + foreach ($errors as $key => $error) { + $errors[$key] = $this->shapeFor($error); + } + $this->errors = $errors; + } else { + $this->errors = []; + } + } + + return $this->errors; + } + + /** + * Gets static modeled static values used for + * endpoint resolution. + * + * @return array + */ + public function getStaticContextParams() + { + return $this->staticContextParams; + } + + /** + * Gets definition of modeled dynamic values used + * for endpoint resolution + * + * @return array + */ + public function getContextParams() + { + return $this->contextParams; + } + + /** + * Gets definition of modeled dynamic values used + * for endpoint resolution + * + * @return array + */ + public function getOperationContextParams(): array + { + return $this->operationContextParams; + } + + private function setContextParams() + { + $members = $this->getInput()->getMembers(); + $contextParams = []; + + foreach($members as $name => $shape) { + if (!empty($contextParam = $shape->getContextParam())) { + $contextParams[$contextParam['name']] = [ + 'shape' => $name, + 'type' => $shape->getType() + ]; + } + } + return $contextParams; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractParser.php new file mode 100644 index 000000000..2d515d2a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractParser.php @@ -0,0 +1,46 @@ +api = $api; + } + + /** + * @param CommandInterface $command Command that was executed. + * @param ResponseInterface $response Response that was received. + * + * @return ResultInterface + */ + abstract public function __invoke( + CommandInterface $command, + ResponseInterface $response + ); + + abstract public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractRestParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractRestParser.php new file mode 100644 index 000000000..a0267e8d7 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/AbstractRestParser.php @@ -0,0 +1,216 @@ +api->getOperation($command->getName())->getOutput(); + $result = []; + + if ($payload = $output['payload']) { + $this->extractPayload($payload, $output, $response, $result); + } + + foreach ($output->getMembers() as $name => $member) { + switch ($member['location']) { + case 'header': + $this->extractHeader($name, $member, $response, $result); + break; + case 'headers': + $this->extractHeaders($name, $member, $response, $result); + break; + case 'statusCode': + $this->extractStatus($name, $response, $result); + break; + } + } + + $body = $response->getBody(); + if (!$payload + && (!$body->isSeekable() || $body->getSize()) + && count($output->getMembers()) > 0 + ) { + // if no payload was found, then parse the contents of the body + $this->payload($response, $output, $result); + } + + return new Result($result); + } + + private function extractPayload( + $payload, + StructureShape $output, + ResponseInterface $response, + array &$result + ) { + $member = $output->getMember($payload); + $body = $response->getBody(); + + if (!empty($member['eventstream'])) { + $result[$payload] = new EventParsingIterator( + $body, + $member, + $this + ); + } elseif ($member instanceof StructureShape) { + //Unions must have at least one member set to a non-null value + // If the body is empty, we can assume it is unset + if (!empty($member['union']) && ($body->isSeekable() && !$body->getSize())) { + return; + } + + $result[$payload] = []; + $this->payload($response, $member, $result[$payload]); + } else { + // Always set the payload to the body stream, regardless of content + $result[$payload] = $body; + } + } + + /** + * Extract a single header from the response into the result. + */ + private function extractHeader( + $name, + Shape $shape, + ResponseInterface $response, + &$result + ) { + $value = $response->getHeaderLine($shape['locationName'] ?: $name); + // Empty headers should not be deserialized + if ($value === null || $value === '') { + return; + } + + switch ($shape->getType()) { + case 'float': + case 'double': + $value = match ($value) { + 'NaN', 'Infinity', '-Infinity' => $value, + default => (float) $value + }; + break; + case 'long': + case 'integer': + $value = (int) $value; + break; + case 'boolean': + $value = filter_var($value, FILTER_VALIDATE_BOOLEAN); + break; + case 'blob': + $value = base64_decode($value); + break; + case 'timestamp': + try { + $value = DateTimeResult::fromTimestamp( + $value, + !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null + ); + break; + } catch (\Exception $e) { + // If the value cannot be parsed, then do not add it to the + // output structure. + return; + } + case 'string': + try { + if ($shape['jsonvalue']) { + $value = $this->parseJson(base64_decode($value), $response); + } + + // If value is not set, do not add to output structure. + if (!isset($value)) { + return; + } + break; + } catch (\Exception $e) { + //If the value cannot be parsed, then do not add it to the + //output structure. + return; + } + case 'list': + $listMember = $shape->getMember(); + $type = $listMember->getType(); + + // Only boolean lists require special handling + // other types can be returned as-is + if ($type !== 'boolean') { + break; + } + + $items = array_map('trim', explode(',', $value)); + $value = array_map( + static fn($item) => filter_var($item, FILTER_VALIDATE_BOOLEAN), + $items + ); + + break; + } + + $result[$name] = $value; + } + + /** + * Extract a map of headers with an optional prefix from the response. + */ + private function extractHeaders( + $name, + Shape $shape, + ResponseInterface $response, + &$result + ) { + // Check if the headers are prefixed by a location name + $result[$name] = []; + $prefix = $shape['locationName']; + $prefixLen = $prefix !== null ? strlen($prefix) : 0; + + foreach ($response->getHeaders() as $k => $values) { + if (!$prefixLen) { + $result[$name][$k] = implode(', ', $values); + } elseif (stripos($k, $prefix) === 0) { + $result[$name][substr($k, $prefixLen)] = implode(', ', $values); + } + } + } + + /** + * Places the status code of the response into the result array. + */ + private function extractStatus( + $name, + ResponseInterface $response, + array &$result + ) { + $result[$name] = (int) $response->getStatusCode(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Crc32ValidatingParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Crc32ValidatingParser.php new file mode 100644 index 000000000..8e5d4f08e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Crc32ValidatingParser.php @@ -0,0 +1,54 @@ +parser = $parser; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + if ($expected = $response->getHeaderLine('x-amz-crc32')) { + $hash = hexdec(Psr7\Utils::hash($response->getBody(), 'crc32b')); + if ($expected != $hash) { + throw new AwsException( + "crc32 mismatch. Expected {$expected}, found {$hash}.", + $command, + [ + 'code' => 'ClientChecksumMismatch', + 'connection_error' => true, + 'response' => $response + ] + ); + } + } + + $fn = $this->parser; + return $fn($command, $response); + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/DecodingEventStreamIterator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/DecodingEventStreamIterator.php new file mode 100644 index 000000000..b31cbd824 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/DecodingEventStreamIterator.php @@ -0,0 +1,347 @@ + 'decodeUint32', + self::LENGTH_HEADERS => 'decodeUint32', + self::CRC_PRELUDE => 'decodeUint32', + ]; + + private static $lengthFormatMap = [ + 1 => 'decodeUint8', + 2 => 'decodeUint16', + 4 => 'decodeUint32', + 8 => 'decodeUint64', + ]; + + private static $headerTypeMap = [ + 0 => 'decodeBooleanTrue', + 1 => 'decodeBooleanFalse', + 2 => 'decodeInt8', + 3 => 'decodeInt16', + 4 => 'decodeInt32', + 5 => 'decodeInt64', + 6 => 'decodeBytes', + 7 => 'decodeString', + 8 => 'decodeTimestamp', + 9 => 'decodeUuid', + ]; + + /** @var StreamInterface Stream of eventstream shape to parse. */ + protected $stream; + + /** @var array Currently parsed event. */ + protected $currentEvent; + + /** @var int Current in-order event key. */ + protected $key; + + /** @var resource|\HashContext CRC32 hash context for event validation */ + protected $hashContext; + + /** @var int $currentPosition */ + protected $currentPosition; + + /** + * DecodingEventStreamIterator constructor. + * + * @param StreamInterface $stream + */ + public function __construct(StreamInterface $stream) + { + $this->stream = $stream; + $this->rewind(); + } + + protected function parseHeaders($headerBytes) + { + $headers = []; + $bytesRead = 0; + + while ($bytesRead < $headerBytes) { + list($key, $numBytes) = $this->decodeString(1); + $bytesRead += $numBytes; + + list($type, $numBytes) = $this->decodeUint8(); + $bytesRead += $numBytes; + + $f = self::$headerTypeMap[$type]; + list($value, $numBytes) = $this->{$f}(); + $bytesRead += $numBytes; + + if (isset($headers[$key])) { + throw new ParserException('Duplicate key in event headers.'); + } + $headers[$key] = $value; + } + + return [$headers, $bytesRead]; + } + + protected function parsePrelude() + { + $prelude = []; + $bytesRead = 0; + + $calculatedCrc = null; + foreach (self::$preludeFormat as $key => $decodeFunction) { + if ($key === self::CRC_PRELUDE) { + $hashCopy = hash_copy($this->hashContext); + $calculatedCrc = hash_final($this->hashContext, true); + $this->hashContext = $hashCopy; + } + list($value, $numBytes) = $this->{$decodeFunction}(); + $bytesRead += $numBytes; + + $prelude[$key] = $value; + } + + if (unpack('N', $calculatedCrc)[1] !== $prelude[self::CRC_PRELUDE]) { + throw new ParserException('Prelude checksum mismatch.'); + } + + return [$prelude, $bytesRead]; + } + + /** + * This method decodes an event from the stream. + * + * @return array + */ + protected function parseEvent() + { + $event = []; + + if ($this->stream->tell() < $this->stream->getSize()) { + $this->hashContext = hash_init('crc32b'); + + $bytesLeft = $this->stream->getSize() - $this->stream->tell(); + list($prelude, $numBytes) = $this->parsePrelude(); + if ($prelude[self::LENGTH_TOTAL] > $bytesLeft) { + throw new ParserException('Message length too long.'); + } + $bytesLeft -= $numBytes; + + if ($prelude[self::LENGTH_HEADERS] > $bytesLeft) { + throw new ParserException('Headers length too long.'); + } + + list( + $event[self::HEADERS], + $numBytes + ) = $this->parseHeaders($prelude[self::LENGTH_HEADERS]); + + $event[self::PAYLOAD] = Psr7\Utils::streamFor( + $this->readAndHashBytes( + $prelude[self::LENGTH_TOTAL] - self::BYTES_PRELUDE + - $numBytes - self::BYTES_TRAILING + ) + ); + + $calculatedCrc = hash_final($this->hashContext, true); + $messageCrc = $this->stream->read(4); + if ($calculatedCrc !== $messageCrc) { + throw new ParserException('Message checksum mismatch.'); + } + } + + return $event; + } + + // Iterator Functionality + + /** + * @return array + */ + #[\ReturnTypeWillChange] + public function current() + { + return $this->currentEvent; + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function key() + { + return $this->key; + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function next() + { + $this->currentPosition = $this->stream->tell(); + if ($this->valid()) { + $this->key++; + $this->currentEvent = $this->parseEvent(); + } + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function rewind() + { + $this->stream->rewind(); + $this->key = 0; + $this->currentPosition = 0; + $this->currentEvent = $this->parseEvent(); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function valid() + { + return $this->currentPosition < $this->stream->getSize(); + } + + // Decoding Utilities + + protected function readAndHashBytes($num) + { + $bytes = $this->stream->read($num); + hash_update($this->hashContext, $bytes); + return $bytes; + } + + private function decodeBooleanTrue() + { + return [true, 0]; + } + + private function decodeBooleanFalse() + { + return [false, 0]; + } + + private function uintToInt($val, $size) + { + $signedCap = pow(2, $size - 1); + if ($val > $signedCap) { + $val -= (2 * $signedCap); + } + return $val; + } + + private function decodeInt8() + { + $val = (int)unpack('C', $this->readAndHashBytes(1))[1]; + return [$this->uintToInt($val, 8), 1]; + } + + private function decodeUint8() + { + return [unpack('C', $this->readAndHashBytes(1))[1], 1]; + } + + private function decodeInt16() + { + $val = (int)unpack('n', $this->readAndHashBytes(2))[1]; + return [$this->uintToInt($val, 16), 2]; + } + + private function decodeUint16() + { + return [unpack('n', $this->readAndHashBytes(2))[1], 2]; + } + + private function decodeInt32() + { + $val = (int)unpack('N', $this->readAndHashBytes(4))[1]; + return [$this->uintToInt($val, 32), 4]; + } + + private function decodeUint32() + { + return [unpack('N', $this->readAndHashBytes(4))[1], 4]; + } + + private function decodeInt64() + { + $val = $this->unpackInt64($this->readAndHashBytes(8))[1]; + return [$this->uintToInt($val, 64), 8]; + } + + private function decodeUint64() + { + return [$this->unpackInt64($this->readAndHashBytes(8))[1], 8]; + } + + private function unpackInt64($bytes) + { + return unpack('J', $bytes); + } + + private function decodeBytes($lengthBytes=2) + { + if (!isset(self::$lengthFormatMap[$lengthBytes])) { + throw new ParserException('Undefined variable length format.'); + } + $f = self::$lengthFormatMap[$lengthBytes]; + list($len, $bytes) = $this->{$f}(); + return [$this->readAndHashBytes($len), $len + $bytes]; + } + + private function decodeString($lengthBytes=2) + { + if (!isset(self::$lengthFormatMap[$lengthBytes])) { + throw new ParserException('Undefined variable length format.'); + } + $f = self::$lengthFormatMap[$lengthBytes]; + list($len, $bytes) = $this->{$f}(); + return [$this->readAndHashBytes($len), $len + $bytes]; + } + + private function decodeTimestamp() + { + list($val, $bytes) = $this->decodeInt64(); + return [ + DateTimeResult::createFromFormat('U.u', $val / 1000), + $bytes + ]; + } + + private function decodeUuid() + { + $val = unpack('H32', $this->readAndHashBytes(16))[1]; + return [ + substr($val, 0, 8) . '-' + . substr($val, 8, 4) . '-' + . substr($val, 12, 4) . '-' + . substr($val, 16, 4) . '-' + . substr($val, 20, 12), + 16 + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/EventParsingIterator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/EventParsingIterator.php new file mode 100644 index 000000000..b14c5fcbe --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/EventParsingIterator.php @@ -0,0 +1,211 @@ +decodingIterator = $this->chooseDecodingIterator($stream); + $this->shape = $shape; + $this->parser = $parser; + } + + /** + * This method choose a decoding iterator implementation based on if the stream + * is seekable or not. + * + * @param $stream + * + * @return Iterator + */ + private function chooseDecodingIterator($stream) + { + if ($stream->isSeekable()) { + return new DecodingEventStreamIterator($stream); + } else { + return new NonSeekableStreamDecodingEventStreamIterator($stream); + } + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function current() + { + return $this->parseEvent($this->decodingIterator->current()); + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function key() + { + return $this->decodingIterator->key(); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function next() + { + $this->decodingIterator->next(); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function rewind() + { + $this->decodingIterator->rewind(); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function valid() + { + return $this->decodingIterator->valid(); + } + + private function parseEvent(array $event) + { + if (!empty($event['headers'][':message-type'])) { + if ($event['headers'][':message-type'] === 'error') { + return $this->parseError($event); + } + + if ($event['headers'][':message-type'] === 'exception') { + return $this->parseException($event); + } + + if ($event['headers'][':message-type'] !== 'event') { + throw new ParserException('Failed to parse unknown message type.'); + } + } + + $eventType = $event['headers'][':event-type'] ?? null; + if (empty($eventType)) { + throw new ParserException('Failed to parse without event type.'); + } + + $eventPayload = $event['payload']; + if ($eventType === 'initial-response') { + return $this->parseInitialResponseEvent($eventPayload); + } + + $eventShape = $this->shape->getMember($eventType); + + return [ + $eventType => array_merge( + $this->parseEventHeaders($event['headers'], $eventShape), + $this->parseEventPayload($eventPayload, $eventShape) + ) + ]; + } + + /** + * @param $headers + * @param $eventShape + * + * @return array + */ + private function parseEventHeaders($headers, $eventShape): array + { + $parsedHeaders = []; + foreach ($eventShape->getMembers() as $memberName => $memberProps) { + if (isset($memberProps['eventheader'])) { + $parsedHeaders[$memberName] = $headers[$memberName]; + } + } + + return $parsedHeaders; + } + + /** + * @param $payload + * @param $eventShape + * + * @return array + */ + private function parseEventPayload($payload, $eventShape): array + { + $parsedPayload = []; + foreach ($eventShape->getMembers() as $memberName => $memberProps) { + $memberShape = $eventShape->getMember($memberName); + if (isset($memberProps['eventpayload'])) { + if ($memberShape->getType() === 'blob') { + $parsedPayload[$memberName] = $payload; + } else { + $parsedPayload[$memberName] = $this->parser->parseMemberFromStream( + $payload, + $memberShape, + null + ); + } + + break; + } + } + + if (empty($parsedPayload) && !empty($payload->getContents())) { + /** + * If we did not find a member with an eventpayload trait, then we should deserialize the payload + * using the event's shape. + */ + $parsedPayload = $this->parser->parseMemberFromStream($payload, $eventShape, null); + } + + return $parsedPayload; + } + + private function parseError(array $event) + { + throw new EventStreamDataException( + $event['headers'][':error-code'], + $event['headers'][':error-message'] + ); + } + + private function parseException(array $event) { + $payload = $event['payload']?->getContents(); + $parsedPayload = json_decode($payload, true); + + throw new EventStreamDataException( + $event['headers'][':exception-type'] ?? 'Unknown', + $parsedPayload['message'] ?? $payload, + ); + } + + private function parseInitialResponseEvent($payload): array + { + return ['initial-response' => json_decode($payload, true)]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Exception/ParserException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Exception/ParserException.php new file mode 100644 index 000000000..f5fd9ec9b --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/Exception/ParserException.php @@ -0,0 +1,56 @@ +errorCode = isset($context['error_code']) ? $context['error_code'] : null; + $this->requestId = isset($context['request_id']) ? $context['request_id'] : null; + $this->response = isset($context['response']) ? $context['response'] : null; + parent::__construct($message, $code, $previous); + } + + /** + * Get the error code, if any. + * + * @return string|null + */ + public function getErrorCode() + { + return $this->errorCode; + } + + /** + * Get the request ID, if any. + * + * @return string|null + */ + public function getRequestId() + { + return $this->requestId; + } + + /** + * Get the received HTTP response if any. + * + * @return ResponseInterface|null + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonParser.php new file mode 100644 index 000000000..da11e31bd --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonParser.php @@ -0,0 +1,74 @@ +getMembers() as $name => $member) { + $locationName = $member['locationName'] ?: $name; + if (isset($value[$locationName])) { + $target[$name] = $this->parse($member, $value[$locationName]); + } + } + if (isset($shape['union']) + && $shape['union'] + && is_array($value) + && empty($target) + ) { + foreach ($value as $key => $val) { + $target['Unknown'][$key] = $val; + } + } + return $target; + + case 'list': + $member = $shape->getMember(); + $target = []; + foreach ($value as $v) { + $target[] = $this->parse($member, $v); + } + return $target; + + case 'map': + $values = $shape->getValue(); + $target = []; + foreach ($value as $k => $v) { + // null map values should not be deserialized + if (!is_null($v)) { + $target[$k] = $this->parse($values, $v); + } + } + return $target; + + case 'timestamp': + return DateTimeResult::fromTimestamp( + $value, + !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null + ); + + case 'blob': + return base64_decode($value); + + default: + return $value; + } + } +} + diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonRpcParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonRpcParser.php new file mode 100644 index 000000000..cd6549c7b --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/JsonRpcParser.php @@ -0,0 +1,82 @@ +parser = $parser ?: new JsonParser(); + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $operation = $this->api->getOperation($command->getName()); + + return $this->parseResponse($response, $operation); + } + + /** + * This method parses a response based on JSON RPC protocol. + * + * @param ResponseInterface $response the response to parse. + * @param Operation $operation the operation which holds information for + * parsing the response. + * + * @return Result + */ + private function parseResponse(ResponseInterface $response, Operation $operation) + { + if (null === $operation['output']) { + return new Result([]); + } + + $outputShape = $operation->getOutput(); + foreach ($outputShape->getMembers() as $memberName => $memberProps) { + if (!empty($memberProps['eventstream'])) { + return new Result([ + $memberName => new EventParsingIterator( + $response->getBody(), + $outputShape->getMember($memberName), + $this + ) + ]); + } + } + + $result = $this->parseMemberFromStream( + $response->getBody(), + $operation->getOutput(), + $response + ); + + return new Result(is_null($result) ? [] : $result); + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parse($member, $this->parseJson($stream, $response)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/MetadataParserTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/MetadataParserTrait.php new file mode 100644 index 000000000..b3bba9938 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/MetadataParserTrait.php @@ -0,0 +1,95 @@ +getHeaderLine($shape['locationName'] ?: $name); + // Empty values should not be deserialized + if ($value === null || $value === '') { + return; + } + + switch ($shape->getType()) { + case 'float': + case 'double': + $value = (float) $value; + break; + case 'long': + case 'integer': + $value = (int) $value; + break; + case 'boolean': + $value = filter_var($value, FILTER_VALIDATE_BOOLEAN); + break; + case 'blob': + $value = base64_decode($value); + break; + case 'timestamp': + try { + $value = DateTimeResult::fromTimestamp( + $value, + !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null + ); + break; + } catch (\Exception $e) { + // If the value cannot be parsed, then do not add it to the + // output structure. + return; + } + case 'string': + if ($shape['jsonvalue']) { + $value = $this->parseJson(base64_decode($value), $response); + } + break; + } + + $result[$name] = $value; + } + + /** + * Extract a map of headers with an optional prefix from the response. + */ + protected function extractHeaders( + $name, + Shape $shape, + ResponseInterface $response, + &$result + ) { + // Check if the headers are prefixed by a location name + $result[$name] = []; + $prefix = $shape['locationName']; + $prefixLen = strlen($prefix); + + foreach ($response->getHeaders() as $k => $values) { + if (!$prefixLen) { + $result[$name][$k] = implode(', ', $values); + } elseif (stripos($k, $prefix) === 0) { + $result[$name][substr($k, $prefixLen)] = implode(', ', $values); + } + } + } + + /** + * Places the status code of the response into the result array. + */ + protected function extractStatus( + $name, + ResponseInterface $response, + array &$result + ) { + $result[$name] = (int) $response->getStatusCode(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php new file mode 100644 index 000000000..ca5388db6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php @@ -0,0 +1,101 @@ +stream = $stream; + if ($this->stream->isSeekable()) { + throw new \InvalidArgumentException('The stream provided must be not seekable.'); + } + + $this->tempBuffer = []; + } + + /** + * @inheritDoc + * + * @return array + */ + protected function parseEvent(): array + { + $event = []; + $this->hashContext = hash_init('crc32b'); + $prelude = $this->parsePrelude()[0]; + list( + $event[self::HEADERS], + $numBytes + ) = $this->parseHeaders($prelude[self::LENGTH_HEADERS]); + $event[self::PAYLOAD] = Psr7\Utils::streamFor( + $this->readAndHashBytes( + $prelude[self::LENGTH_TOTAL] - self::BYTES_PRELUDE + - $numBytes - self::BYTES_TRAILING + ) + ); + $calculatedCrc = hash_final($this->hashContext, true); + $messageCrc = $this->stream->read(4); + if ($calculatedCrc !== $messageCrc) { + throw new ParserException('Message checksum mismatch.'); + } + + return $event; + } + + protected function readAndHashBytes($num): string + { + $bytes = ''; + while (!empty($this->tempBuffer) && $num > 0) { + $byte = array_shift($this->tempBuffer); + $bytes .= $byte; + $num = $num - 1; + } + + $bytes = $bytes . $this->stream->read($num); + hash_update($this->hashContext, $bytes); + + return $bytes; + } + + // Iterator Functionality + + #[\ReturnTypeWillChange] + public function rewind() + { + $this->currentEvent = $this->parseEvent(); + } + + public function next() + { + $this->tempBuffer[] = $this->stream->read(1); + if ($this->valid()) { + $this->key++; + $this->currentEvent = $this->parseEvent(); + } + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function valid() + { + return !$this->stream->eof(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/PayloadParserTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/PayloadParserTrait.php new file mode 100644 index 000000000..43d3d5676 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/PayloadParserTrait.php @@ -0,0 +1,61 @@ + $response] + ); + } + + return $jsonPayload; + } + + /** + * @param string $xml + * + * @throws ParserException + * + * @return \SimpleXMLElement + */ + protected function parseXml($xml, $response) + { + $priorSetting = libxml_use_internal_errors(true); + try { + libxml_clear_errors(); + $xmlPayload = new \SimpleXMLElement($xml); + if ($error = libxml_get_last_error()) { + throw new \RuntimeException($error->message); + } + } catch (\Exception $e) { + throw new ParserException( + "Error parsing XML: {$e->getMessage()}", + 0, + $e, + ['response' => $response] + ); + } finally { + libxml_use_internal_errors($priorSetting); + } + + return $xmlPayload; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/QueryParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/QueryParser.php new file mode 100644 index 000000000..2ea067667 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/QueryParser.php @@ -0,0 +1,68 @@ +parser = $xmlParser ?: new XmlParser(); + $this->honorResultWrapper = $honorResultWrapper; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $output = $this->api->getOperation($command->getName())->getOutput(); + $body = $response->getBody(); + $xml = !$body->isSeekable() || $body->getSize() + ? $this->parseXml($body, $response) + : null; + + // Empty request bodies should not be deserialized. + if (is_null($xml)) { + return new Result(); + } + + if ($this->honorResultWrapper && $output['resultWrapper']) { + $xml = $xml->{$output['resultWrapper']}; + } + + return new Result($this->parser->parse($output, $xml)); + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + $xml = $this->parseXml($stream, $response); + return $this->parser->parse($member, $xml); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestJsonParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestJsonParser.php new file mode 100644 index 000000000..8c14e07a1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestJsonParser.php @@ -0,0 +1,64 @@ +parser = $parser ?: new JsonParser(); + } + + protected function payload( + ResponseInterface $response, + StructureShape $member, + array &$result + ) { + $responseBody = (string) $response->getBody(); + + // Parse JSON if we have content + $parsedJson = null; + if (!empty($responseBody)) { + $parsedJson = $this->parseJson($responseBody, $response); + } else { + // An empty response body should be deserialized as null + $result = $parsedJson; + return; + } + + $parsedBody = $this->parser->parse($member, $parsedJson); + if (is_string($parsedBody) && $member['document']) { + // Document types can be strings: replace entire result + $result = $parsedBody; + } else { + // Merge array/object results into existing result + $result = array_merge($result, (array) $parsedBody); + } + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + $jsonBody = $this->parseJson($stream, $response); + if ($jsonBody) { + return $this->parser->parse($member, $jsonBody); + } + return []; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestXmlParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestXmlParser.php new file mode 100644 index 000000000..057c00ce3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/RestXmlParser.php @@ -0,0 +1,42 @@ +parser = $parser ?: new XmlParser(); + } + + protected function payload( + ResponseInterface $response, + StructureShape $member, + array &$result + ) { + $result += $this->parseMemberFromStream($response->getBody(), $member, $response); + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + $xml = $this->parseXml($stream, $response); + return $this->parser->parse($member, $xml); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/XmlParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/XmlParser.php new file mode 100644 index 000000000..c9d47d235 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Parser/XmlParser.php @@ -0,0 +1,183 @@ +dispatch($shape, $value); + } + + private function dispatch($shape, \SimpleXMLElement $value) + { + static $methods = [ + 'structure' => 'parse_structure', + 'list' => 'parse_list', + 'map' => 'parse_map', + 'blob' => 'parse_blob', + 'boolean' => 'parse_boolean', + 'integer' => 'parse_integer', + 'float' => 'parse_float', + 'double' => 'parse_float', + 'timestamp' => 'parse_timestamp', + ]; + + $type = $shape['type']; + if (isset($methods[$type])) { + return $this->{$methods[$type]}($shape, $value); + } + + return (string) $value; + } + + private function parse_structure( + StructureShape $shape, + \SimpleXMLElement $value + ) { + $target = []; + + foreach ($shape->getMembers() as $name => $member) { + // Extract the name of the XML node + $node = $this->memberKey($member, $name); + if (isset($value->{$node})) { + $target[$name] = $this->dispatch($member, $value->{$node}); + } else { + $memberShape = $shape->getMember($name); + if (!empty($memberShape['xmlAttribute'])) { + $target[$name] = $this->parse_xml_attribute( + $shape, + $memberShape, + $value + ); + } + } + } + if (isset($shape['union']) + && $shape['union'] + && empty($target) + ) { + foreach ($value as $key => $val) { + $name = $val->children()->getName(); + $target['Unknown'][$name] = $val->$name; + } + } + return $target; + } + + private function memberKey(Shape $shape, $name) + { + // Check if locationName came from shape definition + if ($shape instanceof StructureShape && isset($shape['locationName'])) { + $originalDef = $shape->getOriginalDefinition($shape->getName()); + + if ($originalDef && isset($originalDef['locationName']) + && $originalDef['locationName'] === $shape['locationName'] + ) { + return $name; + } + } + + return $shape['locationName'] ?? $name; + } + + private function parse_list(ListShape $shape, \SimpleXMLElement $value) + { + $target = []; + $member = $shape->getMember(); + + if (!$shape['flattened']) { + $value = $value->{$member['locationName'] ?: 'member'}; + } + + foreach ($value as $v) { + $target[] = $this->dispatch($member, $v); + } + + return $target; + } + + private function parse_map(MapShape $shape, \SimpleXMLElement $value) + { + $target = []; + + if (!$shape['flattened']) { + $value = $value->entry; + } + + $mapKey = $shape->getKey(); + $mapValue = $shape->getValue(); + $keyName = $shape->getKey()['locationName'] ?: 'key'; + $valueName = $shape->getValue()['locationName'] ?: 'value'; + + foreach ($value as $node) { + $key = $this->dispatch($mapKey, $node->{$keyName}); + $value = $this->dispatch($mapValue, $node->{$valueName}); + $target[$key] = $value; + } + + return $target; + } + + private function parse_blob(Shape $shape, $value) + { + return base64_decode((string) $value); + } + + private function parse_float(Shape $shape, $value) + { + $value = (string) $value; + + return match ($value) { + 'NaN', 'Infinity', '-Infinity' => $value, + default => (float) $value + }; + } + + private function parse_integer(Shape $shape, $value) + { + return (int) (string) $value; + } + + private function parse_boolean(Shape $shape, $value) + { + return $value == 'true'; + } + + private function parse_timestamp(Shape $shape, $value) + { + if (is_string($value) + || is_int($value) + || (is_object($value) + && method_exists($value, '__toString')) + ) { + return DateTimeResult::fromTimestamp( + (string) $value, + !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null + ); + } + throw new ParserException('Invalid timestamp value passed to XmlParser::parse_timestamp'); + } + + private function parse_xml_attribute(Shape $shape, Shape $memberShape, $value) + { + $namespace = $shape['xmlNamespace']['uri'] ?? ''; + $prefix = $shape['xmlNamespace']['prefix'] ?? ''; + if (!empty($prefix)) { + $prefix .= ':'; + } + $key = str_replace($prefix, '', $memberShape['locationName']); + + $attributes = $value->attributes($namespace); + return isset($attributes[$key]) ? (string) $attributes[$key] : null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/Ec2ParamBuilder.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/Ec2ParamBuilder.php new file mode 100644 index 000000000..a3753cdfe --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/Ec2ParamBuilder.php @@ -0,0 +1,38 @@ +getMember(); + foreach ($value as $k => $v) { + $this->format($items, $v, $prefix . '.' . ($k + 1), $query); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonBody.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonBody.php new file mode 100644 index 000000000..6ac2dd988 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonBody.php @@ -0,0 +1,116 @@ +api = $api; + } + + /** + * Gets the JSON Content-Type header for a service API + * + * @param Service $service + * + * @return string + */ + public static function getContentType(Service $service) + { + if ($service->getMetadata('protocol') === 'rest-json') { + return 'application/json'; + } + + $jsonVersion = $service->getMetadata('jsonVersion'); + if (empty($jsonVersion)) { + throw new \InvalidArgumentException('invalid json'); + } else { + return 'application/x-amz-json-' + . @number_format($service->getMetadata('jsonVersion'), 1); + } + } + + /** + * Builds the JSON body based on an array of arguments. + * + * @param Shape $shape Operation being constructed + * @param array|string $args Associative array of arguments, or a string. + * + * @return string + */ + public function build(Shape $shape, array|string $args) + { + try { + $result = json_encode($this->format($shape, $args), JSON_THROW_ON_ERROR); + } catch (\JsonException $e) { + throw new InvalidJsonException( + 'Unable to encode JSON document ' . $shape->getName() . ': ' . + $e->getMessage() . PHP_EOL + ); + } + + return $result === '[]' ? '{}' : $result; + } + + private function format(Shape $shape, $value) + { + switch ($shape['type']) { + case 'structure': + $data = []; + if ($shape['document'] ?? false) { + return $value; + } + foreach ($value as $k => $v) { + if ($v !== null && $shape->hasMember($k)) { + $valueShape = $shape->getMember($k); + $data[$valueShape['locationName'] ?: $k] + = $this->format($valueShape, $v); + } + } + if (empty($data)) { + return new \stdClass; + } + return $data; + + case 'list': + $items = $shape->getMember(); + foreach ($value as $k => $v) { + $value[$k] = $this->format($items, $v); + } + return $value; + + case 'map': + if (empty($value)) { + return new \stdClass; + } + $values = $shape->getValue(); + foreach ($value as $k => $v) { + $value[$k] = $this->format($values, $v); + } + return $value; + + case 'blob': + return base64_encode($value); + + case 'timestamp': + $timestampFormat = !empty($shape['timestampFormat']) + ? $shape['timestampFormat'] + : 'unixTimestamp'; + return TimestampShape::format($value, $timestampFormat); + + default: + return $value; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonRpcSerializer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonRpcSerializer.php new file mode 100644 index 000000000..a4f5e6f2e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/JsonRpcSerializer.php @@ -0,0 +1,87 @@ +endpoint = $endpoint; + $this->api = $api; + $this->jsonFormatter = $jsonFormatter ?: new JsonBody($this->api); + $this->contentType = JsonBody::getContentType($api); + } + + /** + * When invoked with an AWS command, returns a serialization array + * containing "method", "uri", "headers", and "body" key value pairs. + * + * @param CommandInterface $command Command to serialize into a request. + * @param $endpointProvider Provider used for dynamic endpoint resolution. + * @param $clientArgs Client arguments used for dynamic endpoint resolution. + * + * @return RequestInterface + */ + public function __invoke( + CommandInterface $command, + $endpoint = null + ) + { + $operationName = $command->getName(); + $operation = $this->api->getOperation($operationName); + $commandArgs = $command->toArray(); + $body = $this->jsonFormatter->build($operation->getInput(), $commandArgs); + $headers = [ + 'X-Amz-Target' => $this->api->getMetadata('targetPrefix') . '.' . $operationName, + 'Content-Type' => $this->contentType, + 'Content-Length' => strlen($body) + ]; + + if ($endpoint instanceof RulesetEndpoint) { + $this->setEndpointV2RequestOptions($endpoint, $headers); + } + + $requestUri = $operation['http']['requestUri'] ?? null; + $absoluteUri = str_ends_with($this->endpoint, '/') + ? $this->endpoint : $this->endpoint . $requestUri; + + return new Request( + $operation['http']['method'], + $absoluteUri, + $headers, + $body + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QueryParamBuilder.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QueryParamBuilder.php new file mode 100644 index 000000000..29168da88 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QueryParamBuilder.php @@ -0,0 +1,158 @@ +isFlat($shape) && !empty($shape['member']['locationName'])) { + return $shape['member']['locationName']; + } + + return $default; + } + + protected function isFlat(Shape $shape) + { + return $shape['flattened'] === true; + } + + public function __invoke(StructureShape $shape, array $params) + { + if (!$this->methods) { + $this->methods = array_fill_keys(get_class_methods($this), true); + } + + $query = []; + $this->format_structure($shape, $params, '', $query); + + return $query; + } + + protected function format(Shape $shape, $value, $prefix, array &$query) + { + $type = 'format_' . $shape['type']; + if (isset($this->methods[$type])) { + $this->{$type}($shape, $value, $prefix, $query); + } else { + $query[$prefix] = (string) $value; + } + } + + protected function format_structure( + StructureShape $shape, + array $value, + $prefix, + &$query + ) { + if ($prefix) { + $prefix .= '.'; + } + + foreach ($value as $k => $v) { + if ($shape->hasMember($k)) { + $member = $shape->getMember($k); + $this->format( + $member, + $v, + $prefix . $this->queryName($member, $k), + $query + ); + } + } + } + + protected function format_list( + ListShape $shape, + array $value, + $prefix, + &$query + ) { + // Handle empty list serialization + if (!$value) { + $query[$prefix] = ''; + return; + } + + $items = $shape->getMember(); + + if (!$this->isFlat($shape)) { + $locationName = $shape->getMember()['locationName'] ?: 'member'; + $prefix .= ".$locationName"; + // flattened lists can also model a `locationName` + } elseif ($name = $shape['locationName'] ?? $this->queryName($items)) { + $parts = explode('.', $prefix); + $parts[count($parts) - 1] = $name; + $prefix = implode('.', $parts); + } + + foreach ($value as $k => $v) { + $this->format($items, $v, $prefix . '.' . ($k + 1), $query); + } + } + + protected function format_map( + MapShape $shape, + array $value, + $prefix, + array &$query + ) { + $vals = $shape->getValue(); + $keys = $shape->getKey(); + + if (!$this->isFlat($shape)) { + $prefix .= '.entry'; + } + + $i = 0; + $keyName = '%s.%d.' . $this->queryName($keys, 'key'); + $valueName = '%s.%s.' . $this->queryName($vals, 'value'); + + foreach ($value as $k => $v) { + $i++; + $this->format($keys, $k, sprintf($keyName, $prefix, $i), $query); + $this->format($vals, $v, sprintf($valueName, $prefix, $i), $query); + } + } + + protected function format_blob(Shape $shape, $value, $prefix, array &$query) + { + $query[$prefix] = base64_encode($value); + } + + protected function format_timestamp( + TimestampShape $shape, + $value, + $prefix, + array &$query + ) { + $timestampFormat = !empty($shape['timestampFormat']) + ? $shape['timestampFormat'] + : 'iso8601'; + $query[$prefix] = TimestampShape::format($value, $timestampFormat); + } + + protected function format_boolean(Shape $shape, $value, $prefix, array &$query) + { + $query[$prefix] = ($value) ? 'true' : 'false'; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QuerySerializer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QuerySerializer.php new file mode 100644 index 000000000..c38c88181 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/QuerySerializer.php @@ -0,0 +1,82 @@ +api = $api; + $this->endpoint = $endpoint; + $this->paramBuilder = $paramBuilder ?: new QueryParamBuilder(); + } + + /** + * When invoked with an AWS command, returns a serialization array + * containing "method", "uri", "headers", and "body" key value pairs. + * + * @param CommandInterface $command Command to serialize into a request. + * @param null $endpoint Endpoint resolved using EndpointProviderV2 + * @return RequestInterface + */ + public function __invoke( + CommandInterface $command, + $endpoint = null + ) + { + $operation = $this->api->getOperation($command->getName()); + $body = [ + 'Action' => $command->getName(), + 'Version' => $this->api->getMetadata('apiVersion') + ]; + $commandArgs = $command->toArray(); + + // Only build up the parameters when there are parameters to build + if ($commandArgs) { + $body += call_user_func( + $this->paramBuilder, + $operation->getInput(), + $commandArgs + ); + } + $body = http_build_query($body, '', '&', PHP_QUERY_RFC3986); + $headers = [ + 'Content-Length' => strlen($body), + 'Content-Type' => 'application/x-www-form-urlencoded' + ]; + $requestUri = $operation['http']['requestUri'] ?? null; + + if ($endpoint instanceof RulesetEndpoint) { + $this->setEndpointV2RequestOptions($endpoint, $headers); + } + $absoluteUri = str_ends_with($this->endpoint, '/') + ? $this->endpoint : $this->endpoint . $requestUri; + + return new Request( + 'POST', + $absoluteUri, + $headers, + $body + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestJsonSerializer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestJsonSerializer.php new file mode 100644 index 000000000..e198664c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestJsonSerializer.php @@ -0,0 +1,41 @@ +contentType = JsonBody::getContentType($api); + $this->jsonFormatter = $jsonFormatter ?: new JsonBody($api); + } + + protected function payload(StructureShape $member, array|string $value, array &$opts) + { + $opts['headers']['Content-Type'] = $this->contentType; + $body = $this->jsonFormatter->build($member, $value); + $opts['headers']['Content-Length'] = strlen($body); + $opts['body'] = $body; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php new file mode 100644 index 000000000..a0d342d34 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php @@ -0,0 +1,486 @@ + true, + 'glacier' => true + ]; + + /** @var Service */ + private Service $api; + + /** @var Uri */ + private $endpoint; + + /** @var bool */ + private $isUseEndpointV2; + + use EndpointV2SerializerTrait; + + /** + * @param Service $api Service API description + * @param string $endpoint Endpoint to connect to + */ + public function __construct(Service $api, $endpoint) + { + $this->api = $api; + $this->endpoint = Psr7\Utils::uriFor($endpoint); + } + + /** + * @param CommandInterface $command Command to serialize into a request. + * @param mixed|null $endpoint + * @return RequestInterface + */ + public function __invoke( + CommandInterface $command, + mixed $endpoint = null + ) + { + $operation = $this->api->getOperation($command->getName()); + $commandArgs = $command->toArray(); + $opts = $this->serialize($operation, $commandArgs); + $headers = $opts['headers'] ?? []; + + if ($endpoint instanceof RulesetEndpoint) { + $this->isUseEndpointV2 = true; + $this->setEndpointV2RequestOptions($endpoint, $headers); + } + + $uri = $this->buildEndpoint($operation, $commandArgs, $opts); + + return new Request( + $operation['http']['method'], + $uri, + $headers, + $opts['body'] ?? null + ); + } + + /** + * Modifies a hash of request options for a payload body. + * + * @param StructureShape $member Member to serialize + * @param array $value Value to serialize + * @param array $opts Request options to modify. + */ + abstract protected function payload( + StructureShape $member, + array $value, + array &$opts + ); + + private function serialize(Operation $operation, array $args) + { + $opts = []; + $input = $operation->getInput(); + + // Apply the payload trait if present + if ($payload = $input['payload']) { + $this->applyPayload($input, $payload, $args, $opts); + } + + foreach ($args as $name => $value) { + if ($input->hasMember($name)) { + $member = $input->getMember($name); + $location = $member['location']; + if (!$payload && !$location) { + $bodyMembers[$name] = $value; + } elseif ($location === 'header') { + $this->applyHeader($name, $member, $value, $opts); + } elseif ($location === 'querystring') { + $this->applyQuery($name, $member, $value, $opts); + } elseif ($location === 'headers') { + $this->applyHeaderMap($name, $member, $value, $opts); + } + } + } + + if (isset($bodyMembers)) { + $this->payload($input, $bodyMembers, $opts); + } else if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) { + $this->payload($input, [], $opts); + } + + return $opts; + } + + private function applyPayload(StructureShape $input, $name, array $args, array &$opts) + { + if (!isset($args[$name])) { + return; + } + + $m = $input->getMember($name); + + $type = $m->getType(); + if ($m['streaming'] || + ($type === 'string' || $type === 'blob') + ) { + // This path skips setting the content-type header usually done in + // RestJsonSerializer and RestXmlSerializer.certain S3 and glacier + // operations determine content type in Middleware::ContentType() + if (!isset(self::$excludeContentType[$this->api->getServiceName()])) { + switch ($type) { + case 'string': + $opts['headers']['Content-Type'] = 'text/plain'; + break; + case 'blob': + $opts['headers']['Content-Type'] = 'application/octet-stream'; + break; + } + } + + $body = $args[$name]; + if (!$m['streaming'] && is_string($body)) { + $opts['headers']['Content-Length'] = strlen($body); + } + + // Streaming bodies or payloads that are strings are + // always just a stream of data. + $opts['body'] = Psr7\Utils::streamFor($body); + return; + } + + $this->payload($m, $args[$name], $opts); + } + + private function applyHeader($name, Shape $member, $value, array &$opts) + { + // Handle lists by recursively applying header logic to each element + if ($member instanceof ListShape) { + $listMember = $member->getMember(); + $headerValues = []; + + foreach ($value as $listValue) { + $tempOpts = ['headers' => []]; + $this->applyHeader('temp', $listMember, $listValue, $tempOpts); + $convertedValue = $tempOpts['headers']['temp']; + $headerValues[] = $convertedValue; + } + + $value = $headerValues; + } elseif (!is_null($value)) { + switch ($member->getType()) { + case 'timestamp': + $timestampFormat = $member['timestampFormat'] ?? 'rfc822'; + $value = $this->formatTimestamp($value, $timestampFormat); + break; + case 'boolean': + $value = $this->formatBoolean($value); + break; + } + } + + if ($member['jsonvalue']) { + $value = json_encode($value); + if (empty($value) && JSON_ERROR_NONE !== json_last_error()) { + throw new \InvalidArgumentException('Unable to encode the provided value' + . ' with \'json_encode\'. ' . json_last_error_msg()); + } + + $value = base64_encode($value); + } + + $opts['headers'][$member['locationName'] ?: $name] = $value; + } + + /** + * Note: This is currently only present in the Amazon S3 model. + */ + private function applyHeaderMap($name, Shape $member, array $value, array &$opts) + { + $prefix = $member['locationName']; + foreach ($value as $k => $v) { + $opts['headers'][$prefix . $k] = $v; + } + } + + private function applyQuery($name, Shape $member, $value, array &$opts) + { + if ($member instanceof MapShape) { + $opts['query'] = isset($opts['query']) && is_array($opts['query']) + ? $opts['query'] + $value + : $value; + } elseif ($member instanceof ListShape) { + $listMember = $member->getMember(); + $paramName = $member['locationName'] ?: $name; + + foreach ($value as $listValue) { + // Recursively call applyQuery for each list element + $tempOpts = ['query' => []]; + $this->applyQuery('temp', $listMember, $listValue, $tempOpts); + $opts['query'][$paramName][] = $tempOpts['query']['temp']; + } + } elseif (!is_null($value)) { + switch ($member->getType()) { + case 'timestamp': + $timestampFormat = $member['timestampFormat'] ?? 'iso8601'; + $value = $this->formatTimestamp($value, $timestampFormat); + break; + case 'boolean': + $value = $this->formatBoolean($value); + break; + } + + $opts['query'][$member['locationName'] ?: $name] = $value; + } + } + + private function buildEndpoint( + Operation $operation, + array $args, + array $opts + ): UriInterface + { + // Expand `requestUri` field members + $relativeUri = $this->expandUriTemplate($operation, $args); + + // Add query members to relativeUri + if (!empty($opts['query'])) { + $relativeUri = $this->appendQuery($opts['query'], $relativeUri); + } + + // Special case - S3 keys that need path preservation + if ($this->api->getServiceName() === 's3' + && isset($args['Key']) + && $this->shouldPreservePath($args['Key']) + ) { + return new Uri($this->endpoint . $relativeUri); + } + + return $this->resolveUri($relativeUri, $opts); + } + + /** + * Expands `requestUri` members + * + * @param Operation $operation + * @param array $args + * + * @return string + */ + private function expandUriTemplate(Operation $operation, array $args): string + { + $varDefinitions = $this->getVarDefinitions($operation, $args); + + return preg_replace_callback( + self::TEMPLATE_STRING_REGEX, + static function (array $matches) use ($varDefinitions) { + $isGreedy = str_ends_with($matches[1], '+'); + $varName = $isGreedy ? substr($matches[1], 0, -1) : $matches[1]; + + if (!isset($varDefinitions[$varName])) { + return ''; + } + + $value = $varDefinitions[$varName]; + + if ($isGreedy) { + return str_replace('%2F', '/', rawurlencode($value)); + } + + return rawurlencode($value); + }, + $operation['http']['requestUri'] + ); + } + + /** + * Checks for path-like key names. If detected, traditional + * URI resolution is bypassed. + * + * @param string $key + * @return bool + */ + private function shouldPreservePath(string $key): bool + { + // Keys with dot segments + if (str_contains($key, '.')) { + $segments = explode('/', $key); + foreach ($segments as $segment) { + if ($segment === '.' || $segment === '..') { + return true; + } + } + } + + // Keys starting with slash + if (str_starts_with($key, '/')) { + return true; + } + + return false; + } + + /** + * @param string $relativeUri + * @param array $opts + * + * @return UriInterface + */ + private function resolveUri(string $relativeUri, array $opts): UriInterface + { + $basePath = $this->endpoint->getPath(); + + // Only process if we have a non-empty base path + if (!empty($basePath) && $basePath !== '/') { + // if relative is just '/', we want just the base path without trailing slash + if ($relativeUri === '/' || empty($relativeUri)) { + // Remove trailing slash if present + return $this->endpoint->withPath(rtrim($basePath, '/')); + } + + // if relative is '/?query', we want base path without trailing slash + query + // for now, this is only seen with S3 GetBucketLocation after processing the model + if (empty($opts['query']) + && str_starts_with($relativeUri, '/?') + ) { + $query = substr($relativeUri, 2); // Remove '/?' + return $this->endpoint->withQuery($query); + } + + // Ensure base path has trailing slash + if (!str_ends_with($basePath, '/')) { + $this->endpoint = $this->endpoint->withPath($basePath . '/'); + } + + // Remove leading slash from relative path to make it relative + if (str_starts_with($relativeUri, '/')) { + $relativeUri = substr($relativeUri, 1); + } + } + + return UriResolver::resolve($this->endpoint, new Uri($relativeUri)); + } + + /** + * @param StructureShape $input + * @param $payload + * + * @return bool + */ + private function hasPayloadParam(StructureShape $input, $payload) + { + if ($payload) { + $potentiallyEmptyTypes = ['blob','string']; + if ($this->api->getProtocol() === 'rest-xml') { + $potentiallyEmptyTypes[] = 'structure'; + } + + $payloadMember = $input->getMember($payload); + //unions may also be empty/unset + if (!empty($payloadMember['union']) + || in_array($payloadMember['type'], $potentiallyEmptyTypes) + ) { + return false; + } + } + + foreach ($input->getMembers() as $member) { + if (!isset($member['location'])) { + return true; + } + } + + return false; + } + + /** + * @param $query + * @param $relativeUri + * + * @return string + */ + private function appendQuery($query, $relativeUri): string + { + $append = Psr7\Query::build($query); + return $relativeUri + . (str_contains($relativeUri, '?') ? "&{$append}" : "?{$append}"); + } + + /** + * @param CommandInterface $command + * @param array $args + * + * @return array + */ + private function getVarDefinitions( + Operation $operation, + array $args + ): array + { + $varDefinitions = []; + + foreach ($operation->getInput()->getMembers() as $name => $member) { + if ($member['location'] === 'uri') { + $value = $args[$name] ?? null; + if (!is_null($value)) { + switch ($member->getType()) { + case 'timestamp': + $timestampFormat = $member['timestampFormat'] ?? 'iso8601'; + $value = $this->formatTimestamp($value, $timestampFormat); + break; + case 'boolean': + $value = $this->formatBoolean($value); + break; + } + } + + $varDefinitions[$member['locationName'] ?: $name] = $value; + } + } + + return $varDefinitions; + } + + /** + * @param DateTimeInterface|string|int $value + * @param string $timestampFormat + * + * @return string + */ + private function formatTimestamp( + DateTimeInterface|string|int $value, + string $timestampFormat + ): string + { + return TimestampShape::format($value, $timestampFormat); + } + + /** + * @param $value + * + * @return string + */ + private function formatBoolean($value): string + { + return $value ? 'true' : 'false'; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestXmlSerializer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestXmlSerializer.php new file mode 100644 index 000000000..16d8ae7b9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/RestXmlSerializer.php @@ -0,0 +1,50 @@ +xmlBody = $xmlBody ?: new XmlBody($api); + } + + protected function payload(StructureShape $member, array $value, array &$opts) + { + $opts['headers']['Content-Type'] = 'application/xml'; + $body = $this->getXmlBody($member, $value); + $opts['headers']['Content-Length'] = strlen($body); + $opts['body'] = $body; + } + + /** + * @param StructureShape $member + * @param array $value + * @return string + */ + private function getXmlBody(StructureShape $member, array $value) + { + $xmlBody = (string)$this->xmlBody->build($member, $value); + $xmlBody = str_replace("'", "'", $xmlBody); + $xmlBody = str_replace('\r', " ", $xmlBody); + $xmlBody = str_replace('\n', " ", $xmlBody); + return $xmlBody; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/XmlBody.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/XmlBody.php new file mode 100644 index 000000000..9ce967e2e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Serializer/XmlBody.php @@ -0,0 +1,256 @@ +api = $api; + } + + /** + * Builds the XML body based on an array of arguments. + * + * @param Shape $shape Operation being constructed + * @param array $args Associative array of arguments + * + * @return string + */ + public function build(Shape $shape, array $args) + { + $xml = new XMLWriter(); + $xml->openMemory(); + $xml->startDocument('1.0', 'UTF-8'); + + $rootElementName = $this->determineRootElementName($shape); + + $this->format($shape, $rootElementName, $args, $xml); + $xml->endDocument(); + + return $xml->outputMemory(); + } + + private function startElement(Shape $shape, $name, XMLWriter $xml) + { + $xml->startElement($name); + + if ($ns = $shape['xmlNamespace']) { + $xml->writeAttribute( + isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns', + $ns['uri'] + ); + } + } + + private function format(Shape $shape, $name, $value, XMLWriter $xml) + { + // Any method mentioned here has a custom serialization handler. + static $methods = [ + 'add_structure' => true, + 'add_list' => true, + 'add_blob' => true, + 'add_timestamp' => true, + 'add_boolean' => true, + 'add_map' => true, + 'add_string' => true + ]; + + $type = 'add_' . $shape['type']; + if (isset($methods[$type])) { + $this->{$type}($shape, $name, $value, $xml); + } else { + $this->defaultShape($shape, $name, $value, $xml); + } + } + + private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml) + { + $this->startElement($shape, $name, $xml); + $xml->text($value); + $xml->endElement(); + } + + private function add_structure( + StructureShape $shape, + $name, + array $value, + \XMLWriter $xml + ) { + $this->startElement($shape, $name, $xml); + + foreach ($this->getStructureMembers($shape, $value) as $k => $definition) { + // Default to member name + $elementName = $k; + + // Only use locationName for non-structure members + if (!($definition['member'] instanceof StructureShape) + && $definition['member']['locationName'] + ) { + $elementName = $definition['member']['locationName']; + } + + $this->format( + $definition['member'], + $elementName, + $definition['value'], + $xml + ); + } + + $xml->endElement(); + } + + private function getStructureMembers(StructureShape $shape, array $value) + { + $members = []; + + foreach ($value as $k => $v) { + if ($v !== null && $shape->hasMember($k)) { + $definition = [ + 'member' => $shape->getMember($k), + 'value' => $v, + ]; + + if ($definition['member']['xmlAttribute']) { + // array_unshift_associative + $members = [$k => $definition] + $members; + } else { + $members[$k] = $definition; + } + } + } + + return $members; + } + + private function add_list( + ListShape $shape, + $name, + array $value, + XMLWriter $xml + ) { + $items = $shape->getMember(); + + if ($shape['flattened']) { + $elementName = $name; + } else { + $this->startElement($shape, $name, $xml); + $elementName = $items['locationName'] ?: 'member'; + } + + foreach ($value as $v) { + $this->format($items, $elementName, $v, $xml); + } + + if (!$shape['flattened']) { + $xml->endElement(); + } + } + + private function add_map( + MapShape $shape, + $name, + array $value, + XMLWriter $xml + ) { + $xmlEntry = $shape['flattened'] ? $name : 'entry'; + $xmlKey = $shape->getKey()['locationName'] ?: 'key'; + $xmlValue = $shape->getValue()['locationName'] ?: 'value'; + + if (!$shape['flattened']) { + $this->startElement($shape, $name, $xml); + } + + foreach ($value as $key => $v) { + $this->startElement($shape, $xmlEntry, $xml); + $this->format($shape->getKey(), $xmlKey, $key, $xml); + $this->format($shape->getValue(), $xmlValue, $v, $xml); + $xml->endElement(); + } + + if (!$shape['flattened']) { + $xml->endElement(); + } + } + + private function add_blob(Shape $shape, $name, $value, XMLWriter $xml) + { + $this->startElement($shape, $name, $xml); + $xml->writeRaw(base64_encode($value)); + $xml->endElement(); + } + + private function add_timestamp( + TimestampShape $shape, + $name, + $value, + XMLWriter $xml + ) { + $this->startElement($shape, $name, $xml); + $timestampFormat = !empty($shape['timestampFormat']) + ? $shape['timestampFormat'] + : 'iso8601'; + $xml->writeRaw(TimestampShape::format($value, $timestampFormat)); + $xml->endElement(); + } + + private function add_boolean( + Shape $shape, + $name, + $value, + XMLWriter $xml + ) { + $this->startElement($shape, $name, $xml); + $xml->writeRaw($value ? 'true' : 'false'); + $xml->endElement(); + } + + private function add_string( + Shape $shape, + $name, + $value, + XMLWriter $xml + ) { + if ($shape['xmlAttribute']) { + $xml->writeAttribute($shape['locationName'] ?: $name, $value); + } else { + $this->defaultShape($shape, $name, $value, $xml); + } + } + + private function determineRootElementName(Shape $shape): string + { + $shapeName = $shape->getName(); + + // Look up the shape definition first + if ($shapeName && $shapeMap = $shape->getShapeMap()) { + if (isset($shapeMap[$shapeName]['locationName'])) { + return $shapeMap[$shapeName]['locationName']; + } + } + + // Fall back to shape's current locationName + if ($shape['locationName']) { + return $shape['locationName']; + } + + return $shapeName; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Service.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Service.php new file mode 100644 index 000000000..38bd4513c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Service.php @@ -0,0 +1,564 @@ + [], + 'shapes' => [], + 'metadata' => [], + 'clientContextParams' => [] + ], $defaultMeta = [ + 'apiVersion' => null, + 'serviceFullName' => null, + 'serviceId' => null, + 'endpointPrefix' => null, + 'signingName' => null, + 'signatureVersion' => null, + 'protocol' => null, + 'uid' => null + ]; + + $definition += $defaults; + $definition['metadata'] += $defaultMeta; + $this->definition = $definition; + $this->apiProvider = $provider; + parent::__construct($definition, new ShapeMap($definition['shapes'])); + + if (isset($definition['metadata']['serviceIdentifier'])) { + $this->serviceName = $this->getServiceName(); + } else { + $this->serviceName = $this->getEndpointPrefix(); + } + $this->apiVersion = $this->getApiVersion(); + if (isset($definition['clientContextParams'])) { + $this->clientContextParams = $definition['clientContextParams']; + } + + $this->protocol = $this->selectProtocol($definition); + } + + /** + * Creates a request serializer for the provided API object. + * + * @param Service $api API that contains a protocol. + * @param string $endpoint Endpoint to send requests to. + * + * @return callable + * @throws \UnexpectedValueException + */ + public static function createSerializer(Service $api, $endpoint) + { + static $mapping = [ + 'json' => Serializer\JsonRpcSerializer::class, + 'query' => Serializer\QuerySerializer::class, + 'rest-json' => Serializer\RestJsonSerializer::class, + 'rest-xml' => Serializer\RestXmlSerializer::class + ]; + + $proto = $api->getProtocol(); + + if (isset($mapping[$proto])) { + return new $mapping[$proto]($api, $endpoint); + } + + if ($proto == 'ec2') { + return new Serializer\QuerySerializer($api, $endpoint, new Serializer\Ec2ParamBuilder()); + } + + throw new \UnexpectedValueException( + 'Unknown protocol: ' . $api->getProtocol() + ); + } + + /** + * Creates an error parser for the given protocol. + * + * Redundant method signature to preserve backwards compatibility. + * + * @param string $protocol Protocol to parse (e.g., query, json, etc.) + * + * @return callable + * @throws \UnexpectedValueException + */ + public static function createErrorParser($protocol, ?Service $api = null) + { + static $mapping = [ + 'json' => ErrorParser\JsonRpcErrorParser::class, + 'query' => ErrorParser\XmlErrorParser::class, + 'rest-json' => ErrorParser\RestJsonErrorParser::class, + 'rest-xml' => ErrorParser\XmlErrorParser::class, + 'ec2' => ErrorParser\XmlErrorParser::class + ]; + + if (isset($mapping[$protocol])) { + return new $mapping[$protocol]($api); + } + + throw new \UnexpectedValueException("Unknown protocol: $protocol"); + } + + /** + * Applies the listeners needed to parse client models. + * + * @param Service $api API to create a parser for + * @return callable + * @throws \UnexpectedValueException + */ + public static function createParser(Service $api) + { + static $mapping = [ + 'json' => Parser\JsonRpcParser::class, + 'query' => Parser\QueryParser::class, + 'rest-json' => Parser\RestJsonParser::class, + 'rest-xml' => Parser\RestXmlParser::class + ]; + + $proto = $api->getProtocol(); + if (isset($mapping[$proto])) { + return new $mapping[$proto]($api); + } + + if ($proto == 'ec2') { + return new Parser\QueryParser($api, null, false); + } + + throw new \UnexpectedValueException( + 'Unknown protocol: ' . $api->getProtocol() + ); + } + + /** + * Get the full name of the service + * + * @return string + */ + public function getServiceFullName() + { + return $this->definition['metadata']['serviceFullName']; + } + + /** + * Get the service id + * + * @return string + */ + public function getServiceId() + { + return $this->definition['metadata']['serviceId']; + } + + /** + * Get the API version of the service + * + * @return string + */ + public function getApiVersion() + { + return $this->definition['metadata']['apiVersion']; + } + + /** + * Get the API version of the service + * + * @return string + */ + public function getEndpointPrefix() + { + return $this->definition['metadata']['endpointPrefix']; + } + + /** + * Get the signing name used by the service. + * + * @return string + */ + public function getSigningName() + { + return $this->definition['metadata']['signingName'] + ?: $this->definition['metadata']['endpointPrefix']; + } + + /** + * Get the service name. + * + * @return string + */ + public function getServiceName() + { + return $this->definition['metadata']['serviceIdentifier'] ?? null; + } + + /** + * Get the default signature version of the service. + * + * Note: this method assumes "v4" when not specified in the model. + * + * @return string + */ + public function getSignatureVersion() + { + return $this->definition['metadata']['signatureVersion'] ?: 'v4'; + } + + /** + * Get the protocol used by the service. + * + * @return string + */ + public function getProtocol() + { + return $this->protocol; + } + + /** + * Get the uid string used by the service + * + * @return string + */ + public function getUid() + { + return $this->definition['metadata']['uid']; + } + + /** + * Check if the description has a specific operation by name. + * + * @param string $name Operation to check by name + * + * @return bool + */ + public function hasOperation($name) + { + return isset($this['operations'][$name]); + } + + /** + * Get an operation by name. + * + * @param string $name Operation to retrieve by name + * + * @return Operation + * @throws \InvalidArgumentException If the operation is not found + */ + public function getOperation($name) + { + if (!isset($this->operations[$name])) { + if (!isset($this->definition['operations'][$name])) { + throw new \InvalidArgumentException("Unknown operation: $name"); + } + $this->operations[$name] = new Operation( + $this->definition['operations'][$name], + $this->shapeMap + ); + } elseif ($this->modifiedModel) { + $this->operations[$name] = new Operation( + $this->definition['operations'][$name], + $this->shapeMap + ); + } + + return $this->operations[$name]; + } + + /** + * Get all of the operations of the description. + * + * @return Operation[] + */ + public function getOperations() + { + $result = []; + foreach ($this->definition['operations'] as $name => $definition) { + $result[$name] = $this->getOperation($name); + } + + return $result; + } + + /** + * Get all of the error shapes of the service + * + * @return array + */ + public function getErrorShapes() + { + $result = []; + foreach ($this->definition['shapes'] as $name => $definition) { + if (!empty($definition['exception'])) { + $definition['name'] = $name; + $result[] = new StructureShape($definition, $this->getShapeMap()); + } + } + + return $result; + } + + /** + * Get all of the service metadata or a specific metadata key value. + * + * @param string|null $key Key to retrieve or null to retrieve all metadata + * + * @return mixed Returns the result or null if the key is not found + */ + public function getMetadata($key = null) + { + if (!$key) { + return $this['metadata']; + } + + if (isset($this->definition['metadata'][$key])) { + return $this->definition['metadata'][$key]; + } + + return null; + } + + /** + * Gets an associative array of available paginator configurations where + * the key is the name of the paginator, and the value is the paginator + * configuration. + * + * @return array + * @unstable The configuration format of paginators may change in the future + */ + public function getPaginators() + { + if (!isset($this->paginators)) { + $res = call_user_func( + $this->apiProvider, + 'paginator', + $this->serviceName, + $this->apiVersion + ); + $this->paginators = isset($res['pagination']) + ? $res['pagination'] + : []; + } + + return $this->paginators; + } + + /** + * Determines if the service has a paginator by name. + * + * @param string $name Name of the paginator. + * + * @return bool + */ + public function hasPaginator($name) + { + return isset($this->getPaginators()[$name]); + } + + /** + * Retrieve a paginator by name. + * + * @param string $name Paginator to retrieve by name. This argument is + * typically the operation name. + * @return array + * @throws \UnexpectedValueException if the paginator does not exist. + * @unstable The configuration format of paginators may change in the future + */ + public function getPaginatorConfig($name) + { + static $defaults = [ + 'input_token' => null, + 'output_token' => null, + 'limit_key' => null, + 'result_key' => null, + 'more_results' => null, + ]; + + if ($this->hasPaginator($name)) { + return $this->paginators[$name] + $defaults; + } + + throw new \UnexpectedValueException("There is no {$name} " + . "paginator defined for the {$this->serviceName} service."); + } + + /** + * Gets an associative array of available waiter configurations where the + * key is the name of the waiter, and the value is the waiter + * configuration. + * + * @return array + */ + public function getWaiters() + { + if (!isset($this->waiters)) { + $res = call_user_func( + $this->apiProvider, + 'waiter', + $this->serviceName, + $this->apiVersion + ); + $this->waiters = isset($res['waiters']) + ? $res['waiters'] + : []; + } + + return $this->waiters; + } + + /** + * Determines if the service has a waiter by name. + * + * @param string $name Name of the waiter. + * + * @return bool + */ + public function hasWaiter($name) + { + return isset($this->getWaiters()[$name]); + } + + /** + * Get a waiter configuration by name. + * + * @param string $name Name of the waiter by name. + * + * @return array + * @throws \UnexpectedValueException if the waiter does not exist. + */ + public function getWaiterConfig($name) + { + // Error if the waiter is not defined + if ($this->hasWaiter($name)) { + return $this->waiters[$name]; + } + + throw new \UnexpectedValueException("There is no {$name} waiter " + . "defined for the {$this->serviceName} service."); + } + + /** + * Get the shape map used by the API. + * + * @return ShapeMap + */ + public function getShapeMap() + { + return $this->shapeMap; + } + + /** + * Get all the context params of the description. + * + * @return array + */ + public function getClientContextParams() + { + return $this->clientContextParams; + } + + /** + * Get the service's api provider. + * + * @return callable + */ + public function getProvider() + { + return $this->apiProvider; + } + + /** + * Get the service's definition. + * + * @return callable + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Sets the service's api definition. + * Intended for internal use only. + * + * @return void + * + * @internal + */ + public function setDefinition($definition) + { + $this->definition = $definition; + $this->shapeMap = new ShapeMap($definition['shapes']); + $this->modifiedModel = true; + } + + /** + * Denotes whether or not a service's definition has + * been modified. Intended for internal use only. + * + * @return bool + * + * @internal + */ + public function isModifiedModel() + { + return $this->modifiedModel; + } + + /** + * Accepts a list of protocols derived from the service model. + * Returns the highest priority compatible auth scheme if the `protocols` trait is present. + * Otherwise, returns the value of the `protocol` field, if set, or null. + * + * @param array $definition + * + * @return string|null + */ + private function selectProtocol(array $definition): string | null + { + $modeledProtocols = $definition['metadata']['protocols'] ?? null; + if (!empty($modeledProtocols)) { + foreach(SupportedProtocols::cases() as $protocol) { + if (in_array($protocol->value, $modeledProtocols)) { + return $protocol->value; + } + } + } + + return $definition['metadata']['protocol'] ?? null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Shape.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Shape.php new file mode 100644 index 000000000..765efc035 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Shape.php @@ -0,0 +1,77 @@ + StructureShape::class, + 'map' => MapShape::class, + 'list' => ListShape::class, + 'timestamp' => TimestampShape::class, + 'integer' => Shape::class, + 'double' => Shape::class, + 'float' => Shape::class, + 'long' => Shape::class, + 'string' => Shape::class, + 'byte' => Shape::class, + 'character' => Shape::class, + 'blob' => Shape::class, + 'boolean' => Shape::class + ]; + + if (isset($definition['shape'])) { + return $shapeMap->resolve($definition); + } + + if (!isset($map[$definition['type']])) { + throw new \RuntimeException('Invalid type: ' + . print_r($definition, true)); + } + + $type = $map[$definition['type']]; + + return new $type($definition, $shapeMap); + } + + /** + * Get the type of the shape + * + * @return string + */ + public function getType() + { + return $this->definition['type']; + } + + /** + * Get the name of the shape + * + * @return string + */ + public function getName() + { + return $this->definition['name']; + } + + /** + * Get a context param definition. + */ + public function getContextParam() + { + return $this->contextParam; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ShapeMap.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ShapeMap.php new file mode 100644 index 000000000..269b2d3a0 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/ShapeMap.php @@ -0,0 +1,109 @@ +definitions = $shapeModels; + } + + /** + * Get an array of shape names. + * + * @return array + */ + public function getShapeNames() + { + return array_keys($this->definitions); + } + + /** + * Resolve a shape reference + * + * @param array $shapeRef Shape reference shape + * + * @return Shape + * @throws \InvalidArgumentException + */ + public function resolve(array $shapeRef) + { + $shape = $shapeRef['shape']; + + if (!isset($this->definitions[$shape])) { + throw new \InvalidArgumentException('Shape not found: ' . $shape); + } + + $isSimple = count($shapeRef) == 1; + if ($isSimple && isset($this->simple[$shape])) { + return $this->simple[$shape]; + } + + $definition = $shapeRef + $this->definitions[$shape]; + $definition['name'] = $definition['shape']; + if (isset($definition['shape'])) { + unset($definition['shape']); + } + + $result = Shape::create($definition, $this); + + if ($isSimple) { + $this->simple[$shape] = $result; + } + + return $result; + } + + /** + * @param mixed $offset + * @return bool + */ + public function offsetExists(mixed $offset): bool + { + return isset($this->definitions[$offset]); + } + + /** + * @param mixed $offset + * @return mixed + */ + public function offsetGet(mixed $offset): mixed + { + return $this->definitions[$offset] ?? null; + } + + /** + * @param mixed $offset + * @param mixed $value + * @throws \BadMethodCallException + */ + public function offsetSet(mixed $offset, mixed $value): void + { + throw new \BadMethodCallException( + 'ShapeMap is read-only and cannot be modified.' + ); + } + + /** + * @param mixed $offset + * @throws \BadMethodCallException + */ + public function offsetUnset(mixed $offset): void + { + throw new \BadMethodCallException( + 'ShapeMap is read-only and cannot be modified.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/StructureShape.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/StructureShape.php new file mode 100644 index 000000000..2cfe7702e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/StructureShape.php @@ -0,0 +1,105 @@ +members)) { + $this->generateMembersHash(); + } + + return $this->members; + } + + /** + * Check if a specific member exists by name. + * + * @param string $name Name of the member to check + * + * @return bool + */ + public function hasMember($name) + { + return isset($this->definition['members'][$name]); + } + + /** + * Retrieve a member by name. + * + * @param string $name Name of the member to retrieve + * + * @return Shape + * @throws \InvalidArgumentException if the member is not found. + */ + public function getMember($name) + { + $members = $this->getMembers(); + + if (!isset($members[$name])) { + throw new \InvalidArgumentException('Unknown member ' . $name); + } + + return $members[$name]; + } + + /** + * Used to look up the shape's original definition. + * ShapeMap::resolve() merges properties from both + * member and target shape definitions, causing certain + * properties like `locationName` to be overwritten. + * + * @return ShapeMap + * @internal This method is for internal use only and should not be used + * by external code. It may be changed or removed without notice. + */ + public function getShapeMap(): ShapeMap + { + return $this->shapeMap; + } + + /** + * Used to look up a shape's original definition. + * + * @param string $name + * + * @return array|null + */ + public function getOriginalDefinition(string $name): ?array + { + return $this->shapeMap[$name] ?? null; + } + + private function generateMembersHash() + { + $this->members = []; + + foreach ($this->definition['members'] as $name => $definition) { + $this->members[$name] = $this->shapeFor($definition); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/SupportedProtocols.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/SupportedProtocols.php new file mode 100644 index 000000000..8a06bd0e5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/SupportedProtocols.php @@ -0,0 +1,26 @@ +getTimestamp(); + } elseif (is_string($value)) { + $value = strtotime($value); + } elseif (!is_int($value)) { + throw new \InvalidArgumentException('Unable to handle the provided' + . ' timestamp type: ' . gettype($value)); + } + + switch ($format) { + case 'iso8601': + return gmdate('Y-m-d\TH:i:s\Z', $value); + case 'rfc822': + return gmdate('D, d M Y H:i:s \G\M\T', $value); + case 'unixTimestamp': + return $value; + default: + throw new \UnexpectedValueException('Unknown timestamp format: ' + . $format); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Validator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Validator.php new file mode 100644 index 000000000..886092645 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Api/Validator.php @@ -0,0 +1,346 @@ + true, + 'min' => true, + 'max' => false, + 'pattern' => false + ]; + + /** + * @param array $constraints Associative array of constraints to enforce. + * Accepts the following keys: "required", "min", + * "max", and "pattern". If a key is not + * provided, the constraint will assume false. + */ + public function __construct(?array $constraints = null) + { + static $assumedFalseValues = [ + 'required' => false, + 'min' => false, + 'max' => false, + 'pattern' => false + ]; + $this->constraints = empty($constraints) + ? self::$defaultConstraints + : $constraints + $assumedFalseValues; + } + + /** + * Validates the given input against the schema. + * + * @param string $name Operation name + * @param Shape $shape Shape to validate + * @param array $input Input to validate + * + * @throws \InvalidArgumentException if the input is invalid. + */ + public function validate($name, Shape $shape, array $input) + { + $this->dispatch($shape, $input); + + if ($this->errors) { + $message = sprintf( + "Found %d error%s while validating the input provided for the " + . "%s operation:\n%s", + count($this->errors), + count($this->errors) > 1 ? 's' : '', + $name, + implode("\n", $this->errors) + ); + $this->errors = []; + + throw new \InvalidArgumentException($message); + } + } + + private function dispatch(Shape $shape, $value) + { + static $methods = [ + 'structure' => 'check_structure', + 'list' => 'check_list', + 'map' => 'check_map', + 'blob' => 'check_blob', + 'boolean' => 'check_boolean', + 'integer' => 'check_numeric', + 'float' => 'check_numeric', + 'long' => 'check_numeric', + 'string' => 'check_string', + 'byte' => 'check_string', + 'char' => 'check_string' + ]; + + $type = $shape->getType(); + if (isset($methods[$type])) { + $this->{$methods[$type]}($shape, $value); + } + } + + private function check_structure(StructureShape $shape, $value) + { + $isDocument = (isset($shape['document']) && $shape['document']); + $isUnion = (isset($shape['union']) && $shape['union']); + if ($isDocument) { + if (!$this->checkDocumentType($value)) { + $this->addError("is not a valid document type"); + return; + } + } elseif ($isUnion) { + if (!$this->checkUnion($value)) { + $this->addError("is a union type and must have exactly one non null value"); + return; + } + } elseif (!$this->checkAssociativeArray($value)) { + return; + } + + if ($this->constraints['required'] && $shape['required']) { + foreach ($shape['required'] as $req) { + if (!isset($value[$req])) { + $this->path[] = $req; + $this->addError('is missing and is a required parameter'); + array_pop($this->path); + } + } + } + if (!$isDocument) { + foreach ($value as $name => $v) { + if ($shape->hasMember($name)) { + $this->path[] = $name; + $this->dispatch( + $shape->getMember($name), + isset($value[$name]) ? $value[$name] : null + ); + array_pop($this->path); + } + } + } + } + + private function check_list(ListShape $shape, $value) + { + if (!is_array($value)) { + $this->addError('must be an array. Found ' + . Aws\describe_type($value)); + return; + } + + $this->validateRange($shape, count($value), "list element count"); + + $items = $shape->getMember(); + foreach ($value as $index => $v) { + $this->path[] = $index; + $this->dispatch($items, $v); + array_pop($this->path); + } + } + + private function check_map(MapShape $shape, $value) + { + if (!$this->checkAssociativeArray($value)) { + return; + } + + $values = $shape->getValue(); + foreach ($value as $key => $v) { + $this->path[] = $key; + $this->dispatch($values, $v); + array_pop($this->path); + } + } + + private function check_blob(Shape $shape, $value) + { + static $valid = [ + 'string' => true, + 'integer' => true, + 'double' => true, + 'resource' => true + ]; + + $type = gettype($value); + if (!isset($valid[$type])) { + if ($type != 'object' || !method_exists($value, '__toString')) { + $this->addError('must be an fopen resource, a ' + . 'GuzzleHttp\Stream\StreamInterface object, or something ' + . 'that can be cast to a string. Found ' + . Aws\describe_type($value)); + } + } + } + + private function check_numeric(Shape $shape, $value) + { + if (!is_numeric($value)) { + $this->addError('must be numeric. Found ' + . Aws\describe_type($value)); + return; + } + + $this->validateRange($shape, $value, "numeric value"); + } + + private function check_boolean(Shape $shape, $value) + { + if (!is_bool($value)) { + $this->addError('must be a boolean. Found ' + . Aws\describe_type($value)); + } + } + + private function check_string(Shape $shape, $value) + { + if ($shape['jsonvalue']) { + if (!self::canJsonEncode($value)) { + $this->addError('must be a value encodable with \'json_encode\'.' + . ' Found ' . Aws\describe_type($value)); + } + return; + } + + if (!$this->checkCanString($value)) { + $this->addError('must be a string or an object that implements ' + . '__toString(). Found ' . Aws\describe_type($value)); + return; + } + + $value = isset($value) ? $value : ''; + $this->validateRange($shape, strlen($value), "string length"); + + if ($this->constraints['pattern']) { + $pattern = $shape['pattern']; + if ($pattern && !preg_match("/$pattern/", $value)) { + $this->addError("Pattern /$pattern/ failed to match '$value'"); + } + } + } + + private function validateRange(Shape $shape, $length, $descriptor) + { + if ($this->constraints['min']) { + $min = $shape['min']; + if ($min && $length < $min) { + $this->addError("expected $descriptor to be >= $min, but " + . "found $descriptor of $length"); + } + } + + if ($this->constraints['max']) { + $max = $shape['max']; + if ($max && $length > $max) { + $this->addError("expected $descriptor to be <= $max, but " + . "found $descriptor of $length"); + } + } + } + + private function checkArray($arr) + { + return $this->isIndexed($arr) || $this->isAssociative($arr); + } + + private function isAssociative($arr) + { + return count(array_filter(array_keys($arr), "is_string")) == count($arr); + } + + private function isIndexed(array $arr) + { + return $arr == array_values($arr); + } + + private function checkCanString($value) + { + static $valid = [ + 'string' => true, + 'integer' => true, + 'double' => true, + 'NULL' => true, + ]; + + $type = gettype($value); + + return isset($valid[$type]) || + ($type == 'object' && method_exists($value, '__toString')); + } + + private function checkAssociativeArray($value) + { + $isAssociative = false; + + if (is_array($value)) { + $expectedIndex = 0; + $key = key($value); + + do { + $isAssociative = $key !== $expectedIndex++; + next($value); + $key = key($value); + } while (!$isAssociative && null !== $key); + } + + if (!$isAssociative) { + $this->addError('must be an associative array. Found ' + . Aws\describe_type($value)); + return false; + } + + return true; + } + + private function checkDocumentType($value) + { + if (is_array($value)) { + $typeOfFirstKey = gettype(key($value)); + foreach ($value as $key => $val) { + if (!$this->checkDocumentType($val) || gettype($key) != $typeOfFirstKey) { + return false; + } + } + return $this->checkArray($value); + } + return is_null($value) + || is_numeric($value) + || is_string($value) + || is_bool($value); + } + + private function checkUnion($value) + { + if (is_array($value)) { + $nonNullCount = 0; + foreach ($value as $key => $val) { + if (!is_null($val) && !(strpos($key, "@") === 0)) { + $nonNullCount++; + } + } + return $nonNullCount == 1; + } + return !is_null($value); + } + + private function addError($message) + { + $this->errors[] = + implode('', array_map(function ($s) { return "[{$s}]"; }, $this->path)) + . ' ' + . $message; + } + + private function canJsonEncode($data) + { + return !is_resource($data); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArn.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArn.php new file mode 100644 index 000000000..e7b88eed5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArn.php @@ -0,0 +1,66 @@ +data); + } + + public static function parse($string) + { + $data = parent::parse($string); + $data = self::parseResourceTypeAndId($data); + $data['accesspoint_name'] = $data['resource_id']; + return $data; + } + + public function getAccesspointName() + { + return $this->data['accesspoint_name']; + } + + /** + * Validation specific to AccessPointArn + * + * @param array $data + */ + protected static function validate(array $data) + { + self::validateRegion($data, 'access point ARN'); + self::validateAccountId($data, 'access point ARN'); + + if ($data['resource_type'] !== 'accesspoint') { + throw new InvalidArnException("The 6th component of an access point ARN" + . " represents the resource type and must be 'accesspoint'."); + } + + if (empty($data['resource_id'])) { + throw new InvalidArnException("The 7th component of an access point ARN" + . " represents the resource ID and must not be empty."); + } + if (strpos($data['resource_id'], ':') !== false) { + throw new InvalidArnException("The resource ID component of an access" + . " point ARN must not contain additional components" + . " (delimited by ':')."); + } + if (!self::isValidHostLabel($data['resource_id'])) { + throw new InvalidArnException("The resource ID in an access point ARN" + . " must be a valid host label value."); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArnInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArnInterface.php new file mode 100644 index 000000000..9eb5f2bf9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/AccessPointArnInterface.php @@ -0,0 +1,10 @@ + null, + 'partition' => null, + 'service' => null, + 'region' => null, + 'account_id' => null, + 'resource' => null, + ]; + + $length = strlen($string); + $lastDelim = 0; + $numComponents = 0; + for ($i = 0; $i < $length; $i++) { + + if (($numComponents < 5 && $string[$i] === ':')) { + // Split components between delimiters + $data[key($data)] = substr($string, $lastDelim, $i - $lastDelim); + + // Do not include delimiter character itself + $lastDelim = $i + 1; + next($data); + $numComponents++; + } + + if ($i === $length - 1) { + // Put the remainder in the last component. + if (in_array($numComponents, [5])) { + $data['resource'] = substr($string, $lastDelim); + } else { + // If there are < 5 components, put remainder in current + // component. + $data[key($data)] = substr($string, $lastDelim); + } + } + } + + return $data; + } + + public function __construct($data) + { + if (is_array($data)) { + $this->data = $data; + } elseif (is_string($data)) { + $this->data = static::parse($data); + } else { + throw new InvalidArnException('Constructor accepts a string or an' + . ' array as an argument.'); + } + + static::validate($this->data); + } + + public function __toString() + { + if (!isset($this->string)) { + $components = [ + $this->getPrefix(), + $this->getPartition(), + $this->getService(), + $this->getRegion(), + $this->getAccountId(), + $this->getResource(), + ]; + + $this->string = implode(':', $components); + } + return $this->string; + } + + public function getPrefix() + { + return $this->data['arn']; + } + + public function getPartition() + { + return $this->data['partition']; + } + + public function getService() + { + return $this->data['service']; + } + + public function getRegion() + { + return $this->data['region']; + } + + public function getAccountId() + { + return $this->data['account_id']; + } + + public function getResource() + { + return $this->data['resource']; + } + + public function toArray() + { + return $this->data; + } + + /** + * Minimally restrictive generic ARN validation + * + * @param array $data + */ + protected static function validate(array $data) + { + if ($data['arn'] !== 'arn') { + throw new InvalidArnException("The 1st component of an ARN must be" + . " 'arn'."); + } + + if (empty($data['partition'])) { + throw new InvalidArnException("The 2nd component of an ARN" + . " represents the partition and must not be empty."); + } + + if (empty($data['service'])) { + throw new InvalidArnException("The 3rd component of an ARN" + . " represents the service and must not be empty."); + } + + if (empty($data['resource'])) { + throw new InvalidArnException("The 6th component of an ARN" + . " represents the resource information and must not be empty." + . " Individual service ARNs may include additional delimiters" + . " to further qualify resources."); + } + } + + protected static function validateAccountId($data, $arnName) + { + if (!self::isValidHostLabel($data['account_id'])) { + throw new InvalidArnException("The 5th component of a {$arnName}" + . " is required, represents the account ID, and" + . " must be a valid host label."); + } + } + + protected static function validateRegion($data, $arnName) + { + if (empty($data['region'])) { + throw new InvalidArnException("The 4th component of a {$arnName}" + . " represents the region and must not be empty."); + } + } + + /** + * Validates whether a string component is a valid host label + * + * @param $string + * @return bool + */ + protected static function isValidHostLabel($string) + { + if (empty($string) || strlen($string) > 63) { + return false; + } + if ($value = preg_match("/^[a-zA-Z0-9-]+$/", $string)) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/ArnInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/ArnInterface.php new file mode 100644 index 000000000..c30c6ccd9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/ArnInterface.php @@ -0,0 +1,37 @@ +data['resource_type']; + } + + public function getResourceId() + { + return $this->data['resource_id']; + } + + protected static function parseResourceTypeAndId(array $data) + { + $resourceData = preg_split("/[\/:]/", $data['resource'], 2); + $data['resource_type'] = isset($resourceData[0]) + ? $resourceData[0] + : null; + $data['resource_id'] = isset($resourceData[1]) + ? $resourceData[1] + : null; + return $data; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/AccessPointArn.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/AccessPointArn.php new file mode 100644 index 000000000..5841d904d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/AccessPointArn.php @@ -0,0 +1,27 @@ +data['outpost_id']; + } + + public function getAccesspointName() + { + return $this->data['accesspoint_name']; + } + + private static function parseOutpostData(array $data) + { + $resourceData = preg_split("/[\/:]/", $data['resource_id']); + + $data['outpost_id'] = isset($resourceData[0]) + ? $resourceData[0] + : null; + $data['accesspoint_type'] = isset($resourceData[1]) + ? $resourceData[1] + : null; + $data['accesspoint_name'] = isset($resourceData[2]) + ? $resourceData[2] + : null; + if (isset($resourceData[3])) { + $data['resource_extra'] = implode(':', array_slice($resourceData, 3)); + } + + return $data; + } + + /** + * Validation specific to OutpostsAccessPointArn. Note this uses the base Arn + * class validation instead of the direct parent due to it having slightly + * differing requirements from its parent. + * + * @param array $data + */ + public static function validate(array $data) + { + Arn::validate($data); + + if (($data['service'] !== 's3-outposts')) { + throw new InvalidArnException("The 3rd component of an S3 Outposts" + . " access point ARN represents the service and must be" + . " 's3-outposts'."); + } + + self::validateRegion($data, 'S3 Outposts access point ARN'); + self::validateAccountId($data, 'S3 Outposts access point ARN'); + + if (($data['resource_type'] !== 'outpost')) { + throw new InvalidArnException("The 6th component of an S3 Outposts" + . " access point ARN represents the resource type and must be" + . " 'outpost'."); + } + + if (!self::isValidHostLabel($data['outpost_id'])) { + throw new InvalidArnException("The 7th component of an S3 Outposts" + . " access point ARN is required, represents the outpost ID, and" + . " must be a valid host label."); + } + + if ($data['accesspoint_type'] !== 'accesspoint') { + throw new InvalidArnException("The 8th component of an S3 Outposts" + . " access point ARN must be 'accesspoint'"); + } + + if (!self::isValidHostLabel($data['accesspoint_name'])) { + throw new InvalidArnException("The 9th component of an S3 Outposts" + . " access point ARN is required, represents the accesspoint name," + . " and must be a valid host label."); + } + + if (!empty($data['resource_extra'])) { + throw new InvalidArnException("An S3 Outposts access point ARN" + . " should only have 9 components, delimited by the characters" + . " ':' and '/'. '{$data['resource_extra']}' was found after the" + . " 9th component."); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/OutpostsArnInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/OutpostsArnInterface.php new file mode 100644 index 000000000..20285e0ca --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Arn/S3/OutpostsArnInterface.php @@ -0,0 +1,12 @@ +data['bucket_name']; + } + + public function getOutpostId() + { + return $this->data['outpost_id']; + } + + private static function parseOutpostData(array $data) + { + $resourceData = preg_split("/[\/:]/", $data['resource_id'], 3); + + $data['outpost_id'] = isset($resourceData[0]) + ? $resourceData[0] + : null; + $data['bucket_label'] = isset($resourceData[1]) + ? $resourceData[1] + : null; + $data['bucket_name'] = isset($resourceData[2]) + ? $resourceData[2] + : null; + + return $data; + } + + /** + * + * @param array $data + */ + public static function validate(array $data) + { + Arn::validate($data); + + if (($data['service'] !== 's3-outposts')) { + throw new InvalidArnException("The 3rd component of an S3 Outposts" + . " bucket ARN represents the service and must be 's3-outposts'."); + } + + self::validateRegion($data, 'S3 Outposts bucket ARN'); + self::validateAccountId($data, 'S3 Outposts bucket ARN'); + + if (($data['resource_type'] !== 'outpost')) { + throw new InvalidArnException("The 6th component of an S3 Outposts" + . " bucket ARN represents the resource type and must be" + . " 'outpost'."); + } + + if (!self::isValidHostLabel($data['outpost_id'])) { + throw new InvalidArnException("The 7th component of an S3 Outposts" + . " bucket ARN is required, represents the outpost ID, and" + . " must be a valid host label."); + } + + if ($data['bucket_label'] !== 'bucket') { + throw new InvalidArnException("The 8th component of an S3 Outposts" + . " bucket ARN must be 'bucket'"); + } + + if (empty($data['bucket_name'])) { + throw new InvalidArnException("The 9th component of an S3 Outposts" + . " bucket ARN represents the bucket name and must not be empty."); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolver.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolver.php new file mode 100644 index 000000000..ea7847ac4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolver.php @@ -0,0 +1,181 @@ + 'v4', + 'aws.auth#sigv4a' => 'v4a', + 'smithy.api#httpBearerAuth' => 'bearer', + 'smithy.api#noAuth' => 'anonymous' + ]; + + /** + * @var array Mapping of auth schemes to signature versions used in + * resolving a signature version. + */ + private $authSchemeMap; + private $tokenProvider; + private $credentialProvider; + + + public function __construct( + callable $credentialProvider, + ?callable $tokenProvider = null, + array $authSchemeMap = [] + ){ + $this->credentialProvider = $credentialProvider; + $this->tokenProvider = $tokenProvider; + $this->authSchemeMap = empty($authSchemeMap) + ? self::$defaultAuthSchemeMap + : $authSchemeMap; + } + + /** + * Accepts a priority-ordered list of auth schemes and an Identity + * and selects the first compatible auth schemes, returning a normalized + * signature version. For example, based on the default auth scheme mapping, + * if `aws.auth#sigv4` is selected, `v4` will be returned. + * + * @param array $authSchemes + * @param $identity + * + * @return string + * @throws UnresolvedAuthSchemeException + */ + public function selectAuthScheme( + array $authSchemes, + array $args = [] + ): string + { + $failureReasons = []; + + foreach($authSchemes as $authScheme) { + $normalizedAuthScheme = $this->authSchemeMap[$authScheme] ?? $authScheme; + + if ($this->isCompatibleAuthScheme($normalizedAuthScheme)) { + if ($normalizedAuthScheme === 'v4' && !empty($args['unsigned_payload'])) { + return $normalizedAuthScheme . self::UNSIGNED_BODY; + } + + return $normalizedAuthScheme; + } else { + $failureReasons[] = $this->getIncompatibilityMessage($normalizedAuthScheme); + } + } + + throw new UnresolvedAuthSchemeException( + 'Could not resolve an authentication scheme: ' + . implode('; ', $failureReasons) + ); + } + + /** + * Determines compatibility based on either Identity or the availability + * of the CRT extension. + * + * @param $authScheme + * + * @return bool + */ + private function isCompatibleAuthScheme($authScheme): bool + { + switch ($authScheme) { + case 'v4': + case 'anonymous': + return $this->hasAwsCredentialIdentity(); + case 'v4a': + return extension_loaded('awscrt') && $this->hasAwsCredentialIdentity(); + case 'bearer': + return $this->hasBearerTokenIdentity(); + default: + return false; + } + } + + /** + * Provides incompatibility messages in the event an incompatible auth scheme + * is encountered. + * + * @param $authScheme + * + * @return string + */ + private function getIncompatibilityMessage($authScheme): string + { + switch ($authScheme) { + case 'v4': + return 'Signature V4 requires AWS credentials for request signing'; + case 'anonymous': + return 'Anonymous signatures require AWS credentials for request signing'; + case 'v4a': + return 'The aws-crt-php extension and AWS credentials are required to use Signature V4A'; + case 'bearer': + return 'Bearer token credentials must be provided to use Bearer authentication'; + default: + return "The service does not support `{$authScheme}` authentication."; + } + } + + /** + * @return bool + */ + private function hasAwsCredentialIdentity(): bool + { + $fn = $this->credentialProvider; + $result = $fn(); + + if ($result instanceof PromiseInterface) { + try { + $resolved = $result->wait(); + return $resolved instanceof AwsCredentialIdentity; + } catch (CredentialsException $e) { + return false; + } + } + + return $result instanceof AwsCredentialIdentity; + } + + /** + * @return bool + */ + private function hasBearerTokenIdentity(): bool + { + if ($this->tokenProvider) { + $fn = $this->tokenProvider; + $result = $fn(); + + if ($result instanceof PromiseInterface) { + try { + $resolved = $result->wait(); + return $resolved instanceof BearerTokenIdentity; + } catch (TokenException $e) { + return false; + } + } + + return $result instanceof BearerTokenIdentity; + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolverInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolverInterface.php new file mode 100644 index 000000000..22f1311e8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/AuthSchemeResolverInterface.php @@ -0,0 +1,24 @@ +nextHandler = $nextHandler; + $this->authResolver = $authResolver; + $this->api = $api; + $this->configuredAuthSchemes = $configuredAuthSchemes; + } + + /** + * @param CommandInterface $command + * + * @return Promise + */ + public function __invoke(CommandInterface $command) + { + $nextHandler = $this->nextHandler; + $serviceAuth = $this->api->getMetadata('auth') ?: []; + $operation = $this->api->getOperation($command->getName()); + $operationAuth = $operation['auth'] ?? []; + $unsignedPayload = $operation['unsignedpayload'] ?? false; + $resolvableAuth = $operationAuth ?: $serviceAuth; + + if (!empty($resolvableAuth)) { + if (isset($command['@context']['auth_scheme_resolver']) + && $command['@context']['auth_scheme_resolver'] instanceof AuthSchemeResolverInterface + ){ + $resolver = $command['@context']['auth_scheme_resolver']; + } else { + $resolver = $this->authResolver; + } + + try { + $authSchemeList = $this->buildAuthSchemeList( + $resolvableAuth, + $command['@context']['auth_scheme_preference'] + ?? null, + ); + $selectedAuthScheme = $resolver->selectAuthScheme( + $authSchemeList, + ['unsigned_payload' => $unsignedPayload] + ); + + if (!empty($selectedAuthScheme)) { + $command['@context']['signature_version'] = $selectedAuthScheme; + } + } catch (UnresolvedAuthSchemeException $ignored) { + // There was an error resolving auth + // The signature version will fall back to the modeled `signatureVersion` + // or auth schemes resolved during endpoint resolution + } + } + + return $nextHandler($command); + } + + /** + * Prioritizes auth schemes according to user preference order. + * User-preferred schemes that are available will be placed first, + * followed by remaining available schemes. + * + * @param array $resolvableAuthSchemeList Available auth schemes + * @param array|null $commandConfiguredAuthSchemes Command-level preferences (overrides config) + * + * @return array Reordered auth schemes with user preferences first + */ + private function buildAuthSchemeList( + array $resolvableAuthSchemeList, + ?array $commandConfiguredAuthSchemes, + ): array + { + $userConfiguredAuthSchemes = $commandConfiguredAuthSchemes + ?? $this->configuredAuthSchemes; + + if (empty($userConfiguredAuthSchemes)) { + return $resolvableAuthSchemeList; + } + + $prioritizedAuthSchemes = array_intersect( + $userConfiguredAuthSchemes, + $resolvableAuthSchemeList + ); + + // Get remaining schemes not in user preferences + $remainingAuthSchemes = array_diff( + $resolvableAuthSchemeList, + $prioritizedAuthSchemes + ); + + return array_merge($prioritizedAuthSchemes, $remainingAuthSchemes); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/Exception/UnresolvedAuthSchemeException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/Exception/UnresolvedAuthSchemeException.php new file mode 100644 index 000000000..98f33f4d1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Auth/Exception/UnresolvedAuthSchemeException.php @@ -0,0 +1,15 @@ +parseClass(); + if (!isset($args['service'])) { + $args['service'] = manifest($service)['endpoint']; + } + if (!isset($args['exception_class'])) { + $args['exception_class'] = $exceptionClass; + } + $this->handlerList = new HandlerList(); + $resolver = new ClientResolver(static::getArguments()); + $config = $resolver->resolve($args, $this->handlerList); + $this->api = $config['api']; + $this->signatureProvider = $config['signature_provider']; + $this->authSchemeResolver = $config['auth_scheme_resolver']; + $this->endpoint = new Uri($config['endpoint']); + $this->credentialProvider = $config['credentials']; + $this->tokenProvider = $config['token']; + $this->region = $config['region'] ?? null; + $this->signingRegionSet = $config['sigv4a_signing_region_set'] ?? null; + $this->config = $config['config']; + $this->setClientBuiltIns($args, $config); + $this->clientContextParams = $this->setClientContextParams($args); + $this->defaultRequestOptions = $config['http']; + $this->endpointProvider = $config['endpoint_provider']; + $this->serializer = $config['serializer']; + $this->addSignatureMiddleware($args); + $this->addInvocationId(); + $this->addEndpointParameterMiddleware($args); + $this->addEndpointDiscoveryMiddleware($config, $args); + $this->addRequestCompressionMiddleware($config); + $this->loadAliases(); + $this->addStreamRequestPayload(); + $this->addRecursionDetection(); + if ($this->isUseEndpointV2()) { + $this->addEndpointV2Middleware(); + } + $this->addAuthSelectionMiddleware($config); + + if (!is_null($this->api->getMetadata('awsQueryCompatible'))) { + $this->addQueryCompatibleInputMiddleware($this->api); + $this->addQueryModeHeader(); + } + + if (isset($args['with_resolved'])) { + $args['with_resolved']($config); + } + $this->addUserAgentMiddleware($config); + } + + public function getHandlerList() + { + return $this->handlerList; + } + + public function getConfig($option = null) + { + return $option === null + ? $this->config + : $this->config[$option] ?? null; + } + + public function getCredentials() + { + $fn = $this->credentialProvider; + return $fn(); + } + + public function getToken() + { + $fn = $this->tokenProvider; + return $fn(); + } + + + public function getEndpoint() + { + return $this->endpoint; + } + + public function getRegion() + { + return $this->region; + } + + public function getApi() + { + return $this->api; + } + + public function getCommand($name, array $args = []) + { + // Fail fast if the command cannot be found in the description. + if (!isset($this->getApi()['operations'][$name])) { + $name = ucfirst($name); + if (!isset($this->getApi()['operations'][$name])) { + throw new \InvalidArgumentException("Operation not found: $name"); + } + } + + if (!isset($args['@http'])) { + $args['@http'] = $this->defaultRequestOptions; + } else { + $args['@http'] += $this->defaultRequestOptions; + } + + return new Command($name, $args, clone $this->getHandlerList()); + } + + public function getEndpointProvider() + { + return $this->endpointProvider; + } + + /** + * Provides the set of service context parameter + * key-value pairs used for endpoint resolution. + * + * @return array + */ + public function getClientContextParams() + { + return $this->clientContextParams; + } + + /** + * Provides the set of built-in keys and values + * used for endpoint resolution + * + * @return array + */ + public function getClientBuiltIns() + { + return $this->clientBuiltIns; + } + + public function __sleep() + { + throw new \RuntimeException('Instances of ' . static::class + . ' cannot be serialized'); + } + + /** + * Get the signature_provider function of the client. + * + * @return callable + */ + final public function getSignatureProvider() + { + return $this->signatureProvider; + } + + /** + * Parse the class name and setup the custom exception class of the client + * and return the "service" name of the client and "exception_class". + * + * @return array + */ + private function parseClass() + { + $klass = get_class($this); + + if ($klass === __CLASS__) { + return ['', AwsException::class]; + } + + $service = substr($klass, strrpos($klass, '\\') + 1, -6); + + return [ + strtolower($service), + "Aws\\{$service}\\Exception\\{$service}Exception" + ]; + } + + private function addEndpointParameterMiddleware($args) + { + if (empty($args['disable_host_prefix_injection'])) { + $list = $this->getHandlerList(); + $list->appendBuild( + EndpointParameterMiddleware::wrap( + $this->api + ), + 'endpoint_parameter' + ); + } + } + + private function addEndpointDiscoveryMiddleware($config, $args) + { + $list = $this->getHandlerList(); + + if (!isset($args['endpoint'])) { + $list->appendBuild( + EndpointDiscoveryMiddleware::wrap( + $this, + $args, + $config['endpoint_discovery'] + ), + 'EndpointDiscoveryMiddleware' + ); + } + } + + private function addSignatureMiddleware(array $args) + { + $api = $this->getApi(); + $provider = $this->signatureProvider; + $signatureVersion = $this->config['signature_version']; + $name = $this->config['signing_name']; + $region = $this->config['signing_region']; + $signingRegionSet = $this->signingRegionSet; + + if (isset($args['signature_version']) + || isset($this->config['configured_signature_version']) + ) { + $configuredSignatureVersion = true; + } else { + $configuredSignatureVersion = false; + } + + $resolver = static function ( + CommandInterface $command + ) use ( + $api, + $provider, + $name, + $region, + $signatureVersion, + $configuredSignatureVersion, + $signingRegionSet + ) { + if (!$configuredSignatureVersion) { + if (!empty($command['@context']['signing_region'])) { + $region = $command['@context']['signing_region']; + } + if (!empty($command['@context']['signing_service'])) { + $name = $command['@context']['signing_service']; + } + if (!empty($command['@context']['signature_version'])) { + $signatureVersion = $command['@context']['signature_version']; + } + + $authType = $api->getOperation($command->getName())['authtype']; + switch ($authType){ + case 'none': + $signatureVersion = 'anonymous'; + break; + case 'v4-unsigned-body': + $signatureVersion = 'v4-unsigned-body'; + break; + case 'bearer': + $signatureVersion = 'bearer'; + break; + } + } + + if ($signatureVersion === 'v4a') { + $commandSigningRegionSet = !empty($command['@context']['signing_region_set']) + ? implode(', ', $command['@context']['signing_region_set']) + : null; + + $region = $signingRegionSet + ?? $commandSigningRegionSet + ?? $region; + } + + // Capture signature metric + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'signature', + $signatureVersion + ); + + return SignatureProvider::resolve($provider, $signatureVersion, $name, $region); + }; + $this->handlerList->appendSign( + Middleware::signer($this->credentialProvider, + $resolver, + $this->tokenProvider, + $this->getConfig() + ), + 'signer' + ); + } + + private function addRequestCompressionMiddleware($config) + { + if (empty($config['disable_request_compression'])) { + $list = $this->getHandlerList(); + $list->appendBuild( + RequestCompressionMiddleware::wrap($config), + 'request-compression' + ); + } + } + + private function addQueryCompatibleInputMiddleware(Service $api) + { + $list = $this->getHandlerList(); + $list->appendValidate( + QueryCompatibleInputMiddleware::wrap($api), + 'query-compatible-input' + ); + } + + private function addQueryModeHeader(): void + { + $list = $this->getHandlerList(); + $list->appendBuild( + Middleware::mapRequest(function (RequestInterface $r) { + return $r->withHeader( + 'x-amzn-query-mode', + "true" + ); + }), + 'x-amzn-query-mode-header' + ); + } + + private function addInvocationId() + { + // Add invocation id to each request + $this->handlerList->prependSign(Middleware::invocationId(), 'invocation-id'); + } + + private function loadAliases($file = null) + { + if (!isset($this->aliases)) { + if (is_null($file)) { + $file = __DIR__ . '/data/aliases.json'; + } + $aliases = \Aws\load_compiled_json($file); + $serviceId = $this->api->getServiceId(); + $version = $this->getApi()->getApiVersion(); + if (!empty($aliases['operations'][$serviceId][$version])) { + $this->aliases = array_flip($aliases['operations'][$serviceId][$version]); + } + } + } + + private function addStreamRequestPayload() + { + $streamRequestPayloadMiddleware = StreamRequestPayloadMiddleware::wrap( + $this->api + ); + + $this->handlerList->prependSign( + $streamRequestPayloadMiddleware, + 'StreamRequestPayloadMiddleware' + ); + } + + private function addRecursionDetection() + { + // Add recursion detection header to requests + // originating in supported Lambda runtimes + $this->handlerList->appendBuild( + Middleware::recursionDetection(), 'recursion-detection' + ); + } + + private function addAuthSelectionMiddleware(array $args) + { + $list = $this->getHandlerList(); + + $list->prependBuild( + AuthSelectionMiddleware::wrap( + $this->authSchemeResolver, + $this->getApi(), + $args['auth_scheme_preference'] ?? null + ), + 'auth-selection' + ); + } + + private function addEndpointV2Middleware() + { + $list = $this->getHandlerList(); + $endpointArgs = $this->getEndpointProviderArgs(); + + $list->prependBuild( + EndpointV2Middleware::wrap( + $this->endpointProvider, + $this->getApi(), + $endpointArgs, + $this->credentialProvider + ), + 'endpoint-resolution' + ); + } + + /** + * Appends the user agent middleware. + * This middleware MUST be appended after the + * signature middleware `addSignatureMiddleware`, + * so that metrics around signatures are properly + * captured. + * + * @param $args + * @return void + */ + private function addUserAgentMiddleware($args) + { + $this->getHandlerList()->appendSign( + UserAgentMiddleware::wrap($args), + 'user-agent' + ); + } + + /** + * Retrieves client context param definition from service model, + * creates mapping of client context param names with client-provided + * values. + * + * @return array + */ + private function setClientContextParams($args) + { + $api = $this->getApi(); + $resolvedParams = []; + if (!empty($paramDefinitions = $api->getClientContextParams())) { + foreach($paramDefinitions as $paramName => $paramValue) { + if (isset($args[$paramName])) { + $resolvedParams[$paramName] = $args[$paramName]; + } + } + } + return $resolvedParams; + } + + /** + * Retrieves and sets default values used for endpoint resolution. + */ + private function setClientBuiltIns($args, $resolvedConfig) + { + $builtIns = []; + $config = $resolvedConfig['config']; + $service = $args['service']; + + $builtIns['SDK::Endpoint'] = null; + if (!empty($args['endpoint'])) { + $builtIns['SDK::Endpoint'] = $args['endpoint']; + } elseif (isset($config['configured_endpoint_url'])) { + $builtIns['SDK::Endpoint'] = (string) $this->getEndpoint(); + } + $builtIns['AWS::Region'] = $this->getRegion(); + $builtIns['AWS::UseFIPS'] = $config['use_fips_endpoint']->isUseFipsEndpoint(); + $builtIns['AWS::UseDualStack'] = $config['use_dual_stack_endpoint']->isUseDualstackEndpoint(); + if ($service === 's3' || $service === 's3control'){ + $builtIns['AWS::S3::UseArnRegion'] = $config['use_arn_region']->isUseArnRegion(); + } + if ($service === 's3') { + $builtIns['AWS::S3::UseArnRegion'] = $config['use_arn_region']->isUseArnRegion(); + $builtIns['AWS::S3::Accelerate'] = $config['use_accelerate_endpoint']; + $builtIns['AWS::S3::ForcePathStyle'] = $config['use_path_style_endpoint']; + $builtIns['AWS::S3::DisableMultiRegionAccessPoints'] = $config['disable_multiregion_access_points']; + } + $builtIns['AWS::Auth::AccountIdEndpointMode'] = $resolvedConfig['account_id_endpoint_mode']; + + $this->clientBuiltIns += $builtIns; + } + + /** + * Retrieves arguments to be used in endpoint resolution. + * + * @return array + */ + public function getEndpointProviderArgs() + { + return $this->normalizeEndpointProviderArgs(); + } + + /** + * Combines built-in and client context parameter values in + * order of specificity. Client context parameter values supersede + * built-in values. + * + * @return array + */ + private function normalizeEndpointProviderArgs() + { + $normalizedBuiltIns = []; + + foreach($this->clientBuiltIns as $name => $value) { + $normalizedName = explode('::', $name); + $normalizedName = $normalizedName[count($normalizedName) - 1]; + $normalizedBuiltIns[$normalizedName] = $value; + } + + return array_merge($normalizedBuiltIns, $this->getClientContextParams()); + } + + protected function isUseEndpointV2() + { + return $this->endpointProvider instanceof EndpointProviderV2; + } + + public static function emitDeprecationWarning() { + trigger_error( + "This method is deprecated. It will be removed in an upcoming release." + , E_USER_DEPRECATED + ); + + $phpVersion = PHP_VERSION_ID; + if ($phpVersion < 70205) { + $phpVersionString = phpversion(); + @trigger_error( + "This installation of the SDK is using PHP version" + . " {$phpVersionString}, which will be deprecated on August" + . " 15th, 2023. Please upgrade your PHP version to a minimum of" + . " 7.2.5 before then to continue receiving updates to the AWS" + . " SDK for PHP. To disable this warning, set" + . " suppress_php_deprecation_warning to true on the client constructor" + . " or set the environment variable AWS_SUPPRESS_PHP_DEPRECATION_WARNING" + . " to true.", + E_USER_DEPRECATED + ); + } + } + + + /** + * Returns a service model and doc model with any necessary changes + * applied. + * + * @param array $api Array of service data being documented. + * @param array $docs Array of doc model data. + * + * @return array Tuple containing a [Service, DocModel] + * + * @internal This should only used to document the service API. + * @codeCoverageIgnore + */ + public static function applyDocFilters(array $api, array $docs) + { + $aliases = \Aws\load_compiled_json(__DIR__ . '/data/aliases.json'); + $serviceId = $api['metadata']['serviceId'] ?? ''; + $version = $api['metadata']['apiVersion']; + + // Replace names for any operations with SDK aliases + if (!empty($aliases['operations'][$serviceId][$version])) { + foreach ($aliases['operations'][$serviceId][$version] as $op => $alias) { + $api['operations'][$alias] = $api['operations'][$op]; + $docs['operations'][$alias] = $docs['operations'][$op]; + unset($api['operations'][$op], $docs['operations'][$op]); + } + } + ksort($api['operations']); + + return [ + new Service($api, ApiProvider::defaultProvider()), + new DocModel($docs) + ]; + } + + /** + * @deprecated + * @return static + */ + public static function factory(array $config = []) + { + return new static($config); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientInterface.php new file mode 100644 index 000000000..12a570181 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientInterface.php @@ -0,0 +1,169 @@ +getWaiter('foo', ['bar' => 'baz']); + * $waiter->promise()->then(function () { echo 'Done!'; }); + * + * @param string|callable $name Name of the waiter that defines the wait + * configuration and conditions. + * @param array $args Args to be used with each command executed + * by the waiter. Waiter configuration options + * can be provided in an associative array in + * the @waiter key. + * @return \Aws\Waiter + * @throws \UnexpectedValueException if the waiter is invalid. + */ + public function getWaiter($name, array $args = []); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientTrait.php new file mode 100644 index 000000000..f31a24edc --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/AwsClientTrait.php @@ -0,0 +1,101 @@ +getApi()->getPaginatorConfig($name); + + return new ResultPaginator($this, $name, $args, $config); + } + + public function getIterator($name, array $args = []) + { + $config = $this->getApi()->getPaginatorConfig($name); + if (!$config['result_key']) { + throw new \UnexpectedValueException(sprintf( + 'There are no resources to iterate for the %s operation of %s', + $name, $this->getApi()['serviceFullName'] + )); + } + + $key = is_array($config['result_key']) + ? $config['result_key'][0] + : $config['result_key']; + + if ($config['output_token'] && $config['input_token']) { + return $this->getPaginator($name, $args)->search($key); + } + + $result = $this->execute($this->getCommand($name, $args))->search($key); + + return new \ArrayIterator((array) $result); + } + + public function waitUntil($name, array $args = []) + { + return $this->getWaiter($name, $args)->promise()->wait(); + } + + public function getWaiter($name, array $args = []) + { + $config = isset($args['@waiter']) ? $args['@waiter'] : []; + $config += $this->getApi()->getWaiterConfig($name); + + return new Waiter($this, $name, $args, $config); + } + + public function execute(CommandInterface $command) + { + return $this->executeAsync($command)->wait(); + } + + public function executeAsync(CommandInterface $command) + { + $handler = $command->getHandlerList()->resolve(); + return $handler($command); + } + + public function __call($name, array $args) + { + if (substr($name, -5) === 'Async') { + $name = substr($name, 0, -5); + $isAsync = true; + } + + if (!empty($this->aliases[ucfirst($name)])) { + $name = $this->aliases[ucfirst($name)]; + } + + $params = isset($args[0]) ? $args[0] : []; + + if (!empty($isAsync)) { + return $this->executeAsync( + $this->getCommand($name, $params) + ); + } + + return $this->execute($this->getCommand($name, $params)); + } + + /** + * @param string $name + * @param array $args + * + * @return CommandInterface + */ + abstract public function getCommand($name, array $args = []); + + /** + * @return Service + */ + abstract public function getApi(); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CacheInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CacheInterface.php new file mode 100644 index 000000000..e77f18b14 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CacheInterface.php @@ -0,0 +1,34 @@ + 'is_resource', + 'callable' => 'is_callable', + 'int' => 'is_int', + 'bool' => 'is_bool', + 'boolean' => 'is_bool', + 'string' => 'is_string', + 'object' => 'is_object', + 'array' => 'is_array', + ]; + + private static $defaultArgs = [ + 'service' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Name of the service to utilize. This value will be supplied by default when using one of the SDK clients (e.g., Aws\\S3\\S3Client).', + 'required' => true, + 'internal' => true + ], + 'exception_class' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Exception class to create when an error occurs.', + 'default' => AwsException::class, + 'internal' => true + ], + 'scheme' => [ + 'type' => 'value', + 'valid' => ['string'], + 'default' => 'https', + 'doc' => 'URI scheme to use when connecting connect. The SDK will utilize "https" endpoints (i.e., utilize SSL/TLS connections) by default. You can attempt to connect to a service over an unencrypted "http" endpoint by setting ``scheme`` to "http".', + ], + 'disable_host_prefix_injection' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to true to disable host prefix injection logic for services that use it. This disables the entire prefix injection, including the portions supplied by user-defined parameters. Setting this flag will have no effect on services that do not use host prefix injection.', + 'default' => false, + ], + 'ignore_configured_endpoint_urls' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to true to disable endpoint urls configured using `AWS_ENDPOINT_URL` and `endpoint_url` shared config option.', + 'fn' => [__CLASS__, '_apply_ignore_configured_endpoint_urls'], + 'default' => self::DEFAULT_FROM_ENV_INI, + ], + 'endpoint' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).', + 'fn' => [__CLASS__, '_apply_endpoint'], + 'default' => [__CLASS__, '_default_endpoint'] + ], + 'region' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Region to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html for a list of available regions.', + 'fn' => [__CLASS__, '_apply_region'], + 'default' => self::DEFAULT_FROM_ENV_INI + ], + 'version' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'The version of the webservice to utilize (e.g., 2006-03-01).', + 'default' => 'latest', + ], + 'signature_provider' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'A callable that accepts a signature version name (e.g., "v4"), a service name, and region, and returns a SignatureInterface object or null. This provider is used to create signers utilized by the client. See Aws\\Signature\\SignatureProvider for a list of built-in providers', + 'default' => [__CLASS__, '_default_signature_provider'], + ], + 'api_provider' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'An optional PHP callable that accepts a type, service, and version argument, and returns an array of corresponding configuration data. The type value can be one of api, waiter, or paginator.', + 'fn' => [__CLASS__, '_apply_api_provider'], + 'default' => [ApiProvider::class, 'defaultProvider'], + ], + 'configuration_mode' => [ + 'type' => 'value', + 'valid' => [ConfigModeInterface::class, CacheInterface::class, 'string', 'closure'], + 'doc' => "Sets the default configuration mode. Otherwise provide an instance of Aws\DefaultsMode\ConfigurationInterface, an instance of Aws\CacheInterface, or a string containing a valid mode", + 'fn' => [__CLASS__, '_apply_defaults'], + 'default' => [ConfigModeProvider::class, 'defaultProvider'] + ], + 'use_fips_endpoint' => [ + 'type' => 'value', + 'valid' => ['bool', UseFipsEndpointConfiguration::class, CacheInterface::class, 'callable'], + 'doc' => 'Set to true to enable the use of FIPS pseudo regions', + 'fn' => [__CLASS__, '_apply_use_fips_endpoint'], + 'default' => [__CLASS__, '_default_use_fips_endpoint'], + ], + 'use_dual_stack_endpoint' => [ + 'type' => 'value', + 'valid' => ['bool', UseDualStackEndpointConfiguration::class, CacheInterface::class, 'callable'], + 'doc' => 'Set to true to enable the use of dual-stack endpoints', + 'fn' => [__CLASS__, '_apply_use_dual_stack_endpoint'], + 'default' => [__CLASS__, '_default_use_dual_stack_endpoint'], + ], + 'endpoint_provider' => [ + 'type' => 'value', + 'valid' => ['callable', EndpointV2\EndpointProviderV2::class], + 'fn' => [__CLASS__, '_apply_endpoint_provider'], + 'doc' => 'An optional PHP callable that accepts a hash of options including a "service" and "region" key and returns NULL or a hash of endpoint data, of which the "endpoint" key is required. See Aws\\Endpoint\\EndpointProvider for a list of built-in providers.', + 'default' => [__CLASS__, '_default_endpoint_provider'], + ], + 'serializer' => [ + 'default' => [__CLASS__, '_default_serializer'], + 'fn' => [__CLASS__, '_apply_serializer'], + 'internal' => true, + 'type' => 'value', + 'valid' => ['callable'], + ], + 'signature_version' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom signature version to use with a service (e.g., v4). Note that per/operation signature version MAY override this requested signature version.', + 'default' => [__CLASS__, '_default_signature_version'], + ], + 'signing_name' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom service name to be used when calculating a request signature.', + 'default' => [__CLASS__, '_default_signing_name'], + ], + 'signing_region' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'A string representing a custom region name to be used when calculating a request signature.', + 'default' => [__CLASS__, '_default_signing_region'], + ], + 'profile' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'Allows you to specify which profile to use when credentials are created from the AWS credentials file in your HOME directory. This setting overrides the AWS_PROFILE environment variable. Note: Specifying "profile" will cause the "credentials" and "use_aws_shared_config_files" keys to be ignored.', + 'fn' => [__CLASS__, '_apply_profile'], + ], + 'credentials' => [ + 'type' => 'value', + 'valid' => [CredentialsInterface::class, CacheInterface::class, 'array', 'bool', 'callable'], + 'doc' => 'Specifies the credentials used to sign requests. Provide an Aws\Credentials\CredentialsInterface object, an associative array of "key", "secret", and an optional "token" key, `false` to use null credentials, or a callable credentials provider used to create credentials or return null. See Aws\\Credentials\\CredentialProvider for a list of built-in credentials providers. If no credentials are provided, the SDK will attempt to load them from the environment.', + 'fn' => [__CLASS__, '_apply_credentials'], + 'default' => [__CLASS__, '_default_credential_provider'], + ], + 'auth_scheme_preference' => [ + 'type' => 'value', + 'valid' => ['string', 'array'], + 'doc' => 'Comma-separated list of authentication scheme preferences in priority order. Configure via environment variable `AWS_AUTH_SCHEME_PREFERENCE`, INI config file `auth_scheme_preference`, or client constructor parameter `auth_scheme_preference` (string or array).\nExample: `AWS_AUTH_SCHEME_PREFERENCE=aws.auth#sigv4a,aws.auth#sigv4,smithy.api#httpBearerAuth`', + 'default' => self::DEFAULT_FROM_ENV_INI, + 'fn' => [__CLASS__, '_apply_auth_scheme_preference'], + ], + 'token' => [ + 'type' => 'value', + 'valid' => [TokenInterface::class, CacheInterface::class, 'array', 'bool', 'callable'], + 'doc' => 'Specifies the token used to authorize requests. Provide an Aws\Token\TokenInterface object, an associative array of "token", and an optional "expiration" key, `false` to use a null token, or a callable token provider used to fetch a token or return null. See Aws\\Token\\TokenProvider for a list of built-in credentials providers. If no token is provided, the SDK will attempt to load one from the environment.', + 'fn' => [__CLASS__, '_apply_token'], + 'default' => [__CLASS__, '_default_token_provider'], + ], + 'auth_scheme_resolver' => [ + 'type' => 'value', + 'valid' => [AuthSchemeResolverInterface::class], + 'doc' => 'An instance of Aws\Auth\AuthSchemeResolverInterface which selects a modeled auth scheme and returns a signature version', + 'default' => [__CLASS__, '_default_auth_scheme_resolver'], + ], + 'endpoint_discovery' => [ + 'type' => 'value', + 'valid' => [ConfigurationInterface::class, CacheInterface::class, 'array', 'callable'], + 'doc' => 'Specifies settings for endpoint discovery. Provide an instance of Aws\EndpointDiscovery\ConfigurationInterface, an instance Aws\CacheInterface, a callable that provides a promise for a Configuration object, or an associative array with the following keys: enabled: (bool) Set to true to enable endpoint discovery, false to explicitly disable it. Defaults to false; cache_limit: (int) The maximum number of keys in the endpoints cache. Defaults to 1000.', + 'fn' => [__CLASS__, '_apply_endpoint_discovery'], + 'default' => [__CLASS__, '_default_endpoint_discovery_provider'] + ], + 'stats' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'default' => false, + 'doc' => 'Set to true to gather transfer statistics on requests sent. Alternatively, you can provide an associative array with the following keys: retries: (bool) Set to false to disable reporting on retries attempted; http: (bool) Set to true to enable collecting statistics from lower level HTTP adapters (e.g., values returned in GuzzleHttp\TransferStats). HTTP handlers must support an http_stats_receiver option for this to have an effect; timer: (bool) Set to true to enable a command timer that reports the total wall clock time spent on an operation in seconds.', + 'fn' => [__CLASS__, '_apply_stats'], + ], + 'retries' => [ + 'type' => 'value', + 'valid' => ['int', RetryConfigInterface::class, CacheInterface::class, 'callable', 'array'], + 'doc' => "Configures the retry mode and maximum number of allowed retries for a client (pass 0 to disable retries). Provide an integer for 'legacy' mode with the specified number of retries. Otherwise provide an instance of Aws\Retry\ConfigurationInterface, an instance of Aws\CacheInterface, a callable function, or an array with the following keys: mode: (string) Set to 'legacy', 'standard' (uses retry quota management), or 'adapative' (an experimental mode that adds client-side rate limiting to standard mode); max_attempts: (int) The maximum number of attempts for a given request. ", + 'fn' => [__CLASS__, '_apply_retries'], + 'default' => [RetryConfigProvider::class, 'defaultProvider'] + ], + 'validate' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'default' => true, + 'doc' => 'Set to false to disable client-side parameter validation. Set to true to utilize default validation constraints. Set to an associative array of validation options to enable specific validation constraints.', + 'fn' => [__CLASS__, '_apply_validate'], + ], + 'debug' => [ + 'type' => 'value', + 'valid' => ['bool', 'array'], + 'doc' => 'Set to true to display debug information when sending requests. Alternatively, you can provide an associative array with the following keys: logfn: (callable) Function that is invoked with log messages; stream_size: (int) When the size of a stream is greater than this number, the stream data will not be logged (set to "0" to not log any stream data); scrub_auth: (bool) Set to false to disable the scrubbing of auth data from the logged messages; http: (bool) Set to false to disable the "debug" feature of lower level HTTP adapters (e.g., verbose curl output).', + 'fn' => [__CLASS__, '_apply_debug'], + ], + 'disable_request_compression' => [ + 'type' => 'value', + 'valid' => ['bool', 'callable'], + 'doc' => 'Set to true to disable request compression for supported operations', + 'fn' => [__CLASS__, '_apply_disable_request_compression'], + 'default' => self::DEFAULT_FROM_ENV_INI, + ], + 'request_min_compression_size_bytes' => [ + 'type' => 'value', + 'valid' => ['int', 'callable'], + 'doc' => 'Set to a value between between 0 and 10485760 bytes, inclusive. This value will be ignored if `disable_request_compression` is set to `true`', + 'fn' => [__CLASS__, '_apply_min_compression_size'], + 'default' => [__CLASS__, '_default_min_compression_size'], + ], + 'csm' => [ + 'type' => 'value', + 'valid' => [\Aws\ClientSideMonitoring\ConfigurationInterface::class, 'callable', 'array', 'bool'], + 'doc' => 'CSM options for the client. Provides a callable wrapping a promise, a boolean "false", an instance of ConfigurationInterface, or an associative array of "enabled", "host", "port", and "client_id".', + 'fn' => [__CLASS__, '_apply_csm'], + 'default' => [\Aws\ClientSideMonitoring\ConfigurationProvider::class, 'defaultProvider'] + ], + 'http' => [ + 'type' => 'value', + 'valid' => ['array'], + 'default' => [], + 'doc' => 'Set to an array of SDK request options to apply to each request (e.g., proxy, verify, etc.).', + ], + 'http_handler' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'An HTTP handler is a function that accepts a PSR-7 request object and returns a promise that is fulfilled with a PSR-7 response object or rejected with an array of exception data. NOTE: This option supersedes any provided "handler" option.', + 'fn' => [__CLASS__, '_apply_http_handler'] + ], + 'handler' => [ + 'type' => 'value', + 'valid' => ['callable'], + 'doc' => 'A handler that accepts a command object, request object and returns a promise that is fulfilled with an Aws\ResultInterface object or rejected with an Aws\Exception\AwsException. A handler does not accept a next handler as it is terminal and expected to fulfill a command. If no handler is provided, a default Guzzle handler will be utilized.', + 'fn' => [__CLASS__, '_apply_handler'], + 'default' => [__CLASS__, '_default_handler'] + ], + 'app_id' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'app_id(AppId) is an optional application specific identifier that can be set. + When set it will be appended to the User-Agent header of every request in the form of App/{AppId}. + This value is also sourced from environment variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.', + 'fn' => [__CLASS__, '_apply_app_id'], + 'default' => [__CLASS__, '_default_app_id'] + ], + 'ua_append' => [ + 'type' => 'value', + 'valid' => ['string', 'array'], + 'doc' => 'Provide a string or array of strings to send in the User-Agent header.', + 'fn' => [__CLASS__, '_apply_user_agent'], + 'default' => [], + ], + 'idempotency_auto_fill' => [ + 'type' => 'value', + 'valid' => ['bool', 'callable'], + 'doc' => 'Set to false to disable SDK to populate parameters that enabled \'idempotencyToken\' trait with a random UUID v4 value on your behalf. Using default value \'true\' still allows parameter value to be overwritten when provided. Note: auto-fill only works when cryptographically secure random bytes generator functions(random_bytes, openssl_random_pseudo_bytes or mcrypt_create_iv) can be found. You may also provide a callable source of random bytes.', + 'default' => true, + 'fn' => [__CLASS__, '_apply_idempotency_auto_fill'] + ], + 'use_aws_shared_config_files' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to false to disable checking for shared aws config files usually located in \'~/.aws/config\' and \'~/.aws/credentials\'. This will be ignored if you set the \'profile\' setting.', + 'default' => true, + ], + 'suppress_php_deprecation_warning' => [ + 'type' => 'value', + 'valid' => ['bool'], + 'doc' => 'Set to true to suppress PHP runtime deprecation warnings. The current deprecation campaign is PHP versions 8.0.x and below, taking effect on 1/13/2025.', + 'default' => false, + 'fn' => [__CLASS__, '_apply_suppress_php_deprecation_warning'] + ], + 'account_id_endpoint_mode' => [ + 'type' => 'value', + 'valid' => ['string'], + 'doc' => 'Decides whether account_id must a be a required resolved credentials property. If this configuration is set to disabled, then account_id is not required. If set to preferred a warning will be logged when account_id is not resolved, and when set to required an exception will be thrown if account_id is not resolved.', + 'default' => [__CLASS__, '_default_account_id_endpoint_mode'], + 'fn' => [__CLASS__, '_apply_account_id_endpoint_mode'] + ], + 'sigv4a_signing_region_set' => [ + 'type' => 'value', + 'valid' => ['string', 'array'], + 'doc' => 'A comma-delimited list of supported regions sent in sigv4a requests.', + 'fn' => [__CLASS__, '_apply_sigv4a_signing_region_set'], + 'default' => self::DEFAULT_FROM_ENV_INI + ] + ]; + + /** + * Gets an array of default client arguments, each argument containing a + * hash of the following: + * + * - type: (string, required) option type described as follows: + * - value: The default option type. + * - config: The provided value is made available in the client's + * getConfig() method. + * - valid: (array, required) Valid PHP types or class names. Note: null + * is not an allowed type. + * - required: (bool, callable) Whether or not the argument is required. + * Provide a function that accepts an array of arguments and returns a + * string to provide a custom error message. + * - default: (mixed) The default value of the argument if not provided. If + * a function is provided, then it will be invoked to provide a default + * value. The function is provided the array of options and is expected + * to return the default value of the option. The default value can be a + * closure and can not be a callable string that is not part of the + * defaultArgs array. + * - doc: (string) The argument documentation string. + * - fn: (callable) Function used to apply the argument. The function + * accepts the provided value, array of arguments by reference, and an + * event emitter. + * + * Note: Order is honored and important when applying arguments. + * + * @return array + */ + public static function getDefaultArguments() + { + return self::$defaultArgs; + } + + /** + * @param array $argDefinitions Client arguments. + */ + public function __construct(array $argDefinitions) + { + $this->argDefinitions = $argDefinitions; + } + + /** + * Resolves client configuration options and attached event listeners. + * Check for missing keys in passed arguments + * + * @param array $args Provided constructor arguments. + * @param HandlerList $list Handler list to augment. + * + * @return array Returns the array of provided options. + * @throws \InvalidArgumentException + * @see Aws\AwsClient::__construct for a list of available options. + */ + public function resolve(array $args, HandlerList $list) + { + $args['config'] = []; + foreach ($this->argDefinitions as $key => $a) { + // Add defaults, validate required values, and skip if not set. + if (!isset($args[$key])) { + if (isset($a['default'])) { + // Merge defaults in when not present. + if (is_callable($a['default']) + && ( + is_array($a['default']) + || $a['default'] instanceof \Closure + ) + ) { + if ($a['default'] === self::DEFAULT_FROM_ENV_INI) { + $args[$key] = $a['default']( + $key, + $a['valid'][0] ?? 'string', + $args + ); + } else { + $args[$key] = $a['default']($args); + } + } else { + $args[$key] = $a['default']; + } + } elseif (empty($a['required'])) { + continue; + } else { + $this->throwRequired($args); + } + } + + // Validate the types against the provided value. + foreach ($a['valid'] as $check) { + if (isset(self::$typeMap[$check])) { + $fn = self::$typeMap[$check]; + if ($fn($args[$key])) { + goto is_valid; + } + } elseif ($args[$key] instanceof $check) { + goto is_valid; + } + } + + $this->invalidType($key, $args[$key]); + + // Apply the value + is_valid: + if (isset($a['fn'])) { + $a['fn']($args[$key], $args, $list); + } + + if ($a['type'] === 'config') { + $args['config'][$key] = $args[$key]; + } + } + $this->_apply_client_context_params($args); + + return $args; + } + + /** + * Creates a verbose error message for an invalid argument. + * + * @param string $name Name of the argument that is missing. + * @param array $args Provided arguments + * @param bool $useRequired Set to true to show the required fn text if + * available instead of the documentation. + * @return string + */ + private function getArgMessage($name, $args = [], $useRequired = false) + { + $arg = $this->argDefinitions[$name]; + $msg = ''; + $modifiers = []; + if (isset($arg['valid'])) { + $modifiers[] = implode('|', $arg['valid']); + } + if (isset($arg['choice'])) { + $modifiers[] = 'One of ' . implode(', ', $arg['choice']); + } + if ($modifiers) { + $msg .= '(' . implode('; ', $modifiers) . ')'; + } + $msg = wordwrap("{$name}: {$msg}", 75, "\n "); + + if ($useRequired && is_callable($arg['required'])) { + $msg .= "\n\n "; + $msg .= str_replace("\n", "\n ", call_user_func($arg['required'], $args)); + } elseif (isset($arg['doc'])) { + $msg .= wordwrap("\n\n {$arg['doc']}", 75, "\n "); + } + + return $msg; + } + + /** + * Throw when an invalid type is encountered. + * + * @param string $name Name of the value being validated. + * @param mixed $provided The provided value. + * @throws \InvalidArgumentException + */ + private function invalidType($name, $provided) + { + $expected = implode('|', $this->argDefinitions[$name]['valid']); + $msg = "Invalid configuration value " + . "provided for \"{$name}\". Expected {$expected}, but got " + . describe_type($provided) . "\n\n" + . $this->getArgMessage($name); + throw new IAE($msg); + } + + /** + * Throws an exception for missing required arguments. + * + * @param array $args Passed in arguments. + * @throws \InvalidArgumentException + */ + private function throwRequired(array $args) + { + $missing = []; + foreach ($this->argDefinitions as $k => $a) { + if (empty($a['required']) + || isset($a['default']) + || isset($args[$k]) + ) { + continue; + } + $missing[] = $this->getArgMessage($k, $args, true); + } + $msg = "Missing required client configuration options: \n\n"; + $msg .= implode("\n\n", $missing); + throw new IAE($msg); + } + + public static function _apply_retries($value, array &$args, HandlerList $list) + { + // A value of 0 for the config option disables retries + if ($value) { + $config = RetryConfigProvider::unwrap($value); + + if ($config->getMode() === 'legacy') { + // # of retries is 1 less than # of attempts + $decider = RetryMiddleware::createDefaultDecider( + $config->getMaxAttempts() - 1 + ); + $list->appendSign( + Middleware::retry($decider, null, $args['stats']['retries']), + 'retry' + ); + } else { + $list->appendSign( + RetryMiddlewareV2::wrap( + $config, + ['collect_stats' => $args['stats']['retries']] + ), + 'retry' + ); + } + } + } + + public static function _apply_defaults($value, array &$args, HandlerList $list) + { + $config = ConfigModeProvider::unwrap($value); + if ($config->getMode() !== 'legacy') { + if (!isset($args['retries']) && !is_null($config->getRetryMode())) { + $args['retries'] = ['mode' => $config->getRetryMode()]; + } + if ( + !isset($args['sts_regional_endpoints']) + && !is_null($config->getStsRegionalEndpoints()) + ) { + $args['sts_regional_endpoints'] = ['mode' => $config->getStsRegionalEndpoints()]; + } + if ( + !isset($args['s3_us_east_1_regional_endpoint']) + && !is_null($config->getS3UsEast1RegionalEndpoints()) + ) { + $args['s3_us_east_1_regional_endpoint'] = ['mode' => $config->getS3UsEast1RegionalEndpoints()]; + } + + if (!isset($args['http'])) { + $args['http'] = []; + } + if ( + !isset($args['http']['connect_timeout']) + && !is_null($config->getConnectTimeoutInMillis()) + ) { + $args['http']['connect_timeout'] = $config->getConnectTimeoutInMillis() / 1000; + } + if ( + !isset($args['http']['timeout']) + && !is_null($config->getHttpRequestTimeoutInMillis()) + ) { + $args['http']['timeout'] = $config->getHttpRequestTimeoutInMillis() / 1000; + } + } + } + + public static function _apply_disable_request_compression($value, array &$args) { + if (is_callable($value)) { + $value = $value(); + } + if (!is_bool($value)) { + throw new IAE( + "Invalid configuration value provided for 'disable_request_compression'." + . " value must be a bool." + ); + } + $args['config']['disable_request_compression'] = $value; + } + + public static function _apply_min_compression_size($value, array &$args) { + if (is_callable($value)) { + $value = $value(); + } + if (!is_int($value) + || (is_int($value) + && ($value < 0 || $value > 10485760)) + ) { + throw new IAE(" Invalid configuration value provided for 'min_compression_size_bytes'." + . " value must be an integer between 0 and 10485760, inclusive."); + } + $args['config']['request_min_compression_size_bytes'] = $value; + } + + public static function _default_min_compression_size(array &$args) { + return ConfigurationResolver::resolve( + 'request_min_compression_size_bytes', + 10240, + 'int', + $args + ); + } + + public static function _apply_credentials($value, array &$args) + { + if (is_callable($value)) { + return; + } + + if ($value instanceof CredentialsInterface) { + $args['credentials'] = CredentialProvider::fromCredentials($value); + } elseif (is_array($value) + && isset($value['key']) + && isset($value['secret']) + ) { + $args['credentials'] = CredentialProvider::fromCredentials( + new Credentials( + $value['key'], + $value['secret'], + $value['token'] ?? null, + $value['expires'] ?? null, + $value['accountId'] ?? null + ) + ); + } elseif ($value === false) { + $args['credentials'] = CredentialProvider::fromCredentials( + new Credentials('', '') + ); + $args['config']['signature_version'] = 'anonymous'; + $args['config']['configured_signature_version'] = true; + } elseif ($value instanceof CacheInterface) { + $args['credentials'] = CredentialProvider::defaultProvider($args); + } else { + throw new IAE('Credentials must be an instance of ' + . "'" . CredentialsInterface::class . ', an associative ' + . 'array that contains "key", "secret", and an optional "token" ' + . 'key-value pairs, a credentials provider function, or false.'); + } + } + + public static function _default_credential_provider(array $args) + { + return CredentialProvider::defaultProvider($args); + } + + public static function _apply_token($value, array &$args) + { + if (is_callable($value)) { + return; + } + + if ($value instanceof Token) { + $args['token'] = TokenProvider::fromToken($value); + } elseif (is_array($value) + && isset($value['token']) + ) { + $args['token'] = TokenProvider::fromToken( + new Token( + $value['token'], + $value['expires'] ?? null + ) + ); + } elseif ($value instanceof CacheInterface) { + $args['token'] = TokenProvider::defaultProvider($args); + } else { + throw new IAE('Token must be an instance of ' + . TokenInterface::class . ', an associative ' + . 'array that contains "token" and an optional "expires" ' + . 'key-value pairs, a token provider function, or false.'); + } + } + + public static function _default_token_provider(array &$args) + { + if (($args['config']['signing_name'] ?? '') === 'bedrock') { + // Checks for env value, if present, sets auth_scheme_preference + // to bearer auth and returns a provider + $provider = BedrockTokenProvider::createIfAvailable($args); + if (!is_null($provider)) { + return $provider; + } + } + + return TokenProvider::defaultProvider($args); + } + + public static function _apply_csm($value, array &$args, HandlerList $list) + { + if ($value === false) { + $value = new Configuration( + false, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_HOST, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_PORT, + \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_CLIENT_ID + ); + $args['csm'] = $value; + } + + $list->appendBuild( + ApiCallMonitoringMiddleware::wrap( + $args['credentials'], + $value, + $args['region'], + $args['api']->getServiceId() + ), + 'ApiCallMonitoringMiddleware' + ); + + $list->appendAttempt( + ApiCallAttemptMonitoringMiddleware::wrap( + $args['credentials'], + $value, + $args['region'], + $args['api']->getServiceId() + ), + 'ApiCallAttemptMonitoringMiddleware' + ); + } + + public static function _apply_api_provider(callable $value, array &$args) + { + $api = new Service( + ApiProvider::resolve( + $value, + 'api', + $args['service'], + $args['version'] + ), + $value + ); + + if ( + empty($args['config']['signing_name']) + && isset($api['metadata']['signingName']) + ) { + $args['config']['signing_name'] = $api['metadata']['signingName']; + } + + $args['api'] = $api; + $args['parser'] = Service::createParser($api); + $args['error_parser'] = Service::createErrorParser($api->getProtocol(), $api); + } + + public static function _apply_endpoint_provider($value, array &$args) + { + if (!isset($args['endpoint'])) { + if ($value instanceof \Aws\EndpointV2\EndpointProviderV2) { + $options = self::getEndpointProviderOptions($args); + $value = PartitionEndpointProvider::defaultProvider($options) + ->getPartition($args['region'], $args['service']); + } + + $endpointPrefix = $args['api']['metadata']['endpointPrefix'] ?? $args['service']; + + // Check region is a valid host label when it is being used to + // generate an endpoint + if (!self::isValidRegion($args['region'])) { + throw new InvalidRegionException('Region must be a valid RFC' + . ' host label.'); + } + $serviceEndpoints = + is_array($value) && isset($value['services'][$args['service']]['endpoints']) + ? $value['services'][$args['service']]['endpoints'] + : null; + if (isset($serviceEndpoints[$args['region']]['deprecated'])) { + trigger_error("The service " . $args['service'] . "has " + . " deprecated the region " . $args['region'] . ".", + E_USER_WARNING + ); + } + + $args['region'] = \Aws\strip_fips_pseudo_regions($args['region']); + + // Invoke the endpoint provider and throw if it does not resolve. + $result = EndpointProvider::resolve($value, [ + 'service' => $endpointPrefix, + 'region' => $args['region'], + 'scheme' => $args['scheme'], + 'options' => self::getEndpointProviderOptions($args), + ]); + + $args['endpoint'] = $result['endpoint']; + + if (empty($args['config']['signature_version'])) { + if ( + isset($args['api']) + && $args['api']->getSignatureVersion() == 'bearer' + ) { + $args['config']['signature_version'] = 'bearer'; + } elseif (isset($result['signatureVersion'])) { + $args['config']['signature_version'] = $result['signatureVersion']; + } + } + + if ( + empty($args['config']['signing_region']) + && isset($result['signingRegion']) + ) { + $args['config']['signing_region'] = $result['signingRegion']; + } + + if ( + empty($args['config']['signing_name']) + && isset($result['signingName']) + ) { + $args['config']['signing_name'] = $result['signingName']; + } + } + } + + public static function _apply_endpoint_discovery($value, array &$args) { + $args['endpoint_discovery'] = $value; + } + + public static function _default_endpoint_discovery_provider(array $args) + { + return ConfigurationProvider::defaultProvider($args); + } + + public static function _apply_use_fips_endpoint($value, array &$args) { + if ($value instanceof CacheInterface) { + $value = UseFipsConfigProvider::defaultProvider($args); + } + if (is_callable($value)) { + $value = $value(); + } + if ($value instanceof PromiseInterface) { + $value = $value->wait(); + } + if ($value instanceof UseFipsEndpointConfigurationInterface) { + $args['config']['use_fips_endpoint'] = $value; + } else { + // The Configuration class itself will validate other inputs + $args['config']['use_fips_endpoint'] = new UseFipsEndpointConfiguration($value); + } + } + + public static function _default_use_fips_endpoint(array &$args) { + return UseFipsConfigProvider::defaultProvider($args); + } + + public static function _apply_use_dual_stack_endpoint($value, array &$args) { + if ($value instanceof CacheInterface) { + $value = UseDualStackConfigProvider::defaultProvider($args); + } + if (is_callable($value)) { + $value = $value(); + } + if ($value instanceof PromiseInterface) { + $value = $value->wait(); + } + if ($value instanceof UseDualStackEndpointConfigurationInterface) { + $args['config']['use_dual_stack_endpoint'] = $value; + } else { + // The Configuration class itself will validate other inputs + $args['config']['use_dual_stack_endpoint'] = + new UseDualStackEndpointConfiguration($value, $args['region']); + } + } + + public static function _default_use_dual_stack_endpoint(array &$args) { + return UseDualStackConfigProvider::defaultProvider($args); + } + + public static function _apply_serializer($value, array &$args, HandlerList $list) + { + $list->prependBuild(Middleware::requestBuilder($value), 'builder'); + } + + public static function _apply_debug($value, array &$args, HandlerList $list) + { + if ($value !== false) { + $list->interpose( + new TraceMiddleware( + $value === true ? [] : $value, + $args['api']) + ); + } + } + + public static function _apply_stats($value, array &$args, HandlerList $list) + { + // Create an array of stat collectors that are disabled (set to false) + // by default. If the user has passed in true, enable all stat + // collectors. + $defaults = array_fill_keys( + ['http', 'retries', 'timer'], + $value === true + ); + $args['stats'] = is_array($value) + ? array_replace($defaults, $value) + : $defaults; + + if ($args['stats']['timer']) { + $list->prependInit(Middleware::timer(), 'timer'); + } + } + + public static function _apply_profile($_, array &$args) + { + $args['credentials'] = CredentialProvider::ini($args['profile']); + } + + public static function _apply_validate($value, array &$args, HandlerList $list) + { + if ($value === false) { + return; + } + + $validator = $value === true + ? new Validator() + : new Validator($value); + $list->appendValidate( + Middleware::validation($args['api'], $validator), + 'validation' + ); + } + + public static function _apply_handler($value, array &$args, HandlerList $list) + { + $list->setHandler($value); + } + + public static function _default_handler(array &$args) + { + return new WrappedHttpHandler( + default_http_handler(), + $args['parser'], + $args['error_parser'], + $args['exception_class'], + $args['stats']['http'] + ); + } + + public static function _apply_http_handler($value, array &$args, HandlerList $list) + { + $args['handler'] = new WrappedHttpHandler( + $value, + $args['parser'], + $args['error_parser'], + $args['exception_class'], + $args['stats']['http'] + ); + } + + public static function _apply_app_id($value, array &$args) + { + // AppId should not be longer than 50 chars + static $MAX_APP_ID_LENGTH = 50; + if (strlen($value) > $MAX_APP_ID_LENGTH) { + trigger_error("The provided or configured value for `AppId`, " + ."which is an user agent parameter, exceeds the maximum length of " + ."$MAX_APP_ID_LENGTH characters.", E_USER_WARNING); + } + + $args['app_id'] = $value; + } + + public static function _default_app_id(array $args) + { + return ConfigurationResolver::resolve( + 'sdk_ua_app_id', + '', + 'string', + $args + ); + } + + public static function _apply_user_agent( + $inputUserAgent, + array &$args, + HandlerList $list + ): void + { + // Add endpoint discovery if set + $userAgent = []; + // Add the input to the end + if ($inputUserAgent){ + if (!is_array($inputUserAgent)) { + $inputUserAgent = [$inputUserAgent]; + } + $inputUserAgent = array_map('strval', $inputUserAgent); + $userAgent = array_merge($userAgent, $inputUserAgent); + } + + $args['ua_append'] = $userAgent; + + $list->appendBuild( + Middleware::mapRequest(function (RequestInterface $request) use ($userAgent) { + return $request->withHeader( + 'X-Amz-User-Agent', + implode(' ', array_merge( + $userAgent, + $request->getHeader('X-Amz-User-Agent') + )) + ); + }) + ); + } + + public static function _apply_endpoint($value, array &$args, HandlerList $list) + { + if (empty($value)) { + unset($args['endpoint']); + return; + } + + $args['endpoint_override'] = true; + $args['endpoint'] = $value; + } + + public static function _apply_idempotency_auto_fill( + $value, + array &$args, + HandlerList $list + ) { + $enabled = false; + $generator = null; + + + if (is_bool($value)) { + $enabled = $value; + } elseif (is_callable($value)) { + $enabled = true; + $generator = $value; + } + + if ($enabled) { + $list->prependInit( + IdempotencyTokenMiddleware::wrap($args['api'], $generator), + 'idempotency_auto_fill' + ); + } + } + + public static function _default_account_id_endpoint_mode($args) + { + return ConfigurationResolver::resolve( + 'account_id_endpoint_mode', + 'preferred', + 'string', + $args + ); + } + + public static function _apply_account_id_endpoint_mode($value, array &$args) + { + static $accountIdEndpointModes = ['disabled', 'required', 'preferred']; + if (!in_array($value, $accountIdEndpointModes)) { + throw new IAE( + "The value provided for the config account_id_endpoint_mode is invalid." + ."Valid values are: " . implode(", ", $accountIdEndpointModes) + ); + } + + $args['account_id_endpoint_mode'] = $value; + } + + public static function _default_endpoint_provider(array $args) + { + $service = $args['api'] ?? null; + $serviceName = isset($service) ? $service->getServiceName() : null; + $apiVersion = isset($service) ? $service->getApiVersion() : null; + + if (self::isValidService($serviceName) + && self::isValidApiVersion($serviceName, $apiVersion) + ) { + $ruleset = EndpointDefinitionProvider::getEndpointRuleset( + $service->getServiceName(), + $service->getApiVersion() + ); + return new \Aws\EndpointV2\EndpointProviderV2( + $ruleset, + EndpointDefinitionProvider::getPartitions() + ); + } + $options = self::getEndpointProviderOptions($args); + return PartitionEndpointProvider::defaultProvider($options) + ->getPartition($args['region'], $args['service']); + } + + public static function _default_serializer(array $args) + { + return Service::createSerializer( + $args['api'], + $args['endpoint'] + ); + } + + public static function _default_signature_provider() + { + return SignatureProvider::defaultProvider(); + } + + public static function _default_auth_scheme_resolver(array $args) + { + return new AuthSchemeResolver($args['credentials'], $args['token']); + } + + public static function _apply_auth_scheme_preference( + string|array|null &$value, + array &$args + ): void + { + // Not provided user's preference auth scheme list + if (empty($value)) { + $value = null; + $args['config']['auth_scheme_preference'] = $value; + return; + } + + // Normalize it as an array + if (is_string($value)) { + $value = explode(',', $value); + } + + // Let`s trim each value to remove break lines, spaces and/or tabs + foreach ($value as &$val) { + $val = trim($val); + } + + // Assign user's preferred auth scheme list + $args['auth_scheme_preference'] = $value; + } + + public static function _default_signature_version(array &$args) + { + if (isset($args['config']['signature_version'])) { + return $args['config']['signature_version']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + return isset($args['__partition_result']['signatureVersion']) + ? $args['__partition_result']['signatureVersion'] + : $args['api']->getSignatureVersion(); + } + + public static function _default_signing_name(array &$args) + { + if (isset($args['config']['signing_name'])) { + return $args['config']['signing_name']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + if (isset($args['__partition_result']['signingName'])) { + return $args['__partition_result']['signingName']; + } + + if ($signingName = $args['api']->getSigningName()) { + return $signingName; + } + + return $args['service']; + } + + public static function _default_signing_region(array &$args) + { + if (isset($args['config']['signing_region'])) { + return $args['config']['signing_region']; + } + + $args['__partition_result'] = isset($args['__partition_result']) + ? isset($args['__partition_result']) + : call_user_func(PartitionEndpointProvider::defaultProvider(), [ + 'service' => $args['service'], + 'region' => $args['region'], + ]); + + return $args['__partition_result']['signingRegion'] ?? $args['region']; + } + + public static function _apply_ignore_configured_endpoint_urls($value, array &$args) + { + $args['config']['ignore_configured_endpoint_urls'] = $value; + } + + public static function _apply_suppress_php_deprecation_warning($value, &$args) + { + if ($value) { + $args['suppress_php_deprecation_warning'] = true; + } elseif (!empty(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING"))) { + $args['suppress_php_deprecation_warning'] + = \Aws\boolean_value(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING")); + } elseif (!empty($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) { + $args['suppress_php_deprecation_warning'] = + \Aws\boolean_value($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]); + } elseif (!empty($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) { + $args['suppress_php_deprecation_warning'] = + \Aws\boolean_value($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]); + } + + if ($args['suppress_php_deprecation_warning'] === false + && PHP_VERSION_ID < 80100 + ) { + self::emitDeprecationWarning(); + } + } + + public static function _default_endpoint(array &$args) + { + if ($args['config']['ignore_configured_endpoint_urls'] + || !self::isValidService($args['service']) + ) { + return ''; + } + + $serviceIdentifier = \Aws\manifest($args['service'])['serviceIdentifier']; + $value = ConfigurationResolver::resolve( + 'endpoint_url_' . $serviceIdentifier, + '', + 'string', + $args + [ + 'ini_resolver_options' => [ + 'section' => 'services', + 'subsection' => $serviceIdentifier, + 'key' => 'endpoint_url' + ] + ] + ); + + if (empty($value)) { + $value = ConfigurationResolver::resolve( + 'endpoint_url', + '', + 'string', + $args + ); + } + + if (!empty($value)) { + $args['config']['configured_endpoint_url'] = true; + } + + return $value; + } + + public static function _apply_sigv4a_signing_region_set($value, array &$args) + { + if (empty($value)) { + $args['sigv4a_signing_region_set'] = null; + } elseif (is_array($value)) { + $args['sigv4a_signing_region_set'] = implode(', ', $value); + } else { + $args['sigv4a_signing_region_set'] = $value; + } + } + + public static function _apply_region($value, array &$args) + { + if (empty($value)) { + self::_missing_region($args); + } + $args['region'] = $value; + } + + public static function _missing_region(array $args) + { + $service = $args['service'] ?? ''; + + $msg = << 0, + 'bool' => false, + 'boolean' => false, + 'string' => '', + ]; + + return ConfigurationResolver::resolve( + $key, + $typeDefaultMap[$expectedType] ?? '', + $expectedType, + $args + ); + } + + /** + * Extracts client options for the endpoint provider to its own array + * + * @param array $args + * @return array + */ + private static function getEndpointProviderOptions(array $args) + { + $options = []; + $optionKeys = [ + 'sts_regional_endpoints', + 's3_us_east_1_regional_endpoint', + ]; + $configKeys = [ + 'use_dual_stack_endpoint', + 'use_fips_endpoint', + ]; + foreach ($optionKeys as $key) { + if (isset($args[$key])) { + $options[$key] = $args[$key]; + } + } + foreach ($configKeys as $key) { + if (isset($args['config'][$key])) { + $options[$key] = $args['config'][$key]; + } + } + return $options; + } + + /** + * Validates a region to be used for endpoint construction + * + * @param $region + * @return bool + */ + private static function isValidRegion($region) + { + return is_valid_hostlabel($region); + } + + private function _apply_client_context_params(array $args) + { + if (isset($args['api']) + && !empty($args['api']->getClientContextParams())) + { + $clientContextParams = $args['api']->getClientContextParams(); + foreach($clientContextParams as $paramName => $paramDefinition) { + $definition = [ + 'type' => 'value', + 'valid' => [$paramDefinition['type']], + 'doc' => $paramDefinition['documentation'] ?? null + ]; + $this->argDefinitions[$paramName] = $definition; + + if (isset($args[$paramName])) { + $fn = self::$typeMap[$paramDefinition['type']]; + if (!$fn($args[$paramName])) { + $this->invalidType($paramName, $args[$paramName]); + } + } + } + } + } + + private static function isValidService($service) + { + if (is_null($service)) { + return false; + } + $services = \Aws\manifest(); + return isset($services[$service]); + } + + private static function isValidApiVersion($service, $apiVersion) + { + if (is_null($apiVersion)) { + return false; + } + return is_dir( + __DIR__ . "/data/{$service}/$apiVersion" + ); + } + + private static function emitDeprecationWarning() + { + $phpVersionString = phpversion(); + trigger_error( + "This installation of the SDK is using PHP version" + . " {$phpVersionString}, which will be deprecated on January" + . " 13th, 2025.\nPlease upgrade your PHP version to a minimum of" + . " 8.1.x to continue receiving updates for the AWS" + . " SDK for PHP.\nTo disable this warning, set" + . " suppress_php_deprecation_warning to true on the client constructor" + . " or set the environment variable AWS_SUPPRESS_PHP_DEPRECATION_WARNING" + . " to true.\nMore information can be found at: " + . "https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-php-runtimes-8-0-x-and-below-in-the-aws-sdk-for-php/\n", + E_USER_DEPRECATED + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/AbstractMonitoringMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/AbstractMonitoringMiddleware.php new file mode 100644 index 000000000..d514e8355 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/AbstractMonitoringMiddleware.php @@ -0,0 +1,309 @@ +getResponse(); + if ($response !== null) { + $header = $response->getHeader($headerName); + if (!empty($header[0])) { + return $header[0]; + } + } + return null; + } + + protected static function getResultHeader(ResultInterface $result, $headerName) + { + if (isset($result['@metadata']['headers'][$headerName])) { + return $result['@metadata']['headers'][$headerName]; + } + return null; + } + + protected static function getExceptionHeader(\Exception $e, $headerName) + { + if ($e instanceof ResponseContainerInterface) { + $response = $e->getResponse(); + if ($response instanceof ResponseInterface) { + $header = $response->getHeader($headerName); + if (!empty($header[0])) { + return $header[0]; + } + } + } + return null; + } + + /** + * Constructor stores the passed in handler and options. + * + * @param callable $handler + * @param callable $credentialProvider + * @param $options + * @param $region + * @param $service + */ + public function __construct( + callable $handler, + callable $credentialProvider, + $options, + $region, + $service + ) { + $this->nextHandler = $handler; + $this->credentialProvider = $credentialProvider; + $this->options = $options; + $this->region = $region; + $this->service = $service; + } + + /** + * Standard invoke pattern for middleware execution to be implemented by + * child classes. + * + * @param CommandInterface $cmd + * @param RequestInterface $request + * @return Promise\PromiseInterface + */ + public function __invoke(CommandInterface $cmd, RequestInterface $request) + { + $handler = $this->nextHandler; + $eventData = null; + $enabled = $this->isEnabled(); + + if ($enabled) { + $cmd['@http']['collect_stats'] = true; + $eventData = $this->populateRequestEventData( + $cmd, + $request, + $this->getNewEvent($cmd, $request) + ); + } + + $g = function ($value) use ($eventData, $enabled) { + if ($enabled) { + $eventData = $this->populateResultEventData( + $value, + $eventData + ); + $this->sendEventData($eventData); + + if ($value instanceof MonitoringEventsInterface) { + $value->appendMonitoringEvent($eventData); + } + } + if ($value instanceof \Exception || $value instanceof \Throwable) { + return Promise\Create::rejectionFor($value); + } + return $value; + }; + + return Promise\Create::promiseFor($handler($cmd, $request))->then($g, $g); + } + + private function getClientId() + { + return $this->unwrappedOptions()->getClientId(); + } + + private function getNewEvent( + CommandInterface $cmd, + RequestInterface $request + ) { + $event = [ + 'Api' => $cmd->getName(), + 'ClientId' => $this->getClientId(), + 'Region' => $this->getRegion(), + 'Service' => $this->getService(), + 'Timestamp' => (int) floor(microtime(true) * 1000), + 'UserAgent' => substr( + $request->getHeaderLine('User-Agent') . ' ' . \Aws\default_user_agent(), + 0, + 256 + ), + 'Version' => 1 + ]; + return $event; + } + + private function getHost() + { + return $this->unwrappedOptions()->getHost(); + } + + private function getPort() + { + return $this->unwrappedOptions()->getPort(); + } + + private function getRegion() + { + return $this->region; + } + + private function getService() + { + return $this->service; + } + + /** + * Returns enabled flag from options, unwrapping options if necessary. + * + * @return bool + */ + private function isEnabled() + { + return $this->unwrappedOptions()->isEnabled(); + } + + /** + * Returns $eventData array with information from the request and command. + * + * @param CommandInterface $cmd + * @param RequestInterface $request + * @param array $event + * @return array + */ + protected function populateRequestEventData( + CommandInterface $cmd, + RequestInterface $request, + array $event + ) { + $dataFormat = static::getRequestData($request); + foreach ($dataFormat as $eventKey => $value) { + if ($value !== null) { + $event[$eventKey] = $value; + } + } + return $event; + } + + /** + * Returns $eventData array with information from the response, including + * the calculation for attempt latency. + * + * @param ResultInterface|\Exception $result + * @param array $event + * @return array + */ + protected function populateResultEventData( + $result, + array $event + ) { + $dataFormat = static::getResponseData($result); + foreach ($dataFormat as $eventKey => $value) { + if ($value !== null) { + $event[$eventKey] = $value; + } + } + return $event; + } + + + /** + * Checks if the socket is created. If PHP version is greater or equals to 8 then, + * it will check if the var is instance of \Socket otherwise it will check if is + * a resource. + * + * @return bool Returns true if the socket is created, false otherwise. + */ + private function isSocketCreated(): bool + { + // Before version 8, sockets are resources + // After version 8, sockets are instances of Socket + if (PHP_MAJOR_VERSION >= 8) { + $socketClass = '\Socket'; + return self::$socket instanceof $socketClass; + } else { + return is_resource(self::$socket); + } + } + + /** + * Creates a UDP socket resource and stores it with the class, or retrieves + * it if already instantiated and connected. Handles error-checking and + * re-connecting if necessary. If $forceNewConnection is set to true, a new + * socket will be created. + * + * @param bool $forceNewConnection + * @return Resource + */ + private function prepareSocket($forceNewConnection = false) + { + if (!$this->isSocketCreated() + || $forceNewConnection + || socket_last_error(self::$socket) + ) { + self::$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + socket_clear_error(self::$socket); + socket_connect(self::$socket, $this->getHost(), $this->getPort()); + } + + return self::$socket; + } + + /** + * Sends formatted monitoring event data via the UDP socket connection to + * the CSM agent endpoint. + * + * @param array $eventData + * @return int + */ + private function sendEventData(array $eventData) + { + $socket = $this->prepareSocket(); + $datagram = json_encode($eventData); + $result = socket_write($socket, $datagram, strlen($datagram)); + if ($result === false) { + $this->prepareSocket(true); + } + return $result; + } + + /** + * Unwraps options, if needed, and returns them. + * + * @return ConfigurationInterface + */ + private function unwrappedOptions() + { + if (!($this->options instanceof ConfigurationInterface)) { + try { + $this->options = ConfigurationProvider::unwrap($this->options); + } catch (\Exception $e) { + // Errors unwrapping CSM config defaults to disabling it + $this->options = new Configuration( + false, + ConfigurationProvider::DEFAULT_HOST, + ConfigurationProvider::DEFAULT_PORT + ); + } + } + return $this->options; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallAttemptMonitoringMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallAttemptMonitoringMiddleware.php new file mode 100644 index 000000000..91810bb9c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallAttemptMonitoringMiddleware.php @@ -0,0 +1,262 @@ + $request->getUri()->getHost(), + ]; + } + + /** + * {@inheritdoc} + */ + public static function getResponseData($klass) + { + if ($klass instanceof ResultInterface) { + return [ + 'AttemptLatency' => self::getResultAttemptLatency($klass), + 'DestinationIp' => self::getResultDestinationIp($klass), + 'DnsLatency' => self::getResultDnsLatency($klass), + 'HttpStatusCode' => self::getResultHttpStatusCode($klass), + 'XAmzId2' => self::getResultHeader($klass, 'x-amz-id-2'), + 'XAmzRequestId' => self::getResultHeader($klass, 'x-amz-request-id'), + 'XAmznRequestId' => self::getResultHeader($klass, 'x-amzn-RequestId'), + ]; + } + if ($klass instanceof AwsException) { + return [ + 'AttemptLatency' => self::getAwsExceptionAttemptLatency($klass), + 'AwsException' => substr( + self::getAwsExceptionErrorCode($klass), + 0, + 128 + ), + 'AwsExceptionMessage' => substr( + self::getAwsExceptionMessage($klass), + 0, + 512 + ), + 'DestinationIp' => self::getAwsExceptionDestinationIp($klass), + 'DnsLatency' => self::getAwsExceptionDnsLatency($klass), + 'HttpStatusCode' => self::getAwsExceptionHttpStatusCode($klass), + 'XAmzId2' => self::getAwsExceptionHeader($klass, 'x-amz-id-2'), + 'XAmzRequestId' => self::getAwsExceptionHeader( + $klass, + 'x-amz-request-id' + ), + 'XAmznRequestId' => self::getAwsExceptionHeader( + $klass, + 'x-amzn-RequestId' + ), + ]; + } + if ($klass instanceof \Exception) { + return [ + 'HttpStatusCode' => self::getExceptionHttpStatusCode($klass), + 'SdkException' => substr( + self::getExceptionCode($klass), + 0, + 128 + ), + 'SdkExceptionMessage' => substr( + self::getExceptionMessage($klass), + 0, + 512 + ), + 'XAmzId2' => self::getExceptionHeader($klass, 'x-amz-id-2'), + 'XAmzRequestId' => self::getExceptionHeader($klass, 'x-amz-request-id'), + 'XAmznRequestId' => self::getExceptionHeader($klass, 'x-amzn-RequestId'), + ]; + } + + throw new \InvalidArgumentException('Parameter must be an instance of ResultInterface, AwsException or Exception.'); + } + + private static function getResultAttemptLatency(ResultInterface $result) + { + if (isset($result['@metadata']['transferStats']['http'])) { + $attempt = end($result['@metadata']['transferStats']['http']); + if (isset($attempt['total_time'])) { + return (int) floor($attempt['total_time'] * 1000); + } + } + return null; + } + + private static function getResultDestinationIp(ResultInterface $result) + { + if (isset($result['@metadata']['transferStats']['http'])) { + $attempt = end($result['@metadata']['transferStats']['http']); + if (isset($attempt['primary_ip'])) { + return $attempt['primary_ip']; + } + } + return null; + } + + private static function getResultDnsLatency(ResultInterface $result) + { + if (isset($result['@metadata']['transferStats']['http'])) { + $attempt = end($result['@metadata']['transferStats']['http']); + if (isset($attempt['namelookup_time'])) { + return (int) floor($attempt['namelookup_time'] * 1000); + } + } + return null; + } + + private static function getResultHttpStatusCode(ResultInterface $result) + { + return $result['@metadata']['statusCode']; + } + + private static function getAwsExceptionAttemptLatency(AwsException $e) { + $attempt = $e->getTransferInfo(); + if (isset($attempt['total_time'])) { + return (int) floor($attempt['total_time'] * 1000); + } + return null; + } + + private static function getAwsExceptionErrorCode(AwsException $e) { + return $e->getAwsErrorCode(); + } + + private static function getAwsExceptionMessage(AwsException $e) { + return $e->getAwsErrorMessage(); + } + + private static function getAwsExceptionDestinationIp(AwsException $e) { + $attempt = $e->getTransferInfo(); + if (isset($attempt['primary_ip'])) { + return $attempt['primary_ip']; + } + return null; + } + + private static function getAwsExceptionDnsLatency(AwsException $e) { + $attempt = $e->getTransferInfo(); + if (isset($attempt['namelookup_time'])) { + return (int) floor($attempt['namelookup_time'] * 1000); + } + return null; + } + + private static function getAwsExceptionHttpStatusCode(AwsException $e) { + $response = $e->getResponse(); + if ($response !== null) { + return $response->getStatusCode(); + } + return null; + } + + private static function getExceptionHttpStatusCode(\Exception $e) { + if ($e instanceof ResponseContainerInterface) { + $response = $e->getResponse(); + if ($response instanceof ResponseInterface) { + return $response->getStatusCode(); + } + } + return null; + } + + private static function getExceptionCode(\Exception $e) { + if (!($e instanceof AwsException)) { + return get_class($e); + } + return null; + } + + private static function getExceptionMessage(\Exception $e) { + if (!($e instanceof AwsException)) { + return $e->getMessage(); + } + return null; + } + + /** + * {@inheritdoc} + */ + protected function populateRequestEventData( + CommandInterface $cmd, + RequestInterface $request, + array $event + ) { + $event = parent::populateRequestEventData($cmd, $request, $event); + $event['Type'] = 'ApiCallAttempt'; + return $event; + } + + /** + * {@inheritdoc} + */ + protected function populateResultEventData( + $result, + array $event + ) { + $event = parent::populateResultEventData($result, $event); + + $provider = $this->credentialProvider; + /** @var CredentialsInterface $credentials */ + $credentials = $provider()->wait(); + $event['AccessKey'] = $credentials->getAccessKeyId(); + $sessionToken = $credentials->getSecurityToken(); + if ($sessionToken !== null) { + $event['SessionToken'] = $sessionToken; + } + if (empty($event['AttemptLatency'])) { + $event['AttemptLatency'] = (int) (floor(microtime(true) * 1000) - $event['Timestamp']); + } + return $event; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallMonitoringMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallMonitoringMiddleware.php new file mode 100644 index 000000000..420807384 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ApiCallMonitoringMiddleware.php @@ -0,0 +1,175 @@ + 'AwsException', + 'FinalAwsExceptionMessage' => 'AwsExceptionMessage', + 'FinalSdkException' => 'SdkException', + 'FinalSdkExceptionMessage' => 'SdkExceptionMessage', + 'FinalHttpStatusCode' => 'HttpStatusCode', + ]; + + /** + * Standard middleware wrapper function with CSM options passed in. + * + * @param callable $credentialProvider + * @param mixed $options + * @param string $region + * @param string $service + * @return callable + */ + public static function wrap( + callable $credentialProvider, + $options, + $region, + $service + ) { + return function (callable $handler) use ( + $credentialProvider, + $options, + $region, + $service + ) { + return new static( + $handler, + $credentialProvider, + $options, + $region, + $service + ); + }; + } + + /** + * {@inheritdoc} + */ + public static function getRequestData(RequestInterface $request) + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getResponseData($klass) + { + if ($klass instanceof ResultInterface) { + $data = [ + 'AttemptCount' => self::getResultAttemptCount($klass), + 'MaxRetriesExceeded' => 0, + ]; + } elseif ($klass instanceof \Exception) { + $data = [ + 'AttemptCount' => self::getExceptionAttemptCount($klass), + 'MaxRetriesExceeded' => self::getMaxRetriesExceeded($klass), + ]; + } else { + throw new \InvalidArgumentException('Parameter must be an instance of ResultInterface or Exception.'); + } + + return $data + self::getFinalAttemptData($klass); + } + + private static function getResultAttemptCount(ResultInterface $result) { + if (isset($result['@metadata']['transferStats']['http'])) { + return count($result['@metadata']['transferStats']['http']); + } + return 1; + } + + private static function getExceptionAttemptCount(\Exception $e) { + $attemptCount = 0; + if ($e instanceof MonitoringEventsInterface) { + foreach ($e->getMonitoringEvents() as $event) { + if (isset($event['Type']) && + $event['Type'] === 'ApiCallAttempt') { + $attemptCount++; + } + } + + } + return $attemptCount; + } + + private static function getFinalAttemptData($klass) + { + $data = []; + if ($klass instanceof MonitoringEventsInterface) { + $finalAttempt = self::getFinalAttempt($klass->getMonitoringEvents()); + + if (!empty($finalAttempt)) { + foreach (self::$eventKeys as $callKey => $attemptKey) { + if (isset($finalAttempt[$attemptKey])) { + $data[$callKey] = $finalAttempt[$attemptKey]; + } + } + } + } + + return $data; + } + + private static function getFinalAttempt(array $events) + { + for (end($events); key($events) !== null; prev($events)) { + $current = current($events); + if (isset($current['Type']) + && $current['Type'] === 'ApiCallAttempt' + ) { + return $current; + } + } + + return null; + } + + private static function getMaxRetriesExceeded($klass) + { + if ($klass instanceof AwsException && $klass->isMaxRetriesExceeded()) { + return 1; + } + return 0; + } + + /** + * {@inheritdoc} + */ + protected function populateRequestEventData( + CommandInterface $cmd, + RequestInterface $request, + array $event + ) { + $event = parent::populateRequestEventData($cmd, $request, $event); + $event['Type'] = 'ApiCall'; + return $event; + } + + /** + * {@inheritdoc} + */ + protected function populateResultEventData( + $result, + array $event + ) { + $event = parent::populateResultEventData($result, $event); + $event['Latency'] = (int) (floor(microtime(true) * 1000) - $event['Timestamp']); + return $event; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Configuration.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Configuration.php new file mode 100644 index 000000000..b875274b8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Configuration.php @@ -0,0 +1,77 @@ +host = $host; + $this->port = filter_var($port, FILTER_VALIDATE_INT); + if ($this->port === false) { + throw new \InvalidArgumentException( + "CSM 'port' value must be an integer!"); + } + + // Unparsable $enabled flag errors on the side of disabling CSM + $this->enabled = filter_var($enabled, FILTER_VALIDATE_BOOLEAN); + $this->clientId = trim($clientId); + } + + /** + * {@inheritdoc} + */ + public function isEnabled() + { + return $this->enabled; + } + + /** + * {@inheritdoc} + */ + public function getClientId() + { + return $this->clientId; + } + + /** + * /{@inheritdoc} + */ + public function getHost() + { + return $this->host; + } + + /** + * {@inheritdoc} + */ + public function getPort() + { + return $this->port; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'client_id' => $this->getClientId(), + 'enabled' => $this->isEnabled(), + 'host' => $this->getHost(), + 'port' => $this->getPort() + ]; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ConfigurationInterface.php new file mode 100644 index 000000000..9a548279c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/ConfigurationInterface.php @@ -0,0 +1,44 @@ + + * use Aws\ClientSideMonitoring\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see Aws\ClientSideMonitoring\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const DEFAULT_CLIENT_ID = ''; + const DEFAULT_ENABLED = false; + const DEFAULT_HOST = '127.0.0.1'; + const DEFAULT_PORT = 31000; + const ENV_CLIENT_ID = 'AWS_CSM_CLIENT_ID'; + const ENV_ENABLED = 'AWS_CSM_ENABLED'; + const ENV_HOST = 'AWS_CSM_HOST'; + const ENV_PORT = 'AWS_CSM_PORT'; + const ENV_PROFILE = 'AWS_PROFILE'; + + public static $cacheKey = 'aws_cached_csm_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['csm']) && $config['csm'] instanceof CacheInterface) { + return self::cache($memo, $config['csm'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates CSM config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use credentials from environment variables, if available + $enabled = getenv(self::ENV_ENABLED); + if ($enabled !== false) { + return Promise\Create::promiseFor( + new Configuration( + $enabled, + getenv(self::ENV_HOST) ?: self::DEFAULT_HOST, + getenv(self::ENV_PORT) ?: self::DEFAULT_PORT, + getenv(self:: ENV_CLIENT_ID) ?: self::DEFAULT_CLIENT_ID + ) + ); + } + + return self::reject('Could not find environment variable CSM config' + . ' in ' . self::ENV_ENABLED. '/' . self::ENV_HOST . '/' + . self::ENV_PORT . '/' . self::ENV_CLIENT_ID); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function() { + return Promise\Create::promiseFor( + new Configuration( + self::DEFAULT_ENABLED, + self::DEFAULT_HOST, + self::DEFAULT_PORT, + self::DEFAULT_CLIENT_ID + ) + ); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini($profile = null, $filename = null) + { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'aws_csm'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read CSM config from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile]['csm_enabled'])) { + return self::reject("Required CSM config values not present in + INI profile '{$profile}' ({$filename})"); + } + + // host is optional + if (empty($data[$profile]['csm_host'])) { + $data[$profile]['csm_host'] = self::DEFAULT_HOST; + } + + // port is optional + if (!filter_var($data[$profile]['csm_port'] ?? null, FILTER_VALIDATE_INT)) { + $data[$profile]['csm_port'] = self::DEFAULT_PORT; + } + + // client_id is optional + if (empty($data[$profile]['csm_client_id'])) { + $data[$profile]['csm_client_id'] = self::DEFAULT_CLIENT_ID; + } + + return Promise\Create::promiseFor( + new Configuration( + $data[$profile]['csm_enabled'], + $data[$profile]['csm_host'], + $data[$profile]['csm_port'], + $data[$profile]['csm_client_id'] + ) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } elseif (is_array($config) && isset($config['enabled'])) { + $client_id = isset($config['client_id']) ? $config['client_id'] + : self::DEFAULT_CLIENT_ID; + $host = isset($config['host']) ? $config['host'] + : self::DEFAULT_HOST; + $port = isset($config['port']) ? $config['port'] + : self::DEFAULT_PORT; + return new Configuration($config['enabled'], $host, $port, $client_id); + } + + throw new \InvalidArgumentException('Not a valid CSM configuration ' + . 'argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Exception/ConfigurationException.php new file mode 100644 index 000000000..827743e26 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ClientSideMonitoring/Exception/ConfigurationException.php @@ -0,0 +1,15 @@ +name = $name; + $this->data = $args; + $this->handlerList = $list ?: new HandlerList(); + + if (!isset($this->data['@http'])) { + $this->data['@http'] = []; + } + if (!isset($this->data['@context'])) { + $this->data['@context'] = []; + } + $this->metricsBuilder = $metricsBuilder ?: new MetricsBuilder(); + } + + public function __clone() + { + $this->handlerList = clone $this->handlerList; + } + + public function getName() + { + return $this->name; + } + + public function hasParam($name) + { + return array_key_exists($name, $this->data); + } + + public function getHandlerList() + { + return $this->handlerList; + } + + /** + * For overriding auth schemes on a per endpoint basis when using + * EndpointV2 provider. Intended for internal use only. + * + * @param array $authSchemes + * + * @deprecated In favor of using the @context property bag. + * Auth Schemes are now accessible via the `signature_version` key + * in a Command's context, if applicable. Auth Schemes set using + * This method are no longer consumed. + * + * @internal + */ + public function setAuthSchemes(array $authSchemes) + { + trigger_error(__METHOD__ . ' is deprecated. Auth schemes ' + . 'resolved using the service `auth` trait or via endpoint resolution ' + . 'are now set in the command `@context` property.`' + , E_USER_WARNING + ); + + $this->authSchemes = $authSchemes; + } + + /** + * Get auth schemes added to command as required + * for endpoint resolution + * + * @returns array + * + * @deprecated In favor of using the @context property bag. + * Auth schemes are now accessible via the `signature_version` key + * in a Command's context, if applicable. + */ + public function getAuthSchemes() + { + trigger_error(__METHOD__ . ' is deprecated. Auth schemes ' + . 'resolved using the service `auth` trait or via endpoint resolution ' + . 'can now be found in the command `@context` property.`' + , E_USER_WARNING + ); + + return $this->authSchemes ?: []; + } + + /** @deprecated */ + public function get($name) + { + return $this[$name]; + } + + /** + * Returns the metrics builder instance tied up to this command. + * + * @internal + * + * @return MetricsBuilder + */ + public function getMetricsBuilder(): MetricsBuilder + { + return $this->metricsBuilder; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CommandInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CommandInterface.php new file mode 100644 index 000000000..b35c75d37 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/CommandInterface.php @@ -0,0 +1,42 @@ +getBefore($config); + $mapFn = function ($commands) use ($client, $before, $config) { + foreach ($commands as $key => $command) { + if (!($command instanceof CommandInterface)) { + throw new \InvalidArgumentException('Each value yielded by ' + . 'the iterator must be an Aws\CommandInterface.'); + } + if ($before) { + $before($command, $key); + } + if (!empty($config['preserve_iterator_keys'])) { + yield $key => $client->executeAsync($command); + } else { + yield $client->executeAsync($command); + } + } + }; + + $this->each = new EachPromise($mapFn($commands), $config); + } + + /** + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + return $this->each->promise(); + } + + /** + * Executes a pool synchronously and aggregates the results of the pool + * into an indexed array in the same order as the passed in array. + * + * @param AwsClientInterface $client Client used to execute commands. + * @param mixed $commands Iterable that yields commands. + * @param array $config Configuration options. + * + * @return array + * @see \Aws\CommandPool::__construct for available configuration options. + */ + public static function batch( + AwsClientInterface $client, + $commands, + array $config = [] + ) { + $results = []; + self::cmpCallback($config, 'fulfilled', $results); + self::cmpCallback($config, 'rejected', $results); + + return (new self($client, $commands, $config)) + ->promise() + ->then(static function () use (&$results) { + ksort($results); + return $results; + }) + ->wait(); + } + + /** + * @return callable + */ + private function getBefore(array $config) + { + if (!isset($config['before'])) { + return null; + } + + if (is_callable($config['before'])) { + return $config['before']; + } + + throw new \InvalidArgumentException('before must be callable'); + } + + /** + * Adds an onFulfilled or onRejected callback that aggregates results into + * an array. If a callback is already present, it is replaced with the + * composed function. + * + * @param array $config + * @param $name + * @param array $results + */ + private static function cmpCallback(array &$config, $name, array &$results) + { + if (!isset($config[$name])) { + $config[$name] = function ($v, $k) use (&$results) { + $results[$k] = $v; + }; + } else { + $currentFn = $config[$name]; + $config[$name] = function ($v, $k) use (&$results, $currentFn) { + $currentFn($v, $k); + $results[$k] = $v; + }; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Configuration/ConfigurationResolver.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Configuration/ConfigurationResolver.php new file mode 100644 index 000000000..875c4f179 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Configuration/ConfigurationResolver.php @@ -0,0 +1,251 @@ +client = $config['client']; + $this->assumeRoleParams = $config['assume_role_params']; + } + + /** + * Loads assume role credentials. + * + * @return PromiseInterface + */ + public function __invoke() + { + $client = $this->client; + return $client->assumeRoleAsync($this->assumeRoleParams) + ->then(function (Result $result) { + return $this->client->createCredentials( + $result, + CredentialSources::STS_ASSUME_ROLE + ); + })->otherwise(function (\RuntimeException $exception) { + throw new CredentialsException( + "Error in retrieving assume role credentials.", + 0, + $exception + ); + }); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/AssumeRoleWithWebIdentityCredentialProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/AssumeRoleWithWebIdentityCredentialProvider.php new file mode 100644 index 000000000..ea7052236 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/AssumeRoleWithWebIdentityCredentialProvider.php @@ -0,0 +1,170 @@ +arn = $config['RoleArn']; + + if (!isset($config['WebIdentityTokenFile'])) { + throw new \InvalidArgumentException(self::ERROR_MSG . "'WebIdentityTokenFile'."); + } + $this->tokenFile = $config['WebIdentityTokenFile']; + + if (!preg_match("/^\w\:|^\/|^\\\/", $this->tokenFile)) { + throw new \InvalidArgumentException("'WebIdentityTokenFile' must be an absolute path."); + } + + $this->retries = (int) getenv(self::ENV_RETRIES) ?: (isset($config['retries']) ? $config['retries'] : 3); + $this->authenticationAttempts = 0; + $this->tokenFileReadAttempts = 0; + $this->session = $config['SessionName'] + ?? 'aws-sdk-php-' . round(microtime(true) * 1000); + $region = $config['region'] ?? 'us-east-1'; + if (isset($config['client'])) { + $this->client = $config['client']; + } else { + $this->client = new StsClient([ + 'credentials' => false, + 'region' => $region, + 'version' => 'latest' + ]); + } + + $this->source = $config['source'] + ?? CredentialSources::STS_WEB_ID_TOKEN; + } + + /** + * Loads assume role with web identity credentials. + * + * @return Promise\PromiseInterface + */ + public function __invoke() + { + return Promise\Coroutine::of(function () { + $client = $this->client; + $result = null; + while ($result == null) { + try { + $token = @file_get_contents($this->tokenFile); + if (false === $token) { + clearstatcache(true, dirname($this->tokenFile) . "/" . readlink($this->tokenFile)); + clearstatcache(true, dirname($this->tokenFile) . "/" . dirname(readlink($this->tokenFile))); + clearstatcache(true, $this->tokenFile); + if (!@is_readable($this->tokenFile)) { + throw new CredentialsException( + "Unreadable tokenfile at location {$this->tokenFile}" + ); + } + + $token = @file_get_contents($this->tokenFile); + } + if (empty($token)) { + if ($this->tokenFileReadAttempts < $this->retries) { + sleep((int) pow(1.2, $this->tokenFileReadAttempts)); + $this->tokenFileReadAttempts++; + continue; + } + throw new CredentialsException("InvalidIdentityToken from file: {$this->tokenFile}"); + } + } catch (\Exception $exception) { + throw new CredentialsException( + "Error reading WebIdentityTokenFile from " . $this->tokenFile, + 0, + $exception + ); + } + + $assumeParams = [ + 'RoleArn' => $this->arn, + 'RoleSessionName' => $this->session, + 'WebIdentityToken' => $token + ]; + + try { + $result = $client->assumeRoleWithWebIdentity($assumeParams); + } catch (AwsException $e) { + if ($e->getAwsErrorCode() == 'InvalidIdentityToken') { + if ($this->authenticationAttempts < $this->retries) { + sleep((int) pow(1.2, $this->authenticationAttempts)); + } else { + throw new CredentialsException( + "InvalidIdentityToken, retries exhausted" + ); + } + } else { + throw new CredentialsException( + "Error assuming role from web identity credentials", + 0, + $e + ); + } + } catch (\Exception $e) { + throw new CredentialsException( + "Error retrieving web identity credentials: " . $e->getMessage() + . " (" . $e->getCode() . ")" + ); + } + $this->authenticationAttempts++; + } + + yield $this->client->createCredentials( + $result, + $this->source + ); + }); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialProvider.php new file mode 100644 index 000000000..25535e6b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialProvider.php @@ -0,0 +1,1030 @@ + + * use Aws\Credentials\CredentialProvider; + * $provider = CredentialProvider::defaultProvider(); + * // Returns a CredentialsInterface or throws. + * $creds = $provider()->wait(); + * + * + * Credential providers can be composed to create credentials using conditional + * logic that can create different credentials in different environments. You + * can compose multiple providers into a single provider using + * {@see Aws\Credentials\CredentialProvider::chain}. This function accepts + * providers as variadic arguments and returns a new function that will invoke + * each provider until a successful set of credentials is returned. + * + * + * // First try an INI file at this location. + * $a = CredentialProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = CredentialProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = CredentialProvider::env(); + * // Combine the three providers together. + * $composed = CredentialProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with credentials or throws. + * $promise = $composed(); + * // Wait on the credentials to resolve. + * $creds = $promise->wait(); + * + */ +class CredentialProvider +{ + const ENV_ARN = 'AWS_ROLE_ARN'; + const ENV_KEY = 'AWS_ACCESS_KEY_ID'; + const ENV_PROFILE = 'AWS_PROFILE'; + const ENV_ROLE_SESSION_NAME = 'AWS_ROLE_SESSION_NAME'; + const ENV_SECRET = 'AWS_SECRET_ACCESS_KEY'; + const ENV_ACCOUNT_ID = 'AWS_ACCOUNT_ID'; + const ENV_SESSION = 'AWS_SESSION_TOKEN'; + const ENV_TOKEN_FILE = 'AWS_WEB_IDENTITY_TOKEN_FILE'; + const ENV_SHARED_CREDENTIALS_FILE = 'AWS_SHARED_CREDENTIALS_FILE'; + public const REFRESH_WINDOW = 60; + + /** + * Create a default credential provider that + * first checks for environment variables, + * then checks for assumed role via web identity, + * then checks for cached SSO credentials from the CLI, + * then check for credential_process in the "default" profile in ~/.aws/credentials, + * then checks for the "default" profile in ~/.aws/credentials, + * then for credential_process in the "default profile" profile in ~/.aws/config, + * then checks for "profile default" profile in ~/.aws/config (which is + * the default profile of AWS CLI), + * then tries to make a GET Request to fetch credentials if ECS environment variable is presented, + * finally checks for EC2 instance profile credentials. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided credentials. + * + * @param array $config Optional array of ecs/instance profile credentials + * provider options. + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $cacheable = [ + 'web_identity', + 'sso', + 'process_credentials', + 'process_config', + 'ecs', + 'instance' + ]; + + $profileName = getenv(self::ENV_PROFILE) ?: 'default'; + + $defaultChain = [ + 'env' => self::env(), + 'web_identity' => self::assumeRoleWithWebIdentityCredentialProvider($config), + ]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] !== false + ) { + $defaultChain['sso'] = self::sso( + $profileName, + self::getHomeDir() . '/.aws/config', + $config + ); + $defaultChain['process_credentials'] = self::process(); + $defaultChain['ini'] = self::ini(); + $defaultChain['process_config'] = self::process( + 'profile ' . $profileName, + self::getHomeDir() . '/.aws/config' + ); + $defaultChain['ini_config'] = self::ini( + 'profile '. $profileName, + self::getHomeDir() . '/.aws/config' + ); + } + + if (self::shouldUseEcs()) { + $defaultChain['ecs'] = self::ecsCredentials($config); + } else { + $defaultChain['instance'] = self::instanceProfile($config); + } + + if (isset($config['credentials']) + && $config['credentials'] instanceof CacheInterface + ) { + foreach ($cacheable as $provider) { + if (isset($defaultChain[$provider])) { + $defaultChain[$provider] = self::cache( + $defaultChain[$provider], + $config['credentials'], + 'aws_cached_' . $provider . '_credentials' + ); + } + } + } + + return self::memoize( + call_user_func_array( + [CredentialProvider::class, 'chain'], + array_values($defaultChain) + ) + ); + } + + /** + * Create a credential provider function from a set of static credentials. + * + * @param CredentialsInterface $creds + * + * @return callable + */ + public static function fromCredentials(CredentialsInterface $creds) + { + $promise = Promise\Create::promiseFor($creds); + + return function () use ($promise) { + return $promise; + }; + } + + /** + * Creates an aggregate credentials provider that invokes the provided + * variadic providers one after the other until a provider returns + * credentials. + * + * @return callable + */ + public static function chain() + { + $links = func_get_args(); + if (empty($links)) { + throw new \InvalidArgumentException('No providers in chain'); + } + + return function ($previousCreds = null) use ($links) { + /** @var callable $parent */ + $parent = array_shift($links); + $promise = $parent(); + while ($next = array_shift($links)) { + if ($next instanceof InstanceProfileProvider + && $previousCreds instanceof Credentials + ) { + $promise = $promise->otherwise( + function () use ($next, $previousCreds) {return $next($previousCreds);} + ); + } else { + $promise = $promise->otherwise($next); + } + } + return $promise; + }; + } + + /** + * Wraps a credential provider and caches previously provided credentials. + * + * Ensures that cached credentials are refreshed when they expire. + * + * @param callable $provider Credentials provider function to wrap. + * + * @return callable + */ + public static function memoize(callable $provider) + { + return function () use ($provider) { + static $result; + static $isConstant; + + // Constant credentials will be returned constantly. + if ($isConstant) { + return $result; + } + + // Create the initial promise that will be used as the cached value + // until it expires. + if (null === $result) { + $result = $provider(); + } + + // Return credentials that could expire and refresh when needed. + return $result + ->then(function (CredentialsInterface $creds) use ($provider, &$isConstant, &$result) { + // Determine if these are constant credentials. + if (!$creds->getExpiration()) { + $isConstant = true; + return $creds; + } + + // Check if credentials are expired or will expire in 1 minute + $needsRefresh = $creds->getExpiration() - time() <= self::REFRESH_WINDOW; + + // Refresh if expired or expiring soon + if (!$needsRefresh && !$creds->isExpired()) { + return $creds; + } + + // Refresh the result and forward the promise. + return $result = $provider($creds); + }) + ->otherwise(function($reason) use (&$result) { + // Cleanup rejected promise. + $result = null; + return new Promise\RejectedPromise($reason); + }); + }; + } + + /** + * Wraps a credential provider and saves provided credentials in an + * instance of Aws\CacheInterface. Forwards calls when no credentials found + * in cache and updates cache with the results. + * + * @param callable $provider Credentials provider function to wrap + * @param CacheInterface $cache Cache to store credentials + * @param string|null $cacheKey (optional) Cache key to use + * + * @return callable + */ + public static function cache( + callable $provider, + CacheInterface $cache, + $cacheKey = null + ) { + $cacheKey = $cacheKey ?: 'aws_cached_credentials'; + + return function () use ($provider, $cache, $cacheKey) { + $found = $cache->get($cacheKey); + if ($found instanceof CredentialsInterface && !$found->isExpired()) { + return Promise\Create::promiseFor($found); + } + + return $provider() + ->then(function (CredentialsInterface $creds) use ( + $cache, + $cacheKey + ) { + $cache->set( + $cacheKey, + $creds, + null === $creds->getExpiration() ? + 0 : $creds->getExpiration() - time() + ); + + return $creds; + }); + }; + } + + /** + * Provider that creates credentials from environment variables + * AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. + * + * @return callable + */ + public static function env() + { + return function () { + // Use credentials from environment variables, if available + $key = getenv(self::ENV_KEY); + $secret = getenv(self::ENV_SECRET); + $accountId = getenv(self::ENV_ACCOUNT_ID) ?: null; + $token = getenv(self::ENV_SESSION) ?: null; + + if ($key && $secret) { + return Promise\Create::promiseFor( + new Credentials( + $key, + $secret, + $token, + null, + $accountId, + CredentialSources::ENVIRONMENT + ) + ); + } + + return self::reject('Could not find environment variable ' + . 'credentials in ' . self::ENV_KEY . '/' . self::ENV_SECRET); + }; + } + + /** + * Credential provider that creates credentials using instance profile + * credentials. + * + * @param array $config Array of configuration data. + * + * @return InstanceProfileProvider + * @see Aws\Credentials\InstanceProfileProvider for $config details. + */ + public static function instanceProfile(array $config = []) + { + return new InstanceProfileProvider($config); + } + + /** + * Credential provider that retrieves cached SSO credentials from the CLI + * + * @return callable + */ + public static function sso($ssoProfileName = 'default', + $filename = null, + $config = [] + ) { + $filename = $filename ?: (self::getHomeDir() . '/.aws/config'); + + return function () use ($ssoProfileName, $filename, $config) { + if (!@is_readable($filename)) { + return self::reject("Cannot read credentials from $filename"); + } + $profiles = self::loadProfiles($filename); + + if (isset($profiles[$ssoProfileName])) { + $ssoProfile = $profiles[$ssoProfileName]; + } elseif (isset($profiles['profile ' . $ssoProfileName])) { + $ssoProfileName = 'profile ' . $ssoProfileName; + $ssoProfile = $profiles[$ssoProfileName]; + } else { + return self::reject("Profile {$ssoProfileName} does not exist in {$filename}."); + } + + if (!empty($ssoProfile['sso_session'])) { + return CredentialProvider::getSsoCredentials($profiles, $ssoProfileName, $filename, $config); + } else { + return CredentialProvider::getSsoCredentialsLegacy($profiles, $ssoProfileName, $filename, $config); + } + }; + } + + /** + * Credential provider that creates credentials using + * ecs credentials by a GET request, whose uri is specified + * by environment variable + * + * @param array $config Array of configuration data. + * + * @return EcsCredentialProvider + * @see Aws\Credentials\EcsCredentialProvider for $config details. + */ + public static function ecsCredentials(array $config = []) + { + return new EcsCredentialProvider($config); + } + + /** + * Credential provider that creates credentials using assume role + * + * @param array $config Array of configuration data + * @return callable + * @see Aws\Credentials\AssumeRoleCredentialProvider for $config details. + */ + public static function assumeRole(array $config=[]) + { + return new AssumeRoleCredentialProvider($config); + } + + /** + * Credential provider that creates credentials by assuming role from a + * Web Identity Token + * + * @param array $config Array of configuration data + * @return callable + * @see Aws\Credentials\AssumeRoleWithWebIdentityCredentialProvider for + * $config details. + */ + public static function assumeRoleWithWebIdentityCredentialProvider(array $config = []) + { + return function () use ($config) { + $arnFromEnv = getenv(self::ENV_ARN); + $tokenFromEnv = getenv(self::ENV_TOKEN_FILE); + $stsClient = isset($config['stsClient']) + ? $config['stsClient'] + : null; + $region = isset($config['region']) + ? $config['region'] + : null; + + if ($tokenFromEnv && $arnFromEnv) { + $sessionName = getenv(self::ENV_ROLE_SESSION_NAME) + ? getenv(self::ENV_ROLE_SESSION_NAME) + : null; + $provider = new AssumeRoleWithWebIdentityCredentialProvider([ + 'RoleArn' => $arnFromEnv, + 'WebIdentityTokenFile' => $tokenFromEnv, + 'SessionName' => $sessionName, + 'client' => $stsClient, + 'region' => $region, + 'source' => CredentialSources::ENVIRONMENT_STS_WEB_ID_TOKEN + ]); + + return $provider(); + } + + $profileName = getenv(self::ENV_PROFILE) ?: 'default'; + if (isset($config['filename'])) { + $profiles = self::loadProfiles($config['filename']); + } else { + $profiles = self::loadDefaultProfiles(); + } + + if (isset($profiles[$profileName])) { + $profile = $profiles[$profileName]; + if (isset($profile['region'])) { + $region = $profile['region']; + } + if (isset($profile['web_identity_token_file']) + && isset($profile['role_arn']) + ) { + $sessionName = isset($profile['role_session_name']) + ? $profile['role_session_name'] + : null; + $provider = new AssumeRoleWithWebIdentityCredentialProvider([ + 'RoleArn' => $profile['role_arn'], + 'WebIdentityTokenFile' => $profile['web_identity_token_file'], + 'SessionName' => $sessionName, + 'client' => $stsClient, + 'region' => $region, + 'source' => CredentialSources::PROFILE_STS_WEB_ID_TOKEN + ]); + + return $provider(); + } + } else { + return self::reject("Unknown profile: $profileName"); + } + return self::reject("No RoleArn or WebIdentityTokenFile specified"); + }; + } + + /** + * Credentials provider that creates credentials using an ini file stored + * in the current user's home directory. A source can be provided + * in this file for assuming a role using the credential_source config option. + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile in "~/.aws/credentials". + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the home directory. + * @param array|null $config If provided, may contain the following: + * preferStaticCredentials: If true, prefer static + * credentials to role_arn if both are present + * disableAssumeRole: If true, disable support for + * roles that assume an IAM role. If true and role profile + * is selected, an error is raised. + * stsClient: StsClient used to assume role specified in profile + * + * @return callable + */ + public static function ini($profile = null, $filename = null, array $config = []) + { + $filename = self::getFileName($filename); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename, $config) { + $preferStaticCredentials = isset($config['preferStaticCredentials']) + ? $config['preferStaticCredentials'] + : false; + $disableAssumeRole = isset($config['disableAssumeRole']) + ? $config['disableAssumeRole'] + : false; + $stsClient = isset($config['stsClient']) ? $config['stsClient'] : null; + + if (!@is_readable($filename)) { + return self::reject("Cannot read credentials from $filename"); + } + $data = self::loadProfiles($filename); + if ($data === false) { + return self::reject("Invalid credentials file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in credentials file"); + } + + /* + In the CLI, the presence of both a role_arn and static credentials have + different meanings depending on how many profiles have been visited. For + the first profile processed, role_arn takes precedence over any static + credentials, but for all subsequent profiles, static credentials are + used if present, and only in their absence will the profile's + source_profile and role_arn keys be used to load another set of + credentials. This bool is intended to yield compatible behaviour in this + sdk. + */ + $preferStaticCredentialsToRoleArn = ($preferStaticCredentials + && isset($data[$profile]['aws_access_key_id']) + && isset($data[$profile]['aws_secret_access_key'])); + + if (isset($data[$profile]['role_arn']) + && !$preferStaticCredentialsToRoleArn + ) { + if ($disableAssumeRole) { + return self::reject( + "Role assumption profiles are disabled. " + . "Failed to load profile " . $profile); + } + return self::loadRoleProfile( + $data, + $profile, + $filename, + $stsClient, + $config + ); + } + + if (!isset($data[$profile]['aws_access_key_id']) + || !isset($data[$profile]['aws_secret_access_key']) + ) { + return self::reject("No credentials present in INI profile " + . "'$profile' ($filename)"); + } + + if (empty($data[$profile]['aws_session_token'])) { + $data[$profile]['aws_session_token'] + = isset($data[$profile]['aws_security_token']) + ? $data[$profile]['aws_security_token'] + : null; + } + + return Promise\Create::promiseFor( + new Credentials( + $data[$profile]['aws_access_key_id'], + $data[$profile]['aws_secret_access_key'], + $data[$profile]['aws_session_token'], + null, + $data[$profile]['aws_account_id'] ?? null, + CredentialSources::PROFILE + ) + ); + }; + } + + /** + * Credentials provider that creates credentials using a process configured in + * ini file stored in the current user's home directory. + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile in "~/.aws/credentials". + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the home directory. + * + * @return callable + */ + public static function process($profile = null, $filename = null) + { + $filename = self::getFileName($filename); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read process credentials from $filename"); + } + $data = \Aws\parse_ini_file($filename, true, INI_SCANNER_RAW); + if ($data === false) { + return self::reject("Invalid credentials file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in credentials file"); + } + if (!isset($data[$profile]['credential_process'])) { + return self::reject("No credential_process present in INI profile " + . "'$profile' ($filename)"); + } + + $credentialProcess = $data[$profile]['credential_process']; + $json = shell_exec($credentialProcess); + + $processData = json_decode($json, true); + + // Only support version 1 + if (isset($processData['Version'])) { + if ($processData['Version'] !== 1) { + return self::reject("credential_process does not return Version == 1"); + } + } + + if (!isset($processData['AccessKeyId']) + || !isset($processData['SecretAccessKey'])) + { + return self::reject("credential_process does not return valid credentials"); + } + + if (isset($processData['Expiration'])) { + try { + $expiration = new DateTimeResult($processData['Expiration']); + } catch (\Exception $e) { + return self::reject("credential_process returned invalid expiration"); + } + $now = new DateTimeResult(); + if ($expiration < $now) { + return self::reject("credential_process returned expired credentials"); + } + $expires = $expiration->getTimestamp(); + } else { + $expires = null; + } + + if (empty($processData['SessionToken'])) { + $processData['SessionToken'] = null; + } + + $accountId = null; + if (!empty($processData['AccountId'])) { + $accountId = $processData['AccountId']; + } elseif (!empty($data[$profile]['aws_account_id'])) { + $accountId = $data[$profile]['aws_account_id']; + } + + return Promise\Create::promiseFor( + new Credentials( + $processData['AccessKeyId'], + $processData['SecretAccessKey'], + $processData['SessionToken'], + $expires, + $accountId, + CredentialSources::PROFILE_PROCESS + ) + ); + }; + } + + /** + * Assumes role for profile that includes role_arn + * + * @return callable + */ + private static function loadRoleProfile( + $profiles, + $profileName, + $filename, + $stsClient, + $config = [] + ) { + $roleProfile = $profiles[$profileName]; + $roleArn = isset($roleProfile['role_arn']) ? $roleProfile['role_arn'] : ''; + $roleSessionName = isset($roleProfile['role_session_name']) + ? $roleProfile['role_session_name'] + : 'aws-sdk-php-' . round(microtime(true) * 1000); + + if ( + empty($roleProfile['source_profile']) + == empty($roleProfile['credential_source']) + ) { + return self::reject("Either source_profile or credential_source must be set " . + "using profile " . $profileName . ", but not both." + ); + } + + $sourceProfileName = ""; + if (!empty($roleProfile['source_profile'])) { + $sourceProfileName = $roleProfile['source_profile']; + if (!isset($profiles[$sourceProfileName])) { + return self::reject("source_profile " . $sourceProfileName + . " using profile " . $profileName . " does not exist" + ); + } + if (isset($config['visited_profiles']) && + in_array($roleProfile['source_profile'], $config['visited_profiles']) + ) { + return self::reject("Circular source_profile reference found."); + } + $config['visited_profiles'] [] = $roleProfile['source_profile']; + } else { + if (empty($roleArn)) { + return self::reject( + "A role_arn must be provided with credential_source in " . + "file {$filename} under profile {$profileName} " + ); + } + } + + if (empty($stsClient)) { + $sourceRegion = isset($profiles[$sourceProfileName]['region']) + ? $profiles[$sourceProfileName]['region'] + : 'us-east-1'; + $config['preferStaticCredentials'] = true; + $sourceCredentials = null; + if (!empty($roleProfile['source_profile'])){ + $sourceCredentials = call_user_func( + CredentialProvider::ini($sourceProfileName, $filename, $config) + )->wait(); + } else { + $sourceCredentials = self::getCredentialsFromSource( + $profileName, + $filename + ); + } + $stsClient = new StsClient([ + 'credentials' => $sourceCredentials, + 'region' => $sourceRegion, + 'version' => '2011-06-15', + ]); + } + + $result = $stsClient->assumeRole([ + 'RoleArn' => $roleArn, + 'RoleSessionName' => $roleSessionName + ]); + $credentials = $stsClient->createCredentials( + $result, + CredentialSources::STS_ASSUME_ROLE + ); + + return Promise\Create::promiseFor($credentials); + } + + /** + * Gets the environment's HOME directory if available. + * + * @return null|string + */ + private static function getHomeDir() + { + // On Linux/Unix-like systems, use the HOME environment variable + if ($homeDir = getenv('HOME')) { + return $homeDir; + } + + // Get the HOMEDRIVE and HOMEPATH values for Windows hosts + $homeDrive = getenv('HOMEDRIVE'); + $homePath = getenv('HOMEPATH'); + + return ($homeDrive && $homePath) ? $homeDrive . $homePath : null; + } + + /** + * Gets profiles from specified $filename, or default ini files. + */ + private static function loadProfiles($filename) + { + $profileData = \Aws\parse_ini_file($filename, true, INI_SCANNER_RAW); + + // If loading .aws/credentials, also load .aws/config when AWS_SDK_LOAD_NONDEFAULT_CONFIG is set + if ($filename === self::getHomeDir() . '/.aws/credentials' + && getenv('AWS_SDK_LOAD_NONDEFAULT_CONFIG') + ) { + $configFilename = self::getHomeDir() . '/.aws/config'; + $configProfileData = \Aws\parse_ini_file($configFilename, true, INI_SCANNER_RAW); + foreach ($configProfileData as $name => $profile) { + // standardize config profile names + $name = str_replace('profile ', '', $name); + if (!isset($profileData[$name])) { + $profileData[$name] = $profile; + } + } + } + + return $profileData; + } + + /** + * Gets profiles from ~/.aws/credentials and ~/.aws/config ini files + */ + private static function loadDefaultProfiles() { + $profiles = []; + $credFile = self::getHomeDir() . '/.aws/credentials'; + $configFile = self::getHomeDir() . '/.aws/config'; + if (file_exists($credFile)) { + $profiles = \Aws\parse_ini_file($credFile, true, INI_SCANNER_RAW); + } + + if (file_exists($configFile)) { + $configProfileData = \Aws\parse_ini_file($configFile, true, INI_SCANNER_RAW); + foreach ($configProfileData as $name => $profile) { + // standardize config profile names + $name = str_replace('profile ', '', $name); + if (!isset($profiles[$name])) { + $profiles[$name] = $profile; + } + } + } + + return $profiles; + } + + public static function getCredentialsFromSource( + $profileName = '', + $filename = '', + $config = [] + ) { + $data = self::loadProfiles($filename); + $credentialSource = !empty($data[$profileName]['credential_source']) + ? $data[$profileName]['credential_source'] + : null; + $credentialsPromise = null; + + switch ($credentialSource) { + case 'Environment': + $credentialsPromise = self::env(); + break; + case 'Ec2InstanceMetadata': + $credentialsPromise = self::instanceProfile($config); + break; + case 'EcsContainer': + $credentialsPromise = self::ecsCredentials($config); + break; + default: + throw new CredentialsException( + "Invalid credential_source found in config file: {$credentialSource}. Valid inputs " + . "include Environment, Ec2InstanceMetadata, and EcsContainer." + ); + } + + $credentialsResult = null; + try { + $credentialsResult = $credentialsPromise()->wait(); + } catch (\Exception $reason) { + return self::reject( + "Unable to successfully retrieve credentials from the source specified in the" + . " credentials file: {$credentialSource}; failure message was: " + . $reason->getMessage() + ); + } + return function () use ($credentialsResult) { + return Promise\Create::promiseFor($credentialsResult); + }; + } + + private static function reject($msg) + { + return new Promise\RejectedPromise(new CredentialsException($msg)); + } + + /** + * @param $filename + * @return string + */ + private static function getFileName($filename) + { + if (!isset($filename)) { + $filename = getenv(self::ENV_SHARED_CREDENTIALS_FILE) ?: + (self::getHomeDir() . '/.aws/credentials'); + } + return $filename; + } + + /** + * @return boolean + */ + public static function shouldUseEcs() + { + //Check for relative uri. if not, then full uri. + //fall back to server for each as getenv is not thread-safe. + return !empty(getenv(EcsCredentialProvider::ENV_URI)) + || !empty($_SERVER[EcsCredentialProvider::ENV_URI]) + || !empty(getenv(EcsCredentialProvider::ENV_FULL_URI)) + || !empty($_SERVER[EcsCredentialProvider::ENV_FULL_URI]); + } + + /** + * @param $profiles + * @param $ssoProfileName + * @param $filename + * @param $config + * @return Promise\PromiseInterface + */ + private static function getSsoCredentials($profiles, $ssoProfileName, $filename, $config) + { + if (empty($config['ssoOidcClient'])) { + $ssoProfile = $profiles[$ssoProfileName]; + $sessionName = $ssoProfile['sso_session']; + if (empty($profiles['sso-session ' . $sessionName])) { + return self::reject( + "Could not find sso-session {$sessionName} in {$filename}" + ); + } + $ssoSession = $profiles['sso-session ' . $ssoProfile['sso_session']]; + $ssoOidcClient = new Aws\SSOOIDC\SSOOIDCClient([ + 'region' => $ssoSession['sso_region'], + 'version' => '2019-06-10', + 'credentials' => false + ]); + } else { + $ssoOidcClient = $config['ssoClient']; + } + + $tokenPromise = new Aws\Token\SsoTokenProvider( + $ssoProfileName, + $filename, + $ssoOidcClient + ); + $token = $tokenPromise()->wait(); + $ssoCredentials = CredentialProvider::getCredentialsFromSsoService( + $ssoProfile, + $ssoSession['sso_region'], + $token->getToken(), + $config + ); + + //Expiration value is returned in epoch milliseconds. Conversion to seconds + $expiration = intdiv($ssoCredentials['expiration'], 1000); + return Promise\Create::promiseFor( + new Credentials( + $ssoCredentials['accessKeyId'], + $ssoCredentials['secretAccessKey'], + $ssoCredentials['sessionToken'], + $expiration, + $ssoProfile['sso_account_id'], + CredentialSources::PROFILE_SSO + ) + ); + } + + /** + * @param $profiles + * @param $ssoProfileName + * @param $filename + * @param $config + * @return Promise\PromiseInterface + */ + private static function getSsoCredentialsLegacy($profiles, $ssoProfileName, $filename, $config) + { + $ssoProfile = $profiles[$ssoProfileName]; + if (empty($ssoProfile['sso_start_url']) + || empty($ssoProfile['sso_region']) + || empty($ssoProfile['sso_account_id']) + || empty($ssoProfile['sso_role_name']) + ) { + return self::reject( + "Profile {$ssoProfileName} in {$filename} must contain the following keys: " + . "sso_start_url, sso_region, sso_account_id, and sso_role_name." + ); + } + $tokenLocation = self::getHomeDir() + . '/.aws/sso/cache/' + . sha1($ssoProfile['sso_start_url']) + . ".json"; + + if (!@is_readable($tokenLocation)) { + return self::reject("Unable to read token file at $tokenLocation"); + } + $tokenData = json_decode(file_get_contents($tokenLocation), true); + if (empty($tokenData['accessToken']) || empty($tokenData['expiresAt'])) { + return self::reject( + "Token file at {$tokenLocation} must contain an access token and an expiration" + ); + } + try { + $expiration = (new DateTimeResult($tokenData['expiresAt']))->getTimestamp(); + } catch (\Exception $e) { + return self::reject("Cached SSO credentials returned an invalid expiration"); + } + $now = time(); + if ($expiration < $now) { + return self::reject("Cached SSO credentials returned expired credentials"); + } + $ssoCredentials = CredentialProvider::getCredentialsFromSsoService( + $ssoProfile, + $ssoProfile['sso_region'], + $tokenData['accessToken'], + $config + ); + return Promise\Create::promiseFor( + new Credentials( + $ssoCredentials['accessKeyId'], + $ssoCredentials['secretAccessKey'], + $ssoCredentials['sessionToken'], + $expiration, + $ssoProfile['sso_account_id'], + CredentialSources::PROFILE_SSO_LEGACY + ) + ); + } + /** + * @param array $ssoProfile + * @param string $clientRegion + * @param string $accessToken + * @param array $config + * @return array|null + */ + private static function getCredentialsFromSsoService($ssoProfile, $clientRegion, $accessToken, $config) + { + if (empty($config['ssoClient'])) { + $ssoClient = new Aws\SSO\SSOClient([ + 'region' => $clientRegion, + 'version' => '2019-06-10', + 'credentials' => false + ]); + } else { + $ssoClient = $config['ssoClient']; + } + $ssoResponse = $ssoClient->getRoleCredentials([ + 'accessToken' => $accessToken, + 'accountId' => $ssoProfile['sso_account_id'], + 'roleName' => $ssoProfile['sso_role_name'] + ]); + + $ssoCredentials = $ssoResponse['roleCredentials']; + return $ssoCredentials; + } +} + diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialSources.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialSources.php new file mode 100644 index 000000000..829aa919c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/CredentialSources.php @@ -0,0 +1,22 @@ +key = trim((string) $key); + $this->secret = trim((string) $secret); + $this->token = $token; + $this->expires = $expires; + $this->accountId = $accountId; + $this->source = $source ?? CredentialSources::STATIC; + } + + public static function __set_state(array $state) + { + return new self( + $state['key'], + $state['secret'], + $state['token'], + $state['expires'], + $state['accountId'], + $state['source'] ?? null + ); + } + + public function getAccessKeyId() + { + return $this->key; + } + + public function getSecretKey() + { + return $this->secret; + } + + public function getSecurityToken() + { + return $this->token; + } + + public function getExpiration() + { + return $this->expires; + } + + public function isExpired() + { + return $this->expires !== null && time() >= $this->expires; + } + + public function getAccountId() + { + return $this->accountId; + } + + public function getSource() + { + return $this->source; + } + + public function toArray() + { + return [ + 'key' => $this->key, + 'secret' => $this->secret, + 'token' => $this->token, + 'expires' => $this->expires, + 'accountId' => $this->accountId, + 'source' => $this->source + ]; + } + + public function serialize() + { + return json_encode($this->__serialize()); + } + + public function unserialize($serialized) + { + $data = json_decode($serialized, true); + + $this->__unserialize($data); + } + + public function __serialize() + { + return $this->toArray(); + } + + public function __unserialize($data) + { + $this->key = $data['key']; + $this->secret = $data['secret']; + $this->token = $data['token']; + $this->expires = $data['expires']; + $this->accountId = $data['accountId'] ?? null; + $this->source = $data['source'] ?? null; + } + + /** + * Internal-only. Used when IMDS is unreachable + * or returns expires credentials. + * + * @internal + */ + public function extendExpiration() { + $extension = mt_rand(5, 10); + $this->expires = time() + $extension * 60; + + $message = <<= $loopbackStart && $ipLong <= $loopbackEnd); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/EcsCredentialProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/EcsCredentialProvider.php new file mode 100644 index 000000000..e95b2b005 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/EcsCredentialProvider.php @@ -0,0 +1,262 @@ +timeout = (float) isset($config['timeout']) + ? $config['timeout'] + : (getenv(self::ENV_TIMEOUT) ?: self::DEFAULT_ENV_TIMEOUT); + $this->retries = (int) isset($config['retries']) + ? $config['retries'] + : ((int) getenv(self::ENV_RETRIES) ?: self::DEFAULT_ENV_RETRIES); + + $this->client = $config['client'] ?? \Aws\default_http_handler(); + } + + /** + * Load container credentials. + * + * @return PromiseInterface + * @throws GuzzleException + */ + public function __invoke() + { + $this->attempts = 0; + $uri = $this->getEcsUri(); + if ($this->isCompatibleUri($uri)) { + return Promise\Coroutine::of(function () { + $client = $this->client; + $request = new Request('GET', $this->getEcsUri()); + $headers = $this->getHeadersForAuthToken(); + $credentials = null; + while ($credentials === null) { + $credentials = (yield $client( + $request, + [ + 'timeout' => $this->timeout, + 'proxy' => '', + 'headers' => $headers, + ] + )->then(function (ResponseInterface $response) { + $result = $this->decodeResult((string)$response->getBody()); + if (!isset($result['AccountId']) && isset($result['RoleArn'])) { + try { + $parsedArn = new Arn($result['RoleArn']); + $result['AccountId'] = $parsedArn->getAccountId(); + } catch (\Exception $e) { + // AccountId will be null + } + } + + return new Credentials( + $result['AccessKeyId'], + $result['SecretAccessKey'], + $result['Token'], + strtotime($result['Expiration']), + $result['AccountId'] ?? null, + CredentialSources::ECS + ); + })->otherwise(function ($reason) { + $reason = is_array($reason) ? $reason['exception'] : $reason; + + $isRetryable = $reason instanceof ConnectException; + if ($isRetryable && ($this->attempts < $this->retries)) { + sleep((int)pow(1.2, $this->attempts)); + } else { + $msg = $reason->getMessage(); + throw new CredentialsException( + sprintf('Error retrieving credentials from container metadata after attempt %d/%d (%s)', $this->attempts, $this->retries, $msg) + ); + } + })); + $this->attempts++; + } + + yield $credentials; + }); + } + + throw new CredentialsException("Uri '{$uri}' contains an unsupported host."); + } + + /** + * Returns the number of attempts that have been done. + * + * @return int + */ + public function getAttempts(): int + { + return $this->attempts; + } + + /** + * Retrieves authorization token. + * + * @return array|false|string + */ + private function getEcsAuthToken() + { + if (!empty($path = getenv(self::ENV_AUTH_TOKEN_FILE))) { + $token = @file_get_contents($path); + if (false === $token) { + clearstatcache(true, dirname($path) . DIRECTORY_SEPARATOR . @readlink($path)); + clearstatcache(true, dirname($path) . DIRECTORY_SEPARATOR . dirname(@readlink($path))); + clearstatcache(true, $path); + } + + if (!is_readable($path)) { + throw new CredentialsException("Failed to read authorization token from '{$path}': no such file or directory."); + } + + $token = @file_get_contents($path); + + if (empty($token)) { + throw new CredentialsException("Invalid authorization token read from `$path`. Token file is empty!"); + } + + return $token; + } + + return getenv(self::ENV_AUTH_TOKEN); + } + + /** + * Provides headers for credential metadata request. + * + * @return array|array[]|string[] + */ + private function getHeadersForAuthToken() + { + $authToken = self::getEcsAuthToken(); + $headers = []; + + if (!empty($authToken)) + $headers = ['Authorization' => $authToken]; + + return $headers; + } + + /** @deprecated */ + public function setHeaderForAuthToken() + { + $authToken = self::getEcsAuthToken(); + $headers = []; + if (!empty($authToken)) + $headers = ['Authorization' => $authToken]; + + return $headers; + } + + /** + * Fetch container metadata URI from container environment variable. + * + * @return string Returns container metadata URI + */ + private function getEcsUri() + { + $credsUri = getenv(self::ENV_URI); + + if ($credsUri === false) { + $credsUri = $_SERVER[self::ENV_URI] ?? ''; + } + + if (empty($credsUri)){ + $credFullUri = getenv(self::ENV_FULL_URI); + if ($credFullUri === false){ + $credFullUri = $_SERVER[self::ENV_FULL_URI] ?? ''; + } + + if (!empty($credFullUri)) + return $credFullUri; + } + + return self::SERVER_URI . $credsUri; + } + + private function decodeResult($response) + { + $result = json_decode($response, true); + + if (!isset($result['AccessKeyId'])) { + throw new CredentialsException('Unexpected container metadata credentials value'); + } + return $result; + } + + /** + * Determines whether or not a given request URI is a valid + * container credential request URI. + * + * @param $uri + * + * @return bool + */ + private function isCompatibleUri($uri) + { + $parsed = parse_url($uri); + + if ($parsed['scheme'] !== 'https') { + $host = trim($parsed['host'], '[]'); + $ecsHost = parse_url(self::SERVER_URI)['host']; + $eksHost = self::EKS_SERVER_HOST_IPV4; + + if ($host !== $ecsHost + && $host !== $eksHost + && $host !== self::EKS_SERVER_HOST_IPV6 + && !CredentialsUtils::isLoopBackAddress(gethostbyname($host)) + ) { + return false; + } + } + + return true; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/InstanceProfileProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/InstanceProfileProvider.php new file mode 100644 index 000000000..c17a56413 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Credentials/InstanceProfileProvider.php @@ -0,0 +1,468 @@ +timeout = (float) getenv(self::ENV_TIMEOUT) ?: ($config['timeout'] ?? self::DEFAULT_TIMEOUT); + $this->profile = $config['profile'] ?? null; + $this->retries = (int) getenv(self::ENV_RETRIES) ?: ($config['retries'] ?? self::DEFAULT_RETRIES); + $this->client = $config['client'] ?? \Aws\default_http_handler(); + $this->ec2MetadataV1Disabled = $config[self::CFG_EC2_METADATA_V1_DISABLED] ?? null; + $this->endpoint = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT] ?? null; + if (!empty($this->endpoint) && !$this->isValidEndpoint($this->endpoint)) { + throw new \InvalidArgumentException('The provided URI "' . $this->endpoint . '" is invalid, or contains an unsupported host'); + } + + $this->endpointMode = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE] ?? null; + $this->config = $config; + } + + /** + * Loads instance profile credentials. + * + * @return PromiseInterface + */ + public function __invoke($previousCredentials = null) + { + $this->attempts = 0; + return Promise\Coroutine::of(function () use ($previousCredentials) { + + // Retrieve token or switch out of secure mode + $token = null; + while ($this->secureMode && is_null($token)) { + try { + $token = (yield $this->request( + self::TOKEN_PATH, + 'PUT', + [ + 'x-aws-ec2-metadata-token-ttl-seconds' => self::DEFAULT_TOKEN_TTL_SECONDS + ] + )); + } catch (TransferException $e) { + if ($this->getExceptionStatusCode($e) === 500 + && $previousCredentials instanceof Credentials + ) { + goto generateCredentials; + } elseif ($this->shouldFallbackToIMDSv1() + && (!method_exists($e, 'getResponse') + || empty($e->getResponse()) + || !in_array( + $e->getResponse()->getStatusCode(), + [400, 500, 502, 503, 504] + )) + ) { + $this->secureMode = false; + } else { + $this->handleRetryableException( + $e, + [], + $this->createErrorMessage( + 'Error retrieving metadata token' + ) + ); + } + } + $this->attempts++; + } + + // Set token header only for secure mode + $headers = []; + if ($this->secureMode) { + $headers = [ + 'x-aws-ec2-metadata-token' => $token + ]; + } + + // Retrieve profile + while (!$this->profile) { + try { + $this->profile = (yield $this->request( + self::CRED_PATH, + 'GET', + $headers + )); + } catch (TransferException $e) { + // 401 indicates insecure flow not supported, switch to + // attempting secure mode for subsequent calls + if (!empty($this->getExceptionStatusCode($e)) + && $this->getExceptionStatusCode($e) === 401 + ) { + $this->secureMode = true; + } + $this->handleRetryableException( + $e, + [ 'blacklist' => [401, 403] ], + $this->createErrorMessage($e->getMessage()) + ); + } + + $this->attempts++; + } + + // Retrieve credentials + $result = null; + while ($result == null) { + try { + $json = (yield $this->request( + self::CRED_PATH . $this->profile, + 'GET', + $headers + )); + $result = $this->decodeResult($json); + } catch (InvalidJsonException $e) { + $this->handleRetryableException( + $e, + [ 'blacklist' => [401, 403] ], + $this->createErrorMessage( + 'Invalid JSON response, retries exhausted' + ) + ); + } catch (TransferException $e) { + // 401 indicates insecure flow not supported, switch to + // attempting secure mode for subsequent calls + if (($this->getExceptionStatusCode($e) === 500 + || strpos($e->getMessage(), "cURL error 28") !== false) + && $previousCredentials instanceof Credentials + ) { + goto generateCredentials; + } elseif (!empty($this->getExceptionStatusCode($e)) + && $this->getExceptionStatusCode($e) === 401 + ) { + $this->secureMode = true; + } + $this->handleRetryableException( + $e, + [ 'blacklist' => [401, 403] ], + $this->createErrorMessage($e->getMessage()) + ); + } + $this->attempts++; + } + generateCredentials: + + if (!isset($result)) { + $credentials = $previousCredentials; + } else { + $credentials = new Credentials( + $result['AccessKeyId'], + $result['SecretAccessKey'], + $result['Token'], + strtotime($result['Expiration']), + $result['AccountId'] ?? null, + CredentialSources::IMDS + ); + } + + if ($credentials->isExpired()) { + $credentials->extendExpiration(); + } + + yield $credentials; + }); + } + + /** + * @param string $url + * @param string $method + * @param array $headers + * @return PromiseInterface Returns a promise that is fulfilled with the + * body of the response as a string. + */ + private function request($url, $method = 'GET', $headers = []) + { + $disabled = getenv(self::ENV_DISABLE) ?: false; + if (strcasecmp($disabled, 'true') === 0) { + throw new CredentialsException( + $this->createErrorMessage('EC2 metadata service access disabled') + ); + } + + $fn = $this->client; + $request = new Request($method, $this->resolveEndpoint() . $url); + $userAgent = 'aws-sdk-php/' . Sdk::VERSION; + if (defined('HHVM_VERSION')) { + $userAgent .= ' HHVM/' . HHVM_VERSION; + } + $userAgent .= ' ' . \Aws\default_user_agent(); + $request = $request->withHeader('User-Agent', $userAgent); + foreach ($headers as $key => $value) { + $request = $request->withHeader($key, $value); + } + + return $fn($request, ['timeout' => $this->timeout]) + ->then(function (ResponseInterface $response) { + return (string) $response->getBody(); + })->otherwise(function (array $reason) { + $reason = $reason['exception']; + if ($reason instanceof TransferException) { + throw $reason; + } + $msg = $reason->getMessage(); + throw new CredentialsException( + $this->createErrorMessage($msg) + ); + }); + } + + private function handleRetryableException( + \Exception $e, + $retryOptions, + $message + ) { + $isRetryable = true; + if (!empty($status = $this->getExceptionStatusCode($e)) + && isset($retryOptions['blacklist']) + && in_array($status, $retryOptions['blacklist']) + ) { + $isRetryable = false; + } + if ($isRetryable && $this->attempts < $this->retries) { + sleep((int) pow(1.2, $this->attempts)); + } else { + throw new CredentialsException($message); + } + } + + private function getExceptionStatusCode(\Exception $e) + { + if (method_exists($e, 'getResponse') + && !empty($e->getResponse()) + ) { + return $e->getResponse()->getStatusCode(); + } + return null; + } + + private function createErrorMessage($previous) + { + return "Error retrieving credentials from the instance profile " + . "metadata service. ({$previous})"; + } + + private function decodeResult($response) + { + $result = json_decode($response, true); + + if (json_last_error() > 0) { + throw new InvalidJsonException(); + } + + if ($result['Code'] !== 'Success') { + throw new CredentialsException('Unexpected instance profile ' + . 'response code: ' . $result['Code']); + } + + return $result; + } + + /** + * This functions checks for whether we should fall back to IMDSv1 or not. + * If $ec2MetadataV1Disabled is null then we will try to resolve this value from + * the following sources: + * - From environment: "AWS_EC2_METADATA_V1_DISABLED". + * - From config file: aws_ec2_metadata_v1_disabled + * - Defaulted to false + * + * @return bool + */ + private function shouldFallbackToIMDSv1(): bool + { + $isImdsV1Disabled = \Aws\boolean_value($this->ec2MetadataV1Disabled) + ?? \Aws\boolean_value( + ConfigurationResolver::resolve( + self::CFG_EC2_METADATA_V1_DISABLED, + self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED, + 'bool', + $this->config + ) + ) + ?? self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED; + + return !$isImdsV1Disabled; + } + + /** + * Resolves the metadata service endpoint. If the endpoint is not provided + * or configured then, the default endpoint, based on the endpoint mode resolved, + * will be used. + * Example: if endpoint_mode is resolved to be IPv4 and the endpoint is not provided + * then, the endpoint to be used will be http://169.254.169.254. + * + * @return string + */ + private function resolveEndpoint(): string + { + $endpoint = $this->endpoint; + if (is_null($endpoint)) { + $endpoint = ConfigurationResolver::resolve( + self::CFG_EC2_METADATA_SERVICE_ENDPOINT, + $this->getDefaultEndpoint(), + 'string', + $this->config + ); + } + + if (!$this->isValidEndpoint($endpoint)) { + throw new CredentialsException('The provided URI "' . $endpoint . '" is invalid, or contains an unsupported host'); + } + + if (substr($endpoint, strlen($endpoint) - 1) !== '/') { + $endpoint = $endpoint . '/'; + } + + return $endpoint . 'latest/'; + } + + /** + * Resolves the default metadata service endpoint. + * If endpoint_mode is resolved as IPv4 then: + * - endpoint = http://169.254.169.254 + * If endpoint_mode is resolved as IPv6 then: + * - endpoint = http://[fd00:ec2::254] + * + * @return string + */ + private function getDefaultEndpoint(): string + { + $endpointMode = $this->resolveEndpointMode(); + switch ($endpointMode) { + case self::ENDPOINT_MODE_IPv4: + return self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT; + case self::ENDPOINT_MODE_IPv6: + return self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT; + } + + throw new CredentialsException("Invalid endpoint mode '$endpointMode' resolved"); + } + + /** + * Resolves the endpoint mode to be considered when resolving the default + * metadata service endpoint. + * + * @return string + */ + private function resolveEndpointMode(): string + { + $endpointMode = $this->endpointMode; + if (is_null($endpointMode)) { + $endpointMode = ConfigurationResolver::resolve( + self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE, + self::ENDPOINT_MODE_IPv4, + 'string', + $this->config + ); + } + + return $endpointMode; + } + + /** + * This method checks for whether a provide URI is valid. + * @param string $uri this parameter is the uri to do the validation against to. + * + * @return string|null + */ + private function isValidEndpoint( + $uri + ): bool + { + // We make sure first the provided uri is a valid URL + $isValidURL = filter_var($uri, FILTER_VALIDATE_URL) !== false; + if (!$isValidURL) { + return false; + } + + // We make sure that if is a no secure host then it must be a loop back address. + $parsedUri = parse_url($uri); + if ($parsedUri['scheme'] !== 'https') { + $host = trim($parsedUri['host'], '[]'); + + return CredentialsUtils::isLoopBackAddress(gethostbyname($host)) + || in_array( + $uri, + [self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT, self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT] + ); + } + + return true; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AbstractCryptoClient.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AbstractCryptoClient.php new file mode 100644 index 000000000..823467b78 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AbstractCryptoClient.php @@ -0,0 +1,121 @@ +stream = $cipherText; + $this->key = $key; + $this->cipherMethod = clone $cipherMethod; + } + + public function getOpenSslName() + { + return $this->cipherMethod->getOpenSslName(); + } + + public function getAesName() + { + return $this->cipherMethod->getAesName(); + } + + public function getCurrentIv() + { + return $this->cipherMethod->getCurrentIv(); + } + + public function getSize(): ?int + { + $plainTextSize = $this->stream->getSize(); + + if ($this->cipherMethod->requiresPadding()) { + // PKCS7 padding requires that between 1 and self::BLOCK_SIZE be + // added to the plaintext to make it an even number of blocks. The + // plaintext is between strlen($cipherText) - self::BLOCK_SIZE and + // strlen($cipherText) - 1 + return null; + } + + return $plainTextSize; + } + + public function isWritable(): bool + { + return false; + } + + public function read($length): string + { + if ($length > strlen($this->buffer)) { + $this->buffer .= $this->decryptBlock( + (int) ( + self::BLOCK_SIZE * ceil(($length - strlen($this->buffer)) / self::BLOCK_SIZE) + ) + ); + } + + $data = substr($this->buffer, 0, $length); + $this->buffer = substr($this->buffer, $length); + + return $data ? $data : ''; + } + + public function seek($offset, $whence = SEEK_SET): void + { + if ($offset === 0 && $whence === SEEK_SET) { + $this->buffer = ''; + $this->cipherMethod->seek(0, SEEK_SET); + $this->stream->seek(0, SEEK_SET); + } else { + throw new LogicException('AES encryption streams only support being' + . ' rewound, not arbitrary seeking.'); + } + } + + private function decryptBlock($length) + { + if ($this->stream->eof()) { + return ''; + } + + $cipherText = ''; + do { + $cipherText .= $this->stream->read((int) ($length - strlen($cipherText))); + } while (strlen($cipherText) < $length && !$this->stream->eof()); + + $options = OPENSSL_RAW_DATA; + if (!$this->stream->eof() + && $this->stream->getSize() !== $this->stream->tell() + ) { + $options |= OPENSSL_ZERO_PADDING; + } + + $plaintext = openssl_decrypt( + $cipherText, + $this->cipherMethod->getOpenSslName(), + $this->key, + $options, + $this->cipherMethod->getCurrentIv() + ); + + $this->cipherMethod->update($cipherText); + + return $plaintext; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesEncryptingStream.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesEncryptingStream.php new file mode 100644 index 000000000..2cb5ab696 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesEncryptingStream.php @@ -0,0 +1,151 @@ +stream = $plainText; + $this->key = $key; + $this->cipherMethod = clone $cipherMethod; + } + + public function getOpenSslName() + { + return $this->cipherMethod->getOpenSslName(); + } + + public function getAesName() + { + return $this->cipherMethod->getAesName(); + } + + public function getCurrentIv() + { + return $this->cipherMethod->getCurrentIv(); + } + + public function getSize(): ?int + { + $plainTextSize = $this->stream->getSize(); + + if ($this->cipherMethod->requiresPadding() && $plainTextSize !== null) { + // PKCS7 padding requires that between 1 and self::BLOCK_SIZE be + // added to the plaintext to make it an even number of blocks. + $padding = self::BLOCK_SIZE - $plainTextSize % self::BLOCK_SIZE; + return $plainTextSize + $padding; + } + + return $plainTextSize; + } + + public function isWritable(): bool + { + return false; + } + + public function read($length): string + { + if ($length > strlen($this->buffer)) { + $this->buffer .= $this->encryptBlock( + (int) + self::BLOCK_SIZE * ceil(($length - strlen($this->buffer)) / self::BLOCK_SIZE) + ); + } + + $data = substr($this->buffer, 0, $length); + $this->buffer = substr($this->buffer, $length); + + return $data ? $data : ''; + } + + public function seek($offset, $whence = SEEK_SET): void + { + if ($whence === SEEK_CUR) { + $offset = $this->tell() + $offset; + $whence = SEEK_SET; + } + + if ($whence === SEEK_SET) { + $this->buffer = ''; + $wholeBlockOffset + = (int) ($offset / self::BLOCK_SIZE) * self::BLOCK_SIZE; + $this->stream->seek($wholeBlockOffset); + $this->cipherMethod->seek($wholeBlockOffset); + $this->read($offset - $wholeBlockOffset); + } else { + throw new LogicException('Unrecognized whence.'); + } + } + + private function encryptBlock($length) + { + if ($this->stream->eof()) { + return ''; + } + + $plainText = ''; + do { + $plainText .= $this->stream->read((int) ($length - strlen($plainText))); + } while (strlen($plainText) < $length && !$this->stream->eof()); + + $options = OPENSSL_RAW_DATA; + if (!$this->stream->eof() + || $this->stream->getSize() !== $this->stream->tell() + ) { + $options |= OPENSSL_ZERO_PADDING; + } + + $cipherText = openssl_encrypt( + $plainText, + $this->cipherMethod->getOpenSslName(), + $this->key, + $options, + $this->cipherMethod->getCurrentIv() + ); + + $this->cipherMethod->update($cipherText); + + return $cipherText; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmDecryptingStream.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmDecryptingStream.php new file mode 100644 index 000000000..d3a5d11da --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmDecryptingStream.php @@ -0,0 +1,104 @@ +cipherText = $cipherText; + $this->key = $key; + $this->initializationVector = $initializationVector; + $this->tag = $tag; + $this->aad = $aad; + $this->tagLength = $tagLength; + $this->keySize = $keySize; + // unsetting the property forces the first access to go through + // __get(). + unset($this->stream); + } + + public function getOpenSslName() + { + return "aes-{$this->keySize}-gcm"; + } + + public function getAesName() + { + return 'AES/GCM/NoPadding'; + } + + public function getCurrentIv() + { + return $this->initializationVector; + } + + public function createStream() + { + + $result = \openssl_decrypt( + (string)$this->cipherText, + $this->getOpenSslName(), + $this->key, + OPENSSL_RAW_DATA, + $this->initializationVector, + $this->tag, + $this->aad + ); + if ($result === false) { + throw new CryptoException('The requested object could not be ' + . 'decrypted due to an invalid authentication tag.'); + } + return Psr7\Utils::streamFor($result); + + } + + public function isWritable(): bool + { + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmEncryptingStream.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmEncryptingStream.php new file mode 100644 index 000000000..ab2e5fad1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesGcmEncryptingStream.php @@ -0,0 +1,119 @@ +plaintext = $plaintext; + $this->key = $key; + $this->initializationVector = $initializationVector; + $this->aad = $aad; + $this->tagLength = $tagLength; + $this->keySize = $keySize; + // unsetting the property forces the first access to go through + // __get(). + unset($this->stream); + } + + public function getOpenSslName() + { + return "aes-{$this->keySize}-gcm"; + } + + /** + * Same as static method and retained for backwards compatibility + * + * @return string + */ + public function getAesName() + { + return self::getStaticAesName(); + } + + public function getCurrentIv() + { + return $this->initializationVector; + } + + public function createStream() + { + return Psr7\Utils::streamFor(\openssl_encrypt( + (string)$this->plaintext, + $this->getOpenSslName(), + $this->key, + OPENSSL_RAW_DATA, + $this->initializationVector, + $this->tag, + $this->aad, + $this->tagLength + )); + } + + /** + * @return string + */ + public function getTag() + { + return $this->tag; + } + + public function isWritable(): bool + { + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesStreamInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesStreamInterface.php new file mode 100644 index 000000000..ce7b85d7e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/AesStreamInterface.php @@ -0,0 +1,30 @@ +baseIv = $this->iv = $iv; + $this->keySize = $keySize; + + if (strlen($iv) !== openssl_cipher_iv_length($this->getOpenSslName())) { + throw new InvalidArgumentException('Invalid initialization vector'); + } + } + + public function getOpenSslName() + { + return "aes-{$this->keySize}-cbc"; + } + + public function getAesName() + { + return 'AES/CBC/PKCS5Padding'; + } + + public function getCurrentIv() + { + return $this->iv; + } + + public function requiresPadding() + { + return true; + } + + public function seek($offset, $whence = SEEK_SET) + { + if ($offset === 0 && $whence === SEEK_SET) { + $this->iv = $this->baseIv; + } else { + throw new LogicException('CBC initialization only support being' + . ' rewound, not arbitrary seeking.'); + } + } + + public function update($cipherTextBlock) + { + $this->iv = substr($cipherTextBlock, self::BLOCK_SIZE * -1); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/Cipher/CipherBuilderTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/Cipher/CipherBuilderTrait.php new file mode 100644 index 000000000..ed9feb9a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/Cipher/CipherBuilderTrait.php @@ -0,0 +1,72 @@ +decryptCek( + base64_decode( + $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] + ), + json_decode( + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER], + true + ) + ); + $cipherOptions['KeySize'] = strlen($cek) * 8; + $cipherOptions['Cipher'] = $this->getCipherFromAesName( + $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] + ); + + $decryptionStream = $this->getDecryptingStream( + $cipherText, + $cek, + $cipherOptions + ); + unset($cek); + + return $decryptionStream; + } + + private function getTagFromCiphertextStream( + StreamInterface $cipherText, + $tagLength + ) { + $cipherTextSize = $cipherText->getSize(); + if ($cipherTextSize == null || $cipherTextSize <= 0) { + throw new \RuntimeException('Cannot decrypt a stream of unknown' + . ' size.'); + } + return (string) new LimitStream( + $cipherText, + $tagLength, + $cipherTextSize - $tagLength + ); + } + + private function getStrippedCiphertextStream( + StreamInterface $cipherText, + $tagLength + ) { + $cipherTextSize = $cipherText->getSize(); + if ($cipherTextSize == null || $cipherTextSize <= 0) { + throw new \RuntimeException('Cannot decrypt a stream of unknown' + . ' size.'); + } + return new LimitStream( + $cipherText, + $cipherTextSize - $tagLength, + 0 + ); + } + + /** + * Generates a stream that wraps the cipher text with the proper cipher and + * uses the content encryption key (CEK) to decrypt the data when read. + * + * @param string $cipherText Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param string $cek A content encryption key for use by the stream for + * encrypting the plaintext data. + * @param array $cipherOptions Options for use in determining the cipher to + * be used for encrypting data. + * + * @return AesStreamInterface + * + * @internal + */ + protected function getDecryptingStream( + $cipherText, + $cek, + $cipherOptions + ) { + $cipherTextStream = Psr7\Utils::streamFor($cipherText); + switch ($cipherOptions['Cipher']) { + case 'gcm': + $cipherOptions['Tag'] = $this->getTagFromCiphertextStream( + $cipherTextStream, + $cipherOptions['TagLength'] + ); + + return new AesGcmDecryptingStream( + $this->getStrippedCiphertextStream( + $cipherTextStream, + $cipherOptions['TagLength'] + ), + $cek, + $cipherOptions['Iv'], + $cipherOptions['Tag'], + $cipherOptions['Aad'] = isset($cipherOptions['Aad']) + ? $cipherOptions['Aad'] + : '', + $cipherOptions['TagLength'] ?: null, + $cipherOptions['KeySize'] + ); + default: + $cipherMethod = $this->buildCipherMethod( + $cipherOptions['Cipher'], + $cipherOptions['Iv'], + $cipherOptions['KeySize'] + ); + return new AesDecryptingStream( + $cipherTextStream, + $cek, + $cipherMethod + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/DecryptionTraitV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/DecryptionTraitV2.php new file mode 100644 index 000000000..ed63e0bef --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/DecryptionTraitV2.php @@ -0,0 +1,249 @@ +decryptCek( + base64_decode( + $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] + ), + json_decode( + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER], + true + ), + $options + ); + $options['@CipherOptions']['KeySize'] = strlen($cek) * 8; + $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName( + $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] + ); + + $this->validateOptionsAndEnvelope($options, $envelope); + + $decryptionStream = $this->getDecryptingStream( + $cipherText, + $cek, + $options['@CipherOptions'] + ); + unset($cek); + + return $decryptionStream; + } + + private function getTagFromCiphertextStream( + StreamInterface $cipherText, + $tagLength + ) { + $cipherTextSize = $cipherText->getSize(); + if ($cipherTextSize == null || $cipherTextSize <= 0) { + throw new \RuntimeException('Cannot decrypt a stream of unknown' + . ' size.'); + } + return (string) new LimitStream( + $cipherText, + $tagLength, + $cipherTextSize - $tagLength + ); + } + + private function getStrippedCiphertextStream( + StreamInterface $cipherText, + $tagLength + ) { + $cipherTextSize = $cipherText->getSize(); + if ($cipherTextSize == null || $cipherTextSize <= 0) { + throw new \RuntimeException('Cannot decrypt a stream of unknown' + . ' size.'); + } + return new LimitStream( + $cipherText, + $cipherTextSize - $tagLength, + 0 + ); + } + + private function validateOptionsAndEnvelope($options, $envelope) + { + $allowedCiphers = AbstractCryptoClientV2::$supportedCiphers; + $allowedKeywraps = AbstractCryptoClientV2::$supportedKeyWraps; + if ($options['@SecurityProfile'] == 'V2_AND_LEGACY') { + $allowedCiphers = array_unique(array_merge( + $allowedCiphers, + AbstractCryptoClient::$supportedCiphers + )); + $allowedKeywraps = array_unique(array_merge( + $allowedKeywraps, + AbstractCryptoClient::$supportedKeyWraps + )); + } + + $v1SchemaException = new CryptoException("The requested object is encrypted" + . " with V1 encryption schemas that have been disabled by" + . " client configuration @SecurityProfile=V2. Retry with" + . " V2_AND_LEGACY enabled or reencrypt the object."); + + if (!in_array($options['@CipherOptions']['Cipher'], $allowedCiphers)) { + if (in_array($options['@CipherOptions']['Cipher'], AbstractCryptoClient::$supportedCiphers)) { + throw $v1SchemaException; + } + throw new CryptoException("The requested object is encrypted with" + . " the cipher '{$options['@CipherOptions']['Cipher']}', which is not" + . " supported for decryption with the selected security profile." + . " This profile allows decryption with: " + . implode(", ", $allowedCiphers)); + } + if (!in_array( + $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], + $allowedKeywraps + )) { + if (in_array( + $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], + AbstractCryptoClient::$supportedKeyWraps) + ) { + throw $v1SchemaException; + } + throw new CryptoException("The requested object is encrypted with" + . " the keywrap schema '{$envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER]}'," + . " which is not supported for decryption with the current security" + . " profile."); + } + + $matdesc = json_decode( + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER], + true + ); + if (isset($matdesc['aws:x-amz-cek-alg']) + && $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] !== + $matdesc['aws:x-amz-cek-alg'] + ) { + throw new CryptoException("There is a mismatch in specified content" + . " encryption algrithm between the materials description value" + . " and the metadata envelope value: {$matdesc['aws:x-amz-cek-alg']}" + . " vs. {$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]}."); + } + } + + /** + * Generates a stream that wraps the cipher text with the proper cipher and + * uses the content encryption key (CEK) to decrypt the data when read. + * + * @param string $cipherText Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param string $cek A content encryption key for use by the stream for + * encrypting the plaintext data. + * @param array $cipherOptions Options for use in determining the cipher to + * be used for encrypting data. + * + * @return AesStreamInterface + * + * @internal + */ + protected function getDecryptingStream( + $cipherText, + $cek, + $cipherOptions + ) { + $cipherTextStream = Psr7\Utils::streamFor($cipherText); + switch ($cipherOptions['Cipher']) { + case 'gcm': + $cipherOptions['Tag'] = $this->getTagFromCiphertextStream( + $cipherTextStream, + $cipherOptions['TagLength'] + ); + + return new AesGcmDecryptingStream( + $this->getStrippedCiphertextStream( + $cipherTextStream, + $cipherOptions['TagLength'] + ), + $cek, + $cipherOptions['Iv'], + $cipherOptions['Tag'], + $cipherOptions['Aad'] = isset($cipherOptions['Aad']) + ? $cipherOptions['Aad'] + : '', + $cipherOptions['TagLength'] ?: null, + $cipherOptions['KeySize'] + ); + default: + $cipherMethod = $this->buildCipherMethod( + $cipherOptions['Cipher'], + $cipherOptions['Iv'], + $cipherOptions['KeySize'] + ); + return new AesDecryptingStream( + $cipherTextStream, + $cek, + $cipherMethod + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTrait.php new file mode 100644 index 000000000..fcddba695 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTrait.php @@ -0,0 +1,192 @@ + true, + 'KeySize' => true, + 'Aad' => true, + ]; + + /** + * Dependency to generate a CipherMethod from a set of inputs for loading + * in to an AesEncryptingStream. + * + * @param string $cipherName Name of the cipher to generate for encrypting. + * @param string $iv Base Initialization Vector for the cipher. + * @param int $keySize Size of the encryption key, in bits, that will be + * used. + * + * @return Cipher\CipherMethod + * + * @internal + */ + abstract protected function buildCipherMethod($cipherName, $iv, $keySize); + + /** + * Builds an AesStreamInterface and populates encryption metadata into the + * supplied envelope. + * + * @param Stream $plaintext Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param array $cipherOptions Options for use in determining the cipher to + * be used for encrypting data. + * @param MaterialsProvider $provider A provider to supply and encrypt + * materials used in encryption. + * @param MetadataEnvelope $envelope A storage envelope for encryption + * metadata to be added to. + * + * @return AesStreamInterface + * + * @throws \InvalidArgumentException Thrown when a value in $cipherOptions + * is not valid. + * + * @internal + */ + public function encrypt( + Stream $plaintext, + array $cipherOptions, + MaterialsProvider $provider, + MetadataEnvelope $envelope + ) { + $materialsDescription = $provider->getMaterialsDescription(); + + $cipherOptions = array_intersect_key( + $cipherOptions, + self::$allowedOptions + ); + + if (empty($cipherOptions['Cipher'])) { + throw new \InvalidArgumentException('An encryption cipher must be' + . ' specified in the "cipher_options".'); + } + + if (!self::isSupportedCipher($cipherOptions['Cipher'])) { + throw new \InvalidArgumentException('The cipher requested is not' + . ' supported by the SDK.'); + } + + if (empty($cipherOptions['KeySize'])) { + $cipherOptions['KeySize'] = 256; + } + if (!is_int($cipherOptions['KeySize'])) { + throw new \InvalidArgumentException('The cipher "KeySize" must be' + . ' an integer.'); + } + + if (!MaterialsProvider::isSupportedKeySize( + $cipherOptions['KeySize'] + )) { + throw new \InvalidArgumentException('The cipher "KeySize" requested' + . ' is not supported by AES (128, 192, or 256).'); + } + + $cipherOptions['Iv'] = $provider->generateIv( + $this->getCipherOpenSslName( + $cipherOptions['Cipher'], + $cipherOptions['KeySize'] + ) + ); + + $cek = $provider->generateCek($cipherOptions['KeySize']); + + list($encryptingStream, $aesName) = $this->getEncryptingStream( + $plaintext, + $cek, + $cipherOptions + ); + + // Populate envelope data + $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] = + $provider->encryptCek( + $cek, + $materialsDescription + ); + unset($cek); + + $envelope[MetadataEnvelope::IV_HEADER] = + base64_encode($cipherOptions['Iv']); + $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] = + $provider->getWrapAlgorithmName(); + $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName; + $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] = + strlen($plaintext); + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] = + json_encode($materialsDescription); + if (!empty($cipherOptions['Tag'])) { + $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] = + strlen($cipherOptions['Tag']) * 8; + } + + return $encryptingStream; + } + + /** + * Generates a stream that wraps the plaintext with the proper cipher and + * uses the content encryption key (CEK) to encrypt the data when read. + * + * @param Stream $plaintext Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param string $cek A content encryption key for use by the stream for + * encrypting the plaintext data. + * @param array $cipherOptions Options for use in determining the cipher to + * be used for encrypting data. + * + * @return array returns an array with two elements as follows: [string, AesStreamInterface] + * + * @internal + */ + protected function getEncryptingStream( + Stream $plaintext, + $cek, + &$cipherOptions + ) { + switch ($cipherOptions['Cipher']) { + case 'gcm': + $cipherOptions['TagLength'] = 16; + + $cipherTextStream = new AesGcmEncryptingStream( + $plaintext, + $cek, + $cipherOptions['Iv'], + $cipherOptions['Aad'] = isset($cipherOptions['Aad']) + ? $cipherOptions['Aad'] + : '', + $cipherOptions['TagLength'], + $cipherOptions['KeySize'] + ); + + if (!empty($cipherOptions['Aad'])) { + trigger_error("'Aad' has been supplied for content encryption" + . " with " . $cipherTextStream->getAesName() . ". The" + . " PHP SDK encryption client can decrypt an object" + . " encrypted in this way, but other AWS SDKs may not be" + . " able to.", E_USER_WARNING); + } + + $appendStream = new AppendStream([ + $cipherTextStream->createStream() + ]); + $cipherOptions['Tag'] = $cipherTextStream->getTag(); + $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag'])); + return [$appendStream, $cipherTextStream->getAesName()]; + default: + $cipherMethod = $this->buildCipherMethod( + $cipherOptions['Cipher'], + $cipherOptions['Iv'], + $cipherOptions['KeySize'] + ); + $cipherTextStream = new AesEncryptingStream( + $plaintext, + $cek, + $cipherMethod + ); + return [$cipherTextStream, $cipherTextStream->getAesName()]; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTraitV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTraitV2.php new file mode 100644 index 000000000..2bce1833b --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/EncryptionTraitV2.php @@ -0,0 +1,196 @@ + true, + 'KeySize' => true, + 'Aad' => true, + ]; + + private static $encryptClasses = [ + 'gcm' => AesGcmEncryptingStream::class + ]; + + /** + * Dependency to generate a CipherMethod from a set of inputs for loading + * in to an AesEncryptingStream. + * + * @param string $cipherName Name of the cipher to generate for encrypting. + * @param string $iv Base Initialization Vector for the cipher. + * @param int $keySize Size of the encryption key, in bits, that will be + * used. + * + * @return Cipher\CipherMethod + * + * @internal + */ + abstract protected function buildCipherMethod($cipherName, $iv, $keySize); + + /** + * Builds an AesStreamInterface and populates encryption metadata into the + * supplied envelope. + * + * @param Stream $plaintext Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param array $options Options for use in encryption, including cipher + * options, and encryption context. + * @param MaterialsProviderV2 $provider A provider to supply and encrypt + * materials used in encryption. + * @param MetadataEnvelope $envelope A storage envelope for encryption + * metadata to be added to. + * + * @return StreamInterface + * + * @throws \InvalidArgumentException Thrown when a value in $options['@CipherOptions'] + * is not valid. + *s + * @internal + */ + public function encrypt( + Stream $plaintext, + array $options, + MaterialsProviderV2 $provider, + MetadataEnvelope $envelope + ) { + $options = array_change_key_case($options); + $cipherOptions = array_intersect_key( + $options['@cipheroptions'], + self::$allowedOptions + ); + + if (empty($cipherOptions['Cipher'])) { + throw new \InvalidArgumentException('An encryption cipher must be' + . ' specified in @CipherOptions["Cipher"].'); + } + + $cipherOptions['Cipher'] = strtolower($cipherOptions['Cipher']); + + if (!self::isSupportedCipher($cipherOptions['Cipher'])) { + throw new \InvalidArgumentException('The cipher requested is not' + . ' supported by the SDK.'); + } + + if (empty($cipherOptions['KeySize'])) { + $cipherOptions['KeySize'] = 256; + } + if (!is_int($cipherOptions['KeySize'])) { + throw new \InvalidArgumentException('The cipher "KeySize" must be' + . ' an integer.'); + } + + if (!MaterialsProviderV2::isSupportedKeySize( + $cipherOptions['KeySize'] + )) { + throw new \InvalidArgumentException('The cipher "KeySize" requested' + . ' is not supported by AES (128 or 256).'); + } + + $cipherOptions['Iv'] = $provider->generateIv( + $this->getCipherOpenSslName( + $cipherOptions['Cipher'], + $cipherOptions['KeySize'] + ) + ); + + $encryptClass = self::$encryptClasses[$cipherOptions['Cipher']]; + $aesName = $encryptClass::getStaticAesName(); + $materialsDescription = ['aws:x-amz-cek-alg' => $aesName]; + + $keys = $provider->generateCek( + $cipherOptions['KeySize'], + $materialsDescription, + $options + ); + + // Some providers modify materials description based on options + if (isset($keys['UpdatedContext'])) { + $materialsDescription = $keys['UpdatedContext']; + } + + $encryptingStream = $this->getEncryptingStream( + $plaintext, + $keys['Plaintext'], + $cipherOptions + ); + + // Populate envelope data + $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] = $keys['Ciphertext']; + unset($keys); + + $envelope[MetadataEnvelope::IV_HEADER] = + base64_encode($cipherOptions['Iv']); + $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] = + $provider->getWrapAlgorithmName(); + $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName; + $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] = + strlen($plaintext); + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] = + json_encode($materialsDescription); + if (!empty($cipherOptions['Tag'])) { + $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] = + strlen($cipherOptions['Tag']) * 8; + } + + return $encryptingStream; + } + + /** + * Generates a stream that wraps the plaintext with the proper cipher and + * uses the content encryption key (CEK) to encrypt the data when read. + * + * @param Stream $plaintext Plain-text data to be encrypted using the + * materials, algorithm, and data provided. + * @param string $cek A content encryption key for use by the stream for + * encrypting the plaintext data. + * @param array $cipherOptions Options for use in determining the cipher to + * be used for encrypting data. + * + * @return array returns an array with two elements as follows: [string, AesStreamInterface] + * + * @internal + */ + protected function getEncryptingStream( + Stream $plaintext, + $cek, + &$cipherOptions + ) { + switch ($cipherOptions['Cipher']) { + // Only 'gcm' is supported for encryption currently + case 'gcm': + $cipherOptions['TagLength'] = 16; + $encryptClass = self::$encryptClasses['gcm']; + $cipherTextStream = new $encryptClass( + $plaintext, + $cek, + $cipherOptions['Iv'], + $cipherOptions['Aad'] = isset($cipherOptions['Aad']) + ? $cipherOptions['Aad'] + : '', + $cipherOptions['TagLength'], + $cipherOptions['KeySize'] + ); + + if (!empty($cipherOptions['Aad'])) { + trigger_error("'Aad' has been supplied for content encryption" + . " with " . $cipherTextStream->getAesName() . ". The" + . " PHP SDK encryption client can decrypt an object" + . " encrypted in this way, but other AWS SDKs may not be" + . " able to.", E_USER_WARNING); + } + + $appendStream = new AppendStream([ + $cipherTextStream->createStream() + ]); + $cipherOptions['Tag'] = $cipherTextStream->getTag(); + $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag'])); + return $appendStream; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProvider.php new file mode 100644 index 000000000..fc75138b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProvider.php @@ -0,0 +1,121 @@ +kmsClient = $kmsClient; + $this->kmsKeyId = $kmsKeyId; + } + + public function fromDecryptionEnvelope(MetadataEnvelope $envelope) + { + if (empty($envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER])) { + throw new \RuntimeException('Not able to detect the materials description.'); + } + + $materialsDescription = json_decode( + $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER], + true + ); + + if (empty($materialsDescription['kms_cmk_id']) + && empty($materialsDescription['aws:x-amz-cek-alg'])) { + throw new \RuntimeException('Not able to detect kms_cmk_id (legacy' + . ' implementation) or aws:x-amz-cek-alg (current implementation)' + . ' from kms materials description.'); + } + + return new self( + $this->kmsClient, + isset($materialsDescription['kms_cmk_id']) + ? $materialsDescription['kms_cmk_id'] + : null + ); + } + + /** + * The KMS key id for use in matching this Provider to its keys, + * consistently with other SDKs as 'kms_cmk_id'. + * + * @return array + */ + public function getMaterialsDescription() + { + return ['kms_cmk_id' => $this->kmsKeyId]; + } + + public function getWrapAlgorithmName() + { + return self::WRAP_ALGORITHM_NAME; + } + + /** + * Takes a content encryption key (CEK) and description to return an encrypted + * key by using KMS' Encrypt API. + * + * @param string $unencryptedCek Key for use in encrypting other data + * that itself needs to be encrypted by the + * Provider. + * @param string $materialDescription Material Description for use in + * encrypting the $cek. + * + * @return string + */ + public function encryptCek($unencryptedCek, $materialDescription) + { + $encryptedDataKey = $this->kmsClient->encrypt([ + 'Plaintext' => $unencryptedCek, + 'KeyId' => $this->kmsKeyId, + 'EncryptionContext' => $materialDescription + ]); + return base64_encode($encryptedDataKey['CiphertextBlob']); + } + + /** + * Takes an encrypted content encryption key (CEK) and material description + * for use decrypting the key by using KMS' Decrypt API. + * + * @param string $encryptedCek Encrypted key to be decrypted by the Provider + * for use decrypting other data. + * @param string $materialDescription Material Description for use in + * encrypting the $cek. + * + * @return string + */ + public function decryptCek($encryptedCek, $materialDescription) + { + $result = $this->kmsClient->decrypt([ + 'CiphertextBlob' => $encryptedCek, + 'EncryptionContext' => $materialDescription + ]); + + return $result['Plaintext']; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProviderV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProviderV2.php new file mode 100644 index 000000000..e7da8b92e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/KmsMaterialsProviderV2.php @@ -0,0 +1,100 @@ +kmsClient = $kmsClient; + $this->kmsKeyId = $kmsKeyId; + } + + /** + * @inheritDoc + */ + public function getWrapAlgorithmName() + { + return self::WRAP_ALGORITHM_NAME; + } + + /** + * @inheritDoc + */ + public function decryptCek($encryptedCek, $materialDescription, $options) + { + $params = [ + 'CiphertextBlob' => $encryptedCek, + 'EncryptionContext' => $materialDescription + ]; + if (empty($options['@KmsAllowDecryptWithAnyCmk'])) { + if (empty($this->kmsKeyId)) { + throw new CryptoException('KMS CMK ID was not specified and the' + . ' operation is not opted-in to attempting to use any valid' + . ' CMK it discovers. Please specify a CMK ID, or explicitly' + . ' enable attempts to use any valid KMS CMK with the' + . ' @KmsAllowDecryptWithAnyCmk option.'); + } + $params['KeyId'] = $this->kmsKeyId; + } + + $result = $this->kmsClient->decrypt($params); + return $result['Plaintext']; + } + + /** + * @inheritDoc + */ + public function generateCek($keySize, $context, $options) + { + if (empty($this->kmsKeyId)) { + throw new CryptoException('A KMS key id is required for encryption' + . ' with KMS keywrap. Use a KmsMaterialsProviderV2 that has been' + . ' instantiated with a KMS key id.'); + } + $options = array_change_key_case($options); + if (!isset($options['@kmsencryptioncontext']) + || !is_array($options['@kmsencryptioncontext']) + ) { + throw new CryptoException("'@KmsEncryptionContext' is a" + . " required argument when using KmsMaterialsProviderV2, and" + . " must be an associative array (or empty array)."); + } + if (isset($options['@kmsencryptioncontext']['aws:x-amz-cek-alg'])) { + throw new CryptoException("Conflict in reserved @KmsEncryptionContext" + . " key aws:x-amz-cek-alg. This value is reserved for the S3" + . " Encryption Client and cannot be set by the user."); + } + $context = array_merge($options['@kmsencryptioncontext'], $context); + $result = $this->kmsClient->generateDataKey([ + 'KeyId' => $this->kmsKeyId, + 'KeySpec' => "AES_{$keySize}", + 'EncryptionContext' => $context + ]); + return [ + 'Plaintext' => $result['Plaintext'], + 'Ciphertext' => base64_encode($result['CiphertextBlob']), + 'UpdatedContext' => $context + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProvider.php new file mode 100644 index 000000000..1c6941c23 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProvider.php @@ -0,0 +1,105 @@ + true, + 192 => true, + 256 => true, + ]; + + /** + * Returns if the requested size is supported by AES. + * + * @param int $keySize Size of the requested key in bits. + * + * @return bool + */ + public static function isSupportedKeySize($keySize) + { + return isset(self::$supportedKeySizes[$keySize]); + } + + /** + * Performs further initialization of the MaterialsProvider based on the + * data inside the MetadataEnvelope. + * + * @param MetadataEnvelope $envelope A storage envelope for encryption + * metadata to be read from. + * + * @return MaterialsProvider + * + * @throws \RuntimeException Thrown when there is an empty or improperly + * formed materials description in the envelope. + * + * @internal + */ + abstract public function fromDecryptionEnvelope(MetadataEnvelope $envelope); + + /** + * Returns the material description for this Provider so it can be verified + * by encryption mechanisms. + * + * @return string + */ + abstract public function getMaterialsDescription(); + + /** + * Returns the wrap algorithm name for this Provider. + * + * @return string + */ + abstract public function getWrapAlgorithmName(); + + /** + * Takes a content encryption key (CEK) and description to return an + * encrypted key according to the Provider's specifications. + * + * @param string $unencryptedCek Key for use in encrypting other data + * that itself needs to be encrypted by the + * Provider. + * @param string $materialDescription Material Description for use in + * encrypting the $cek. + * + * @return string + */ + abstract public function encryptCek($unencryptedCek, $materialDescription); + + /** + * Takes an encrypted content encryption key (CEK) and material description + * for use decrypting the key according to the Provider's specifications. + * + * @param string $encryptedCek Encrypted key to be decrypted by the Provider + * for use decrypting other data. + * @param string $materialDescription Material Description for use in + * encrypting the $cek. + * + * @return string + */ + abstract public function decryptCek($encryptedCek, $materialDescription); + + /** + * @param string $keySize Length of a cipher key in bits for generating a + * random content encryption key (CEK). + * + * @return string + */ + public function generateCek($keySize) + { + return openssl_random_pseudo_bytes($keySize / 8); + } + + /** + * @param string $openSslName Cipher OpenSSL name to use for generating + * an initialization vector. + * + * @return string + */ + public function generateIv($openSslName) + { + return openssl_random_pseudo_bytes( + openssl_cipher_iv_length($openSslName) + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProviderInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProviderInterface.php new file mode 100644 index 000000000..a22016d63 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MaterialsProviderInterface.php @@ -0,0 +1,61 @@ + true, + 256 => true, + ]; + + /** + * Returns if the requested size is supported by AES. + * + * @param int $keySize Size of the requested key in bits. + * + * @return bool + */ + public static function isSupportedKeySize($keySize) + { + return isset(self::$supportedKeySizes[$keySize]); + } + + /** + * Returns the wrap algorithm name for this Provider. + * + * @return string + */ + abstract public function getWrapAlgorithmName(); + + /** + * Takes an encrypted content encryption key (CEK) and material description + * for use decrypting the key according to the Provider's specifications. + * + * @param string $encryptedCek Encrypted key to be decrypted by the Provider + * for use decrypting other data. + * @param string $materialDescription Material Description for use in + * decrypting the CEK. + * @param string $options Options for use in decrypting the CEK. + * + * @return string + */ + abstract public function decryptCek($encryptedCek, $materialDescription, $options); + + /** + * @param string $keySize Length of a cipher key in bits for generating a + * random content encryption key (CEK). + * @param array $context Context map needed for key encryption + * @param array $options Additional options to be used in CEK generation + * + * @return array + */ + abstract public function generateCek($keySize, $context, $options); + + /** + * @param string $openSslName Cipher OpenSSL name to use for generating + * an initialization vector. + * + * @return string + */ + public function generateIv($openSslName) + { + return openssl_random_pseudo_bytes( + openssl_cipher_iv_length($openSslName) + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataEnvelope.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataEnvelope.php new file mode 100644 index 000000000..5a7c69205 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataEnvelope.php @@ -0,0 +1,61 @@ +getConstants()) as $constant) { + self::$constants[$constant] = true; + } + } + + return array_keys(self::$constants); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($name, $value) + { + $constants = self::getConstantValues(); + if (is_null($name) || !in_array($name, $constants)) { + throw new InvalidArgumentException('MetadataEnvelope fields must' + . ' must match a predefined offset; use the header constants.'); + } + + $this->data[$name] = $value; + } + + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->data; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataStrategyInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataStrategyInterface.php new file mode 100644 index 000000000..5270c7e8f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Crypto/MetadataStrategyInterface.php @@ -0,0 +1,30 @@ +validModes)) { + throw new \InvalidArgumentException("'{$mode}' is not a valid mode." + . " The mode has to be 'legacy', 'standard', 'cross-region', 'in-region'," + . " 'mobile', or 'auto'."); + } + + $this->mode = $mode; + if ($this->mode == 'legacy') { + return; + } + + $data = \Aws\load_compiled_json( + __DIR__ . '/../data/sdk-default-configuration.json' + ); + + $this->retryMode = $data['base']['retryMode']; + $this->stsRegionalEndpoints = $data['base']['stsRegionalEndpoints']; + $this->s3UsEast1RegionalEndpoints = $data['base']['s3UsEast1RegionalEndpoints']; + $this->connectTimeoutInMillis = $data['base']['connectTimeoutInMillis']; + + if (isset($data['modes'][$mode])) { + $modeData = $data['modes'][$mode]; + foreach ($modeData as $settingName => $settingValue) { + if (isset($this->$settingName)) { + if (isset($settingValue['override'])) { + $this->$settingName = $settingValue['override']; + } else if (isset($settingValue['multiply'])) { + $this->$settingName *= $settingValue['multiply']; + } else if (isset($settingValue['add'])) { + $this->$settingName += $settingValue['add']; + } + } else { + if (isset($settingValue['override'])) { + if (property_exists($this, $settingName)) { + $this->$settingName = $settingValue['override']; + } + } + } + } + } + } + + /** + * {@inheritdoc} + */ + public function getMode() + { + return $this->mode; + } + + /** + * {@inheritdoc} + */ + public function getRetryMode() + { + return $this->retryMode; + } + + /** + * {@inheritdoc} + */ + public function getStsRegionalEndpoints() + { + return $this->stsRegionalEndpoints; + } + + /** + * {@inheritdoc} + */ + public function getS3UsEast1RegionalEndpoints() + { + return $this->s3UsEast1RegionalEndpoints; + } + + /** + * {@inheritdoc} + */ + public function getConnectTimeoutInMillis() + { + return $this->connectTimeoutInMillis; + } + + /** + * {@inheritdoc} + */ + public function getHttpRequestTimeoutInMillis() + { + return $this->httpRequestTimeoutInMillis; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'mode' => $this->getMode(), + 'retry_mode' => $this->getRetryMode(), + 'sts_regional_endpoints' => $this->getStsRegionalEndpoints(), + 's3_us_east_1_regional_endpoint' => $this->getS3UsEast1RegionalEndpoints(), + 'connect_timeout_in_milliseconds' => $this->getConnectTimeoutInMillis(), + 'http_request_timeout_in_milliseconds' => $this->getHttpRequestTimeoutInMillis(), + ]; + } + +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/ConfigurationInterface.php new file mode 100644 index 000000000..34c5a63f9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/ConfigurationInterface.php @@ -0,0 +1,51 @@ + + * use Aws\Sts\RegionalEndpoints\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see \Aws\DefaultsMode\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const DEFAULT_MODE = 'legacy'; + const ENV_MODE = 'AWS_DEFAULTS_MODE'; + const ENV_PROFILE = 'AWS_PROFILE'; + const INI_MODE = 'defaults_mode'; + + public static $cacheKey = 'aws_defaults_mode'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['defaultsMode']) + && $config['defaultsMode'] instanceof CacheInterface + ) { + return self::cache($memo, $config['defaultsMode'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use config from environment variables, if available + $mode = getenv(self::ENV_MODE); + if (!empty($mode)) { + return Promise\Create::promiseFor( + new Configuration($mode) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_MODE); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function () { + return Promise\Create::promiseFor( + new Configuration( self::DEFAULT_MODE) + ); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini( + $profile = null, + $filename = null + ) { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_MODE])) { + return self::reject("Required defaults mode config values + not present in INI profile '{$profile}' ({$filename})"); + } + return Promise\Create::promiseFor( + new Configuration( + $data[$profile][self::INI_MODE] + ) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } + + if (is_string($config)) { + return new Configuration($config); + } + + throw new \InvalidArgumentException('Not a valid defaults mode configuration' + . ' argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/Exception/ConfigurationException.php new file mode 100644 index 000000000..b7186a5b8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/DefaultsMode/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +cache = $cache; + } + + public function get($key) + { + return $this->cache->fetch($key); + } + + /** + * @return mixed + */ + public function fetch($key) + { + return $this->get($key); + } + + public function set($key, $value, $ttl = 0) + { + return $this->cache->save($key, $value, $ttl); + } + + /** + * @return bool + */ + public function save($key, $value, $ttl = 0) + { + return $this->set($key, $value, $ttl); + } + + public function remove($key) + { + return $this->cache->delete($key); + } + + /** + * @return bool + */ + public function delete($key) + { + return $this->remove($key); + } + + /** + * @return bool + */ + public function contains($key) + { + return $this->cache->contains($key); + } + + /** + * @return mixed[]|null + */ + public function getStats() + { + return $this->cache->getStats(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/EndpointProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/EndpointProvider.php new file mode 100644 index 000000000..ba5357421 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/EndpointProvider.php @@ -0,0 +1,96 @@ + 'ec2', 'region' => 'us-west-2']); + * // Returns an endpoint array or throws. + * $endpoint = EndpointProvider::resolve($provider, [ + * 'service' => 'ec2', + * 'region' => 'us-west-2' + * ]); + * + * You can compose multiple providers into a single provider using + * {@see Aws\or_chain}. This function accepts providers as arguments and + * returns a new function that will invoke each provider until a non-null value + * is returned. + * + * $a = function (array $args) { + * if ($args['region'] === 'my-test-region') { + * return ['endpoint' => 'http://localhost:123/api']; + * } + * }; + * $b = EndpointProvider::defaultProvider(); + * $c = \Aws\or_chain($a, $b); + * $config = ['service' => 'ec2', 'region' => 'my-test-region']; + * $res = $c($config); // $a handles this. + * $config['region'] = 'us-west-2'; + * $res = $c($config); // $b handles this. + */ +class EndpointProvider +{ + /** + * Resolves and endpoint provider and ensures a non-null return value. + * + * @param callable $provider Provider function to invoke. + * @param array $args Endpoint arguments to pass to the provider. + * + * @return array + * @throws UnresolvedEndpointException + */ + public static function resolve(callable $provider, array $args = []) + { + $result = $provider($args); + if (is_array($result)) { + return $result; + } + + throw new UnresolvedEndpointException( + 'Unable to resolve an endpoint using the provider arguments: ' + . json_encode($args) . '. Note: you can provide an "endpoint" ' + . 'option to a client constructor to bypass invoking an endpoint ' + . 'provider.'); + } + + /** + * Creates and returns the default SDK endpoint provider. + * + * @deprecated Use an instance of \Aws\Endpoint\Partition instead. + * + * @return callable + */ + public static function defaultProvider() + { + return PartitionEndpointProvider::defaultProvider(); + } + + /** + * Creates and returns an endpoint provider that uses patterns from an + * array. + * + * @param array $patterns Endpoint patterns + * + * @return callable + */ + public static function patterns(array $patterns) + { + return new PatternEndpointProvider($patterns); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/Partition.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/Partition.php new file mode 100644 index 000000000..46d23712f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/Partition.php @@ -0,0 +1,322 @@ +data = $definition; + } + + public function getName() + { + return $this->data['partition']; + } + + /** + * @internal + * @return mixed + */ + public function getDnsSuffix() + { + return $this->data['dnsSuffix']; + } + + public function isRegionMatch($region, $service) + { + if (isset($this->data['regions'][$region]) + || isset($this->data['services'][$service]['endpoints'][$region]) + ) { + return true; + } + + if (isset($this->data['regionRegex'])) { + return (bool) preg_match( + "@{$this->data['regionRegex']}@", + $region + ); + } + + return false; + } + + public function getAvailableEndpoints( + $service, + $allowNonRegionalEndpoints = false + ) { + if ($this->isServicePartitionGlobal($service)) { + return [$this->getPartitionEndpoint($service)]; + } + + if (isset($this->data['services'][$service]['endpoints'])) { + $serviceRegions = array_keys( + $this->data['services'][$service]['endpoints'] + ); + + return $allowNonRegionalEndpoints + ? $serviceRegions + : array_intersect($serviceRegions, array_keys( + $this->data['regions'] + )); + } + + return []; + } + + public function __invoke(array $args = []) + { + $service = isset($args['service']) ? $args['service'] : ''; + $region = isset($args['region']) ? $args['region'] : ''; + $scheme = isset($args['scheme']) ? $args['scheme'] : 'https'; + $options = isset($args['options']) ? $args['options'] : []; + $data = $this->getEndpointData($service, $region, $options); + $variant = $this->getVariant($options, $data); + if (isset($variant['hostname'])) { + $template = $variant['hostname']; + } else { + $template = isset($data['hostname']) ? $data['hostname'] : ''; + } + $dnsSuffix = isset($variant['dnsSuffix']) + ? $variant['dnsSuffix'] + : $this->data['dnsSuffix']; + return [ + 'endpoint' => "{$scheme}://" . $this->formatEndpoint( + $template, + $service, + $region, + $dnsSuffix + ), + 'signatureVersion' => $this->getSignatureVersion($data), + 'signingRegion' => isset($data['credentialScope']['region']) + ? $data['credentialScope']['region'] + : $region, + 'signingName' => isset($data['credentialScope']['service']) + ? $data['credentialScope']['service'] + : $service, + ]; + } + + private function getEndpointData($service, $region, $options) + { + $defaultRegion = $this->resolveRegion($service, $region, $options); + $data = isset($this->data['services'][$service]['endpoints'][$defaultRegion]) + ? $this->data['services'][$service]['endpoints'][$defaultRegion] + : []; + $data += isset($this->data['services'][$service]['defaults']) + ? $this->data['services'][$service]['defaults'] + : []; + $data += isset($this->data['defaults']) + ? $this->data['defaults'] + : []; + + return $data; + } + + private function getSignatureVersion(array $data) + { + static $supportedBySdk = [ + 's3v4', + 'v4', + 'anonymous', + ]; + + $possibilities = array_intersect( + $supportedBySdk, + isset($data['signatureVersions']) + ? $data['signatureVersions'] + : ['v4'] + ); + + return array_shift($possibilities); + } + + private function resolveRegion($service, $region, $options) + { + if (isset($this->data['services'][$service]['endpoints'][$region]) + && $this->isFipsEndpointUsed($region) + ) { + return $region; + } + + if ($this->isServicePartitionGlobal($service) + || $this->isStsLegacyEndpointUsed($service, $region, $options) + || $this->isS3LegacyEndpointUsed($service, $region, $options) + ) { + return $this->getPartitionEndpoint($service); + } + + return $region; + } + + private function isServicePartitionGlobal($service) + { + return isset($this->data['services'][$service]['isRegionalized']) + && false === $this->data['services'][$service]['isRegionalized'] + && isset($this->data['services'][$service]['partitionEndpoint']); + } + + /** + * STS legacy endpoints used for valid regions unless option is explicitly + * set to 'regional' + * + * @param string $service + * @param string $region + * @param array $options + * @return bool + */ + private function isStsLegacyEndpointUsed($service, $region, $options) + { + return $service === 'sts' + && in_array($region, $this->stsLegacyGlobalRegions) + && (empty($options['sts_regional_endpoints']) + || ConfigurationProvider::unwrap( + $options['sts_regional_endpoints'] + )->getEndpointsType() !== 'regional' + ); + } + + /** + * S3 legacy us-east-1 endpoint used for valid regions unless option is explicitly + * set to 'regional' + * + * @param string $service + * @param string $region + * @param array $options + * @return bool + */ + private function isS3LegacyEndpointUsed($service, $region, $options) + { + return $service === 's3' + && $region === 'us-east-1' + && (empty($options['s3_us_east_1_regional_endpoint']) + || S3ConfigurationProvider::unwrap( + $options['s3_us_east_1_regional_endpoint'] + )->getEndpointsType() !== 'regional' + ); + } + + private function getPartitionEndpoint($service) + { + return $this->data['services'][$service]['partitionEndpoint']; + } + + private function formatEndpoint($template, $service, $region, $dnsSuffix) + { + return strtr($template, [ + '{service}' => $service, + '{region}' => $region, + '{dnsSuffix}' => $dnsSuffix, + ]); + } + + /** + * @param $region + * @return bool + */ + private function isFipsEndpointUsed($region) + { + return strpos($region, "fips") !== false; + } + + /** + * @param array $options + * @param array $data + * @return array + */ + private function getVariant(array $options, array $data) + { + $variantTags = []; + if (isset($options['use_fips_endpoint'])) { + $useFips = $options['use_fips_endpoint']; + if (is_bool($useFips)) { + $useFips && $variantTags[] = 'fips'; + } elseif ($useFips->isUseFipsEndpoint()) { + $variantTags[] = 'fips'; + } + } + if (isset($options['use_dual_stack_endpoint'])) { + $useDualStack = $options['use_dual_stack_endpoint']; + if (is_bool($useDualStack)) { + $useDualStack && $variantTags[] = 'dualstack'; + } elseif ($useDualStack->isUseDualStackEndpoint()) { + $variantTags[] = 'dualstack'; + } + } + if (!empty($variantTags)) { + if (isset($data['variants'])) { + foreach ($data['variants'] as $variant) { + if (array_count_values($variant['tags']) == array_count_values($variantTags)) { + return $variant; + } + } + } + if (isset($this->data['defaults']['variants'])) { + foreach ($this->data['defaults']['variants'] as $variant) { + if (array_count_values($variant['tags']) == array_count_values($variantTags)) { + return $variant; + } + } + } + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionEndpointProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionEndpointProvider.php new file mode 100644 index 000000000..21ca2c838 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionEndpointProvider.php @@ -0,0 +1,130 @@ +partitions = array_map(function (array $definition) { + return new Partition($definition); + }, array_values($partitions)); + $this->defaultPartition = $defaultPartition; + $this->options = $options; + } + + public function __invoke(array $args = []) + { + $partition = $this->getPartition( + isset($args['region']) ? $args['region'] : '', + isset($args['service']) ? $args['service'] : '' + ); + $args['options'] = $this->options; + + return $partition($args); + } + + /** + * Returns the partition containing the provided region or the default + * partition if no match is found. + * + * @param string $region + * @param string $service + * + * @return Partition + */ + public function getPartition($region, $service) + { + foreach ($this->partitions as $partition) { + if ($partition->isRegionMatch($region, $service)) { + return $partition; + } + } + + return $this->getPartitionByName($this->defaultPartition); + } + + /** + * Returns the partition with the provided name or null if no partition with + * the provided name can be found. + * + * @param string $name + * + * @return Partition|null + */ + public function getPartitionByName($name) + { + foreach ($this->partitions as $partition) { + if ($name === $partition->getName()) { + return $partition; + } + } + } + + /** + * Creates and returns the default SDK partition provider. + * + * @param array $options + * @return PartitionEndpointProvider + */ + public static function defaultProvider($options = []) + { + $data = \Aws\load_compiled_json(__DIR__ . '/../data/endpoints.json'); + $prefixData = \Aws\load_compiled_json(__DIR__ . '/../data/endpoints_prefix_history.json'); + $mergedData = self::mergePrefixData($data, $prefixData); + + return new self($mergedData['partitions'], 'aws', $options); + } + + /** + * Copy endpoint data for other prefixes used by a given service + * + * @param $data + * @param $prefixData + * @return array + */ + public static function mergePrefixData($data, $prefixData) + { + $prefixGroups = $prefixData['prefix-groups']; + + foreach ($data["partitions"] as $index => $partition) { + foreach ($prefixGroups as $current => $old) { + $serviceData = Env::search("services.\"{$current}\"", $partition); + if (!empty($serviceData)) { + foreach ($old as $prefix) { + if (empty(Env::search("services.\"{$prefix}\"", $partition))) { + $data["partitions"][$index]["services"][$prefix] = $serviceData; + } + } + } + } + } + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionInterface.php new file mode 100644 index 000000000..0f2572d93 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/PartitionInterface.php @@ -0,0 +1,56 @@ +patterns = $patterns; + } + + public function __invoke(array $args = []) + { + $service = isset($args['service']) ? $args['service'] : ''; + $region = isset($args['region']) ? $args['region'] : ''; + $keys = ["{$region}/{$service}", "{$region}/*", "*/{$service}", "*/*"]; + + foreach ($keys as $key) { + if (isset($this->patterns[$key])) { + return $this->expand( + $this->patterns[$key], + isset($args['scheme']) ? $args['scheme'] : 'https', + $service, + $region + ); + } + } + + return null; + } + + private function expand(array $config, $scheme, $service, $region) + { + $config['endpoint'] = $scheme . '://' + . strtr($config['endpoint'], [ + '{service}' => $service, + '{region}' => $region + ]); + + return $config; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Configuration.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Configuration.php new file mode 100644 index 000000000..5506fca98 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Configuration.php @@ -0,0 +1,41 @@ +useDualstackEndpoint = Aws\boolean_value($useDualstackEndpoint); + if (is_null($this->useDualstackEndpoint)) { + throw new ConfigurationException("'use_dual_stack_endpoint' config option" + . " must be a boolean value."); + } + if ($this->useDualstackEndpoint == true + && (strpos($region, "iso-") !== false || strpos($region, "-iso") !== false) + ) { + throw new ConfigurationException("Dual-stack is not supported in ISO regions"); } + } + + /** + * {@inheritdoc} + */ + public function isUseDualstackEndpoint() + { + return $this->useDualstackEndpoint; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'use_dual_stack_endpoint' => $this->isUseDualstackEndpoint(), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/ConfigurationInterface.php new file mode 100644 index 000000000..e1c7d5e86 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/ConfigurationInterface.php @@ -0,0 +1,19 @@ + + * use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const ENV_USE_DUAL_STACK_ENDPOINT = 'AWS_USE_DUALSTACK_ENDPOINT'; + const INI_USE_DUAL_STACK_ENDPOINT = 'use_dualstack_endpoint'; + + public static $cacheKey = 'aws_cached_use_dualstack_endpoint_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $region = $config['region']; + $configProviders = [self::env($region)]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini($region); + } + $configProviders[] = self::fallback($region); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['use_dual_stack_endpoint']) + && $config['use_dual_stack_endpoint'] instanceof CacheInterface + ) { + return self::cache($memo, $config['use_dual_stack_endpoint'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env($region) + { + return function () use ($region) { + // Use config from environment variables, if available + $useDualstackEndpoint = getenv(self::ENV_USE_DUAL_STACK_ENDPOINT); + if (!empty($useDualstackEndpoint)) { + return Promise\Create::promiseFor( + new Configuration($useDualstackEndpoint, $region) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_USE_DUAL_STACK_ENDPOINT); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini($region, $profile = null, $filename = null) + { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($region, $profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + + // Use INI_SCANNER_NORMAL instead of INI_SCANNER_TYPED for PHP 5.5 compatibility + $data = \Aws\parse_ini_file($filename, true, INI_SCANNER_NORMAL); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_USE_DUAL_STACK_ENDPOINT])) { + return self::reject("Required use dualstack endpoint config values + not present in INI profile '{$profile}' ({$filename})"); + } + + // INI_SCANNER_NORMAL parses false-y values as an empty string + if ($data[$profile][self::INI_USE_DUAL_STACK_ENDPOINT] === "") { + $data[$profile][self::INI_USE_DUAL_STACK_ENDPOINT] = false; + } + + return Promise\Create::promiseFor( + new Configuration($data[$profile][self::INI_USE_DUAL_STACK_ENDPOINT], $region) + ); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback($region) + { + return function () use ($region) { + return Promise\Create::promiseFor(new Configuration(false, $region)); + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Exception/ConfigurationException.php new file mode 100644 index 000000000..796adc945 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +useFipsEndpoint = Aws\boolean_value($useFipsEndpoint); + if (is_null($this->useFipsEndpoint)) { + throw new ConfigurationException("'use_fips_endpoint' config option" + . " must be a boolean value."); + } + } + + /** + * {@inheritdoc} + */ + public function isUseFipsEndpoint() + { + return $this->useFipsEndpoint; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'use_fips_endpoint' => $this->isUseFipsEndpoint(), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/ConfigurationInterface.php new file mode 100644 index 000000000..da23f872f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/ConfigurationInterface.php @@ -0,0 +1,19 @@ + + * use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const ENV_USE_FIPS_ENDPOINT = 'AWS_USE_FIPS_ENDPOINT'; + const INI_USE_FIPS_ENDPOINT = 'use_fips_endpoint'; + + public static $cacheKey = 'aws_cached_use_fips_endpoint_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback($config['region']); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['use_fips_endpoint']) + && $config['use_fips_endpoint'] instanceof CacheInterface + ) { + return self::cache($memo, $config['use_fips_endpoint'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use config from environment variables, if available + $useFipsEndpoint = getenv(self::ENV_USE_FIPS_ENDPOINT); + if (!empty($useFipsEndpoint)) { + return Promise\Create::promiseFor( + new Configuration($useFipsEndpoint) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_USE_FIPS_ENDPOINT); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini($profile = null, $filename = null) + { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + + // Use INI_SCANNER_NORMAL instead of INI_SCANNER_TYPED for PHP 5.5 compatibility + $data = \Aws\parse_ini_file($filename, true, INI_SCANNER_NORMAL); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_USE_FIPS_ENDPOINT])) { + return self::reject("Required use fips endpoint config values + not present in INI profile '{$profile}' ({$filename})"); + } + + // INI_SCANNER_NORMAL parses false-y values as an empty string + if ($data[$profile][self::INI_USE_FIPS_ENDPOINT] === "") { + $data[$profile][self::INI_USE_FIPS_ENDPOINT] = false; + } + + return Promise\Create::promiseFor( + new Configuration($data[$profile][self::INI_USE_FIPS_ENDPOINT]) + ); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback($region) + { + return function () use ($region) { + $isFipsPseudoRegion = strpos($region, 'fips-') !== false + || strpos($region, '-fips') !== false; + if ($isFipsPseudoRegion){ + $configuration = new Configuration(true); + } else { + $configuration = new Configuration(false); + } + return Promise\Create::promiseFor($configuration); + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/Exception/ConfigurationException.php new file mode 100644 index 000000000..468aa650a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +cacheLimit = filter_var($cacheLimit, FILTER_VALIDATE_INT); + if ($this->cacheLimit == false || $this->cacheLimit < 1) { + throw new \InvalidArgumentException( + "'cache_limit' value must be a positive integer." + ); + } + + // Unparsable $enabled flag errs on the side of disabling endpoint discovery + $this->enabled = filter_var($enabled, FILTER_VALIDATE_BOOLEAN); + } + + /** + * {@inheritdoc} + */ + public function isEnabled() + { + return $this->enabled; + } + + /** + * {@inheritdoc} + */ + public function getCacheLimit() + { + return $this->cacheLimit; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'enabled' => $this->isEnabled(), + 'cache_limit' => $this->getCacheLimit() + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/ConfigurationInterface.php new file mode 100644 index 000000000..3228d1d86 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/ConfigurationInterface.php @@ -0,0 +1,30 @@ + + * use Aws\EndpointDiscovery\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see Aws\EndpointDiscovery\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const DEFAULT_ENABLED = false; + const DEFAULT_CACHE_LIMIT = 1000; + const ENV_ENABLED = 'AWS_ENDPOINT_DISCOVERY_ENABLED'; + const ENV_ENABLED_ALT = 'AWS_ENABLE_ENDPOINT_DISCOVERY'; + const ENV_PROFILE = 'AWS_PROFILE'; + + public static $cacheKey = 'aws_cached_endpoint_discovery_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback($config); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['endpoint_discovery']) + && $config['endpoint_discovery'] instanceof CacheInterface + ) { + return self::cache($memo, $config['endpoint_discovery'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @param $cacheLimit + * @return callable + */ + public static function env($cacheLimit = self::DEFAULT_CACHE_LIMIT) + { + return function () use ($cacheLimit) { + // Use config from environment variables, if available + $enabled = getenv(self::ENV_ENABLED); + if ($enabled === false || $enabled === '') { + $enabled = getenv(self::ENV_ENABLED_ALT); + } + if ($enabled !== false && $enabled !== '') { + return Promise\Create::promiseFor( + new Configuration($enabled, $cacheLimit) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_ENABLED); + }; + } + + /** + * Fallback config options when other sources are not set. Will check the + * service model for any endpoint discovery required operations, and enable + * endpoint discovery in that case. If no required operations found, will use + * the class default values. + * + * @param array $config + * @return callable + */ + public static function fallback($config = []) + { + $enabled = self::DEFAULT_ENABLED; + if (!empty($config['api_provider']) + && !empty($config['service']) + && !empty($config['version']) + ) { + $provider = $config['api_provider']; + $apiData = $provider('api', $config['service'], $config['version']); + if (!empty($apiData['operations'])) { + foreach ($apiData['operations'] as $operation) { + if (!empty($operation['endpointdiscovery']['required'])) { + $enabled = true; + } + } + } + } + + return function () use ($enabled) { + return Promise\Create::promiseFor( + new Configuration( + $enabled, + self::DEFAULT_CACHE_LIMIT + ) + ); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * @param int $cacheLimit + * + * @return callable + */ + public static function ini( + $profile = null, + $filename = null, + $cacheLimit = self::DEFAULT_CACHE_LIMIT + ) { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename, $cacheLimit) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile]['endpoint_discovery_enabled'])) { + return self::reject("Required endpoint discovery config values + not present in INI profile '{$profile}' ({$filename})"); + } + + return Promise\Create::promiseFor( + new Configuration( + $data[$profile]['endpoint_discovery_enabled'], + $cacheLimit + ) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } elseif (is_array($config) && isset($config['enabled'])) { + if (isset($config['cache_limit'])) { + return new Configuration( + $config['enabled'], + $config['cache_limit'] + ); + } + return new Configuration( + $config['enabled'], + self::DEFAULT_CACHE_LIMIT + ); + } + + throw new \InvalidArgumentException('Not a valid endpoint_discovery ' + . 'configuration argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointDiscoveryMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointDiscoveryMiddleware.php new file mode 100644 index 000000000..30f18200e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointDiscoveryMiddleware.php @@ -0,0 +1,423 @@ +nextHandler = $handler; + $this->client = $client; + $this->args = $args; + $this->service = $client->getApi(); + $this->config = $config; + } + + public function __invoke(CommandInterface $cmd, RequestInterface $request) + { + $nextHandler = $this->nextHandler; + $op = $this->service->getOperation($cmd->getName())->toArray(); + + // Continue only if endpointdiscovery trait is set + if (isset($op['endpointdiscovery'])) { + $config = ConfigurationProvider::unwrap($this->config); + $isRequired = !empty($op['endpointdiscovery']['required']); + + if ($isRequired && !($config->isEnabled())) { + throw new UnresolvedEndpointException('This operation ' + . 'requires the use of endpoint discovery, but this has ' + . 'been disabled in the configuration. Enable endpoint ' + . 'discovery or use a different operation.'); + } + + // Continue only if enabled by config + if ($config->isEnabled()) { + if (isset($op['endpointoperation'])) { + throw new UnresolvedEndpointException('This operation is ' + . 'contradictorily marked both as using endpoint discovery ' + . 'and being the endpoint discovery operation. Please ' + . 'verify the accuracy of your model files.'); + } + + // Original endpoint may be used if discovery optional + $originalUri = $request->getUri(); + + $identifiers = $this->getIdentifiers($op); + + $cacheKey = $this->getCacheKey( + $this->client->getCredentials()->wait(), + $cmd, + $identifiers + ); + + // Check/create cache + if (!isset(self::$cache)) { + self::$cache = new LruArrayCache($config->getCacheLimit()); + } + + if (empty($endpointList = self::$cache->get($cacheKey))) { + $endpointList = new EndpointList([]); + } + $endpoint = $endpointList->getActive(); + + // Retrieve endpoints if there is no active endpoint + if (empty($endpoint)) { + try { + $endpoint = $this->discoverEndpoint( + $cacheKey, + $cmd, + $identifiers + ); + } catch (\Exception $e) { + // Use cached endpoint, expired or active, if any remain + $endpoint = $endpointList->getEndpoint(); + + if (empty($endpoint)) { + return $this->handleDiscoveryException( + $isRequired, + $originalUri, + $e, + $cmd, + $request + ); + } + } + } + + $request = $this->modifyRequest($request, $endpoint); + + $g = function ($value) use ( + $cacheKey, + $cmd, + $identifiers, + $isRequired, + $originalUri, + $request, + &$endpoint, + &$g + ) { + if ($value instanceof AwsException + && ( + $value->getAwsErrorCode() == 'InvalidEndpointException' + || $value->getStatusCode() == 421 + ) + ) { + return $this->handleInvalidEndpoint( + $cacheKey, + $cmd, + $identifiers, + $isRequired, + $originalUri, + $request, + $value, + $endpoint, + $g + ); + } + + return $value; + }; + + return $nextHandler($cmd, $request)->otherwise($g); + } + } + + return $nextHandler($cmd, $request); + } + + private function discoverEndpoint( + $cacheKey, + CommandInterface $cmd, + array $identifiers + ) { + $discCmd = $this->getDiscoveryCommand($cmd, $identifiers); + $this->discoveryTimes[$cacheKey] = time(); + $result = $this->client->execute($discCmd); + + if (isset($result['Endpoints'])) { + $endpointData = []; + foreach ($result['Endpoints'] as $datum) { + $endpointData[$datum['Address']] = time() + + ($datum['CachePeriodInMinutes'] * 60); + } + $endpointList = new EndpointList($endpointData); + self::$cache->set($cacheKey, $endpointList); + return $endpointList->getEndpoint(); + } + + throw new UnresolvedEndpointException('The endpoint discovery operation ' + . 'yielded a response that did not contain properly formatted ' + . 'endpoint data.'); + } + + private function getCacheKey( + CredentialsInterface $creds, + CommandInterface $cmd, + array $identifiers + ) { + $key = $this->service->getServiceName() . '_' . $creds->getAccessKeyId(); + if (!empty($identifiers)) { + $key .= '_' . $cmd->getName(); + foreach ($identifiers as $identifier) { + $key .= "_{$cmd[$identifier]}"; + } + } + + return $key; + } + + private function getDiscoveryCommand( + CommandInterface $cmd, + array $identifiers + ) { + foreach ($this->service->getOperations() as $op) { + if (isset($op['endpointoperation'])) { + $endpointOperation = $op->toArray()['name']; + break; + } + } + + if (!isset($endpointOperation)) { + throw new UnresolvedEndpointException('This command is set to use ' + . 'endpoint discovery, but no endpoint discovery operation was ' + . 'found. Please verify the accuracy of your model files.'); + } + + $params = []; + if (!empty($identifiers)) { + $params['Operation'] = $cmd->getName(); + $params['Identifiers'] = []; + foreach ($identifiers as $identifier) { + $params['Identifiers'][$identifier] = $cmd[$identifier]; + } + } + $command = $this->client->getCommand($endpointOperation, $params); + $command->getHandlerList()->appendBuild( + Middleware::mapRequest(function (RequestInterface $r) { + return $r->withHeader( + 'x-amz-api-version', + $this->service->getApiVersion() + ); + }), + 'x-amz-api-version-header' + ); + + return $command; + } + + private function getIdentifiers(array $operation) + { + $inputShape = $this->service->getShapeMap() + ->resolve($operation['input']) + ->toArray(); + $identifiers = []; + foreach ($inputShape['members'] as $key => $member) { + if (!empty($member['endpointdiscoveryid'])) { + $identifiers[] = $key; + } + } + return $identifiers; + } + + private function handleDiscoveryException( + $isRequired, + $originalUri, + \Exception $e, + CommandInterface $cmd, + RequestInterface $request + ) { + // If no cached endpoints and discovery required, + // throw exception + if ($isRequired) { + $message = 'The endpoint required for this service is currently ' + . 'unable to be retrieved, and your request can not be fulfilled ' + . 'unless you manually specify an endpoint.'; + throw new AwsException( + $message, + $cmd, + [ + 'code' => 'EndpointDiscoveryException', + 'message' => $message + ], + $e + ); + } + + // If discovery isn't required, use original endpoint + return $this->useOriginalUri( + $originalUri, + $cmd, + $request + ); + } + + private function handleInvalidEndpoint( + $cacheKey, + $cmd, + $identifiers, + $isRequired, + $originalUri, + $request, + $value, + &$endpoint, + &$g + ) { + $nextHandler = $this->nextHandler; + $endpointList = self::$cache->get($cacheKey); + if ($endpointList instanceof EndpointList) { + + // Remove invalid endpoint from cached list + $endpointList->remove($endpoint); + + // If possible, get another cached endpoint + $newEndpoint = $endpointList->getEndpoint(); + } + if (empty($newEndpoint)) { + + // If no more cached endpoints, make discovery call + // if none made within cooldown for given key + if (time() - $this->discoveryTimes[$cacheKey] + < self::$discoveryCooldown + ) { + + // If no more cached endpoints and it's required, + // fail with original exception + if ($isRequired) { + return $value; + } + + // Use original endpoint if not required + return $this->useOriginalUri( + $originalUri, + $cmd, + $request + ); + } + + $newEndpoint = $this->discoverEndpoint( + $cacheKey, + $cmd, + $identifiers + ); + } + $endpoint = $newEndpoint; + $request = $this->modifyRequest($request, $endpoint); + return $nextHandler($cmd, $request)->otherwise($g); + } + + private function modifyRequest(RequestInterface $request, $endpoint) + { + $parsed = $this->parseEndpoint($endpoint); + if (!empty($request->getHeader('User-Agent'))) { + $userAgent = $request->getHeader('User-Agent')[0]; + if (strpos($userAgent, 'endpoint-discovery') === false) { + $userAgent = $userAgent . ' endpoint-discovery'; + } + } else { + $userAgent = 'endpoint-discovery'; + } + + return $request + ->withUri( + $request->getUri() + ->withHost($parsed['host']) + ->withPath($parsed['path']) + ) + ->withHeader('User-Agent', $userAgent); + } + + /** + * Parses an endpoint returned from the discovery API into an array with + * 'host' and 'path' keys. + * + * @param $endpoint + * @return array + */ + private function parseEndpoint($endpoint) + { + $parsed = parse_url($endpoint); + + // parse_url() will correctly parse full URIs with schemes + if (isset($parsed['host'])) { + return $parsed; + } + + // parse_url() will put host & path in 'path' if scheme is not provided + if (isset($parsed['path'])) { + $split = explode('/', $parsed['path'], 2); + $parsed['host'] = $split[0]; + if (isset($split[1])) { + if (substr($split[1], 0 , 1) !== '/') { + $split[1] = '/' . $split[1]; + } + $parsed['path'] = $split[1]; + } else { + $parsed['path'] = ''; + } + return $parsed; + } + + throw new UnresolvedEndpointException("The supplied endpoint '" + . "{$endpoint}' is invalid."); + } + + private function useOriginalUri( + UriInterface $uri, + CommandInterface $cmd, + RequestInterface $request + ) { + $nextHandler = $this->nextHandler; + $endpoint = $uri->getHost() . $uri->getPath(); + $request = $this->modifyRequest( + $request, + $endpoint + ); + return $nextHandler($cmd, $request); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointList.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointList.php new file mode 100644 index 000000000..80ccc4729 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/EndpointList.php @@ -0,0 +1,85 @@ +active = $endpoints; + reset($this->active); + } + + /** + * Gets an active (unexpired) endpoint. Returns null if none found. + * + * @return null|string + */ + public function getActive() + { + if (count($this->active) < 1) { + return null; + } + while (time() > current($this->active)) { + $key = key($this->active); + $this->expired[$key] = current($this->active); + $this->increment($this->active); + unset($this->active[$key]); + if (count($this->active) < 1) { + return null; + } + } + $active = key($this->active); + $this->increment($this->active); + return $active; + } + + /** + * Gets an active endpoint if possible, then an expired endpoint if possible. + * Returns null if no endpoints found. + * + * @return null|string + */ + public function getEndpoint() + { + if (!empty($active = $this->getActive())) { + return $active; + } + return $this->getExpired(); + } + + /** + * Removes an endpoint from both lists. + * + * @param string $key + */ + public function remove($key) + { + unset($this->active[$key]); + unset($this->expired[$key]); + } + + /** + * Get an expired endpoint. Returns null if none found. + * + * @return null|string + */ + private function getExpired() + { + if (count($this->expired) < 1) { + return null; + } + $expired = key($this->expired); + $this->increment($this->expired); + return $expired; + } + + private function increment(&$array) + { + if (next($array) === false) { + reset($array); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/Exception/ConfigurationException.php new file mode 100644 index 000000000..f87cdbfa4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointDiscovery/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +nextHandler = $nextHandler; + $this->service = $service; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + $nextHandler = $this->nextHandler; + + $operation = $this->service->getOperation($command->getName()); + + if (!empty($operation['endpoint']['hostPrefix'])) { + $prefix = $operation['endpoint']['hostPrefix']; + + // Captures endpoint parameters stored in the modeled host. + // These are denoted by enclosure in braces, i.e. '{param}' + preg_match_all("/\{([a-zA-Z0-9]+)}/", $prefix, $parameters); + + if (!empty($parameters[1])) { + + // Captured parameters without braces stored in $parameters[1], + // which should correspond to members in the Command object + foreach ($parameters[1] as $index => $parameter) { + if (empty($command[$parameter])) { + throw new \InvalidArgumentException( + "The parameter '{$parameter}' must be set and not empty." + ); + } + + // Captured parameters with braces stored in $parameters[0], + // which are replaced by their corresponding Command value + $prefix = str_replace( + $parameters[0][$index], + $command[$parameter], + $prefix + ); + } + } + + $uri = $request->getUri(); + $host = $prefix . $uri->getHost(); + if (!\Aws\is_valid_hostname($host)) { + throw new \InvalidArgumentException( + "The supplied parameters result in an invalid hostname: '{$host}'." + ); + } + $request = $request->withUri($uri->withHost($host)); + } + + return $nextHandler($command, $request); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointDefinitionProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointDefinitionProvider.php new file mode 100644 index 000000000..6da2685ce --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointDefinitionProvider.php @@ -0,0 +1,71 @@ +ruleset = new Ruleset($ruleset, $partitions); + $this->cache = new LruArrayCache(100); + } + + /** + * @return Ruleset + */ + public function getRuleset() + { + return $this->ruleset; + } + + /** + * Given a Ruleset and input parameters, determines the correct endpoint + * or an error to be thrown for a given request. + * + * @return RulesetEndpoint + * @throws UnresolvedEndpointException + */ + public function resolveEndpoint(array $inputParameters) + { + $hashedParams = $this->hashInputParameters($inputParameters); + $match = $this->cache->get($hashedParams); + + if (!is_null($match)) { + return $match; + } + + $endpoint = $this->ruleset->evaluate($inputParameters); + if ($endpoint === false) { + throw new UnresolvedEndpointException( + 'Unable to resolve an endpoint using the provider arguments: ' + . json_encode($inputParameters) + ); + } + $this->cache->set($hashedParams, $endpoint); + + return $endpoint; + } + + private function hashInputParameters($inputParameters) + { + return md5(serialize($inputParameters)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2Middleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2Middleware.php new file mode 100644 index 000000000..d9fe44316 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2Middleware.php @@ -0,0 +1,427 @@ + 'v4', + 'sigv4a' => 'v4a', + 'none' => 'anonymous', + 'bearer' => 'bearer', + 'sigv4-s3express' => 'v4-s3express' + ]; + + /** @var callable */ + private $nextHandler; + + /** @var EndpointProviderV2 */ + private $endpointProvider; + + /** @var Service */ + private $api; + + /** @var array */ + private $clientArgs; + + /** @var Closure */ + private $credentialProvider; + + /** + * Create a middleware wrapper function + * + * @param EndpointProviderV2 $endpointProvider + * @param Service $api + * @param array $args + * @param callable $credentialProvider + * + * @return Closure + */ + public static function wrap( + EndpointProviderV2 $endpointProvider, + Service $api, + array $args, + callable $credentialProvider + ) : Closure + { + return function (callable $handler) use ($endpointProvider, $api, $args, $credentialProvider) { + return new self($handler, $endpointProvider, $api, $args, $credentialProvider); + }; + } + + /** + * @param callable $nextHandler + * @param EndpointProviderV2 $endpointProvider + * @param Service $api + * @param array $args + */ + public function __construct( + callable $nextHandler, + EndpointProviderV2 $endpointProvider, + Service $api, + array $args, + ?callable $credentialProvider = null + ) + { + $this->nextHandler = $nextHandler; + $this->endpointProvider = $endpointProvider; + $this->api = $api; + $this->clientArgs = $args; + $this->credentialProvider = $credentialProvider; + } + + /** + * @param CommandInterface $command + * + * @return Promise + */ + public function __invoke(CommandInterface $command) + { + $nextHandler = $this->nextHandler; + $operation = $this->api->getOperation($command->getName()); + $commandArgs = $command->toArray(); + $providerArgs = $this->resolveArgs($commandArgs, $operation); + + $endpoint = $this->endpointProvider->resolveEndpoint($providerArgs); + + $this->appendEndpointMetrics($providerArgs, $endpoint, $command); + + if (!empty($authSchemes = $endpoint->getProperty('authSchemes'))) { + $this->applyAuthScheme( + $authSchemes, + $command + ); + } + + return $nextHandler($command, $endpoint); + } + + /** + * Resolves client, context params, static context params and endpoint provider + * arguments provided at the command level. + * + * @param array $commandArgs + * @param Operation $operation + * + * @return array + */ + private function resolveArgs(array $commandArgs, Operation $operation): array + { + $rulesetParams = $this->endpointProvider->getRuleset()->getParameters(); + + if (isset($rulesetParams[self::ACCOUNT_ID_PARAM]) + && isset($rulesetParams[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM])) { + $this->clientArgs[self::ACCOUNT_ID_PARAM] = $this->resolveAccountId(); + } + + $endpointCommandArgs = $this->filterEndpointCommandArgs( + $rulesetParams, + $commandArgs + ); + $staticContextParams = $this->bindStaticContextParams( + $operation->getStaticContextParams() + ); + $contextParams = $this->bindContextParams( + $commandArgs, $operation->getContextParams() + ); + $operationContextParams = $this->bindOperationContextParams( + $commandArgs, + $operation->getOperationContextParams() + ); + + return array_merge( + $this->clientArgs, + $operationContextParams, + $contextParams, + $staticContextParams, + $endpointCommandArgs + ); + } + + /** + * Compares Ruleset parameters against Command arguments + * to create a mapping of arguments to pass into the + * endpoint provider for endpoint resolution. + * + * @param array $rulesetParams + * @param array $commandArgs + * @return array + */ + private function filterEndpointCommandArgs( + array $rulesetParams, + array $commandArgs + ): array + { + $endpointMiddlewareOpts = [ + '@use_dual_stack_endpoint' => 'UseDualStack', + '@use_accelerate_endpoint' => 'Accelerate', + '@use_path_style_endpoint' => 'ForcePathStyle' + ]; + + $filteredArgs = []; + + foreach($rulesetParams as $name => $value) { + if (isset($commandArgs[$name])) { + if (!empty($value->getBuiltIn())) { + continue; + } + $filteredArgs[$name] = $commandArgs[$name]; + } + } + + if ($this->api->getServiceName() === 's3') { + foreach($endpointMiddlewareOpts as $optionName => $newValue) { + if (isset($commandArgs[$optionName])) { + $filteredArgs[$newValue] = $commandArgs[$optionName]; + } + } + } + + return $filteredArgs; + } + + /** + * Binds static context params to their corresponding values. + * + * @param $staticContextParams + * + * @return array + */ + private function bindStaticContextParams($staticContextParams): array + { + $scopedParams = []; + + forEach($staticContextParams as $paramName => $paramValue) { + $scopedParams[$paramName] = $paramValue['value']; + } + + return $scopedParams; + } + + /** + * Binds context params to their corresponding values found in + * command arguments. + * + * @param array $commandArgs + * @param array $contextParams + * + * @return array + */ + private function bindContextParams( + array $commandArgs, + array $contextParams + ): array + { + $scopedParams = []; + + foreach($contextParams as $name => $spec) { + if (isset($commandArgs[$spec['shape']])) { + $scopedParams[$name] = $commandArgs[$spec['shape']]; + } + } + + return $scopedParams; + } + + /** + * Binds context params to their corresponding values found in + * command arguments. + * + * @param array $commandArgs + * @param array $contextParams + * + * @return array + */ + private function bindOperationContextParams( + array $commandArgs, + array $operationContextParams + ): array + { + $scopedParams = []; + + foreach($operationContextParams as $name => $spec) { + $scopedValue = search($spec['path'], $commandArgs); + + if ($scopedValue) { + $scopedParams[$name] = $scopedValue; + } + } + + return $scopedParams; + } + + /** + * Applies resolved auth schemes to the command object. + * + * @param $authSchemes + * @param $command + * + * @return void + */ + private function applyAuthScheme( + array $authSchemes, + CommandInterface $command + ): void + { + $authScheme = $this->resolveAuthScheme($authSchemes); + + $command['@context']['signature_version'] = $authScheme['version']; + + if (isset($authScheme['name'])) { + $command['@context']['signing_service'] = $authScheme['name']; + } + + if (isset($authScheme['region'])) { + $command['@context']['signing_region'] = $authScheme['region']; + } elseif (isset($authScheme['signingRegionSet'])) { + $command['@context']['signing_region_set'] = $authScheme['signingRegionSet']; + } + } + + /** + * Returns the first compatible auth scheme in an endpoint object's + * auth schemes. + * + * @param array $authSchemes + * + * @return array + */ + private function resolveAuthScheme(array $authSchemes): array + { + $invalidAuthSchemes = []; + + foreach($authSchemes as $authScheme) { + if ($this->isValidAuthScheme($authScheme['name'])) { + return $this->normalizeAuthScheme($authScheme); + } + $invalidAuthSchemes[$authScheme['name']] = false; + } + + $invalidAuthSchemesString = '`' . implode( + '`, `', + array_keys($invalidAuthSchemes)) + . '`'; + $validAuthSchemesString = '`' + . implode('`, `', array_keys( + array_diff_key(self::$validAuthSchemes, $invalidAuthSchemes)) + ) + . '`'; + throw new UnresolvedAuthSchemeException( + "This operation requests {$invalidAuthSchemesString}" + . " auth schemes, but the client currently supports {$validAuthSchemesString}." + ); + } + + /** + * Normalizes an auth scheme's name, signing region or signing region set + * to the auth keys recognized by the SDK. + * + * @param array $authScheme + * @return array + */ + private function normalizeAuthScheme(array $authScheme): array + { + /* + sigv4a will contain a regionSet property. which is guaranteed to be `*` + for now. The SigV4 class handles this automatically for now. It seems + complexity will be added here in the future. + */ + $normalizedAuthScheme = []; + + if (isset($authScheme['disableDoubleEncoding']) + && $authScheme['disableDoubleEncoding'] === true + && $authScheme['name'] !== 'sigv4a' + && $authScheme['name'] !== 'sigv4-s3express' + ) { + $normalizedAuthScheme['version'] = 's3v4'; + } else { + $normalizedAuthScheme['version'] = self::$validAuthSchemes[$authScheme['name']]; + } + + $normalizedAuthScheme['name'] = $authScheme['signingName'] ?? null; + $normalizedAuthScheme['region'] = $authScheme['signingRegion'] ?? null; + $normalizedAuthScheme['signingRegionSet'] = $authScheme['signingRegionSet'] ?? null; + + return $normalizedAuthScheme; + } + + private function isValidAuthScheme($signatureVersion): bool + { + if (isset(self::$validAuthSchemes[$signatureVersion])) { + if ($signatureVersion === 'sigv4a') { + return extension_loaded('awscrt'); + } + return true; + } + + return false; + } + + /** + * This method tries to resolve an `AccountId` parameter from a resolved identity. + * We will just perform this operation if the parameter `AccountId` is part of the ruleset parameters and + * `AccountIdEndpointMode` is not disabled, otherwise, we will ignore it. + * + * @return null|string + */ + private function resolveAccountId(): ?string + { + if (isset($this->clientArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM]) + && $this->clientArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM] === 'disabled') { + return null; + } + + if (is_null($this->credentialProvider)) { + return null; + } + + $identityProviderFn = $this->credentialProvider; + $identity = $identityProviderFn()->wait(); + + return $identity->getAccountId(); + } + + private function appendEndpointMetrics( + array $providerArgs, + RulesetEndpoint $endpoint, + CommandInterface $command + ): void + { + // Resolved AccountId Metric + if (!empty($providerArgs[self::ACCOUNT_ID_PARAM])) { + $command->getMetricsBuilder()->append(MetricsBuilder::RESOLVED_ACCOUNT_ID); + } + // AccountIdMode Metric + if(!empty($providerArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM])) { + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'account_id_endpoint_mode', + $providerArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM] + ); + } + + // AccountId Endpoint Metric + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'account_id_endpoint', + $endpoint->getUrl() + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2SerializerTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2SerializerTrait.php new file mode 100644 index 000000000..951cbcbc3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/EndpointV2SerializerTrait.php @@ -0,0 +1,77 @@ +applyHeaders($endpoint, $headers); + $resolvedUrl = $endpoint->getUrl(); + $this->applyScheme($resolvedUrl); + $this->endpoint = $this instanceof RestSerializer + ? new Uri($resolvedUrl) + : $resolvedUrl; + } + + /** + * Combines modeled headers and headers resolved from an endpoint object. + * + * @param $endpoint + * @param $headers + * @return void + */ + private function applyHeaders(RulesetEndpoint $endpoint, array &$headers): void + { + if (!is_null($endpoint->getHeaders())) { + $headers = array_merge( + $headers, + $endpoint->getHeaders() + ); + } + } + + /** + * Applies custom HTTP schemes provided in client configuration. + * + * @param $resolvedUrl + * @return void + */ + private function applyScheme(&$resolvedUrl): void + { + $resolvedEndpointScheme = parse_url($resolvedUrl, PHP_URL_SCHEME); + $scheme = $this->endpoint instanceof Uri + ? $this->endpoint->getScheme() + : parse_url($this->endpoint, PHP_URL_SCHEME); + + if (!empty($scheme) && $scheme !== $resolvedEndpointScheme) { + $resolvedUrl = str_replace( + $resolvedEndpointScheme, + $scheme, + $resolvedUrl + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/AbstractRule.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/AbstractRule.php new file mode 100644 index 000000000..adedb4e19 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/AbstractRule.php @@ -0,0 +1,62 @@ +conditions = $definition['conditions']; + $this->documentation = isset($definition['documentation']) ? + $definition['documentation'] : null; + } + + /** + * @return array + */ + public function getConditions() + { + return $this->conditions; + } + + /** + * @return mixed + */ + public function getDocumentation() + { + return $this->documentation; + } + + /** + * Determines if all conditions for a given rule are met. + * + * @return boolean + */ + protected function evaluateConditions( + array &$inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + foreach($this->getConditions() as $condition) { + $result = $standardLibrary->callFunction($condition, $inputParameters); + if (is_null($result) || $result === false) { + return false; + } + } + return true; + } + + abstract public function evaluate( + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/EndpointRule.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/EndpointRule.php new file mode 100644 index 000000000..c3a0e9b7e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/EndpointRule.php @@ -0,0 +1,111 @@ +endpoint = $definition['endpoint']; + } + + /** + * @return array + */ + public function getEndpoint() + { + return $this->endpoint; + } + + /** + * If all the rule's conditions are met, return the resolved + * endpoint object. + * + * @return RulesetEndpoint | null + */ + public function evaluate(array $inputParameters, RulesetStandardLibrary $standardLibrary) + { + if ($this->evaluateConditions($inputParameters, $standardLibrary)) { + return $this->resolve($inputParameters, $standardLibrary); + } + return false; + } + + /** + * Given input parameters, resolve an endpoint in its entirety. + * + * @return RulesetEndpoint + */ + private function resolve( + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + $uri = $standardLibrary->resolveValue($this->endpoint['url'], $inputParameters); + $properties = isset($this->endpoint['properties']) + ? $this->resolveProperties($this->endpoint['properties'], $inputParameters, $standardLibrary) + : null; + $headers = $this->resolveHeaders($inputParameters, $standardLibrary); + + return new RulesetEndpoint($uri, $properties, $headers); + } + + /** + * Recurse through an endpoint's `properties` attribute, resolving template + * strings when found. Return the fully resolved attribute. + * + * @return array + */ + private function resolveProperties( + $properties, + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + if (is_array($properties)) { + $propertiesArr = []; + foreach($properties as $key => $val) { + $propertiesArr[$key] = $this->resolveProperties($val, $inputParameters, $standardLibrary); + } + return $propertiesArr; + } elseif ($standardLibrary->isTemplate($properties)) { + return $standardLibrary->resolveTemplateString($properties, $inputParameters); + } + return $properties; + } + + /** + * If present, iterate through an endpoint's headers attribute resolving + * values along the way. Return the fully resolved attribute. + * + * @return array + */ + private function resolveHeaders( + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + $headers = isset($this->endpoint['headers']) ? $this->endpoint['headers'] : null; + if (is_null($headers)) { + return null; + } + $resolvedHeaders = []; + + foreach($headers as $headerName => $headerValues) { + $resolvedValues = []; + foreach($headerValues as $value) { + $resolvedValue = $standardLibrary->resolveValue($value, $inputParameters, $standardLibrary); + $resolvedValues[] = $resolvedValue; + } + $resolvedHeaders[$headerName] = $resolvedValues; + } + return $resolvedHeaders; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/ErrorRule.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/ErrorRule.php new file mode 100644 index 000000000..941624a12 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/ErrorRule.php @@ -0,0 +1,45 @@ +error = $definition['error']; + } + + /** + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * If an error rule's conditions are met, raise an + * UnresolvedEndpointError containing the fully resolved error string. + * + * @return null + * @throws UnresolvedEndpointException + */ + public function evaluate( + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + if ($this->evaluateConditions($inputParameters, $standardLibrary)) { + $message = $standardLibrary->resolveValue($this->error, $inputParameters); + throw new UnresolvedEndpointException($message); + } + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/RuleCreator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/RuleCreator.php new file mode 100644 index 000000000..279477e81 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Rule/RuleCreator.php @@ -0,0 +1,26 @@ +rules = $this->createRules($definition['rules']); + } + + /** + * @return array + */ + public function getRules() + { + return $this->rules; + } + + /** + * If a tree rule's conditions evaluate successfully, iterate over its + * subordinate rules and return a result if there is one. If any of the + * subsequent rules are trees, the function will recurse until it reaches + * an error or an endpoint rule + * + * @return mixed + */ + public function evaluate( + array $inputParameters, + RulesetStandardLibrary $standardLibrary + ) + { + if ($this->evaluateConditions($inputParameters, $standardLibrary)) { + foreach($this->rules as $rule) { + $inputParametersCopy = $inputParameters; + $evaluation = $rule->evaluate($inputParametersCopy, $standardLibrary); + if ($evaluation !== false) { + return $evaluation; + } + } + } + return false; + } + + private function createRules(array $rules) + { + $rulesList = []; + + forEach($rules as $rule) { + $ruleType = RuleCreator::create($rule['type'], $rule); + $rulesList[] = $ruleType; + } + return $rulesList; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/Ruleset.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/Ruleset.php new file mode 100644 index 000000000..21828c195 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/Ruleset.php @@ -0,0 +1,117 @@ +version = $ruleset['version']; + $this->parameters = $this->createParameters($ruleset['parameters']); + $this->rules = $this->createRules($ruleset['rules']); + $this->standardLibrary = new RulesetStandardLibrary($partitions); + } + + /** + * @return mixed + */ + public function getVersion() + { + return $this->version; + } + + /** + * @return array + */ + public function getParameters() + { + return $this->parameters; + } + + /** + * @return array + */ + public function getRules() + { + return $this->rules; + } + + /** + * Evaluate the ruleset against the input parameters. + * Return the first rule the parameters match against. + * + * @return mixed + */ + public function evaluate(array $inputParameters) + { + $this->validateInputParameters($inputParameters); + + foreach($this->rules as $rule) { + $evaluation = $rule->evaluate($inputParameters, $this->standardLibrary); + if ($evaluation !== false) { + return $evaluation; + } + } + return false; + } + + /** + * Ensures all corresponding client-provided parameters match + * the Ruleset parameter's specified type. + * + * @return void + */ + private function validateInputParameters(array &$inputParameters) + { + foreach($this->parameters as $paramName => $param) { + $inputParam = isset($inputParameters[$paramName]) ? $inputParameters[$paramName] : null; + + if (is_null($inputParam) && !is_null($param->getDefault())) { + $inputParameters[$paramName] = $param->getDefault(); + } elseif (!is_null($inputParam)) { + $param->validateInputParam($inputParam); + } + } + } + + private function createParameters(array $parameters) + { + $parameterList = []; + + foreach($parameters as $name => $definition) { + $parameterList[$name] = new RulesetParameter($name, $definition); + } + + return $parameterList; + } + + private function createRules(array $rules) + { + $rulesList = []; + + forEach($rules as $rule) { + $ruleObj = RuleCreator::create($rule['type'], $rule); + $rulesList[] = $ruleObj; + } + return $rulesList; + } +} + diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetEndpoint.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetEndpoint.php new file mode 100644 index 000000000..46f844e46 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetEndpoint.php @@ -0,0 +1,63 @@ +url = $url; + $this->properties = $properties; + $this->headers = $headers; + } + + /** + * @return mixed + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param $property + * @return mixed + */ + public function getProperty($property) + { + if (isset($this->properties[$property])) { + return $this->properties[$property]; + } + + return null; + } + + /** + * @return mixed + */ + public function getProperties() + { + return $this->properties; + } + + /** + * @return mixed + */ + public function getHeaders() + { + return $this->headers; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetParameter.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetParameter.php new file mode 100644 index 000000000..1a3322cd1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetParameter.php @@ -0,0 +1,179 @@ + */ + private static $typeMap = [ + 'String' => 'is_string', + 'Boolean' => 'is_bool', + 'StringArray' => 'isStringArray' + ]; + + public function __construct($name, array $definition) + { + $type = ucfirst($definition['type']); + if ($this->isValidType($type)) { + $this->type = $type; + } else { + throw new UnresolvedEndpointException( + 'Unknown parameter type ' . "`{$type}`" . + '. Parameters must be of type `String`, `Boolean` or `StringArray.' + ); + } + + $this->name = $name; + $this->builtIn = $definition['builtIn'] ?? null; + $this->default = $definition['default'] ?? null; + $this->required = $definition['required'] ?? false; + $this->documentation = $definition['documentation'] ?? null; + $this->deprecated = $definition['deprecated'] ?? false; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @return mixed + */ + public function getBuiltIn() + { + return $this->builtIn; + } + + /** + * @return mixed + */ + public function getDefault() + { + return $this->default; + } + + /** + * @return boolean + */ + public function getRequired() + { + return $this->required; + } + + /** + * @return string + */ + public function getDocumentation() + { + return $this->documentation; + } + + /** + * @return boolean + */ + public function getDeprecated() + { + return $this->deprecated; + } + + /** + * Validates that an input parameter matches the type provided in its definition. + * + * @return void + * @throws InvalidArgumentException + */ + public function validateInputParam($inputParam) + { + if (!$this->isValidInput($inputParam)) { + throw new UnresolvedEndpointException( + "Input parameter `{$this->name}` is the wrong type. Must be a {$this->type}." + ); + } + + if ($this->deprecated) { + $deprecated = $this->deprecated; + $deprecationString = "{$this->name} has been deprecated "; + $msg = $deprecated['message'] ?? null; + $since = $deprecated['since'] ?? null; + + if (!is_null($since)){ + $deprecationString .= 'since ' . $since . '. '; + } + if (!is_null($msg)) { + $deprecationString .= $msg; + } + + trigger_error($deprecationString, E_USER_WARNING); + } + } + + private function isValidType($type) + { + return isset(self::$typeMap[$type]); + } + + private function isValidInput($inputParam): bool + { + $method = self::$typeMap[$this->type]; + if (is_callable($method)) { + return $method($inputParam); + } elseif (method_exists($this, $method)) { + return $this->$method($inputParam); + } + + return false; + } + + private function isStringArray(array $array): bool + { + if (is_associative($array)) { + return false; + } + + foreach($array as $value) { + if (!is_string($value)) { + return false; + } + } + + return true; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetStandardLibrary.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetStandardLibrary.php new file mode 100644 index 000000000..910bc5a47 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/EndpointV2/Ruleset/RulesetStandardLibrary.php @@ -0,0 +1,434 @@ +[^\{\}]+)|(?R))*\}#x'; + const HOST_LABEL_RE = '/^(?!-)[a-zA-Z\d-]{1,63}(?partitions = $partitions; + } + + /** + * Determines if a value is set. + * + * @return boolean + */ + public function is_set($value) + { + return isset($value); + } + + /** + * Function implementation of logical operator `not` + * + * @return boolean + */ + public function not($value) + { + return !$value; + } + + /** + * Find an attribute within a value given a path string. + * + * @return mixed + */ + public function getAttr($from, $path) + { + // Handles the case where "[= $stop or strlen($input) < $stop) { + return null; + } + if (!$reverse) { + return substr($input, $start, $stop - $start); + } else { + $offset = strlen($input) - $stop; + $length = $stop - $start; + return substr($input, $offset, $length); + } + } + + /** + * Evaluates two strings for equality. + * + * @return boolean + */ + public function stringEquals($string1, $string2) + { + if (!is_string($string1) || !is_string($string2)) { + throw new UnresolvedEndpointException( + 'Values passed to StringEquals must be `string`.' + ); + } + return $string1 === $string2; + } + + /** + * Evaluates two booleans for equality. + * + * @return boolean + */ + public function booleanEquals($boolean1, $boolean2) + { + return + filter_var($boolean1, FILTER_VALIDATE_BOOLEAN) + === filter_var($boolean2, FILTER_VALIDATE_BOOLEAN); + } + + /** + * Percent-encodes an input string. + * + * @return mixed + */ + public function uriEncode($input) + { + if (is_null($input)) { + return null; + } + return str_replace('%7E', '~', rawurlencode($input)); + } + + /** + * Parses URL string into components. + * + * @return mixed + */ + public function parseUrl($url) + { + if (is_null($url)) { + return null; + } + + $parsed = parse_url($url); + + if ($parsed === false || !empty($parsed['query'])) { + return null; + } elseif (!isset($parsed['scheme'])) { + return null; + } + + if ($parsed['scheme'] !== 'http' + && $parsed['scheme'] !== 'https' + ) { + return null; + } + + $urlInfo = []; + $urlInfo['scheme'] = $parsed['scheme']; + $urlInfo['authority'] = isset($parsed['host']) ? $parsed['host'] : ''; + if (isset($parsed['port'])) { + $urlInfo['authority'] = $urlInfo['authority'] . ":" . $parsed['port']; + } + $urlInfo['path'] = isset($parsed['path']) ? $parsed['path'] : ''; + $urlInfo['normalizedPath'] = !empty($parsed['path']) + ? rtrim($urlInfo['path'] ?: '', '/' . "/") . '/' + : '/'; + $urlInfo['isIp'] = !isset($parsed['host']) ? + 'false' : $this->isValidIp($parsed['host']); + + return $urlInfo; + } + + /** + * Evaluates whether a value is a valid host label per + * RFC 1123. If allow_subdomains is true, split on `.` and validate + * each subdomain separately. + * + * @return boolean + */ + public function isValidHostLabel($hostLabel, $allowSubDomains) + { + if (!isset($hostLabel) + || (!$allowSubDomains && strpos($hostLabel, '.') != false) + ) { + return false; + } + + if ($allowSubDomains) { + foreach (explode('.', $hostLabel) as $subdomain) { + if (!$this->validateHostLabel($subdomain)) { + return false; + } + } + return true; + } else { + return $this->validateHostLabel($hostLabel); + } + } + + /** + * Parse and validate string for ARN components. + * + * @return array|null + */ + public function parseArn($arnString) + { + if (is_null($arnString) + || substr( $arnString, 0, 3 ) !== "arn" + ) { + return null; + } + + $arn = []; + $parts = explode(':', $arnString, 6); + if (sizeof($parts) < 6) { + return null; + } + + $arn['partition'] = isset($parts[1]) ? $parts[1] : null; + $arn['service'] = isset($parts[2]) ? $parts[2] : null; + $arn['region'] = isset($parts[3]) ? $parts[3] : null; + $arn['accountId'] = isset($parts[4]) ? $parts[4] : null; + $arn['resourceId'] = isset($parts[5]) ? $parts[5] : null; + + if (empty($arn['partition']) + || empty($arn['service']) + || empty($arn['resourceId']) + ) { + return null; + } + $resource = $arn['resourceId']; + $arn['resourceId'] = preg_split("/[:\/]/", $resource); + + return $arn; + } + + /** + * Matches a region string to an AWS partition. + * + * @return mixed + */ + public function partition($region) + { + if (!is_string($region)) { + throw new UnresolvedEndpointException( + 'Value passed to `partition` must be `string`.' + ); + } + + $partitions = $this->partitions; + foreach ($partitions['partitions'] as $partition) { + if (array_key_exists($region, $partition['regions']) + || preg_match("/{$partition['regionRegex']}/", $region) + ) { + return $partition['outputs']; + } + } + //return `aws` partition if no match is found. + return $partitions['partitions'][0]['outputs']; + } + + /** + * Evaluates whether a value is a valid bucket name for virtual host + * style bucket URLs. + * + * @return boolean + */ + public function isVirtualHostableS3Bucket($bucketName, $allowSubdomains) + { + if ((is_null($bucketName) + || (strlen($bucketName) < 3 || strlen($bucketName) > 63)) + || preg_match(self::IPV4_RE, $bucketName) + || strtolower($bucketName) !== $bucketName + ) { + return false; + } + + if ($allowSubdomains) { + $labels = explode('.', $bucketName); + $results = []; + forEach($labels as $label) { + $results[] = $this->isVirtualHostableS3Bucket($label, false); + } + return !in_array(false, $results); + } + return $this->isValidHostLabel($bucketName, false); + } + + public function callFunction($funcCondition, &$inputParameters) + { + $funcArgs = []; + + forEach($funcCondition['argv'] as $arg) { + $funcArgs[] = $this->resolveValue($arg, $inputParameters); + } + + $funcName = str_replace('aws.', '', $funcCondition['fn']); + if ($funcName === 'isSet') { + $funcName = 'is_set'; + } + + $result = call_user_func_array( + [RulesetStandardLibrary::class, $funcName], + $funcArgs + ); + + if (isset($funcCondition['assign'])) { + $assign = $funcCondition['assign']; + if (isset($inputParameters[$assign])){ + throw new UnresolvedEndpointException( + "Assignment `{$assign}` already exists in input parameters" . + " or has already been assigned by an endpoint rule and cannot be overwritten." + ); + } + $inputParameters[$assign] = $result; + } + return $result; + } + + public function resolveValue($value, $inputParameters) + { + //Given a value, check if it's a function, reference or template. + //returns resolved value + if ($this->isFunc($value)) { + return $this->callFunction($value, $inputParameters); + } elseif ($this->isRef($value)) { + return isset($inputParameters[$value['ref']]) ? $inputParameters[$value['ref']] : null; + } elseif ($this->isTemplate($value)) { + return $this->resolveTemplateString($value, $inputParameters); + } + return $value; + } + + public function isFunc($arg) + { + return is_array($arg) && isset($arg['fn']); + } + + public function isRef($arg) + { + return is_array($arg) && isset($arg['ref']); + } + + public function isTemplate($arg) + { + return is_string($arg) && !empty(preg_match(self::TEMPLATE_SEARCH_RE, $arg)); + } + + public function resolveTemplateString($value, $inputParameters) + { + return preg_replace_callback( + self::TEMPLATE_PARSE_RE, + function ($match) use ($inputParameters) { + if (preg_match(self::TEMPLATE_ESCAPE_RE, $match[0])) { + return $match[1]; + } + + $notFoundMessage = 'Resolved value was null. Please check rules and ' . + 'input parameters and try again.'; + + $parts = explode("#", $match[1]); + if (count($parts) > 1) { + $resolvedValue = $inputParameters; + foreach($parts as $part) { + if (!isset($resolvedValue[$part])) { + throw new UnresolvedEndpointException($notFoundMessage); + } + $resolvedValue = $resolvedValue[$part]; + } + return $resolvedValue; + } else { + if (!isset($inputParameters[$parts[0]])) { + throw new UnresolvedEndpointException($notFoundMessage); + } + return $inputParameters[$parts[0]]; + } + }, + $value + ); + } + + private function validateHostLabel ($hostLabel) + { + if (empty($hostLabel) || strlen($hostLabel) > 63) { + return false; + } + if (preg_match(self::HOST_LABEL_RE, $hostLabel)) { + return true; + } + return false; + } + + private function isValidIp($hostName) + { + $isWrapped = strpos($hostName, '[') === 0 + && strrpos($hostName, ']') === strlen($hostName) - 1; + + return preg_match( + self::IPV4_RE, + $hostName + ) + //IPV6 enclosed in brackets + || ($isWrapped && preg_match( + self::IPV6_RE, + $hostName + )) + ? 'true' : 'false'; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/AwsException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/AwsException.php new file mode 100644 index 000000000..05b7b955f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/AwsException.php @@ -0,0 +1,270 @@ +data = isset($context['body']) ? $context['body'] : []; + $this->command = $command; + $this->response = isset($context['response']) ? $context['response'] : null; + $this->request = isset($context['request']) ? $context['request'] : null; + $this->requestId = isset($context['request_id']) + ? $context['request_id'] + : null; + $this->errorType = isset($context['type']) ? $context['type'] : null; + $this->errorCode = isset($context['code']) ? $context['code'] : null; + $this->errorShape = isset($context['error_shape']) ? $context['error_shape'] : null; + $this->connectionError = !empty($context['connection_error']); + $this->result = isset($context['result']) ? $context['result'] : null; + $this->transferInfo = isset($context['transfer_stats']) + ? $context['transfer_stats'] + : []; + $this->errorMessage = isset($context['message']) + ? $context['message'] + : null; + $this->monitoringEvents = []; + $this->maxRetriesExceeded = false; + parent::__construct($message, 0, $previous); + } + + public function __toString() + { + if (!$this->getPrevious()) { + return parent::__toString(); + } + + // PHP strangely shows the innermost exception first before the outer + // exception message. It also has a default character limit for + // exception message strings such that the "next" exception (this one) + // might not even get shown, causing developers to attempt to catch + // the inner exception instead of the actual exception because they + // can't see the outer exception's __toString output. + return sprintf( + "exception '%s' with message '%s'\n\n%s", + get_class($this), + $this->getMessage(), + parent::__toString() + ); + } + + /** + * Get the command that was executed. + * + * @return CommandInterface + */ + public function getCommand() + { + return $this->command; + } + + /** + * Get the concise error message if any. + * + * @return string|null + */ + public function getAwsErrorMessage() + { + return $this->errorMessage; + } + + /** + * Get the sent HTTP request if any. + * + * @return RequestInterface|null + */ + public function getRequest() + { + return $this->request; + } + + /** + * Get the received HTTP response if any. + * + * @return ResponseInterface|null + */ + public function getResponse() + { + return $this->response; + } + + /** + * Get the result of the exception if available + * + * @return ResultInterface|null + */ + public function getResult() + { + return $this->result; + } + + /** + * Returns true if this is a connection error. + * + * @return bool + */ + public function isConnectionError() + { + return $this->connectionError; + } + + /** + * If available, gets the HTTP status code of the corresponding response + * + * @return int|null + */ + public function getStatusCode() + { + return $this->response ? $this->response->getStatusCode() : null; + } + + /** + * Get the request ID of the error. This value is only present if a + * response was received and is not present in the event of a networking + * error. + * + * @return string|null Returns null if no response was received + */ + public function getAwsRequestId() + { + return $this->requestId; + } + + /** + * Get the AWS error type. + * + * @return string|null Returns null if no response was received + */ + public function getAwsErrorType() + { + return $this->errorType; + } + + /** + * Get the AWS error code. + * + * @return string|null Returns null if no response was received + */ + public function getAwsErrorCode() + { + return $this->errorCode; + } + + /** + * Get the AWS error shape. + * + * @return Shape|null Returns null if no response was received + */ + public function getAwsErrorShape() + { + return $this->errorShape; + } + + /** + * Get all transfer information as an associative array if no $name + * argument is supplied, or gets a specific transfer statistic if + * a $name attribute is supplied (e.g., 'retries_attempted'). + * + * @param string $name Name of the transfer stat to retrieve + * + * @return mixed|null|array + */ + public function getTransferInfo($name = null) + { + if (!$name) { + return $this->transferInfo; + } + + return isset($this->transferInfo[$name]) + ? $this->transferInfo[$name] + : null; + } + + /** + * Replace the transfer information associated with an exception. + * + * @param array $info + */ + public function setTransferInfo(array $info) + { + $this->transferInfo = $info; + } + + /** + * Returns whether the max number of retries is exceeded. + * + * @return bool + */ + public function isMaxRetriesExceeded() + { + return $this->maxRetriesExceeded; + } + + /** + * Sets the flag for max number of retries exceeded. + */ + public function setMaxRetriesExceeded() + { + $this->maxRetriesExceeded = true; + } + + public function hasKey($name) + { + return isset($this->data[$name]); + } + + public function get($key) + { + return $this[$key]; + } + + public function search($expression) + { + return JmesPath::search($expression, $this->toArray()); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/CommonRuntimeException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/CommonRuntimeException.php new file mode 100644 index 000000000..d17cd3a70 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/CommonRuntimeException.php @@ -0,0 +1,7 @@ +errorCode = $code; + $this->errorMessage = $message; + parent::__construct($message); + } + + /** + * Get the AWS error code. + * + * @return string|null Returns null if no response was received + */ + public function getAwsErrorCode() + { + return $this->errorCode; + } + + /** + * Get the concise error message if any. + * + * @return string|null + */ + public function getAwsErrorMessage() + { + return $this->errorMessage; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/IncalculablePayloadException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/IncalculablePayloadException.php new file mode 100644 index 000000000..a64e7428f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/IncalculablePayloadException.php @@ -0,0 +1,11 @@ + 'uploading parts to']); + $msg .= ". The following parts had errors:\n"; + /** @var $error AwsException */ + foreach ($prev as $part => $error) { + $msg .= "- Part {$part}: " . $error->getMessage(). "\n"; + } + } elseif ($prev instanceof AwsException) { + switch ($prev->getCommand()->getName()) { + case 'CreateMultipartUpload': + case 'InitiateMultipartUpload': + $action = 'initiating'; + break; + case 'CompleteMultipartUpload': + $action = 'completing'; + break; + } + if (isset($action)) { + $msg = strtr($msg, ['performing' => $action]); + } + $msg .= ": {$prev->getMessage()}"; + } + + if (!$prev instanceof \Exception) { + $prev = null; + } + + parent::__construct($msg, 0, $prev); + $this->state = $state; + } + + /** + * Get the state of the transfer + * + * @return UploadState + */ + public function getState() + { + return $this->state; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/TokenException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/TokenException.php new file mode 100644 index 000000000..f66960158 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Exception/TokenException.php @@ -0,0 +1,11 @@ +client = $client ?: new Client(); + } + + /** + * @param Psr7Request $request + * @param array $options + * + * @return Promise\Promise + */ + public function __invoke(Psr7Request $request, array $options = []) + { + $request = $request->withHeader( + 'User-Agent', + $request->getHeaderLine('User-Agent') + . ' ' . Utils::defaultUserAgent() + ); + + return $this->client->sendAsync($request, $this->parseOptions($options)) + ->otherwise( + static function ($e) { + $error = [ + 'exception' => $e, + 'connection_error' => $e instanceof ConnectException, + 'response' => null, + ]; + + if ( + ($e instanceof RequestException) + && $e->getResponse() + ) { + $error['response'] = $e->getResponse(); + } + + return new Promise\RejectedPromise($error); + } + ); + } + + private function parseOptions(array $options) + { + if (isset($options['http_stats_receiver'])) { + $fn = $options['http_stats_receiver']; + unset($options['http_stats_receiver']); + + $prev = isset($options['on_stats']) + ? $options['on_stats'] + : null; + + $options['on_stats'] = static function ( + TransferStats $stats + ) use ($fn, $prev) { + if (is_callable($prev)) { + $prev($stats); + } + $transferStats = ['total_time' => $stats->getTransferTime()]; + $transferStats += $stats->getHandlerStats(); + $fn($transferStats); + }; + } + + return $options; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Handler/GuzzleV6/GuzzleHandler.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Handler/GuzzleV6/GuzzleHandler.php new file mode 100644 index 000000000..9d08d2a81 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Handler/GuzzleV6/GuzzleHandler.php @@ -0,0 +1,11 @@ + [], + self::SIGN => [], + self::BUILD => [], + self::VALIDATE => [], + self::INIT => [], + ]; + + /** + * @param callable $handler HTTP handler. + */ + public function __construct(?callable $handler = null) + { + $this->handler = $handler; + } + + /** + * Dumps a string representation of the list. + * + * @return string + */ + public function __toString() + { + $str = ''; + $i = 0; + + foreach (array_reverse($this->steps) as $k => $step) { + foreach (array_reverse($step) as $j => $tuple) { + $str .= "{$i}) Step: {$k}, "; + if ($tuple[1]) { + $str .= "Name: {$tuple[1]}, "; + } + $str .= "Function: " . $this->debugCallable($tuple[0]) . "\n"; + $i++; + } + } + + if ($this->handler) { + $str .= "{$i}) Handler: " . $this->debugCallable($this->handler) . "\n"; + } + + return $str; + } + + /** + * Set the HTTP handler that actually returns a response. + * + * @param callable $handler Function that accepts a request and array of + * options and returns a Promise. + */ + public function setHandler(callable $handler) + { + $this->handler = $handler; + } + + /** + * Returns true if the builder has a handler. + * + * @return bool + */ + public function hasHandler() + { + return (bool) $this->handler; + } + + /** + * Checks if a middleware exists. The middleware + * should have been added with a name in order to + * use this method. + * + * @param string $name + * + * @return bool + */ + public function hasMiddleware(string $name): bool + { + return isset($this->named[$name]); + } + + /** + * Append a middleware to the init step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function appendInit(callable $middleware, $name = null) + { + $this->add(self::INIT, $name, $middleware); + } + + /** + * Prepend a middleware to the init step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function prependInit(callable $middleware, $name = null) + { + $this->add(self::INIT, $name, $middleware, true); + } + + /** + * Append a middleware to the validate step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function appendValidate(callable $middleware, $name = null) + { + $this->add(self::VALIDATE, $name, $middleware); + } + + /** + * Prepend a middleware to the validate step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function prependValidate(callable $middleware, $name = null) + { + $this->add(self::VALIDATE, $name, $middleware, true); + } + + /** + * Append a middleware to the build step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function appendBuild(callable $middleware, $name = null) + { + $this->add(self::BUILD, $name, $middleware); + } + + /** + * Prepend a middleware to the build step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function prependBuild(callable $middleware, $name = null) + { + $this->add(self::BUILD, $name, $middleware, true); + } + + /** + * Append a middleware to the sign step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function appendSign(callable $middleware, $name = null) + { + $this->add(self::SIGN, $name, $middleware); + } + + /** + * Prepend a middleware to the sign step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function prependSign(callable $middleware, $name = null) + { + $this->add(self::SIGN, $name, $middleware, true); + } + + /** + * Append a middleware to the attempt step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function appendAttempt(callable $middleware, $name = null) + { + $this->add(self::ATTEMPT, $name, $middleware); + } + + /** + * Prepend a middleware to the attempt step. + * + * @param callable $middleware Middleware function to add. + * @param string $name Name of the middleware. + */ + public function prependAttempt(callable $middleware, $name = null) + { + $this->add(self::ATTEMPT, $name, $middleware, true); + } + + /** + * Add a middleware before the given middleware by name. + * + * @param string|callable $findName Add before this + * @param string $withName Optional name to give the middleware + * @param callable $middleware Middleware to add. + */ + public function before($findName, $withName, callable $middleware) + { + $this->splice($findName, $withName, $middleware, true); + } + + /** + * Add a middleware after the given middleware by name. + * + * @param string|callable $findName Add after this + * @param string $withName Optional name to give the middleware + * @param callable $middleware Middleware to add. + */ + public function after($findName, $withName, callable $middleware) + { + $this->splice($findName, $withName, $middleware, false); + } + + /** + * Remove a middleware by name or by instance from the list. + * + * @param string|callable $nameOrInstance Middleware to remove. + */ + public function remove($nameOrInstance) + { + if (is_callable($nameOrInstance)) { + $this->removeByInstance($nameOrInstance); + } elseif (is_string($nameOrInstance)) { + $this->removeByName($nameOrInstance); + } + } + + /** + * Interpose a function between each middleware (e.g., allowing for a trace + * through the middleware layers). + * + * The interpose function is a function that accepts a "step" argument as a + * string and a "name" argument string. This function must then return a + * function that accepts the next handler in the list. This function must + * then return a function that accepts a CommandInterface and optional + * RequestInterface and returns a promise that is fulfilled with an + * Aws\ResultInterface or rejected with an Aws\Exception\AwsException + * object. + * + * @param callable|null $fn Pass null to remove any previously set function + */ + public function interpose(?callable $fn = null) + { + $this->sorted = null; + $this->interposeFn = $fn; + } + + /** + * Compose the middleware and handler into a single callable function. + * + * @return callable + */ + public function resolve() + { + if (!($prev = $this->handler)) { + throw new \LogicException('No handler has been specified'); + } + + if ($this->sorted === null) { + $this->sortMiddleware(); + } + + foreach ($this->sorted as $fn) { + $prev = $fn($prev); + } + + return $prev; + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return count($this->steps[self::INIT]) + + count($this->steps[self::VALIDATE]) + + count($this->steps[self::BUILD]) + + count($this->steps[self::SIGN]) + + count($this->steps[self::ATTEMPT]); + } + + /** + * Splices a function into the middleware list at a specific position. + * + * @param $findName + * @param $withName + * @param callable $middleware + * @param $before + */ + private function splice($findName, $withName, callable $middleware, $before) + { + if (!isset($this->named[$findName])) { + throw new \InvalidArgumentException("$findName not found"); + } + + $idx = $this->sorted = null; + $step = $this->named[$findName]; + + if ($withName) { + $this->named[$withName] = $step; + } + + foreach ($this->steps[$step] as $i => $tuple) { + if ($tuple[1] === $findName) { + $idx = $i; + break; + } + } + + $replacement = $before + ? [$this->steps[$step][$idx], [$middleware, $withName]] + : [[$middleware, $withName], $this->steps[$step][$idx]]; + array_splice($this->steps[$step], $idx, 1, $replacement); + } + + /** + * Provides a debug string for a given callable. + * + * @param array|callable $fn Function to write as a string. + * + * @return string + */ + private function debugCallable($fn) + { + if (is_string($fn)) { + return "callable({$fn})"; + } + + if (is_array($fn)) { + $ele = is_string($fn[0]) ? $fn[0] : get_class($fn[0]); + return "callable(['{$ele}', '{$fn[1]}'])"; + } + + return 'callable(' . spl_object_hash($fn) . ')'; + } + + /** + * Sort the middleware, and interpose if needed in the sorted list. + */ + private function sortMiddleware() + { + $this->sorted = []; + + if (!$this->interposeFn) { + foreach ($this->steps as $step) { + foreach ($step as $fn) { + $this->sorted[] = $fn[0]; + } + } + return; + } + + $ifn = $this->interposeFn; + // Interpose the interposeFn into the handler stack. + foreach ($this->steps as $stepName => $step) { + foreach ($step as $fn) { + $this->sorted[] = $ifn($stepName, $fn[1]); + $this->sorted[] = $fn[0]; + } + } + } + + private function removeByName($name) + { + if (!isset($this->named[$name])) { + return; + } + + $this->sorted = null; + $step = $this->named[$name]; + $this->steps[$step] = array_values( + array_filter( + $this->steps[$step], + function ($tuple) use ($name) { + return $tuple[1] !== $name; + } + ) + ); + } + + private function removeByInstance(callable $fn) + { + foreach ($this->steps as $k => $step) { + foreach ($step as $j => $tuple) { + if ($tuple[0] === $fn) { + $this->sorted = null; + unset($this->named[$this->steps[$k][$j][1]]); + unset($this->steps[$k][$j]); + } + } + } + } + + /** + * Add a middleware to a step. + * + * @param string $step Middleware step. + * @param string $name Middleware name. + * @param callable $middleware Middleware function to add. + * @param bool $prepend Prepend instead of append. + */ + private function add($step, $name, callable $middleware, $prepend = false) + { + $this->sorted = null; + + if ($prepend) { + $this->steps[$step][] = [$middleware, $name]; + } else { + array_unshift($this->steps[$step], [$middleware, $name]); + } + + if ($name) { + $this->named[$name] = $step; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasDataTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasDataTrait.php new file mode 100644 index 000000000..5910fff52 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasDataTrait.php @@ -0,0 +1,81 @@ +data); + } + + /** + * This method returns a reference to the variable to allow for indirect + * array modification (e.g., $foo['bar']['baz'] = 'qux'). + * + * @param $offset + * + * @return mixed|null + */ + #[\ReturnTypeWillChange] + public function & offsetGet($offset) + { + if (isset($this->data[$offset])) { + return $this->data[$offset]; + } + + $value = null; + return $value; + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + public function toArray() + { + return $this->data; + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return count($this->data); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasMonitoringEventsTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasMonitoringEventsTrait.php new file mode 100644 index 000000000..b28f0a462 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HasMonitoringEventsTrait.php @@ -0,0 +1,39 @@ +monitoringEvents; + } + + /** + * Prepend a client-side monitoring event to this object's event list + * + * @param array $event + */ + public function prependMonitoringEvent(array $event) + { + array_unshift($this->monitoringEvents, $event); + } + + /** + * Append a client-side monitoring event to this object's event list + * + * @param array $event + */ + public function appendMonitoringEvent(array $event) + { + $this->monitoringEvents []= $event; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HashInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HashInterface.php new file mode 100644 index 000000000..6304e4dfe --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/HashInterface.php @@ -0,0 +1,27 @@ +stream = $stream; + $this->hash = $hash; + $this->callback = $onComplete; + } + + public function read($length): string + { + $data = $this->stream->read($length); + $this->hash->update($data); + if ($this->eof()) { + $result = $this->hash->complete(); + if ($this->callback) { + call_user_func($this->callback, $result); + } + } + + return $data; + } + + public function seek($offset, $whence = SEEK_SET): void + { + // Seeking arbitrarily is not supported. + if ($offset !== 0) { + return; + } + + $this->hash->reset(); + $this->stream->seek($offset); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/History.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/History.php new file mode 100644 index 000000000..9f8a3bf04 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/History.php @@ -0,0 +1,161 @@ +maxEntries = $maxEntries; + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return count($this->entries); + } + + #[\ReturnTypeWillChange] + public function getIterator() + { + return new \ArrayIterator(array_values($this->entries)); + } + + /** + * Get the last finished command seen by the history container. + * + * @return CommandInterface + * @throws \LogicException if no commands have been seen. + */ + public function getLastCommand() + { + if (!$this->entries) { + throw new \LogicException('No commands received'); + } + + return end($this->entries)['command']; + } + + /** + * Get the last finished request seen by the history container. + * + * @return RequestInterface + * @throws \LogicException if no requests have been seen. + */ + public function getLastRequest() + { + if (!$this->entries) { + throw new \LogicException('No requests received'); + } + + return end($this->entries)['request']; + } + + /** + * Get the last received result or exception. + * + * @return ResultInterface|AwsException + * @throws \LogicException if no return values have been received. + */ + public function getLastReturn() + { + if (!$this->entries) { + throw new \LogicException('No entries'); + } + + $last = end($this->entries); + + if (isset($last['result'])) { + return $last['result']; + } + + if (isset($last['exception'])) { + return $last['exception']; + } + + throw new \LogicException('No return value for last entry.'); + } + + /** + * Initiate an entry being added to the history. + * + * @param CommandInterface $cmd Command be executed. + * @param RequestInterface $req Request being sent. + * + * @return string Returns the ticket used to finish the entry. + */ + public function start(CommandInterface $cmd, RequestInterface $req) + { + $ticket = uniqid(); + $this->entries[$ticket] = [ + 'command' => $cmd, + 'request' => $req, + 'result' => null, + 'exception' => null, + ]; + + return $ticket; + } + + /** + * Finish adding an entry to the history container. + * + * @param string $ticket Ticket returned from the start call. + * @param mixed $result The result (an exception or AwsResult). + */ + public function finish($ticket, $result) + { + if (!isset($this->entries[$ticket])) { + throw new \InvalidArgumentException('Invalid history ticket'); + } + + if (isset($this->entries[$ticket]['result']) + || isset($this->entries[$ticket]['exception']) + ) { + throw new \LogicException('History entry is already finished'); + } + + if ($result instanceof \Exception) { + $this->entries[$ticket]['exception'] = $result; + } else { + $this->entries[$ticket]['result'] = $result; + } + + if (count($this->entries) >= $this->maxEntries) { + $this->entries = array_slice($this->entries, -$this->maxEntries, null, true); + } + } + + /** + * Flush the history + */ + public function clear() + { + $this->entries = []; + } + + /** + * Converts the history to an array. + * + * @return array + */ + public function toArray() + { + return array_values($this->entries); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/IdempotencyTokenMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/IdempotencyTokenMiddleware.php new file mode 100644 index 000000000..c87d0bba6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/IdempotencyTokenMiddleware.php @@ -0,0 +1,120 @@ +bytesGenerator = $bytesGenerator + ?: $this->findCompatibleRandomSource(); + $this->service = $service; + $this->nextHandler = $nextHandler; + } + + public function __invoke( + CommandInterface $command, + ?RequestInterface $request = null + ) { + $handler = $this->nextHandler; + if ($this->bytesGenerator) { + $operation = $this->service->getOperation($command->getName()); + $members = $operation->getInput()->getMembers(); + foreach ($members as $member => $value) { + if ($value['idempotencyToken']) { + $bytes = call_user_func($this->bytesGenerator, 16); + // populating UUIDv4 only when the parameter is not set + $command[$member] = $command[$member] + ?: $this->getUuidV4($bytes); + // only one member could have the trait enabled + break; + } + } + } + return $handler($command, $request); + } + + /** + * This function generates a random UUID v4 string, + * which is used as auto filled token value. + * + * @param string $bytes 16 bytes of pseudo-random bytes + * @return string + * More information about UUID v4, see: + * https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 + * https://tools.ietf.org/html/rfc4122#page-14 + */ + private static function getUuidV4($bytes) + { + // set version to 0100 + $bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40); + // set bits 6-7 to 10 + $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80); + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4)); + } + + /** + * This function decides the PHP function used in generating random bytes. + * + * @return callable|null + */ + private function findCompatibleRandomSource() + { + if (function_exists('random_bytes')) { + return 'random_bytes'; + } + + if (function_exists('openssl_random_pseudo_bytes')) { + return 'openssl_random_pseudo_bytes'; + } + + if (function_exists('mcrypt_create_iv')) { + return 'mcrypt_create_iv'; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Identity/AwsCredentialIdentity.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Identity/AwsCredentialIdentity.php new file mode 100644 index 000000000..f7971126a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Identity/AwsCredentialIdentity.php @@ -0,0 +1,19 @@ +cache = new LruArrayCache(100); + $this->region = $clientRegion; + $this->config = $config; + } + + public function __invoke($command) + { + $s3Client = $this->getS3Client(); + $bucket = $command['Bucket']; + if ($identity = $this->cache->get($bucket)) { + if (!$identity->isExpired()) { + return Promise\Create::promiseFor($identity); + } + } + $response = $s3Client->createSession(['Bucket' => $bucket]); + $identity = new Aws\Identity\S3\S3ExpressIdentity( + $response['Credentials']['AccessKeyId'], + $response['Credentials']['SecretAccessKey'], + $response['Credentials']['SessionToken'], + $response['Credentials']['Expiration']->getTimestamp() + ); + $this->cache->set($bucket, $identity); + return Promise\Create::promiseFor($identity); + } + + private function getS3Client() + { + if (is_null($this->s3Client)) { + $this->s3Client = $this->config['client'] + ?? new Aws\S3\S3Client([ + 'region' => $this->region, + 'disable_express_session_auth' => true + ]); + } + return $this->s3Client; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/InputValidationMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/InputValidationMiddleware.php new file mode 100644 index 000000000..0c5a24dcc --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/InputValidationMiddleware.php @@ -0,0 +1,74 @@ +service = $service; + $this->nextHandler = $nextHandler; + $this->mandatoryAttributeList = $mandatoryAttributeList; + } + + public function __invoke(CommandInterface $cmd) { + $nextHandler = $this->nextHandler; + $op = $this->service->getOperation($cmd->getName())->toArray(); + if (!empty($op['input']['shape'])) { + $service = $this->service->toArray(); + if (!empty($input = $service['shapes'][$op['input']['shape']])) { + if (!empty($input['required'])) { + foreach ($input['required'] as $key => $member) { + if (in_array($member, $this->mandatoryAttributeList)) { + $argument = is_string($cmd[$member]) ? trim($cmd[$member]) : $cmd[$member]; + if ($argument === '' || $argument === null) { + $commandName = $cmd->getName(); + throw new \InvalidArgumentException( + "The {$commandName} operation requires non-empty parameter: {$member}" + ); + } + } + } + } + } + } + return $nextHandler($cmd); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/JsonCompiler.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/JsonCompiler.php new file mode 100644 index 000000000..5358b315a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/JsonCompiler.php @@ -0,0 +1,25 @@ +maxItems = $maxItems; + } + + public function get($key) + { + if (!isset($this->items[$key])) { + return null; + } + + $entry = $this->items[$key]; + + // Ensure the item is not expired. + if (!$entry[1] || time() < $entry[1]) { + // LRU: remove the item and push it to the end of the array. + unset($this->items[$key]); + $this->items[$key] = $entry; + return $entry[0]; + } + + unset($this->items[$key]); + return null; + } + + public function set($key, $value, $ttl = 0) + { + // Only call time() if the TTL is not 0/false/null + $ttl = $ttl ? time() + $ttl : 0; + $this->items[$key] = [$value, $ttl]; + + // Determine if there are more items in the cache than allowed. + $diff = count($this->items) - $this->maxItems; + + // Clear out least recently used items. + if ($diff > 0) { + // Reset to the beginning of the array and begin unsetting. + reset($this->items); + for ($i = 0; $i < $diff; $i++) { + unset($this->items[key($this->items)]); + next($this->items); + } + } + } + + public function remove($key) + { + unset($this->items[$key]); + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return count($this->items); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MetricsBuilder.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MetricsBuilder.php new file mode 100644 index 000000000..2d634cf57 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MetricsBuilder.php @@ -0,0 +1,480 @@ +metrics = []; + // The first metrics does not include the separator + // therefore it is reduced by default. + $this->metricsSize = -(strlen(self::$METRIC_SEPARATOR)); + } + + /** + * Build the metrics string value. + * + * @return string + */ + public function build(): string + { + if (empty($this->metrics)) { + return ""; + } + + return $this->encode(); + } + + /** + * Encodes the metrics by separating each metric + * with a comma. Example: for the metrics[A,B,C] then + * the output would be "A,B,C". + * + * @return string + */ + private function encode(): string + { + return implode(self::$METRIC_SEPARATOR, array_keys($this->metrics)); + } + + /** + * Appends a metric to the internal metrics holder after validating it. + * Increases the current metrics size by the length of the new metric + * plus the length of the encoding separator. + * Example: $currentSize = $currentSize + len($newMetric) + len($separator) + * + * @param string $metric The metric to append. + * + * @return void + */ + public function append(string $metric): void + { + if (!$this->canMetricBeAppended($metric)) { + return; + } + + $this->metrics[$metric] = true; + $this->metricsSize += strlen($metric) + strlen(self::$METRIC_SEPARATOR); + } + + /** + * Receives a feature group and a value to identify which one is the metric. + * For example, a group could be `signature` and a value could be `v4a`, + * then the metric will be `SIGV4A_SIGNING`. + * + * @param string $featureGroup the feature group such as `signature`. + * @param mixed $value the value for identifying the metric. + * + * @return void + */ + public function identifyMetricByValueAndAppend( + string $featureGroup, + $value + ): void + { + if (empty($value)) { + return; + } + + static $appendMetricFns = [ + 'signature' => 'appendSignatureMetric', + 'request_compression' => 'appendRequestCompressionMetric', + 'request_checksum' => 'appendRequestChecksumMetric', + 'credentials' => 'appendCredentialsMetric', + 'account_id_endpoint_mode' => 'appendAccountIdEndpointMode', + 'account_id_endpoint' => 'appendAccountIdEndpoint', + 'request_checksum_calculation' => 'appendRequestChecksumCalculationMetric', + ]; + + $fn = $appendMetricFns[$featureGroup]; + $this->{$fn}($value); + } + + /** + * Appends the signature metric based on the signature value. + * + * @param string $signature + * + * @return void + */ + private function appendSignatureMetric(string $signature): void + { + if ($signature === 'v4-s3express') { + $this->append(self::S3_EXPRESS_BUCKET); + } elseif ($signature === 'v4a') { + $this->append(self::SIGV4A_SIGNING); + } + } + + /** + * Appends the request compression metric based on the format resolved. + * + * @param string $format + * + * @return void + */ + private function appendRequestCompressionMetric(string $format): void + { + if ($format === 'gzip') { + $this->append(self::GZIP_REQUEST_COMPRESSION); + } + } + + /** + * Appends the request checksum metric based on the algorithm. + * + * @param string $algorithm + * + * @return void + */ + private function appendRequestChecksumMetric(string $algorithm): void + { + if ($algorithm === 'crc32') { + $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC32); + } elseif ($algorithm === 'crc32c') { + $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC32C); + } elseif ($algorithm === 'crc64') { + $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC64); + } elseif ($algorithm === 'sha1') { + $this->append(self::FLEXIBLE_CHECKSUMS_REQ_SHA1); + } elseif ($algorithm === 'sha256') { + $this->append(self::FLEXIBLE_CHECKSUMS_REQ_SHA256); + } + } + + + /** + * Appends the credentials metric based on the type of credentials + * resolved. + * + * @param CredentialsInterface $credentials + * + * @return void + */ + private function appendCredentialsMetric( + CredentialsInterface $credentials + ): void + { + $source = $credentials->toArray()['source'] ?? null; + if (empty($source)) { + return; + } + + static $credentialsMetricMapping = [ + CredentialSources::STATIC => + self::CREDENTIALS_CODE, + CredentialSources::ENVIRONMENT => + self::CREDENTIALS_ENV_VARS, + CredentialSources::ENVIRONMENT_STS_WEB_ID_TOKEN => + self::CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN, + CredentialSources::STS_ASSUME_ROLE => + self::CREDENTIALS_STS_ASSUME_ROLE, + CredentialSources::STS_WEB_ID_TOKEN => + self::CREDENTIALS_STS_ASSUME_ROLE_WEB_ID, + CredentialSources::PROFILE => + self::CREDENTIALS_PROFILE, + CredentialSources::IMDS => + self::CREDENTIALS_IMDS, + CredentialSources::ECS => + self::CREDENTIALS_HTTP, + CredentialSources::PROFILE_STS_WEB_ID_TOKEN => + self::CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN, + CredentialSources::PROFILE_PROCESS => + self::CREDENTIALS_PROFILE_PROCESS, + CredentialSources::PROFILE_SSO => + self::CREDENTIALS_PROFILE_SSO, + CredentialSources::PROFILE_SSO_LEGACY => + self::CREDENTIALS_PROFILE_SSO_LEGACY, + ]; + if (isset($credentialsMetricMapping[$source])) { + $this->append($credentialsMetricMapping[$source]); + } + } + + private function appendRequestChecksumCalculationMetric( + string $checkSumCalculation + ): void + { + static $checksumCalculationMetricMapping = [ + 'when_supported' => self::FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED, + 'when_required' => self::FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED, + ]; + + if (isset($checksumCalculationMetricMapping[$checkSumCalculation])) { + $this->append($checksumCalculationMetricMapping[$checkSumCalculation]); + } + } + + /** + * Appends the account_id_endpoint_mode metrics based on + * the value resolved. + * + * @param string $accountIdEndpointMode + * + * @return void + */ + private function appendAccountIdEndpointMode( + string $accountIdEndpointMode + ): void + { + if (empty($accountIdEndpointMode)) { + return; + } + + if ($accountIdEndpointMode === 'preferred') { + $this->append(self::ACCOUNT_ID_MODE_PREFERRED); + } elseif ($accountIdEndpointMode === 'disabled') { + $this->append(self::ACCOUNT_ID_MODE_DISABLED); + } elseif ($accountIdEndpointMode === 'required') { + $this->append(self::ACCOUNT_ID_MODE_REQUIRED); + } + } + + /** + * Appends the account_id_endpoint metric whenever a resolved endpoint + * matches an account_id endpoint pattern which also defined here. + * + * @param string $endpoint + * + * @return void + */ + private function appendAccountIdEndpoint(string $endpoint): void + { + static $pattern = "/(https|http):\\/\\/\\d{12}\\.ddb/"; + if (preg_match($pattern, $endpoint)) { + $this->append(self::ACCOUNT_ID_ENDPOINT); + } + } + + /** + * Resolves metrics from client arguments. + * + * @param array $args + * + * @return void + */ + public function resolveAndAppendFromArgs(array $args = []): void + { + static $metricsFnList = [ + 'appendEndpointMetric', + 'appendRetryConfigMetric', + 'appendResponseChecksumValidationMetric', + ]; + foreach ($metricsFnList as $metricFn) { + $this->{$metricFn}($args); + } + } + + /** + * Appends the endpoint metric into the metrics builder, + * just if a custom endpoint was provided at client construction. + * + * @param array $args + * + * @return void + */ + private function appendEndpointMetric(array $args): void + { + if (!empty($args['endpoint_override'])) { + $this->append(MetricsBuilder::ENDPOINT_OVERRIDE); + } + } + + /** + * Appends the retry mode metric into the metrics builder, + * based on the resolved retry config mode. + * + * @param array $args + * + * @return void + */ + private function appendRetryConfigMetric(array $args): void + { + $retries = $args['retries'] ?? null; + if ($retries === null) { + return; + } + + $retryMode = ''; + if ($retries instanceof \Aws\Retry\Configuration) { + $retryMode = $retries->getMode(); + } elseif (is_array($retries) + && isset($retries["mode"]) + ) { + $retryMode = $retries["mode"]; + } + + if ($retryMode === 'legacy') { + $this->append( + MetricsBuilder::RETRY_MODE_LEGACY + ); + } elseif ($retryMode === 'standard') { + $this->append( + MetricsBuilder::RETRY_MODE_STANDARD + ); + } elseif ($retryMode === 'adaptive') { + $this->append( + MetricsBuilder::RETRY_MODE_ADAPTIVE + ); + } + } + + /** + * Appends the provided/resolved response checksum validation mode. + * + * @param array $args + * + * @return void + */ + private function appendResponseChecksumValidationMetric(array $args): void + { + if (empty($args['response_checksum_validation'])) { + return; + } + + $checksumValidation = $args['response_checksum_validation']; + static $checksumValidationMetricMapping = [ + 'when_supported' => MetricsBuilder::FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED, + 'when_required' => MetricsBuilder::FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED, + ]; + + if (isset($checksumValidationMetricMapping[$checksumValidation])) { + $this->append($checksumValidationMetricMapping[$checksumValidation]); + } + } + + /** + * Validates if a metric can be appended by ensuring the total size, + * including the new metric and separator, does not exceed the limit. + * Also checks that the metric does not already exist. + * Example: Appendable if: + * $currentSize + len($newMetric) + len($separator) <= MAX_SIZE + * and: + * $newMetric not in $existingMetrics + * + * @param string $newMetric The metric to validate. + * + * @return bool True if the metric can be appended, false otherwise. + */ + private function canMetricBeAppended(string $newMetric): bool + { + if ($newMetric === "") { + return false; + } + + if ($this->metricsSize + + (strlen($newMetric) + strlen(self::$METRIC_SEPARATOR)) + > self::$MAX_METRICS_SIZE + ) { + return false; + } + + if (isset($this->metrics[$newMetric])) { + return false; + } + + return true; + } + + /** + * Returns the metrics builder from the property @context of a command. + * + * @param Command $command + * + * @return MetricsBuilder + */ + public static function fromCommand(CommandInterface $command): MetricsBuilder + { + return $command->getMetricsBuilder(); + } + + /** + * Helper method for appending a metrics capture middleware into a + * handler stack given. The middleware appended here is on top of the + * build step. + * + * @param HandlerList $handlerList + * @param $metric + * + * @return void + */ + public static function appendMetricsCaptureMiddleware( + HandlerList $handlerList, + $metric + ): void + { + $middlewareName = 'metrics-capture-'.$metric; + if (!$handlerList->hasMiddleware($middlewareName)) { + $handlerList->appendBuild( + Middleware::tap( + function (CommandInterface $command) use ($metric) { + self::fromCommand($command)->append( + $metric + ); + } + ), + $middlewareName + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Middleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Middleware.php new file mode 100644 index 000000000..a5705ad82 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Middleware.php @@ -0,0 +1,470 @@ +getOperation($command->getName()); + $source = $command[$sourceParameter]; + + if ($source !== null + && $operation->getInput()->hasMember($bodyParameter) + ) { + $lazyOpenStream = new LazyOpenStream($source, 'r'); + $command[$bodyParameter] = $lazyOpenStream; + unset($command[$sourceParameter]); + + $next = $handler($command, $request); + // To avoid failures in some tests cases + if ($next !== null && method_exists($next, 'then')) { + return $next->then( + function ($result) use ($lazyOpenStream) { + // To make sure the resource is closed. + $lazyOpenStream->close(); + + return $result; + } + )->otherwise(function (\Throwable $e) use ($lazyOpenStream) { + $lazyOpenStream->close(); + + throw $e; + }); + } + + return $next; + } + + return $handler($command, $request); + }; + }; + } + + /** + * Adds a middleware that uses client-side validation. + * + * @param Service $api API being accessed. + * + * @return callable + */ + public static function validation(Service $api, ?Validator $validator = null) + { + $validator = $validator ?: new Validator(); + return function (callable $handler) use ($api, $validator) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($api, $validator, $handler) { + if ($api->isModifiedModel()) { + $api = new Service( + $api->getDefinition(), + $api->getProvider() + ); + } + $operation = $api->getOperation($command->getName()); + $validator->validate( + $command->getName(), + $operation->getInput(), + $command->toArray() + ); + return $handler($command, $request); + }; + }; + } + + /** + * Builds an HTTP request for a command. + * + * @param callable $serializer Function used to serialize a request for a + * command. + * @param EndpointProviderV2 | null $endpointProvider + * @param array $providerArgs + * @return callable + */ + public static function requestBuilder($serializer) + { + return function (callable $handler) use ($serializer) { + return function (CommandInterface $command, $endpoint = null) use ($serializer, $handler) { + return $handler($command, $serializer($command, $endpoint)); + }; + }; + } + + /** + * Creates a middleware that signs requests for a command. + * + * @param callable $credProvider Credentials provider function that + * returns a promise that is resolved + * with a CredentialsInterface object. + * @param callable $signatureFunction Function that accepts a Command + * object and returns a + * SignatureInterface. + * + * @return callable + */ + public static function signer( + callable $credProvider, + callable $signatureFunction, + $tokenProvider = null, + $config = [] + ) { + return function (callable $handler) use ($signatureFunction, $credProvider, $tokenProvider, $config) { + return function ( + CommandInterface $command, + RequestInterface $request + ) use ($handler, $signatureFunction, $credProvider, $tokenProvider, $config) { + $signer = $signatureFunction($command); + if ($signer instanceof TokenAuthorization) { + return $tokenProvider()->then( + function (TokenInterface $token) + use ($handler, $command, $signer, $request) { + return $handler( + $command, + $signer->authorizeRequest($request, $token) + ); + } + ); + } + + if ($signer instanceof S3ExpressSignature) { + $credentialPromise = $config['s3_express_identity_provider']($command); + } else { + $credentialPromise = $credProvider(); + } + + return $credentialPromise->then( + function (CredentialsInterface $creds) + use ($handler, $command, $signer, $request) { + // Capture credentials metric + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'credentials', + $creds + ); + + return $handler( + $command, + $signer->signRequest($request, $creds) + ); + } + ); + }; + }; + } + + /** + * Creates a middleware that invokes a callback at a given step. + * + * The tap callback accepts a CommandInterface and RequestInterface as + * arguments but is not expected to return a new value or proxy to + * downstream middleware. It's simply a way to "tap" into the handler chain + * to debug or get an intermediate value. + * + * @param callable $fn Tap function + * + * @return callable + */ + public static function tap(callable $fn) + { + return function (callable $handler) use ($fn) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $fn) { + $fn($command, $request); + return $handler($command, $request); + }; + }; + } + + /** + * Middleware wrapper function that retries requests based on the boolean + * result of invoking the provided "decider" function. + * + * If no delay function is provided, a simple implementation of exponential + * backoff will be utilized. + * + * @param callable $decider Function that accepts the number of retries, + * a request, [result], and [exception] and + * returns true if the command is to be retried. + * @param callable $delay Function that accepts the number of retries and + * returns the number of milliseconds to delay. + * @param bool $stats Whether to collect statistics on retries and the + * associated delay. + * + * @return callable + */ + public static function retry( + ?callable $decider = null, + ?callable $delay = null, + $stats = false + ) { + $decider = $decider ?: RetryMiddleware::createDefaultDecider(); + $delay = $delay ?: [RetryMiddleware::class, 'exponentialDelay']; + + return function (callable $handler) use ($decider, $delay, $stats) { + return new RetryMiddleware($decider, $delay, $handler, $stats); + }; + } + /** + * Middleware wrapper function that adds an invocation id header to + * requests, which is only applied after the build step. + * + * This is a uniquely generated UUID to identify initial and subsequent + * retries as part of a complete request lifecycle. + * + * @return callable + */ + public static function invocationId() + { + return function (callable $handler) { + return function ( + CommandInterface $command, + RequestInterface $request + ) use ($handler){ + return $handler($command, $request->withHeader( + 'aws-sdk-invocation-id', + md5(uniqid(gethostname(), true)) + )); + }; + }; + } + /** + * Middleware wrapper function that adds a Content-Type header to requests. + * This is only done when the Content-Type has not already been set, and the + * request body's URI is available. It then checks the file extension of the + * URI to determine the mime-type. + * + * @param array $operations Operations that Content-Type should be added to. + * + * @return callable + */ + public static function contentType(array $operations) + { + return function (callable $handler) use ($operations) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $operations) { + if (!$request->hasHeader('Content-Type') + && in_array($command->getName(), $operations, true) + && ($uri = $request->getBody()->getMetadata('uri')) + ) { + $request = $request->withHeader( + 'Content-Type', + Psr7\MimeType::fromFilename($uri) ?: 'application/octet-stream' + ); + } + + return $handler($command, $request); + }; + }; + } + /** + * Middleware wrapper function that adds a trace id header to requests + * from clients instantiated in supported Lambda runtime environments. + * + * The purpose for this header is to track and stop Lambda functions + * from being recursively invoked due to misconfigured resources. + * + * @return callable + */ + public static function recursionDetection() + { + return function (callable $handler) { + return function ( + CommandInterface $command, + RequestInterface $request + ) use ($handler){ + $isLambda = getenv('AWS_LAMBDA_FUNCTION_NAME'); + $traceId = str_replace('\e', '\x1b', getenv('_X_AMZN_TRACE_ID')); + + if ($isLambda && $traceId) { + if (!$request->hasHeader('X-Amzn-Trace-Id')) { + $ignoreChars = ['=', ';', ':', '+', '&', '[', ']', '{', '}', '"', '\'', ',']; + $traceIdEncoded = rawurlencode(stripcslashes($traceId)); + + foreach($ignoreChars as $char) { + $encodedChar = rawurlencode($char); + $traceIdEncoded = str_replace($encodedChar, $char, $traceIdEncoded); + } + + return $handler($command, $request->withHeader( + 'X-Amzn-Trace-Id', + $traceIdEncoded + )); + } + } + return $handler($command, $request); + }; + }; + } + /** + * Tracks command and request history using a history container. + * + * This is useful for testing. + * + * @param History $history History container to store entries. + * + * @return callable + */ + public static function history(History $history) + { + return function (callable $handler) use ($history) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $history) { + $ticket = $history->start($command, $request); + return $handler($command, $request) + ->then( + function ($result) use ($history, $ticket) { + $history->finish($ticket, $result); + return $result; + }, + function ($reason) use ($history, $ticket) { + $history->finish($ticket, $reason); + return Promise\Create::rejectionFor($reason); + } + ); + }; + }; + } + + /** + * Creates a middleware that applies a map function to requests as they + * pass through the middleware. + * + * @param callable $f Map function that accepts a RequestInterface and + * returns a RequestInterface. + * + * @return callable + */ + public static function mapRequest(callable $f) + { + return function (callable $handler) use ($f) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $f) { + return $handler($command, $f($request)); + }; + }; + } + + /** + * Creates a middleware that applies a map function to commands as they + * pass through the middleware. + * + * @param callable $f Map function that accepts a command and returns a + * command. + * + * @return callable + */ + public static function mapCommand(callable $f) + { + return function (callable $handler) use ($f) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $f) { + return $handler($f($command), $request); + }; + }; + } + + /** + * Creates a middleware that applies a map function to results. + * + * @param callable $f Map function that accepts an Aws\ResultInterface and + * returns an Aws\ResultInterface. + * + * @return callable + */ + public static function mapResult(callable $f) + { + return function (callable $handler) use ($f) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, $f) { + return $handler($command, $request)->then($f); + }; + }; + } + + public static function timer() + { + return function (callable $handler) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler) { + $start = microtime(true); + return $handler($command, $request) + ->then( + function (ResultInterface $res) use ($start) { + if (!isset($res['@metadata'])) { + $res['@metadata'] = []; + } + if (!isset($res['@metadata']['transferStats'])) { + $res['@metadata']['transferStats'] = []; + } + + $res['@metadata']['transferStats']['total_time'] + = microtime(true) - $start; + + return $res; + }, + function ($err) use ($start) { + if ($err instanceof AwsException) { + $err->setTransferInfo([ + 'total_time' => microtime(true) - $start, + ] + $err->getTransferInfo()); + } + return Promise\Create::rejectionFor($err); + } + ); + }; + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MockHandler.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MockHandler.php new file mode 100644 index 000000000..7d6b4539e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MockHandler.php @@ -0,0 +1,148 @@ +queue = []; + $this->onFulfilled = $onFulfilled; + $this->onRejected = $onRejected; + + if ($resultOrQueue) { + call_user_func_array([$this, 'append'], array_values($resultOrQueue)); + } + } + + /** + * Adds one or more variadic ResultInterface or AwsException objects to the + * queue. + */ + public function append() + { + foreach (func_get_args() as $value) { + if ($value instanceof ResultInterface + || $value instanceof Exception + || is_callable($value) + ) { + $this->queue[] = $value; + } else { + throw new \InvalidArgumentException('Expected an Aws\ResultInterface or Exception.'); + } + } + } + + /** + * Adds one or more \Exception or \Throwable to the queue + */ + public function appendException() + { + foreach (func_get_args() as $value) { + if ($value instanceof \Exception || $value instanceof \Throwable) { + $this->queue[] = $value; + } else { + throw new \InvalidArgumentException('Expected an \Exception or \Throwable.'); + } + } + } + + public function __invoke( + CommandInterface $command, + RequestInterface $request + ) { + if (!$this->queue) { + $last = $this->lastCommand + ? ' The last command sent was ' . $this->lastCommand->getName() . '.' + : ''; + throw new \RuntimeException('Mock queue is empty. Trying to send a ' + . $command->getName() . ' command failed.' . $last); + } + + $this->lastCommand = $command; + $this->lastRequest = $request; + + $result = array_shift($this->queue); + + if (is_callable($result)) { + $result = $result($command, $request); + } + + if ($result instanceof \Exception) { + $result = new RejectedPromise($result); + } else { + // Add an effective URI and statusCode if not present. + $meta = $result['@metadata']; + if (!isset($meta['effectiveUri'])) { + $meta['effectiveUri'] = (string) $request->getUri(); + } + if (!isset($meta['statusCode'])) { + $meta['statusCode'] = 200; + } + $result['@metadata'] = $meta; + $result = Promise\Create::promiseFor($result); + } + + $result->then($this->onFulfilled, $this->onRejected); + + return $result; + } + + /** + * Get the last received request. + * + * @return RequestInterface|null + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + /** + * Get the last received command. + * + * @return CommandInterface + */ + public function getLastCommand() + { + return $this->lastCommand; + } + + /** + * Returns the number of remaining items in the queue. + * + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return count($this->queue); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MonitoringEventsInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MonitoringEventsInterface.php new file mode 100644 index 000000000..662927fe0 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/MonitoringEventsInterface.php @@ -0,0 +1,30 @@ + true, 'region' => true] + ); + $args['region']['required'] = false; + unset($args['region']['fn']); + unset($args['region']['default']); + + return $args + [ + 'client_factory' => [ + 'type' => 'config', + 'valid' => ['callable'], + 'doc' => 'A callable that takes an array of client' + . ' configuration arguments and returns a regionalized' + . ' client.', + 'required' => true, + 'internal' => true, + 'default' => function (array $args) { + $namespace = manifest($args['service'])['namespace']; + $klass = "Aws\\{$namespace}\\{$namespace}Client"; + $region = isset($args['region']) ? $args['region'] : null; + + return function (array $args) use ($klass, $region) { + if ($region && empty($args['region'])) { + $args['region'] = $region; + } + + return new $klass($args); + }; + }, + ], + 'partition' => [ + 'type' => 'config', + 'valid' => ['string', PartitionInterface::class], + 'doc' => 'AWS partition to connect to. Valid partitions' + . ' include "aws," "aws-cn," and "aws-us-gov." Used to' + . ' restrict the scope of the mapRegions method.', + 'default' => function (array $args) { + $region = isset($args['region']) ? $args['region'] : ''; + return PartitionEndpointProvider::defaultProvider() + ->getPartition($region, $args['service']); + }, + 'fn' => function ($value, array &$args) { + if (is_string($value)) { + $value = PartitionEndpointProvider::defaultProvider() + ->getPartitionByName($value); + } + + if (!$value instanceof PartitionInterface) { + throw new \InvalidArgumentException('No valid partition' + . ' was provided. Provide a concrete partition or' + . ' the name of a partition (e.g., "aws," "aws-cn,"' + . ' or "aws-us-gov").' + ); + } + $ruleset = EndpointDefinitionProvider::getEndpointRuleset( + $args['service'], + isset($args['version']) ? $args['version'] : 'latest' + ); + $partitions = EndpointDefinitionProvider::getPartitions(); + $args['endpoint_provider'] = new EndpointProviderV2($ruleset, $partitions); + } + ], + ]; + } + + /** + * The multi-region client constructor accepts the following options: + * + * - client_factory: (callable) An optional callable that takes an array of + * client configuration arguments and returns a regionalized client. + * - partition: (Aws\Endpoint\Partition|string) AWS partition to connect to. + * Valid partitions include "aws," "aws-cn," and "aws-us-gov." Used to + * restrict the scope of the mapRegions method. + * - region: (string) Region to connect to when no override is provided. + * Used to create the default client factory and determine the appropriate + * AWS partition when present. + * + * @param array $args Client configuration arguments. + */ + public function __construct(array $args = []) + { + if (!isset($args['service'])) { + $args['service'] = $this->parseClass(); + } + + $this->handlerList = new HandlerList(function ( + CommandInterface $command + ) { + list($region, $args) = $this->getRegionFromArgs($command->toArray()); + $command = $this->getClientFromPool($region) + ->getCommand($command->getName(), $args); + + if ($this->isUseCustomHandler()) { + $command->getHandlerList()->setHandler($this->customHandler); + } + + return $this->executeAsync($command); + }); + + $argDefinitions = static::getArguments(); + $resolver = new ClientResolver($argDefinitions); + $args = $resolver->resolve($args, $this->handlerList); + $this->config = $args['config']; + $this->factory = $args['client_factory']; + $this->partition = $args['partition']; + $this->args = array_diff_key($args, $args['config']); + } + + /** + * Get the region to which the client is configured to send requests by + * default. + * + * @return string + */ + public function getRegion() + { + return $this->getClientFromPool()->getRegion(); + } + + /** + * Create a command for an operation name. + * + * Special keys may be set on the command to control how it behaves, + * including: + * + * - @http: Associative array of transfer specific options to apply to the + * request that is serialized for this command. Available keys include + * "proxy", "verify", "timeout", "connect_timeout", "debug", "delay", and + * "headers". + * - @region: The region to which the command should be sent. + * + * @param string $name Name of the operation to use in the command + * @param array $args Arguments to pass to the command + * + * @return CommandInterface + * @throws \InvalidArgumentException if no command can be found by name + */ + public function getCommand($name, array $args = []) + { + return new Command($name, $args, clone $this->getHandlerList()); + } + + public function getConfig($option = null) + { + if (null === $option) { + return $this->config; + } + + if (isset($this->config[$option])) { + return $this->config[$option]; + } + + return $this->getClientFromPool()->getConfig($option); + } + + public function getCredentials() + { + return $this->getClientFromPool()->getCredentials(); + } + + public function getHandlerList() + { + return $this->handlerList; + } + + public function getApi() + { + return $this->getClientFromPool()->getApi(); + } + + public function getEndpoint() + { + return $this->getClientFromPool()->getEndpoint(); + } + + public function useCustomHandler(callable $handler) + { + $this->customHandler = $handler; + } + + private function isUseCustomHandler() + { + return isset($this->customHandler); + } + + /** + * @param string $region Omit this argument or pass in an empty string to + * allow the configured client factory to apply the + * region. + * + * @return AwsClientInterface + */ + protected function getClientFromPool($region = '') + { + if (empty($this->clientPool[$region])) { + $factory = $this->factory; + $this->clientPool[$region] = $factory( + array_replace($this->args, array_filter(['region' => $region])) + ); + } + + return $this->clientPool[$region]; + } + + /** + * Parse the class name and return the "service" name of the client. + * + * @return string + */ + private function parseClass() + { + $klass = get_class($this); + + if ($klass === __CLASS__) { + return ''; + } + + return strtolower(substr($klass, strrpos($klass, '\\') + 1, -17)); + } + + private function getRegionFromArgs(array $args) + { + $region = isset($args['@region']) + ? $args['@region'] + : $this->getRegion(); + unset($args['@region']); + + return [$region, $args]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploadManager.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploadManager.php new file mode 100644 index 000000000..adc356ede --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploadManager.php @@ -0,0 +1,328 @@ + null, + 'state' => null, + 'concurrency' => self::DEFAULT_CONCURRENCY, + 'prepare_data_source' => null, + 'before_initiate' => null, + 'before_upload' => null, + 'before_complete' => null, + 'exception_class' => MultipartUploadException::class, + ]; + + /** @var Client Client used for the upload. */ + protected $client; + + /** @var array Configuration used to perform the upload. */ + protected $config; + + /** @var array Service-specific information about the upload workflow. */ + protected $info; + + /** @var PromiseInterface Promise that represents the multipart upload. */ + protected $promise; + + /** @var UploadState State used to manage the upload. */ + protected $state; + + /** @var bool Configuration used to indicate if upload progress will be displayed. */ + protected $displayProgress; + + /** + * @param Client $client + * @param array $config + */ + public function __construct(Client $client, array $config = []) + { + $this->client = $client; + $this->info = $this->loadUploadWorkflowInfo(); + $this->config = $config + self::$defaultConfig; + $this->state = $this->determineState(); + + if (isset($config['display_progress']) + && is_bool($config['display_progress']) + ) { + $this->displayProgress = $config['display_progress']; + } + } + + /** + * Returns the current state of the upload + * + * @return UploadState + */ + public function getState() + { + return $this->state; + } + + /** + * Upload the source using multipart upload operations. + * + * @return Result The result of the CompleteMultipartUpload operation. + * @throws \LogicException if the upload is already complete or aborted. + * @throws MultipartUploadException if an upload operation fails. + */ + public function upload() + { + return $this->promise()->wait(); + } + + /** + * Upload the source asynchronously using multipart upload operations. + * + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + if ($this->promise) { + return $this->promise; + } + + return $this->promise = Promise\Coroutine::of(function () { + // Initiate the upload. + if ($this->state->isCompleted()) { + throw new \LogicException('This multipart upload has already ' + . 'been completed or aborted.' + ); + } + + if (!$this->state->isInitiated()) { + // Execute the prepare callback. + if (is_callable($this->config["prepare_data_source"])) { + $this->config["prepare_data_source"](); + } + + $result = (yield $this->execCommand('initiate', $this->getInitiateParams())); + $this->state->setUploadId( + $this->info['id']['upload_id'], + $result[$this->info['id']['upload_id']] + ); + $this->state->setStatus(UploadState::INITIATED); + } + + // Create a command pool from a generator that yields UploadPart + // commands for each upload part. + $resultHandler = $this->getResultHandler($errors); + $commands = new CommandPool( + $this->client, + $this->getUploadCommands($resultHandler), + [ + 'concurrency' => $this->config['concurrency'], + 'before' => $this->config['before_upload'], + ] + ); + + // Execute the pool of commands concurrently, and process errors. + yield $commands->promise(); + if ($errors) { + throw new $this->config['exception_class']($this->state, $errors); + } + + // Complete the multipart upload. + yield $this->execCommand('complete', $this->getCompleteParams()); + $this->state->setStatus(UploadState::COMPLETED); + })->otherwise($this->buildFailureCatch()); + } + + private function transformException($e) + { + // Throw errors from the operations as a specific Multipart error. + if ($e instanceof AwsException) { + $e = new $this->config['exception_class']($this->state, $e); + } + throw $e; + } + + private function buildFailureCatch() + { + if (interface_exists("Throwable")) { + return function (\Throwable $e) { + return $this->transformException($e); + }; + } else { + return function (\Exception $e) { + return $this->transformException($e); + }; + } + } + + protected function getConfig() + { + return $this->config; + } + + /** + * Provides service-specific information about the multipart upload + * workflow. + * + * This array of data should include the keys: 'command', 'id', and 'part_num'. + * + * @return array + */ + abstract protected function loadUploadWorkflowInfo(); + + /** + * Determines the part size to use for upload parts. + * + * Examines the provided partSize value and the source to determine the + * best possible part size. + * + * @throws \InvalidArgumentException if the part size is invalid. + * + * @return int + */ + abstract protected function determinePartSize(); + + /** + * Uses information from the Command and Result to determine which part was + * uploaded and mark it as uploaded in the upload's state. + * + * @param CommandInterface $command + * @param ResultInterface $result + */ + abstract protected function handleResult( + CommandInterface $command, + ResultInterface $result + ); + + /** + * Gets the service-specific parameters used to initiate the upload. + * + * @return array + */ + abstract protected function getInitiateParams(); + + /** + * Gets the service-specific parameters used to complete the upload. + * + * @return array + */ + abstract protected function getCompleteParams(); + + /** + * Based on the config and service-specific workflow info, creates a + * `Promise` for an `UploadState` object. + */ + private function determineState(): UploadState + { + // If the state was provided via config, then just use it. + if ($this->config['state'] instanceof UploadState) { + return $this->config['state']; + } + + // Otherwise, construct a new state from the provided identifiers. + $required = $this->info['id']; + $id = [$required['upload_id'] => null]; + unset($required['upload_id']); + foreach ($required as $key => $param) { + if (!$this->config[$key]) { + throw new IAE('You must provide a value for "' . $key . '" in ' + . 'your config for the MultipartUploader for ' + . $this->client->getApi()->getServiceFullName() . '.'); + } + $id[$param] = $this->config[$key]; + } + $state = new UploadState($id, $this->config); + $state->setPartSize($this->determinePartSize()); + + return $state; + } + + /** + * Executes a MUP command with all of the parameters for the operation. + * + * @param string $operation Name of the operation. + * @param array $params Service-specific params for the operation. + * + * @return PromiseInterface + */ + protected function execCommand($operation, array $params) + { + // Create the command. + $command = $this->client->getCommand( + $this->info['command'][$operation], + $params + $this->state->getId() + ); + + // Execute the before callback. + if (is_callable($this->config["before_{$operation}"])) { + $this->config["before_{$operation}"]($command); + } + + // Execute the command asynchronously and return the promise. + return $this->client->executeAsync($command); + } + + /** + * Returns a middleware for processing responses of part upload operations. + * + * - Adds an onFulfilled callback that calls the service-specific + * handleResult method on the Result of the operation. + * - Adds an onRejected callback that adds the error to an array of errors. + * - Has a passedByRef $errors arg that the exceptions get added to. The + * caller should use that &$errors array to do error handling. + * + * @param array $errors Errors from upload operations are added to this. + * + * @return callable + */ + protected function getResultHandler(&$errors = []) + { + return function (callable $handler) use (&$errors) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler, &$errors) { + return $handler($command, $request)->then( + function (ResultInterface $result) use ($command) { + $this->handleResult($command, $result); + return $result; + }, + function (AwsException $e) use (&$errors) { + $errors[$e->getCommand()[$this->info['part_num']]] = $e; + return new Result(); + } + ); + }; + }; + } + + /** + * Creates a generator that yields part data for the upload's source. + * + * Yields associative arrays of parameters that are ultimately merged in + * with others to form the complete parameters of a command. This can + * include the Body parameter, which is a limited stream (i.e., a Stream + * object, decorated with a LimitStream). + * + * @param callable $resultHandler + * + * @return \Generator + */ + abstract protected function getUploadCommands(callable $resultHandler); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploader.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploader.php new file mode 100644 index 000000000..306be14f1 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/AbstractUploader.php @@ -0,0 +1,153 @@ +source = $this->determineSource($source); + parent::__construct($client, $config); + } + + /** + * Create a stream for a part that starts at the current position and + * has a length of the upload part size (or less with the final part). + * + * @param Stream $stream + * + * @return Psr7\LimitStream + */ + protected function limitPartStream(Stream $stream) + { + // Limit what is read from the stream to the part size. + return new Psr7\LimitStream( + $stream, + $this->state->getPartSize(), + $this->source->tell() + ); + } + + protected function getUploadCommands(callable $resultHandler) + { + // Determine if the source can be seeked. + $seekable = $this->source->isSeekable() + && $this->source->getMetadata('wrapper_type') === 'plainfile'; + + for ($partNumber = 1; $this->isEof($seekable); $partNumber++) { + // If we haven't already uploaded this part, yield a new part. + if (!$this->state->hasPartBeenUploaded($partNumber)) { + $partStartPos = $this->source->tell(); + if (!($data = $this->createPart($seekable, $partNumber))) { + break; + } + $command = $this->client->getCommand( + $this->info['command']['upload'], + $data + $this->state->getId() + ); + $command->getHandlerList()->appendSign($resultHandler, 'mup'); + $numberOfParts = $this->getNumberOfParts($this->state->getPartSize()); + if (isset($numberOfParts) && $partNumber > $numberOfParts) { + throw new $this->config['exception_class']( + $this->state, + new AwsException( + "Maximum part number for this job exceeded, file has likely been corrupted." . + " Please restart this upload.", + $command + ) + ); + } + + yield $command; + if ($this->source->tell() > $partStartPos) { + continue; + } + } + + // Advance the source's offset if not already advanced. + if ($seekable) { + $this->source->seek(min( + $this->source->tell() + $this->state->getPartSize(), + $this->source->getSize() + )); + } else { + $this->source->read($this->state->getPartSize()); + } + } + } + + /** + * Generates the parameters for an upload part by analyzing a range of the + * source starting from the current offset up to the part size. + * + * @param bool $seekable + * @param int $number + * + * @return array|null + */ + abstract protected function createPart($seekable, $number); + + /** + * Checks if the source is at EOF. + * + * @param bool $seekable + * + * @return bool + */ + private function isEof($seekable) + { + return $seekable + ? $this->source->tell() < $this->source->getSize() + : !$this->source->eof(); + } + + /** + * Turns the provided source into a stream and stores it. + * + * If a string is provided, it is assumed to be a filename, otherwise, it + * passes the value directly to `Psr7\Utils::streamFor()`. + * + * @param mixed $source + * + * @return Stream + */ + private function determineSource($source) + { + // Use the contents of a file as the data source. + if (is_string($source)) { + $source = Psr7\Utils::tryFopen($source, 'r'); + } + + // Create a source stream. + $stream = Psr7\Utils::streamFor($source); + if (!$stream->isReadable()) { + throw new IAE('Source stream must be readable.'); + } + + return $stream; + } + + protected function getNumberOfParts($partSize) + { + if ($sourceSize = $this->source->getSize()) { + return ceil($sourceSize/$partSize); + } + return null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/UploadState.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/UploadState.php new file mode 100644 index 000000000..83b05650d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Multipart/UploadState.php @@ -0,0 +1,218 @@ +id = $id; + + if (isset($config['display_progress']) + && is_bool($config['display_progress']) + ) { + $this->displayProgress = $config['display_progress']; + } + } + + /** + * Get the upload's ID, which is a tuple of parameters that can uniquely + * identify the upload. + * + * @return array + */ + public function getId() + { + return $this->id; + } + + /** + * Sets the "upload_id", or 3rd part of the upload's ID. This typically + * only needs to be done after initiating an upload. + * + * @param string $key The param key of the upload_id. + * @param string $value The param value of the upload_id. + */ + public function setUploadId($key, $value) + { + $this->id[$key] = $value; + } + + /** + * Get the part size. + * + * @return int + */ + public function getPartSize() + { + return $this->partSize; + } + + /** + * Set the part size. + * + * @param $partSize int Size of upload parts. + */ + public function setPartSize($partSize) + { + $this->partSize = $partSize; + } + + /** + * Sets the 1/8th thresholds array. $totalSize is only sent if + * 'track_upload' is true. + * + * @param $totalSize numeric Size of object to upload. + * + * @return array + */ + public function setProgressThresholds($totalSize): array + { + if(!is_numeric($totalSize)) { + throw new \InvalidArgumentException( + 'The total size of the upload must be a number.' + ); + } + + $this->progressThresholds[0] = 0; + for ($i = 1; $i <= self::PROGRESS_THRESHOLD_SIZE; $i++) { + $this->progressThresholds[] = round( + $totalSize * ($i / self::PROGRESS_THRESHOLD_SIZE) + ); + } + + return $this->progressThresholds; + } + + /** + * Prints progress of upload. + * + * @param $totalUploaded numeric Size of upload so far. + */ + public function getDisplayProgress($totalUploaded): void + { + if (!is_numeric($totalUploaded)) { + throw new \InvalidArgumentException( + 'The size of the bytes being uploaded must be a number.' + ); + } + + if ($this->displayProgress) { + while (!empty($this->progressBar) + && $totalUploaded >= $this->progressThresholds[0] + ) { + echo array_shift($this->progressBar); + array_shift($this->progressThresholds); + } + } + } + + /** + * Marks a part as being uploaded. + * + * @param int $partNumber The part number. + * @param array $partData Data from the upload operation that needs to be + * recalled during the complete operation. + */ + public function markPartAsUploaded($partNumber, array $partData = []) + { + $this->uploadedParts[$partNumber] = $partData; + } + + /** + * Returns whether a part has been uploaded. + * + * @param int $partNumber The part number. + * + * @return bool + */ + public function hasPartBeenUploaded($partNumber) + { + return isset($this->uploadedParts[$partNumber]); + } + + /** + * Returns a sorted list of all the uploaded parts. + * + * @return array + */ + public function getUploadedParts() + { + ksort($this->uploadedParts); + return $this->uploadedParts; + } + + /** + * Set the status of the upload. + * + * @param int $status Status is an integer code defined by the constants + * CREATED, INITIATED, and COMPLETED on this class. + */ + public function setStatus($status) + { + $this->status = $status; + } + + /** + * Determines whether the upload state is in the INITIATED status. + * + * @return bool + */ + public function isInitiated() + { + return $this->status === self::INITIATED; + } + + /** + * Determines whether the upload state is in the COMPLETED status. + * + * @return bool + */ + public function isCompleted() + { + return $this->status === self::COMPLETED; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PhpHash.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PhpHash.php new file mode 100644 index 000000000..7a82815ae --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PhpHash.php @@ -0,0 +1,81 @@ +algo = $algo; + $this->options = $options; + } + + public function update($data) + { + if ($this->hash !== null) { + $this->reset(); + } + + hash_update($this->getContext(), $data); + } + + public function complete() + { + if ($this->hash) { + return $this->hash; + } + + $this->hash = hash_final($this->getContext(), true); + + if (isset($this->options['base64']) && $this->options['base64']) { + $this->hash = base64_encode($this->hash); + } + + return $this->hash; + } + + public function reset() + { + $this->context = $this->hash = null; + } + + /** + * Get a hash context or create one if needed + * + * @return resource|\HashContext + */ + private function getContext() + { + if (!$this->context) { + $key = isset($this->options['key']) ? $this->options['key'] : ''; + $this->context = hash_init( + $this->algo, + $key ? HASH_HMAC : 0, + $key + ); + } + + return $this->context; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PresignUrlMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PresignUrlMiddleware.php new file mode 100644 index 000000000..6fb3c92fa --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PresignUrlMiddleware.php @@ -0,0 +1,128 @@ +endpointProvider = $endpointProvider; + $this->client = $client; + $this->nextHandler = $nextHandler; + $this->commandPool = $options['operations']; + $this->serviceName = $options['service']; + $this->presignParam = !empty($options['presign_param']) + ? $options['presign_param'] + : 'PresignedUrl'; + $this->extraQueryParams = !empty($options['extra_query_params']) + ? $options['extra_query_params'] + : []; + $this->requireDifferentRegion = !empty($options['require_different_region']); + } + + public static function wrap( + AwsClientInterface $client, + $endpointProvider, + array $options = [] + ) { + return function (callable $handler) use ($endpointProvider, $client, $options) { + $f = new PresignUrlMiddleware($options, $endpointProvider, $client, $handler); + return $f; + }; + } + + public function __invoke(CommandInterface $cmd, ?RequestInterface $request = null) + { + if (in_array($cmd->getName(), $this->commandPool) + && (!isset($cmd['__skip' . $cmd->getName()])) + ) { + $cmd['DestinationRegion'] = $this->client->getRegion(); + if (!empty($cmd['SourceRegion']) && !empty($cmd[$this->presignParam])) { + goto nexthandler; + } + if (!$this->requireDifferentRegion + || (!empty($cmd['SourceRegion']) + && $cmd['SourceRegion'] !== $cmd['DestinationRegion']) + ) { + $cmd[$this->presignParam] = $this->createPresignedUrl($this->client, $cmd); + } + } + nexthandler: + $nextHandler = $this->nextHandler; + return $nextHandler($cmd, $request); + } + + private function createPresignedUrl( + AwsClientInterface $client, + CommandInterface $cmd + ) { + $cmdName = $cmd->getName(); + $newCmd = $client->getCommand($cmdName, $cmd->toArray()); + // Avoid infinite recursion by flagging the new command. + $newCmd['__skip' . $cmdName] = true; + + // Serialize a request for the operation. + $request = \Aws\serialize($newCmd); + // Create the new endpoint for the target endpoint. + if ($this->endpointProvider instanceof \Aws\EndpointV2\EndpointProviderV2) { + $providerArgs = array_merge( + $this->client->getEndpointProviderArgs(), + ['Region' => $cmd['SourceRegion']] + ); + $endpoint = $this->endpointProvider->resolveEndpoint($providerArgs)->getUrl(); + } else { + $endpoint = EndpointProvider::resolve($this->endpointProvider, [ + 'region' => $cmd['SourceRegion'], + 'service' => $this->serviceName, + ])['endpoint']; + } + + // Set the request to hit the target endpoint. + $uri = $request->getUri()->withHost((new Uri($endpoint))->getHost()); + $request = $request->withUri($uri); + + // Create a presigned URL for our generated request. + $signer = new SignatureV4($this->serviceName, $cmd['SourceRegion']); + + $currentQueryParams = (string) $request->getBody(); + $paramsToAdd = false; + if (!empty($this->extraQueryParams[$cmdName])) { + foreach ($this->extraQueryParams[$cmdName] as $param) { + if (!strpos($currentQueryParams, $param)) { + $paramsToAdd = "&{$param}={$cmd[$param]}"; + } + } + } + + return (string) $signer->presign( + SignatureV4::convertPostToGet($request, $paramsToAdd ?: ""), + $client->getCredentials()->wait(), + '+1 hour' + )->getUri(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Psr16CacheAdapter.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Psr16CacheAdapter.php new file mode 100644 index 000000000..b1ac8edf2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Psr16CacheAdapter.php @@ -0,0 +1,30 @@ +cache = $cache; + } + + public function get($key) + { + return $this->cache->get($key); + } + + public function set($key, $value, $ttl = 0) + { + $this->cache->set($key, $value, $ttl); + } + + public function remove($key) + { + $this->cache->delete($key); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PsrCacheAdapter.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PsrCacheAdapter.php new file mode 100644 index 000000000..9dd2d941c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/PsrCacheAdapter.php @@ -0,0 +1,38 @@ +pool = $pool; + } + + public function get($key) + { + $item = $this->pool->getItem($key); + + return $item->isHit() ? $item->get() : null; + } + + public function set($key, $value, $ttl = 0) + { + $item = $this->pool->getItem($key); + $item->set($value); + if ($ttl > 0) { + $item->expiresAfter($ttl); + } + + $this->pool->save($item); + } + + public function remove($key) + { + $this->pool->deleteItem($key); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/QueryCompatibleInputMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/QueryCompatibleInputMiddleware.php new file mode 100644 index 000000000..9da75b6c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/QueryCompatibleInputMiddleware.php @@ -0,0 +1,234 @@ +service = $service; + $this->nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $cmd) + { + $this->command = $cmd; + $nextHandler = $this->nextHandler; + $op = $this->service->getOperation($cmd->getName()); + $inputMembers = $op->getInput()->getMembers(); + $input = $cmd->toArray(); + + foreach ($input as $param => $value) { + if (isset($inputMembers[$param])) { + $shape = $inputMembers[$param]; + $this->processInput($value, $shape, [$param]); + } + } + + return $nextHandler($this->command); + } + + /** + * Recurses a given input shape. if a given scalar input does not match its + * modeled type, it is cast to its modeled type. + * + * @param $input + * @param $shape + * @param array $path + * + * @return void + */ + private function processInput($input, $shape, array $path) : void + { + switch ($shape->getType()) { + case 'structure': + $this->processStructure($input, $shape, $path); + break; + case 'list': + $this->processList($input, $shape, $path); + break; + case 'map': + $this->processMap($input, $shape, $path); + break; + default: + $this->processScalar($input, $shape, $path); + } + } + + /** + * @param array $input + * @param StructureShape $shape + * @param array $path + * + * @return void + */ + private function processStructure( + array $input, + StructureShape $shape, + array $path + ) : void + { + foreach ($input as $param => $value) { + if ($shape->hasMember($param)) { + $memberPath = array_merge($path, [$param]); + $this->processInput($value, $shape->getMember($param), $memberPath); + } + } + } + + /** + * @param array $input + * @param ListShape $shape + * @param array $path + * + * @return void + */ + private function processList( + array $input, + ListShape $shape, + array $path + ) : void + { + foreach ($input as $param => $value) { + $memberPath = array_merge($path, [$param]); + $this->processInput($value, $shape->getMember(), $memberPath); + } + } + + /** + * @param array $input + * @param MapShape $shape + * @param array $path + * + * @return void + */ + private function processMap(array $input, MapShape $shape, array $path) : void + { + foreach ($input as $param => $value) { + $memberPath = array_merge($path, [$param]); + $this->processInput($value, $shape->getValue(), $memberPath); + } + } + + /** + * @param $input + * @param Shape $shape + * @param array $path + * + * @return void + */ + private function processScalar($input, Shape $shape, array $path) : void + { + $expectedType = $shape->getType(); + + if (!$this->isModeledType($input, $expectedType)) { + trigger_error( + "The provided type for `". implode(' -> ', $path) ."` value was `" + . (gettype($input) === 'double' ? 'float' : gettype($input)) . "`." + . " The modeled type is `{$expectedType}`.", + E_USER_WARNING + ); + $value = $this->castValue($input, $expectedType); + $this->changeValueAtPath($path, $value); + } + } + + /** + * Modifies command in place + * + * @param array $path + * @param $newValue + * + * @return void + */ + private function changeValueAtPath(array $path, $newValue) : void + { + $commandRef = &$this->command; + + foreach ($path as $segment) { + if (!isset($commandRef[$segment])) { + return; + } + $commandRef = &$commandRef[$segment]; + } + $commandRef = $newValue; + } + + /** + * @param $value + * @param $type + * + * @return bool + */ + private function isModeledType($value, $type) : bool + { + switch ($type) { + case 'string': + return is_string($value); + case 'integer': + case 'long': + return is_int($value); + case 'float': + return is_float($value); + default: + return true; + } + } + + /** + * @param $value + * @param $type + * + * @return float|int|mixed|string + */ + private function castValue($value, $type) + { + switch ($type) { + case 'integer': + return (int) $value; + case 'long' : + return $value + 0; + case 'float': + return (float) $value; + case 'string': + return (string) $value; + default: + return $value; + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RequestCompressionMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RequestCompressionMiddleware.php new file mode 100644 index 000000000..f8e5015a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RequestCompressionMiddleware.php @@ -0,0 +1,172 @@ + 'gzencode' + ]; + + /** + * Create a middleware wrapper function. + * + * @return callable + */ + public static function wrap(array $config) + { + return function (callable $handler) use ($config) { + return new self($handler, $config); + }; + } + + public function __construct(callable $nextHandler, $config) + { + $this->minimumCompressionSize = $this->determineMinimumCompressionSize($config); + $this->api = $config['api']; + $this->nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + if (isset($command['@request_min_compression_size_bytes']) + && is_int($command['@request_min_compression_size_bytes']) + && $this->isValidCompressionSize($command['@request_min_compression_size_bytes']) + ) { + $this->minimumCompressionSize = $command['@request_min_compression_size_bytes']; + } + $nextHandler = $this->nextHandler; + $operation = $this->api->getOperation($command->getName()); + $compressionInfo = $operation['requestcompression'] ?? null; + + if (!$this->shouldCompressRequestBody( + $compressionInfo, + $command, + $operation, + $request + )) { + return $nextHandler($command, $request); + } + + $this->encodings = $compressionInfo['encodings']; + $request = $this->compressRequestBody($request); + + // Capture request compression metric + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'request_compression', + $request->getHeaderLine('content-encoding') + ); + + return $nextHandler($command, $request); + } + + private function compressRequestBody( + RequestInterface $request + ) { + $fn = $this->determineEncoding(); + if (is_null($fn)) { + return $request; + } + + $body = $request->getBody()->getContents(); + $compressedBody = $fn($body); + + $request = $request->withBody(Psr7\Utils::streamFor($compressedBody)); + if ($request->hasHeader('Content-Encoding')) { + return $request->withAddedHeader('Content-Encoding', $this->encoding); + } + + return $request->withHeader('Content-Encoding', $this->encoding); + } + + private function determineEncoding() + { + foreach ($this->encodings as $encoding) { + if (isset($this->encodingMap[$encoding])) { + $this->encoding = $encoding; + return $this->encodingMap[$encoding]; + } + } + return null; + } + + private function shouldCompressRequestBody( + $compressionInfo, + $command, + $operation, + $request + ){ + if ($compressionInfo) { + if (isset($command['@disable_request_compression']) + && $command['@disable_request_compression'] === true + ) { + return false; + } elseif ($this->hasStreamingTraitWithoutRequiresLength($command, $operation) + ) { + return true; + } + + $requestBodySize = $request->hasHeader('content-length') + ? (int) $request->getHeaderLine('content-length') + : $request->getBody()->getSize(); + + if ($requestBodySize >= $this->minimumCompressionSize) { + return true; + } + } + return false; + } + + private function hasStreamingTraitWithoutRequiresLength($command, $operation) + { + foreach ($operation->getInput()->getMembers() as $name => $member) { + if (isset($command[$name]) + && !empty($member['streaming']) + && empty($member['requiresLength']) + ){ + return true; + } + } + return false; + } + + private function determineMinimumCompressionSize($config) { + if (is_callable($config['request_min_compression_size_bytes'])) { + $minCompressionSz = $config['request_min_compression_size_bytes'](); + } else { + $minCompressionSz = $config['request_min_compression_size_bytes']; + } + + if ($this->isValidCompressionSize($minCompressionSz)) { + return $minCompressionSz; + } + } + + private function isValidCompressionSize($compressionSize) + { + if (is_numeric($compressionSize) + && ($compressionSize >= 0 && $compressionSize <= 10485760) + ) { + return true; + } + + throw new \InvalidArgumentException( + 'The minimum request compression size must be a ' + . 'non-negative integer value between 0 and 10485760 bytes, inclusive.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResponseContainerInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResponseContainerInterface.php new file mode 100644 index 000000000..d26921bb8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResponseContainerInterface.php @@ -0,0 +1,15 @@ +data = $data; + } + + public function hasKey($name) + { + return isset($this->data[$name]); + } + + public function get($key) + { + return $this[$key]; + } + + public function search($expression) + { + return JmesPath::search($expression, $this->toArray()); + } + + public function __toString() + { + $jsonData = json_encode($this->toArray(), JSON_PRETTY_PRINT); + return <<get(\$key)`) or "accessing the result like an +associative array (e.g. `\$result['key']`). You can also execute JMESPath +expressions on the result data using the search() method. + +{$jsonData} + +EOT; + } + + /** + * @deprecated + */ + public function getPath($path) + { + return $this->search(str_replace('/', '.', $path)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultInterface.php new file mode 100644 index 000000000..18a166abb --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultInterface.php @@ -0,0 +1,54 @@ +execute($command); + * $jpResult = $result->search('foo.*.bar[?baz > `10`]'); + * + * @param string $expression JMESPath expression to execute + * + * @return mixed Returns the result of the JMESPath expression. + * @link http://jmespath.readthedocs.org/en/latest/ JMESPath documentation + */ + public function search($expression); +}; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultPaginator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultPaginator.php new file mode 100644 index 000000000..396ed1a93 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/ResultPaginator.php @@ -0,0 +1,206 @@ +client = $client; + $this->operation = $operation; + $this->args = $args; + $this->config = $config; + MetricsBuilder::appendMetricsCaptureMiddleware( + $this->client->getHandlerList(), + MetricsBuilder::PAGINATOR + ); + } + + /** + * Runs a paginator asynchronously and uses a callback to handle results. + * + * The callback should have the signature: function (Aws\Result $result). + * A non-null return value from the callback will be yielded by the + * promise. This means that you can return promises from the callback that + * will need to be resolved before continuing iteration over the remaining + * items, essentially merging in other promises to the iteration. The last + * non-null value returned by the callback will be the result that fulfills + * the promise to any downstream promises. + * + * @param callable $handleResult Callback for handling each page of results. + * The callback accepts the result that was + * yielded as a single argument. If the + * callback returns a promise, the promise + * will be merged into the coroutine. + * + * @return Promise\Promise + */ + public function each(callable $handleResult) + { + return Promise\Coroutine::of(function () use ($handleResult) { + $nextToken = null; + do { + $command = $this->createNextCommand($this->args, $nextToken); + $result = (yield $this->client->executeAsync($command)); + $nextToken = $this->determineNextToken($result); + $retVal = $handleResult($result); + if ($retVal !== null) { + yield Promise\Create::promiseFor($retVal); + } + } while ($nextToken); + }); + } + + /** + * Returns an iterator that iterates over the values of applying a JMESPath + * search to each result yielded by the iterator as a flat sequence. + * + * @param string $expression JMESPath expression to apply to each result. + * + * @return \Iterator + */ + public function search($expression) + { + // Apply JMESPath expression on each result, but as a flat sequence. + return flatmap($this, function (Result $result) use ($expression) { + return (array) $result->search($expression); + }); + } + + /** + * @return Result + */ + #[\ReturnTypeWillChange] + public function current() + { + return $this->valid() ? $this->result : false; + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function key() + { + return $this->valid() ? $this->requestCount - 1 : null; + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function next() + { + $this->result = null; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function valid() + { + if ($this->result) { + return true; + } + + if ($this->nextToken || !$this->requestCount) { + //Forward/backward paging can result in a case where the last page's nextforwardtoken + //is the same as the one that came before it. This can cause an infinite loop. + $hasBidirectionalPaging = $this->config['output_token'] === 'nextForwardToken'; + if ($hasBidirectionalPaging && $this->nextToken) { + $tokenKey = $this->config['input_token']; + $previousToken = $this->nextToken[$tokenKey]; + } + + $this->result = $this->client->execute( + $this->createNextCommand($this->args, $this->nextToken) + ); + + $this->nextToken = $this->determineNextToken($this->result); + + if (isset($previousToken) + && $previousToken === $this->nextToken[$tokenKey] + ) { + return false; + } + + $this->requestCount++; + return true; + } + + return false; + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function rewind() + { + $this->requestCount = 0; + $this->nextToken = null; + $this->result = null; + } + + private function createNextCommand(array $args, ?array $nextToken = null) + { + return $this->client->getCommand($this->operation, array_merge($args, ($nextToken ?: []))); + } + + private function determineNextToken(Result $result) + { + if (!$this->config['output_token']) { + return null; + } + + if ($this->config['more_results'] + && !$result->search($this->config['more_results']) + ) { + return null; + } + + $nextToken = is_scalar($this->config['output_token']) + ? [$this->config['input_token'] => $this->config['output_token']] + : array_combine($this->config['input_token'], $this->config['output_token']); + + return array_filter(array_map(function ($outputToken) use ($result) { + return $result->search($outputToken); + }, $nextToken)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Configuration.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Configuration.php new file mode 100644 index 000000000..aa370c409 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Configuration.php @@ -0,0 +1,61 @@ +validModes)) { + throw new ConfigurationException("'{$mode}' is not a valid mode." + . " The mode has to be 'legacy', 'standard', or 'adaptive'."); + } + if (!is_numeric($maxAttempts) + || intval($maxAttempts) != $maxAttempts + || $maxAttempts < 1 + ) { + throw new ConfigurationException("The 'maxAttempts' parameter has" + . " to be an integer >= 1."); + } + + $this->mode = $mode; + $this->maxAttempts = intval($maxAttempts); + } + + /** + * {@inheritdoc} + */ + public function getMode() + { + return $this->mode; + } + + /** + * {@inheritdoc} + */ + public function getMaxAttempts() + { + return $this->maxAttempts; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'mode' => $this->getMode(), + 'max_attempts' => $this->getMaxAttempts(), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php new file mode 100644 index 000000000..3f57b62d6 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php @@ -0,0 +1,30 @@ + + * use Aws\Sts\RegionalEndpoints\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see \Aws\Retry\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const DEFAULT_MAX_ATTEMPTS = 3; + const DEFAULT_MODE = 'legacy'; + const ENV_MAX_ATTEMPTS = 'AWS_MAX_ATTEMPTS'; + const ENV_MODE = 'AWS_RETRY_MODE'; + const ENV_PROFILE = 'AWS_PROFILE'; + const INI_MAX_ATTEMPTS = 'max_attempts'; + const INI_MODE = 'retry_mode'; + + public static $cacheKey = 'aws_retries_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['retries']) + && $config['retries'] instanceof CacheInterface + ) { + return self::cache($memo, $config['retries'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use config from environment variables, if available + $mode = getenv(self::ENV_MODE); + $maxAttempts = getenv(self::ENV_MAX_ATTEMPTS) + ? getenv(self::ENV_MAX_ATTEMPTS) + : self::DEFAULT_MAX_ATTEMPTS; + if (!empty($mode)) { + return Promise\Create::promiseFor( + new Configuration($mode, $maxAttempts) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_MODE); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function () { + return Promise\Create::promiseFor( + new Configuration(self::DEFAULT_MODE, self::DEFAULT_MAX_ATTEMPTS) + ); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini( + $profile = null, + $filename = null + ) { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_MODE])) { + return self::reject("Required retry config values + not present in INI profile '{$profile}' ({$filename})"); + } + + $maxAttempts = isset($data[$profile][self::INI_MAX_ATTEMPTS]) + ? $data[$profile][self::INI_MAX_ATTEMPTS] + : self::DEFAULT_MAX_ATTEMPTS; + + return Promise\Create::promiseFor( + new Configuration( + $data[$profile][self::INI_MODE], + $maxAttempts + ) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } + + // An integer value for this config indicates the legacy 'retries' + // config option, which is incremented to translate to max attempts + if (is_int($config)) { + return new Configuration('legacy', $config + 1); + } + + if (is_array($config) && isset($config['mode'])) { + $maxAttempts = isset($config['max_attempts']) + ? $config['max_attempts'] + : self::DEFAULT_MAX_ATTEMPTS; + return new Configuration($config['mode'], $maxAttempts); + } + + throw new \InvalidArgumentException('Not a valid retry configuration' + . ' argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php new file mode 100644 index 000000000..0705c2ee9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +initialRetryTokens = isset($config['initial_retry_tokens']) + ? $config['initial_retry_tokens'] + : 500; + $this->noRetryIncrement = isset($config['no_retry_increment']) + ? $config['no_retry_increment'] + : 1; + $this->retryCost = isset($config['retry_cost']) + ? $config['retry_cost'] + : 5; + $this->timeoutRetryCost = isset($config['timeout_retry_cost']) + ? $config['timeout_retry_cost'] + : 10; + $this->maxCapacity = $this->initialRetryTokens; + $this->availableCapacity = $this->initialRetryTokens; + } + + public function hasRetryQuota($result) + { + if ($result instanceof AwsException && $result->isConnectionError()) { + $this->capacityAmount = $this->timeoutRetryCost; + } else { + $this->capacityAmount = $this->retryCost; + } + + if ($this->capacityAmount > $this->availableCapacity) { + return false; + } + + $this->availableCapacity -= $this->capacityAmount; + return true; + } + + public function releaseToQuota($result) + { + if ($result instanceof AwsException) { + $statusCode = (int) $result->getStatusCode(); + } elseif ($result instanceof ResultInterface) { + $statusCode = isset($result['@metadata']['statusCode']) + ? (int) $result['@metadata']['statusCode'] + : null; + } + + if (!empty($statusCode) && $statusCode >= 200 && $statusCode < 300) { + if (isset($this->capacityAmount)) { + $amount = $this->capacityAmount; + $this->availableCapacity += $amount; + unset($this->capacityAmount); + } else { + $amount = $this->noRetryIncrement; + $this->availableCapacity += $amount; + } + $this->availableCapacity = min( + $this->availableCapacity, + $this->maxCapacity + ); + } + + return (isset($amount) ? $amount : 0); + } + + public function getAvailableCapacity() + { + return $this->availableCapacity; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RateLimiter.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RateLimiter.php new file mode 100644 index 000000000..b58cc5929 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RateLimiter.php @@ -0,0 +1,182 @@ +beta = isset($options['beta']) + ? $options['beta'] + : 0.7; + $this->minCapacity = isset($options['min_capacity']) + ? $options['min_capacity'] + : 1; + $this->minFillRate = isset($options['min_fill_rate']) + ? $options['min_fill_rate'] + : 0.5; + $this->scaleConstant = isset($options['scale_constant']) + ? $options['scale_constant'] + : 0.4; + $this->smooth = isset($options['smooth']) + ? $options['smooth'] + : 0.8; + $this->timeProvider = isset($options['time_provider']) + ? $options['time_provider'] + : null; + + $this->lastTxRateBucket = floor($this->time()); + $this->lastThrottleTime = $this->time(); + } + + public function isEnabled() + { + return $this->enabled; + } + + public function getSendToken() + { + $this->acquireToken(1); + } + + public function updateSendingRate($isThrottled) + { + $this->updateMeasuredRate(); + + if ($isThrottled) { + if (!$this->isEnabled()) { + $rateToUse = $this->measuredTxRate; + } else { + $rateToUse = min($this->measuredTxRate, $this->fillRate); + } + + $this->lastMaxRate = $rateToUse; + $this->calculateTimeWindow(); + $this->lastThrottleTime = $this->time(); + $calculatedRate = $this->cubicThrottle($rateToUse); + $this->enableTokenBucket(); + } else { + $this->calculateTimeWindow(); + $calculatedRate = $this->cubicSuccess($this->time()); + } + $newRate = min($calculatedRate, 2 * $this->measuredTxRate); + $this->updateTokenBucketRate($newRate); + return $newRate; + } + + private function acquireToken($amount) + { + if (!$this->enabled) { + return true; + } + + $this->refillTokenBucket(); + + if ($amount > $this->currentCapacity) { + usleep((int) (1000000 * ($amount - $this->currentCapacity) / $this->fillRate)); + } + + $this->currentCapacity -= $amount; + return true; + } + + private function calculateTimeWindow() + { + $this->timeWindow = pow(($this->lastMaxRate * (1 - $this->beta) / $this->scaleConstant), 0.333); + } + + private function cubicSuccess($timestamp) + { + $dt = $timestamp - $this->lastThrottleTime; + return $this->scaleConstant * pow($dt - $this->timeWindow, 3) + $this->lastMaxRate; + } + + private function cubicThrottle($rateToUse) + { + return $rateToUse * $this->beta; + } + + private function enableTokenBucket() + { + $this->enabled = true; + } + + private function refillTokenBucket() + { + $timestamp = $this->time(); + if (!isset($this->lastTimestamp)) { + $this->lastTimestamp = $timestamp; + return; + } + $fillAmount = ($timestamp - $this->lastTimestamp) * $this->fillRate; + $this->currentCapacity = $this->currentCapacity + $fillAmount; + if (!is_null($this->maxCapacity)) { + $this->currentCapacity = min( + $this->maxCapacity, + $this->currentCapacity + ); + } + + $this->lastTimestamp = $timestamp; + } + + private function time() + { + if (is_callable($this->timeProvider)) { + $provider = $this->timeProvider; + $time = $provider(); + return $time; + } + return microtime(true); + } + + private function updateMeasuredRate() + { + $timestamp = $this->time(); + $timeBucket = floor(round($timestamp, 3) * 2) / 2; + $this->requestCount++; + if ($timeBucket > $this->lastTxRateBucket) { + $currentRate = $this->requestCount / ($timeBucket - $this->lastTxRateBucket); + $this->measuredTxRate = ($currentRate * $this->smooth) + + ($this->measuredTxRate * (1 - $this->smooth)); + $this->requestCount = 0; + $this->lastTxRateBucket = $timeBucket; + } + } + + private function updateTokenBucketRate($newRps) + { + $this->refillTokenBucket(); + $this->fillRate = max($newRps, $this->minFillRate); + $this->maxCapacity = max($newRps, $this->minCapacity); + $this->currentCapacity = min($this->currentCapacity, $this->maxCapacity); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php new file mode 100644 index 000000000..a7edb72b5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php @@ -0,0 +1,56 @@ +withHeader('aws-sdk-retry', "{$retries}/{$delayBy}"); + } + + + private function updateStats($retries, $delay, array &$stats) + { + if (!isset($stats['total_retry_delay'])) { + $stats['total_retry_delay'] = 0; + } + + $stats['total_retry_delay'] += $delay; + $stats['retries_attempted'] = $retries; + } + + private function updateHttpStats($value, array &$stats) + { + if (empty($stats['http'])) { + $stats['http'] = []; + } + + if ($value instanceof AwsException) { + $resultStats = $value->getTransferInfo(); + $stats['http'] []= $resultStats; + } elseif ($value instanceof ResultInterface) { + $resultStats = isset($value['@metadata']['transferStats']['http'][0]) + ? $value['@metadata']['transferStats']['http'][0] + : []; + $stats['http'] []= $resultStats; + } + } + + private function bindStatsToReturn($return, array $stats) + { + if ($return instanceof ResultInterface) { + if (!isset($return['@metadata'])) { + $return['@metadata'] = []; + } + + $return['@metadata']['transferStats'] = $stats; + } elseif ($return instanceof AwsException) { + $return->setTransferInfo($stats); + } + + return $return; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddleware.php new file mode 100644 index 000000000..bb550df97 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddleware.php @@ -0,0 +1,277 @@ + true, + 502 => true, + 503 => true, + 504 => true + ]; + + private static $retryCodes = [ + // Throttling error + 'RequestLimitExceeded' => true, + 'Throttling' => true, + 'ThrottlingException' => true, + 'ThrottledException' => true, + 'ProvisionedThroughputExceededException' => true, + 'RequestThrottled' => true, + 'BandwidthLimitExceeded' => true, + 'RequestThrottledException' => true, + 'TooManyRequestsException' => true, + 'IDPCommunicationError' => true, + 'EC2ThrottledException' => true, + ]; + + private $decider; + private $delay; + private $nextHandler; + private $collectStats; + + public function __construct( + callable $decider, + callable $delay, + callable $nextHandler, + $collectStats = false + ) { + $this->decider = $decider; + $this->delay = $delay; + $this->nextHandler = $nextHandler; + $this->collectStats = (bool) $collectStats; + } + + /** + * Creates a default AWS retry decider function. + * + * The optional $extraConfig parameter is an associative array + * that specifies additional retry conditions on top of the ones specified + * by default by the Aws\RetryMiddleware class, with the following keys: + * + * - errorCodes: (string[]) An indexed array of AWS exception codes to retry. + * Optional. + * - statusCodes: (int[]) An indexed array of HTTP status codes to retry. + * Optional. + * - curlErrors: (int[]) An indexed array of Curl error codes to retry. Note + * these should be valid Curl constants. Optional. + * + * @param int $maxRetries + * @param array $extraConfig + * @return callable + */ + public static function createDefaultDecider( + $maxRetries = 3, + $extraConfig = [] + ) { + $retryCurlErrors = []; + if (extension_loaded('curl')) { + $retryCurlErrors[CURLE_RECV_ERROR] = true; + } + + return function ( + $retries, + CommandInterface $command, + RequestInterface $request, + ?ResultInterface $result = null, + $error = null + ) use ($maxRetries, $retryCurlErrors, $extraConfig) { + // Allow command-level options to override this value + $maxRetries = null !== $command['@retries'] ? + $command['@retries'] + : $maxRetries; + + $isRetryable = self::isRetryable( + $result, + $error, + $retryCurlErrors, + $extraConfig + ); + + if ($retries >= $maxRetries) { + if (!empty($error) + && $error instanceof AwsException + && $isRetryable + ) { + $error->setMaxRetriesExceeded(); + } + return false; + } + + return $isRetryable; + }; + } + + private static function isRetryable( + $result, + $error, + $retryCurlErrors, + $extraConfig = [] + ) { + $errorCodes = self::$retryCodes; + if (!empty($extraConfig['error_codes']) + && is_array($extraConfig['error_codes']) + ) { + foreach($extraConfig['error_codes'] as $code) { + $errorCodes[$code] = true; + } + } + + $statusCodes = self::$retryStatusCodes; + if (!empty($extraConfig['status_codes']) + && is_array($extraConfig['status_codes']) + ) { + foreach($extraConfig['status_codes'] as $code) { + $statusCodes[$code] = true; + } + } + + if (!empty($extraConfig['curl_errors']) + && is_array($extraConfig['curl_errors']) + ) { + foreach($extraConfig['curl_errors'] as $code) { + $retryCurlErrors[$code] = true; + } + } + + if (!$error) { + if (!isset($result['@metadata']['statusCode'])) { + return false; + } + return isset($statusCodes[$result['@metadata']['statusCode']]); + } + + if (!($error instanceof AwsException)) { + return false; + } + + if ($error->isConnectionError()) { + return true; + } + + if (isset($errorCodes[$error->getAwsErrorCode()])) { + return true; + } + + if (isset($statusCodes[$error->getStatusCode()])) { + return true; + } + + if (count($retryCurlErrors) + && ($previous = $error->getPrevious()) + && $previous instanceof RequestException + ) { + if (method_exists($previous, 'getHandlerContext')) { + $context = $previous->getHandlerContext(); + return !empty($context['errno']) + && isset($retryCurlErrors[$context['errno']]); + } + + $message = $previous->getMessage(); + foreach (array_keys($retryCurlErrors) as $curlError) { + if (strpos($message, 'cURL error ' . $curlError . ':') === 0) { + return true; + } + } + } + + return false; + } + + /** + * Delay function that calculates an exponential delay. + * + * Exponential backoff with jitter, 100ms base, 20 sec ceiling + * + * @param $retries - The number of retries that have already been attempted + * + * @return int + * + * @link https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + */ + public static function exponentialDelay($retries) + { + return mt_rand(0, (int) min(20000, (int) pow(2, $retries) * 100)); + } + + /** + * @param CommandInterface $command + * @param RequestInterface $request + * + * @return PromiseInterface + */ + public function __invoke( + CommandInterface $command, + ?RequestInterface $request = null + ) { + $retries = 0; + $requestStats = []; + $monitoringEvents = []; + $handler = $this->nextHandler; + $decider = $this->decider; + $delay = $this->delay; + + $request = $this->addRetryHeader($request, 0, 0); + + $g = function ($value) use ( + $handler, + $decider, + $delay, + $command, + $request, + &$retries, + &$requestStats, + &$monitoringEvents, + &$g + ) { + $this->updateHttpStats($value, $requestStats); + + if ($value instanceof MonitoringEventsInterface) { + $reversedEvents = array_reverse($monitoringEvents); + $monitoringEvents = array_merge($monitoringEvents, $value->getMonitoringEvents()); + foreach ($reversedEvents as $event) { + $value->prependMonitoringEvent($event); + } + } + if ($value instanceof \Exception || $value instanceof \Throwable) { + if (!$decider($retries, $command, $request, null, $value)) { + return Promise\Create::rejectionFor( + $this->bindStatsToReturn($value, $requestStats) + ); + } + } elseif ($value instanceof ResultInterface + && !$decider($retries, $command, $request, $value, null) + ) { + return $this->bindStatsToReturn($value, $requestStats); + } + + // Delay fn is called with 0, 1, ... so increment after the call. + $delayBy = $delay($retries++); + $command['@http']['delay'] = $delayBy; + if ($this->collectStats) { + $this->updateStats($retries, $delayBy, $requestStats); + } + + // Update retry header with retry count and delayBy + $request = $this->addRetryHeader($request, $retries, $delayBy); + + return $handler($command, $request)->then($g, $g); + }; + + return $handler($command, $request)->then($g, $g); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddlewareV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddlewareV2.php new file mode 100644 index 000000000..ba989ad6c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/RetryMiddlewareV2.php @@ -0,0 +1,377 @@ + true, + 'ThrottlingException' => true, + 'ThrottledException' => true, + 'RequestThrottledException' => true, + 'TooManyRequestsException' => true, + 'ProvisionedThroughputExceededException' => true, + 'TransactionInProgressException' => true, + 'RequestLimitExceeded' => true, + 'BandwidthLimitExceeded' => true, + 'LimitExceededException' => true, + 'RequestThrottled' => true, + 'SlowDown' => true, + 'PriorRequestNotComplete' => true, + 'EC2ThrottledException' => true, + ]; + + private static $standardTransientErrors = [ + 'RequestTimeout' => true, + 'RequestTimeoutException' => true, + ]; + + private static $standardTransientStatusCodes = [ + 500 => true, + 502 => true, + 503 => true, + 504 => true, + ]; + + private $collectStats; + private $decider; + private $delayer; + private $maxAttempts; + private $maxBackoff; + private $mode; + private $nextHandler; + private $options; + private $quotaManager; + private $rateLimiter; + + public static function wrap($config, $options) + { + return function (callable $handler) use ( + $config, + $options + ) { + return new static( + $config, + $handler, + $options + ); + }; + } + + public static function createDefaultDecider( + QuotaManager $quotaManager, + $maxAttempts = 3, + $options = [] + ) { + $retryCurlErrors = []; + if (extension_loaded('curl')) { + $retryCurlErrors[CURLE_RECV_ERROR] = true; + } + + return function( + $attempts, + CommandInterface $command, + $result + ) use ($options, $quotaManager, $retryCurlErrors, $maxAttempts) { + + // Release retry tokens back to quota on a successful result + $quotaManager->releaseToQuota($result); + + // Allow command-level option to override this value + // # of attempts = # of retries + 1 + $maxAttempts = (null !== $command['@retries']) + ? $command['@retries'] + 1 + : $maxAttempts; + + $isRetryable = self::isRetryable( + $result, + $retryCurlErrors, + $options + ); + + if ($isRetryable) { + + // Retrieve retry tokens and check if quota has been exceeded + if (!$quotaManager->hasRetryQuota($result)) { + return false; + } + + if ($attempts >= $maxAttempts) { + if (!empty($result) && $result instanceof AwsException) { + $result->setMaxRetriesExceeded(); + } + return false; + } + } + + return $isRetryable; + }; + } + + public function __construct( + ConfigurationInterface $config, + callable $handler, + $options = [] + ) { + $this->options = $options; + $this->maxAttempts = $config->getMaxAttempts(); + $this->mode = $config->getMode(); + $this->nextHandler = $handler; + $this->quotaManager = new QuotaManager(); + + $this->maxBackoff = isset($options['max_backoff']) + ? $options['max_backoff'] + : 20000; + + $this->collectStats = isset($options['collect_stats']) + ? (bool) $options['collect_stats'] + : false; + + $this->decider = isset($options['decider']) + ? $options['decider'] + : self::createDefaultDecider( + $this->quotaManager, + $this->maxAttempts, + $options + ); + + $this->delayer = isset($options['delayer']) + ? $options['delayer'] + : function ($attempts) { + return $this->exponentialDelayWithJitter($attempts); + }; + + if ($this->mode === 'adaptive') { + $this->rateLimiter = isset($options['rate_limiter']) + ? $options['rate_limiter'] + : new RateLimiter(); + } + } + + public function __invoke(CommandInterface $cmd, RequestInterface $req) + { + $decider = $this->decider; + $delayer = $this->delayer; + $handler = $this->nextHandler; + + $attempts = 1; + $monitoringEvents = []; + $requestStats = []; + + $req = $this->addRetryHeader($req, 0, 0); + + $callback = function ($value) use ( + $handler, + $cmd, + $req, + $decider, + $delayer, + &$attempts, + &$requestStats, + &$monitoringEvents, + &$callback + ) { + if ($this->mode === 'adaptive') { + $this->rateLimiter->updateSendingRate($this->isThrottlingError($value)); + } + + $this->updateHttpStats($value, $requestStats); + + if ($value instanceof MonitoringEventsInterface) { + $reversedEvents = array_reverse($monitoringEvents); + $monitoringEvents = array_merge($monitoringEvents, $value->getMonitoringEvents()); + foreach ($reversedEvents as $event) { + $value->prependMonitoringEvent($event); + } + } + if ($value instanceof \Exception || $value instanceof \Throwable) { + if (!$decider($attempts, $cmd, $value)) { + return Promise\Create::rejectionFor( + $this->bindStatsToReturn($value, $requestStats) + ); + } + } elseif ($value instanceof ResultInterface + && !$decider($attempts, $cmd, $value) + ) { + return $this->bindStatsToReturn($value, $requestStats); + } + + $delayBy = $delayer($attempts++); + $cmd['@http']['delay'] = $delayBy; + if ($this->collectStats) { + $this->updateStats($attempts - 1, $delayBy, $requestStats); + } + + // Update retry header with retry count and delayBy + $req = $this->addRetryHeader($req, $attempts - 1, $delayBy); + + // Get token from rate limiter, which will sleep if necessary + if ($this->mode === 'adaptive') { + $this->rateLimiter->getSendToken(); + } + + return $handler($cmd, $req)->then($callback, $callback); + }; + + // Get token from rate limiter, which will sleep if necessary + if ($this->mode === 'adaptive') { + $this->rateLimiter->getSendToken(); + } + + return $handler($cmd, $req)->then($callback, $callback); + } + + /** + * Amount of milliseconds to delay as a function of attempt number + * + * @param $attempts + * @return mixed + */ + public function exponentialDelayWithJitter($attempts) + { + $rand = mt_rand() / mt_getrandmax(); + return min(1000 * $rand * pow(2, $attempts) , $this->maxBackoff); + } + + private static function isRetryable( + $result, + $retryCurlErrors, + $options = [] + ) { + $errorCodes = self::$standardThrottlingErrors + self::$standardTransientErrors; + if (!empty($options['transient_error_codes']) + && is_array($options['transient_error_codes']) + ) { + foreach($options['transient_error_codes'] as $code) { + $errorCodes[$code] = true; + } + } + if (!empty($options['throttling_error_codes']) + && is_array($options['throttling_error_codes']) + ) { + foreach($options['throttling_error_codes'] as $code) { + $errorCodes[$code] = true; + } + } + + $statusCodes = self::$standardTransientStatusCodes; + if (!empty($options['status_codes']) + && is_array($options['status_codes']) + ) { + foreach($options['status_codes'] as $code) { + $statusCodes[$code] = true; + } + } + + if (!empty($options['curl_errors']) + && is_array($options['curl_errors']) + ) { + foreach($options['curl_errors'] as $code) { + $retryCurlErrors[$code] = true; + } + } + + if ($result instanceof \Exception || $result instanceof \Throwable) { + $isError = true; + } else { + $isError = false; + } + + if (!$isError) { + if (!isset($result['@metadata']['statusCode'])) { + return false; + } + return isset($statusCodes[$result['@metadata']['statusCode']]); + } + + if (!($result instanceof AwsException)) { + return false; + } + + if ($result->isConnectionError()) { + return true; + } + + if (!empty($errorCodes[$result->getAwsErrorCode()])) { + return true; + } + + if (!empty($statusCodes[$result->getStatusCode()])) { + return true; + } + + if (count($retryCurlErrors) + && ($previous = $result->getPrevious()) + && $previous instanceof RequestException + ) { + if (method_exists($previous, 'getHandlerContext')) { + $context = $previous->getHandlerContext(); + return !empty($context['errno']) + && isset($retryCurlErrors[$context['errno']]); + } + + $message = $previous->getMessage(); + foreach (array_keys($retryCurlErrors) as $curlError) { + if (strpos($message, 'cURL error ' . $curlError . ':') === 0) { + return true; + } + } + } + + // Check error shape for the retryable trait + if (!empty($errorShape = $result->getAwsErrorShape())) { + $definition = $errorShape->toArray(); + if (!empty($definition['retryable'])) { + return true; + } + } + + return false; + } + + private function isThrottlingError($result) + { + if ($result instanceof AwsException) { + // Check pre-defined throttling errors + $throttlingErrors = self::$standardThrottlingErrors; + if (!empty($this->options['throttling_error_codes']) + && is_array($this->options['throttling_error_codes']) + ) { + foreach($this->options['throttling_error_codes'] as $code) { + $throttlingErrors[$code] = true; + } + } + if (!empty($result->getAwsErrorCode()) + && !empty($throttlingErrors[$result->getAwsErrorCode()]) + ) { + return true; + } + + // Check error shape for the throttling trait + if (!empty($errorShape = $result->getAwsErrorShape())) { + $definition = $errorShape->toArray(); + if (!empty($definition['retryable']['throttling'])) { + return true; + } + } + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/AmbiguousSuccessParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/AmbiguousSuccessParser.php new file mode 100644 index 000000000..18d3a174d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/AmbiguousSuccessParser.php @@ -0,0 +1,79 @@ + true, + 'UploadPartCopy' => true, + 'CopyObject' => true, + 'CompleteMultipartUpload' => true, + ]; + + /** @var callable */ + private $errorParser; + /** @var string */ + private $exceptionClass; + + public function __construct( + callable $parser, + callable $errorParser, + $exceptionClass = AwsException::class + ) { + $this->parser = $parser; + $this->errorParser = $errorParser; + $this->exceptionClass = $exceptionClass; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + if (200 === $response->getStatusCode() + && isset(self::$ambiguousSuccesses[$command->getName()]) + ) { + $errorParser = $this->errorParser; + try { + $parsed = $errorParser($response); + } catch (ParserException $e) { + $parsed = [ + 'code' => 'ConnectionError', + 'message' => "An error connecting to the service occurred" + . " while performing the " . $command->getName() + . " operation." + ]; + } + if (isset($parsed['code']) && isset($parsed['message'])) { + throw new $this->exceptionClass( + $parsed['message'], + $command, + ['connection_error' => true] + ); + } + } + + $fn = $this->parser; + return $fn($command, $response); + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ApplyChecksumMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ApplyChecksumMiddleware.php new file mode 100644 index 000000000..2ed451927 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ApplyChecksumMiddleware.php @@ -0,0 +1,242 @@ + true, + 'UploadPart' => true, + ]; + + /** @var Service */ + private $api; + + /** @var array */ + private $config; + + /** @var callable */ + private $nextHandler; + + /** + * Create a middleware wrapper function. + * + * @param Service $api + * @return callable + */ + public static function wrap(Service $api, array $config = []) + { + return function (callable $handler) use ($api, $config) { + return new self($handler, $api, $config); + }; + } + + public function __construct( + callable $nextHandler, + Service $api, + array $config = [] + ) + { + $this->api = $api; + $this->nextHandler = $nextHandler; + $this->config = $config; + } + + public function __invoke( + CommandInterface $command, + RequestInterface $request + ) { + $next = $this->nextHandler; + $name = $command->getName(); + $body = $request->getBody(); + $operation = $this->api->getOperation($name); + $mode = $this->config['request_checksum_calculation'] + ?? self::DEFAULT_CALCULATION_MODE; + + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'request_checksum_calculation', + $mode + ); + + // Trigger warning if AddContentMD5 is specified for PutObject or UploadPart + $this->handleDeprecatedAddContentMD5($command); + + $checksumInfo = $operation['httpChecksum'] ?? []; + $checksumMemberName = $checksumInfo['requestAlgorithmMember'] ?? ''; + $checksumMember = !empty($checksumMemberName) + ? $operation->getInput()->getMember($checksumMemberName) + : null; + $checksumRequired = $checksumInfo['requestChecksumRequired'] ?? false; + $requestedAlgorithm = $command[$checksumMemberName] ?? null; + + $shouldAddChecksum = $this->shouldAddChecksum( + $mode, + $checksumRequired, + $checksumMember, + $requestedAlgorithm + ); + if ($shouldAddChecksum) { + if (!$this->hasAlgorithmHeader($request)) { + $supportedAlgorithms = array_map('strtolower', $checksumMember['enum'] ?? []); + $algorithm = $this->determineChecksumAlgorithm( + $supportedAlgorithms, + $requestedAlgorithm, + $checksumMemberName + ); + $request = $this->addAlgorithmHeader($algorithm, $request, $body); + + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'request_checksum', + $algorithm + ); + } + } + + // Set the content hash header if ContentSHA256 is provided + if (isset(self::$sha256[$name]) && $command['ContentSHA256']) { + $request = $request->withHeader( + 'X-Amz-Content-Sha256', + $command['ContentSHA256'] + ); + $command->getMetricsBuilder()->append( + MetricsBuilder::FLEXIBLE_CHECKSUMS_REQ_SHA256 + ); + } + + return $next($command, $request); + } + + /** + * @param CommandInterface $command + * + * @return void + */ + private function handleDeprecatedAddContentMD5(CommandInterface $command): void + { + if (!empty($command['AddContentMD5'])) { + trigger_error( + 'S3 no longer supports MD5 checksums. ' . + 'A CRC32 checksum will be computed and applied on your behalf.', + E_USER_DEPRECATED + ); + $command['ChecksumAlgorithm'] = self::DEFAULT_ALGORITHM; + } + } + + /** + * @param string $mode + * @param Shape|null $checksumMember + * @param string $name + * @param bool $checksumRequired + * @param string|null $requestedAlgorithm + * + * @return bool + */ + private function shouldAddChecksum( + string $mode, + bool $checksumRequired, + ?Shape $checksumMember, + ?string $requestedAlgorithm + ): bool + { + return ($mode === 'when_supported' && $checksumMember) + || ($mode === 'when_required' + && ($checksumRequired || ($checksumMember && $requestedAlgorithm))); + } + + /** + * @param Shape|null $checksumMember + * @param string|null $requestedAlgorithm + * @param string|null $checksumMemberName + * + * @return string + */ + private function determineChecksumAlgorithm( + array $supportedAlgorithms, + ?string $requestedAlgorithm, + ?string $checksumMemberName + ): string + { + $algorithm = self::DEFAULT_ALGORITHM; + + if ($requestedAlgorithm) { + $requestedAlgorithm = strtolower($requestedAlgorithm); + if (!in_array($requestedAlgorithm, $supportedAlgorithms)) { + throw new InvalidArgumentException( + "Unsupported algorithm supplied for input variable {$checksumMemberName}. " . + "Supported checksums for this operation include: " + . implode(", ", $supportedAlgorithms) . "." + ); + } + $algorithm = $requestedAlgorithm; + } + + return $algorithm; + } + + /** + * @param string $requestedAlgorithm + * @param RequestInterface $request + * @param StreamInterface $body + * + * @return RequestInterface + */ + private function addAlgorithmHeader( + string $requestedAlgorithm, + RequestInterface $request, + StreamInterface $body + ): RequestInterface + { + $headerName = "x-amz-checksum-{$requestedAlgorithm}"; + if (!$request->hasHeader($headerName)) { + $encoded = self::getEncodedValue($requestedAlgorithm, $body); + $request = $request->withHeader($headerName, $encoded); + } + + return $request; + } + + /** + * @param RequestInterface $request + * + * @return bool + */ + private function hasAlgorithmHeader(RequestInterface $request): bool + { + $headers = $request->getHeaders(); + + foreach ($headers as $name => $values) { + if (stripos($name, 'x-amz-checksum-') === 0) { + return true; + } + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BatchDelete.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BatchDelete.php new file mode 100644 index 000000000..db81bebc5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BatchDelete.php @@ -0,0 +1,240 @@ + 'us-west-2', + * 'version' => 'latest' + * ]); + * + * $listObjectsParams = ['Bucket' => 'foo', 'Prefix' => 'starts/with/']; + * $delete = Aws\S3\BatchDelete::fromListObjects($s3, $listObjectsParams); + * // Asynchronously delete + * $promise = $delete->promise(); + * // Force synchronous completion + * $delete->delete(); + * + * When using one of the batch delete creational static methods, you can supply + * an associative array of options: + * + * - before: Function invoked before executing a command. The function is + * passed the command that is about to be executed. This can be useful + * for logging, adding custom request headers, etc. + * - batch_size: The size of each delete batch. Defaults to 1000. + * + * @link http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html + */ +class BatchDelete implements PromisorInterface +{ + private $bucket; + /** @var AwsClientInterface */ + private $client; + /** @var callable */ + private $before; + /** @var PromiseInterface */ + private $cachedPromise; + /** @var callable */ + private $promiseCreator; + private $batchSize = 1000; + private $queue = []; + + /** + * Creates a BatchDelete object from all of the paginated results of a + * ListObjects operation. Each result that is returned by the ListObjects + * operation will be deleted. + * + * @param AwsClientInterface $client AWS Client to use. + * @param array $listObjectsParams ListObjects API parameters + * @param array $options BatchDelete options. + * + * @return BatchDelete + */ + public static function fromListObjects( + AwsClientInterface $client, + array $listObjectsParams, + array $options = [] + ) { + $iter = $client->getPaginator('ListObjects', $listObjectsParams); + $bucket = $listObjectsParams['Bucket']; + $fn = function (BatchDelete $that) use ($iter) { + return $iter->each(function ($result) use ($that) { + $promises = []; + if (is_array($result['Contents'])) { + foreach ($result['Contents'] as $object) { + if ($promise = $that->enqueue($object)) { + $promises[] = $promise; + } + } + } + return $promises ? Promise\Utils::all($promises) : null; + }); + }; + + return new self($client, $bucket, $fn, $options); + } + + /** + * Creates a BatchDelete object from an iterator that yields results. + * + * @param AwsClientInterface $client AWS Client to use to execute commands + * @param string $bucket Bucket where the objects are stored + * @param \Iterator $iter Iterator that yields assoc arrays + * @param array $options BatchDelete options + * + * @return BatchDelete + */ + public static function fromIterator( + AwsClientInterface $client, + $bucket, + \Iterator $iter, + array $options = [] + ) { + $fn = function (BatchDelete $that) use ($iter) { + return Promise\Coroutine::of(function () use ($that, $iter) { + foreach ($iter as $obj) { + if ($promise = $that->enqueue($obj)) { + yield $promise; + } + } + }); + }; + + return new self($client, $bucket, $fn, $options); + } + + /** + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + if (!$this->cachedPromise) { + $this->cachedPromise = $this->createPromise(); + } + + return $this->cachedPromise; + } + + /** + * Synchronously deletes all of the objects. + * + * @throws DeleteMultipleObjectsException on error. + */ + public function delete() + { + $this->promise()->wait(); + } + + /** + * @param AwsClientInterface $client Client used to transfer the requests + * @param string $bucket Bucket to delete from. + * @param callable $promiseFn Creates a promise. + * @param array $options Hash of options used with the batch + * + * @throws \InvalidArgumentException if the provided batch_size is <= 0 + */ + private function __construct( + AwsClientInterface $client, + $bucket, + callable $promiseFn, + array $options = [] + ) { + $this->client = $client; + $this->bucket = $bucket; + $this->promiseCreator = $promiseFn; + + if (isset($options['before'])) { + if (!is_callable($options['before'])) { + throw new \InvalidArgumentException('before must be callable'); + } + $this->before = $options['before']; + } + + if (isset($options['batch_size'])) { + if ($options['batch_size'] <= 0) { + throw new \InvalidArgumentException('batch_size is not > 0'); + } + $this->batchSize = min($options['batch_size'], 1000); + } + } + + private function enqueue(array $obj) + { + $this->queue[] = $obj; + return count($this->queue) >= $this->batchSize + ? $this->flushQueue() + : null; + } + + private function flushQueue() + { + static $validKeys = ['Key' => true, 'VersionId' => true]; + + if (count($this->queue) === 0) { + return null; + } + + $batch = []; + while ($obj = array_shift($this->queue)) { + $batch[] = array_intersect_key($obj, $validKeys); + } + + $command = $this->client->getCommand('DeleteObjects', [ + 'Bucket' => $this->bucket, + 'Delete' => ['Objects' => $batch] + ]); + + if ($this->before) { + call_user_func($this->before, $command); + } + + return $this->client->executeAsync($command) + ->then(function ($result) { + if (!empty($result['Errors'])) { + throw new DeleteMultipleObjectsException( + $result['Deleted'] ?: [], + $result['Errors'] + ); + } + return $result; + }); + } + + /** + * Returns a promise that will clean up any references when it completes. + * + * @return PromiseInterface + */ + private function createPromise() + { + // Create the promise + $promise = call_user_func($this->promiseCreator, $this); + $this->promiseCreator = null; + + // Cleans up the promise state and references. + $cleanup = function () { + $this->before = $this->client = $this->queue = null; + }; + + // When done, ensure cleanup and that any remaining are processed. + return $promise->then( + function () use ($cleanup) { + return Promise\Create::promiseFor($this->flushQueue()) + ->then($cleanup); + }, + function ($reason) use ($cleanup) { + $cleanup(); + return Promise\Create::rejectionFor($reason); + } + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php new file mode 100644 index 000000000..becfded6f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php @@ -0,0 +1,355 @@ +partitionProvider = PartitionEndpointProvider::defaultProvider(); + $this->region = $region; + $this->service = $service; + $this->config = $config; + $this->nextHandler = $nextHandler; + $this->isUseEndpointV2 = $isUseEndpointV2; + } + + public function __invoke(CommandInterface $cmd, RequestInterface $req) + { + $nextHandler = $this->nextHandler; + + $op = $this->service->getOperation($cmd->getName())->toArray(); + if (!empty($op['input']['shape'])) { + $service = $this->service->toArray(); + if (!empty($input = $service['shapes'][$op['input']['shape']])) { + foreach ($input['members'] as $key => $member) { + if ($member['shape'] === 'BucketName') { + $arnableKey = $key; + break; + } + } + + if (!empty($arnableKey) && ArnParser::isArn($cmd[$arnableKey])) { + + try { + // Throw for commands that do not support ARN inputs + if (in_array($cmd->getName(), $this->nonArnableCommands)) { + throw new S3Exception( + 'ARN values cannot be used in the bucket field for' + . ' the ' . $cmd->getName() . ' operation.', + $cmd + ); + } + + if (!$this->isUseEndpointV2) { + $arn = ArnParser::parse($cmd[$arnableKey]); + $partition = $this->validateArn($arn); + $host = $this->generateAccessPointHost($arn, $req); + } + // Remove encoded bucket string from path + $path = $req->getUri()->getPath(); + $encoded = rawurlencode($cmd[$arnableKey]); + $len = strlen($encoded) + 1; + if (trim(substr($path, 0, $len), '/') === "{$encoded}") { + $path = substr($path, $len); + if (substr($path, 0, 1) !== "/") { + $path = '/' . $path; + } + } + if (empty($path)) { + $path = ''; + } + + // Set modified request + if ($this->isUseEndpointV2) { + $req = $req->withUri( + $req->getUri()->withPath($path) + + ); + goto next; + } + + $req = $req->withUri( + $req->getUri()->withPath($path)->withHost($host) + ); + + // Update signing region based on ARN data if configured to do so + if ($this->config['use_arn_region']->isUseArnRegion() + && !$this->config['use_fips_endpoint']->isUseFipsEndpoint() + ) { + $region = $arn->getRegion(); + } else { + $region = $this->region; + } + $endpointData = $partition([ + 'region' => $region, + 'service' => $arn->getService() + ]); + $cmd['@context']['signing_region'] = $endpointData['signingRegion']; + + // Update signing service for Outposts and Lambda ARNs + if ($arn instanceof OutpostsArnInterface + || $arn instanceof ObjectLambdaAccessPointArn + ) { + $cmd['@context']['signing_service'] = $arn->getService(); + } + } catch (InvalidArnException $e) { + // Add context to ARN exception + throw new S3Exception( + 'Bucket parameter parsed as ARN and failed with: ' + . $e->getMessage(), + $cmd, + [], + $e + ); + } + } + } + } + next: + return $nextHandler($cmd, $req); + } + + + private function generateAccessPointHost( + BaseAccessPointArn $arn, + RequestInterface $req + ) { + if ($arn instanceof OutpostsAccessPointArn) { + $accesspointName = $arn->getAccesspointName(); + } else { + $accesspointName = $arn->getResourceId(); + } + + if ($arn instanceof MultiRegionAccessPointArn) { + $partition = $this->partitionProvider->getPartitionByName( + $arn->getPartition(), + 's3' + ); + $dnsSuffix = $partition->getDnsSuffix(); + return "{$accesspointName}.accesspoint.s3-global.{$dnsSuffix}"; + } + + $host = "{$accesspointName}-" . $arn->getAccountId(); + + $useFips = $this->config['use_fips_endpoint']->isUseFipsEndpoint(); + $fipsString = $useFips ? "-fips" : ""; + + if ($arn instanceof OutpostsAccessPointArn) { + $host .= '.' . $arn->getOutpostId() . '.s3-outposts'; + } else if ($arn instanceof ObjectLambdaAccessPointArn) { + if (!empty($this->config['endpoint'])) { + return $host . '.' . $this->config['endpoint']; + } else { + $host .= ".s3-object-lambda{$fipsString}"; + } + } else { + $host .= ".s3-accesspoint{$fipsString}"; + if (!empty($this->config['dual_stack'])) { + $host .= '.dualstack'; + } + } + + if (!empty($this->config['use_arn_region']->isUseArnRegion())) { + $region = $arn->getRegion(); + } else { + $region = $this->region; + } + $region = \Aws\strip_fips_pseudo_regions($region); + $host .= '.' . $region . '.' . $this->getPartitionSuffix($arn, $this->partitionProvider); + return $host; + } + + /** + * Validates an ARN, returning a partition object corresponding to the ARN + * if successful + * + * @param $arn + * @return \Aws\Endpoint\Partition + */ + private function validateArn($arn) + { + if ($arn instanceof AccessPointArnInterface) { + + // Dualstack is not supported with Outposts access points + if ($arn instanceof OutpostsAccessPointArn + && !empty($this->config['dual_stack']) + ) { + throw new UnresolvedEndpointException( + 'Dualstack is currently not supported with S3 Outposts access' + . ' points. Please disable dualstack or do not supply an' + . ' access point ARN.'); + } + if ($arn instanceof MultiRegionAccessPointArn) { + if (!empty($this->config['disable_multiregion_access_points'])) { + throw new UnresolvedEndpointException( + 'Multi-Region Access Point ARNs are disabled, but one was provided. Please' + . ' enable them or provide a different ARN.' + ); + } + if (!empty($this->config['dual_stack'])) { + throw new UnresolvedEndpointException( + 'Multi-Region Access Point ARNs do not currently support dual stack. Please' + . ' disable dual stack or provide a different ARN.' + ); + } + } + // Accelerate is not supported with access points + if (!empty($this->config['accelerate'])) { + throw new UnresolvedEndpointException( + 'Accelerate is currently not supported with access points.' + . ' Please disable accelerate or do not supply an access' + . ' point ARN.'); + } + + // Path-style is not supported with access points + if (!empty($this->config['path_style'])) { + throw new UnresolvedEndpointException( + 'Path-style addressing is currently not supported with' + . ' access points. Please disable path-style or do not' + . ' supply an access point ARN.'); + } + + // Custom endpoint is not supported with access points + if (!is_null($this->config['endpoint']) + && !$arn instanceof ObjectLambdaAccessPointArn + ) { + throw new UnresolvedEndpointException( + 'A custom endpoint has been supplied along with an access' + . ' point ARN, and these are not compatible with each other.' + . ' Please only use one or the other.'); + } + + // Dualstack is not supported with object lambda access points + if ($arn instanceof ObjectLambdaAccessPointArn + && !empty($this->config['dual_stack']) + ) { + throw new UnresolvedEndpointException( + 'Dualstack is currently not supported with Object Lambda access' + . ' points. Please disable dualstack or do not supply an' + . ' access point ARN.'); + } + // Global endpoints do not support cross-region requests + if ($this->isGlobal($this->region) + && $this->config['use_arn_region']->isUseArnRegion() == false + && $arn->getRegion() != $this->region + && !$arn instanceof MultiRegionAccessPointArn + ) { + throw new UnresolvedEndpointException( + 'Global endpoints do not support cross region requests.' + . ' Please enable use_arn_region or do not supply a global region' + . ' with a different region in the ARN.'); + } + + // Get partitions for ARN and client region + $arnPart = $this->partitionProvider->getPartition( + $arn->getRegion(), + 's3' + ); + $clientPart = $this->partitionProvider->getPartition( + $this->region, + 's3' + ); + + // If client partition not found, try removing pseudo-region qualifiers + if (!($clientPart->isRegionMatch($this->region, 's3'))) { + $clientPart = $this->partitionProvider->getPartition( + \Aws\strip_fips_pseudo_regions($this->region), + 's3' + ); + } + if (!$arn instanceof MultiRegionAccessPointArn) { + // Verify that the partition matches for supplied partition and region + if ($arn->getPartition() !== $clientPart->getName()) { + throw new InvalidRegionException('The supplied ARN partition' + . " does not match the client's partition."); + } + if ($clientPart->getName() !== $arnPart->getName()) { + throw new InvalidRegionException('The corresponding partition' + . ' for the supplied ARN region does not match the' + . " client's partition."); + } + + // Ensure ARN region matches client region unless + // configured for using ARN region over client region + $this->validateMatchingRegion($arn); + + // Ensure it is not resolved to fips pseudo-region for S3 Outposts + $this->validateFipsConfigurations($arn); + } + + return $arnPart; + } + + throw new InvalidArnException('Provided ARN was not a valid S3 access' + . ' point ARN or S3 Outposts access point ARN.'); + } + + /** + * Checks if a region is global + * + * @param $region + * @return bool + */ + private function isGlobal($region) + { + return $region == 's3-external-1' || $region == 'aws-global'; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointMiddleware.php new file mode 100644 index 000000000..131043b21 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/BucketEndpointMiddleware.php @@ -0,0 +1,111 @@ + true]; + private $nextHandler; + private bool $useEndpointV2; + private ?string $endpoint; + + /** + * Create a middleware wrapper function. + * + * @param bool $useEndpointV2 + * @param string|null $endpoint + * + * @return callable + */ + public static function wrap( + bool $useEndpointV2 = false, + ?string $endpoint = null + ): callable + { + return function (callable $handler) use ($useEndpointV2, $endpoint) { + return new self($handler, $useEndpointV2, $endpoint); + }; + } + + public function __construct( + callable $nextHandler, + bool $useEndpointV2, + ?string $endpoint = null + ) + { + $this->nextHandler = $nextHandler; + $this->useEndpointV2 = $useEndpointV2; + $this->endpoint = $endpoint; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + $nextHandler = $this->nextHandler; + $bucket = $command['Bucket']; + + if ($bucket && !isset(self::$exclusions[$command->getName()])) { + $request = $this->modifyRequest($request, $command); + } + + return $nextHandler($command, $request); + } + + /** + * @param string $path + * @param string $bucket + * + * @return string + */ + private function removeBucketFromPath(string $path, string $bucket): string + { + $len = strlen($bucket) + 1; + if (str_starts_with($path, "/{$bucket}")) { + $path = substr($path, $len); + } + + return $path ?: '/'; + } + + /** + * @param RequestInterface $request + * @param CommandInterface $command + * + * @return RequestInterface + */ + private function modifyRequest( + RequestInterface $request, + CommandInterface $command + ): RequestInterface + { + $uri = $request->getUri(); + $path = $uri->getPath(); + $host = $uri->getHost(); + $bucket = $command['Bucket']; + + if ($this->useEndpointV2 && !empty($this->endpoint)) { + // V2 provider adds bucket name to host by default + // preserve original host + $host = (new Uri($this->endpoint))->getHost(); + } + + $path = $this->removeBucketFromPath($path, $bucket); + + // Modify the Key to make sure the key is encoded, but slashes are not. + if ($command['Key']) { + $path = S3Client::encodeKey(rawurldecode($path)); + } + + return $request->withUri($uri->withPath($path)->withHost($host)); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/CalculatesChecksumTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/CalculatesChecksumTrait.php new file mode 100644 index 000000000..6b2b19413 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/CalculatesChecksumTrait.php @@ -0,0 +1,59 @@ + true, + 'crc32' => true, + 'sha256' => true, + 'sha1' => true + ]; + + /** + * @param string $requestedAlgorithm the algorithm to encode with + * @param string $value the value to be encoded + * @return string + */ + public static function getEncodedValue($requestedAlgorithm, $value) { + $requestedAlgorithm = strtolower($requestedAlgorithm); + $useCrt = extension_loaded('awscrt'); + + if (isset(self::$supportedAlgorithms[$requestedAlgorithm])) { + if ($useCrt) { + $crt = new Crt(); + switch ($requestedAlgorithm) { + case 'crc32c': + return base64_encode(pack('N*',($crt::crc32c($value)))); + case 'crc32': + return base64_encode(pack('N*',($crt::crc32($value)))); + default: + break; + } + } + + if ($requestedAlgorithm === 'crc32c') { + throw new CommonRuntimeException("crc32c is not supported for checksums " + . "without use of the common runtime for php. Please enable the CRT or choose " + . "a different algorithm." + ); + } + + if ($requestedAlgorithm === "crc32") { + $requestedAlgorithm = "crc32b"; + } + return base64_encode(Psr7\Utils::hash($value, $requestedAlgorithm, true)); + } + + $validAlgorithms = implode(', ', array_keys(self::$supportedAlgorithms)); + throw new InvalidArgumentException( + "Invalid checksum requested: {$requestedAlgorithm}." + . " Valid algorithms supported by the runtime are {$validAlgorithms}." + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php new file mode 100644 index 000000000..57253a4d3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php @@ -0,0 +1,75 @@ +instructionFileSuffix; + } + + protected function determineGetObjectStrategy( + $result, + $instructionFileSuffix + ) { + if (isset($result['Metadata'][MetadataEnvelope::CONTENT_KEY_V2_HEADER])) { + return new HeadersMetadataStrategy(); + } + + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + } + + protected function getMetadataStrategy(array $args, $instructionFileSuffix) + { + if (!empty($args['@MetadataStrategy'])) { + if ($args['@MetadataStrategy'] instanceof MetadataStrategyInterface) { + return $args['@MetadataStrategy']; + } + + if (is_string($args['@MetadataStrategy'])) { + switch ($args['@MetadataStrategy']) { + case HeadersMetadataStrategy::class: + return new HeadersMetadataStrategy(); + case InstructionFileMetadataStrategy::class: + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + default: + throw new \InvalidArgumentException('Could not match the' + . ' specified string in "MetadataStrategy" to a' + . ' predefined strategy.'); + } + } else { + throw new \InvalidArgumentException('The metadata strategy that' + . ' was passed to "MetadataStrategy" was unrecognized.'); + } + } elseif ($instructionFileSuffix) { + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + } + + return null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php new file mode 100644 index 000000000..05498176c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php @@ -0,0 +1,19 @@ +$value) { + $args['Metadata'][$header] = $value; + } + + return $args; + } + + /** + * Generates a MetadataEnvelope according to the metadata headers from the + * GetObject result. + * + * @param array $args Arguments from Command and Result that contains + * S3 Object information, relevant headers, and command + * configuration. + * + * @return MetadataEnvelope + */ + public function load(array $args) + { + $envelope = new MetadataEnvelope(); + $constantValues = MetadataEnvelope::getConstantValues(); + + foreach ($constantValues as $constant) { + if (!empty($args['Metadata'][$constant])) { + $envelope[$constant] = $args['Metadata'][$constant]; + } + } + + return $envelope; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php new file mode 100644 index 000000000..5065928c7 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php @@ -0,0 +1,90 @@ +suffix = empty($suffix) + ? self::DEFAULT_FILE_SUFFIX + : $suffix; + $this->client = $client; + } + + /** + * Places the information in the MetadataEnvelope to a location on S3. + * + * @param MetadataEnvelope $envelope Encryption data to save according to + * the strategy. + * @param array $args Starting arguments for PutObject, used for saving + * extra the instruction file. + * + * @return array Updated arguments for PutObject. + */ + public function save(MetadataEnvelope $envelope, array $args) + { + $this->client->putObject([ + 'Bucket' => $args['Bucket'], + 'Key' => $args['Key'] . $this->suffix, + 'Body' => json_encode($envelope) + ]); + + return $args; + } + + /** + * Uses the strategy's client to retrieve the instruction file from S3 and generates + * a MetadataEnvelope from its contents. + * + * @param array $args Arguments from Command and Result that contains + * S3 Object information, relevant headers, and command + * configuration. + * + * @return MetadataEnvelope + */ + public function load(array $args) + { + $result = $this->client->getObject([ + 'Bucket' => $args['Bucket'], + 'Key' => $args['Key'] . $this->suffix + ]); + + $metadataHeaders = json_decode($result['Body'], true); + $envelope = new MetadataEnvelope(); + $constantValues = MetadataEnvelope::getConstantValues(); + + foreach ($constantValues as $constant) { + if (!empty($metadataHeaders[$constant])) { + $envelope[$constant] = $metadataHeaders[$constant]; + } + } + + return $envelope; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php new file mode 100644 index 000000000..96cb152a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php @@ -0,0 +1,344 @@ +client = $client; + $this->instructionFileSuffix = $instructionFileSuffix; + MetricsBuilder::appendMetricsCaptureMiddleware( + $this->client->getHandlerList(), + MetricsBuilder::S3_CRYPTO_V1N + ); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + /** + * Encrypts the data in the 'Body' field of $args and promises to upload it + * to the specified location on S3. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. Only the + * Cipher option is required. Accepts the following: + * - Cipher: (string) cbc|gcm + * See also: AbstractCryptoClient::$supportedCiphers. Note that + * cbc is deprecated and gcm should be used when possible. + * - KeySize: (int) 128|192|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. Note if you pass in Aad for gcm encryption, the + * PHP SDK will be able to decrypt the resulting object, but other + * AWS SDKs may not be able to do so. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if using an InstructionFileMetadataHandler. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $envelope = new MetadataEnvelope(); + + return Promise\Create::promiseFor($this->encrypt( + Psr7\Utils::streamFor($args['Body']), + $args['@CipherOptions'] ?: [], + $provider, + $envelope + ))->then( + function ($encryptedBodyStream) use ($args) { + $hash = new PhpHash('sha256'); + $hashingEncryptedBodyStream = new HashingStream( + $encryptedBodyStream, + $hash, + self::getContentShaDecorator($args) + ); + return [$hashingEncryptedBodyStream, $args]; + } + )->then( + function ($putObjectContents) use ($strategy, $envelope) { + list($bodyStream, $args) = $putObjectContents; + if ($strategy === null) { + $strategy = self::getDefaultStrategy(); + } + + $updatedArgs = $strategy->save($envelope, $args); + $updatedArgs['Body'] = $bodyStream; + return $updatedArgs; + } + )->then( + function ($args) { + unset($args['@CipherOptions']); + return $this->client->putObjectAsync($args); + } + ); + } + + private static function getContentShaDecorator(&$args) + { + return function ($hash) use (&$args) { + $args['ContentSHA256'] = bin2hex($hash); + }; + } + + /** + * Encrypts the data in the 'Body' field of $args and uploads it to the + * specified location on S3. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) cbc|gcm + * See also: AbstractCryptoClient::$supportedCiphers. Note that + * cbc is deprecated and gcm should be used when possible. + * - KeySize: (int) 128|192|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. Note if you pass in Aad for gcm encryption, the + * PHP SDK will be able to decrypt the resulting object, but other + * AWS SDKs may not be able to do so. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * + * @return \Aws\Result PutObject call result with the details of uploading + * the encrypted file. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObject(array $args) + { + return $this->putObjectAsync($args)->wait(); + } + + /** + * Promises to retrieve an object from S3 and decrypt the data in the + * 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading + * MetadataEnvelope information. Defaults to determining based on object + * response headers. Can either be a class implementing MetadataStrategy, + * a class name of a predefined strategy, or empty/null to default. + * - @InstructionFileSuffix: (string) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler is being used. + * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when required arguments are not + * passed or are passed incorrectly. + */ + public function getObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $saveAs = null; + if (!empty($args['SaveAs'])) { + $saveAs = $args['SaveAs']; + } + + $promise = $this->client->getObjectAsync($args) + ->then( + function ($result) use ( + $provider, + $instructionFileSuffix, + $strategy, + $args + ) { + if ($strategy === null) { + $strategy = $this->determineGetObjectStrategy( + $result, + $instructionFileSuffix + ); + } + + $envelope = $strategy->load($args + [ + 'Metadata' => $result['Metadata'] + ]); + + $provider = $provider->fromDecryptionEnvelope($envelope); + + $result['Body'] = $this->decrypt( + $result['Body'], + $provider, + $envelope, + isset($args['@CipherOptions']) + ? $args['@CipherOptions'] + : [] + ); + return $result; + } + )->then( + function ($result) use ($saveAs) { + if (!empty($saveAs)) { + file_put_contents( + $saveAs, + (string)$result['Body'], + LOCK_EX + ); + } + return $result; + } + ); + + return $promise; + } + + /** + * Retrieves an object from S3 and decrypts the data in the 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * - @InstructionFileSuffix: (string|null) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler was detected. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * + * @return \Aws\Result GetObject call result with the 'Body' field + * wrapped in a decryption stream with its metadata + * information. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function getObject(array $args) + { + return $this->getObjectAsync($args)->wait(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php new file mode 100644 index 000000000..fe917800f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php @@ -0,0 +1,450 @@ + + * use Aws\Crypto\KmsMaterialsProviderV2; + * use Aws\S3\Crypto\S3EncryptionClientV2; + * use Aws\S3\S3Client; + * + * $encryptionClient = new S3EncryptionClientV2( + * new S3Client([ + * 'region' => 'us-west-2', + * 'version' => 'latest' + * ]) + * ); + * $materialsProvider = new KmsMaterialsProviderV2( + * new KmsClient([ + * 'profile' => 'default', + * 'region' => 'us-east-1', + * 'version' => 'latest', + * ], + * 'your-kms-key-id' + * ); + * + * $encryptionClient->putObject([ + * '@MaterialsProvider' => $materialsProvider, + * '@CipherOptions' => [ + * 'Cipher' => 'gcm', + * 'KeySize' => 256, + * ], + * '@KmsEncryptionContext' => ['foo' => 'bar'], + * 'Bucket' => 'your-bucket', + * 'Key' => 'your-key', + * 'Body' => 'your-encrypted-data', + * ]); + * + * + * Example read call (using objects from previous example): + * + * + * $encryptionClient->getObject([ + * '@MaterialsProvider' => $materialsProvider, + * '@CipherOptions' => [ + * 'Cipher' => 'gcm', + * 'KeySize' => 256, + * ], + * 'Bucket' => 'your-bucket', + * 'Key' => 'your-key', + * ]); + * + */ +class S3EncryptionClientV2 extends AbstractCryptoClientV2 +{ + use CipherBuilderTrait; + use CryptoParamsTraitV2; + use DecryptionTraitV2; + use EncryptionTraitV2; + use UserAgentTrait; + + const CRYPTO_VERSION = '2.1'; + + private $client; + private $instructionFileSuffix; + private $legacyWarningCount; + + /** + * @param S3Client $client The S3Client to be used for true uploading and + * retrieving objects from S3 when using the + * encryption client. + * @param string|null $instructionFileSuffix Suffix for a client wide + * default when using instruction + * files for metadata storage. + */ + public function __construct( + S3Client $client, + $instructionFileSuffix = null + ) { + $this->client = $client; + $this->instructionFileSuffix = $instructionFileSuffix; + $this->legacyWarningCount = 0; + MetricsBuilder::appendMetricsCaptureMiddleware( + $this->client->getHandlerList(), + MetricsBuilder::S3_CRYPTO_V2 + ); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + /** + * Encrypts the data in the 'Body' field of $args and promises to upload it + * to the specified location on S3. + * + * Note that for PHP versions of < 7.1, this operation uses an AES-GCM + * polyfill for encryption since there is no native PHP support. The + * performance for large inputs will be a lot slower than for PHP 7.1+, so + * upgrading older PHP version environments may be necessary to use this + * effectively. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProviderV2) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. Only the + * Cipher option is required. Accepts the following: + * - Cipher: (string) gcm + * See also: AbstractCryptoClientV2::$supportedCiphers + * - KeySize: (int) 128|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. Note if you pass in + * Aad, the PHP SDK will be able to decrypt the resulting object, + * but other AWS SDKs may not be able to do so. + * - @KmsEncryptionContext: (array) Only required if using + * KmsMaterialsProviderV2. An associative array of key-value + * pairs to be added to the encryption context for KMS key encryption. An + * empty array may be passed if no additional context is desired. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if using an InstructionFileMetadataHandler. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $envelope = new MetadataEnvelope(); + + return Promise\Create::promiseFor($this->encrypt( + Psr7\Utils::streamFor($args['Body']), + $args, + $provider, + $envelope + ))->then( + function ($encryptedBodyStream) use ($args) { + $hash = new PhpHash('sha256'); + $hashingEncryptedBodyStream = new HashingStream( + $encryptedBodyStream, + $hash, + self::getContentShaDecorator($args) + ); + return [$hashingEncryptedBodyStream, $args]; + } + )->then( + function ($putObjectContents) use ($strategy, $envelope) { + list($bodyStream, $args) = $putObjectContents; + if ($strategy === null) { + $strategy = self::getDefaultStrategy(); + } + + $updatedArgs = $strategy->save($envelope, $args); + $updatedArgs['Body'] = $bodyStream; + return $updatedArgs; + } + )->then( + function ($args) { + unset($args['@CipherOptions']); + return $this->client->putObjectAsync($args); + } + ); + } + + private static function getContentShaDecorator(&$args) + { + return function ($hash) use (&$args) { + $args['ContentSHA256'] = bin2hex($hash); + }; + } + + /** + * Encrypts the data in the 'Body' field of $args and uploads it to the + * specified location on S3. + * + * Note that for PHP versions of < 7.1, this operation uses an AES-GCM + * polyfill for encryption since there is no native PHP support. The + * performance for large inputs will be a lot slower than for PHP 7.1+, so + * upgrading older PHP version environments may be necessary to use this + * effectively. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) gcm + * See also: AbstractCryptoClientV2::$supportedCiphers + * - KeySize: (int) 128|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. Note if you pass in + * Aad, the PHP SDK will be able to decrypt the resulting object, + * but other AWS SDKs may not be able to do so. + * - @KmsEncryptionContext: (array) Only required if using + * KmsMaterialsProviderV2. An associative array of key-value + * pairs to be added to the encryption context for KMS key encryption. An + * empty array may be passed if no additional context is desired. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * + * @return \Aws\Result PutObject call result with the details of uploading + * the encrypted file. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObject(array $args) + { + return $this->putObjectAsync($args)->wait(); + } + + /** + * Promises to retrieve an object from S3 and decrypt the data in the + * 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'. + * - 'V2' indicates that only objects encrypted with S3EncryptionClientV2 + * content encryption and key wrap schemas are able to be decrypted. + * - 'V2_AND_LEGACY' indicates that objects encrypted with both + * S3EncryptionClientV2 and older legacy encryption clients are able + * to be decrypted. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading + * MetadataEnvelope information. Defaults to determining based on object + * response headers. Can either be a class implementing MetadataStrategy, + * a class name of a predefined strategy, or empty/null to default. + * - @InstructionFileSuffix: (string) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler is being used. + * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with + * KMS materials for any KMS key ID, instead of needing the KMS key ID to + * be specified and provided to the decrypt operation. Ignored for non-KMS + * materials providers. Defaults to false. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when required arguments are not + * passed or are passed incorrectly. + */ + public function getObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + if (!isset($args['@SecurityProfile']) + || !in_array($args['@SecurityProfile'], self::$supportedSecurityProfiles) + ) { + throw new CryptoException("@SecurityProfile is required and must be" + . " set to 'V2' or 'V2_AND_LEGACY'"); + } + + // Only throw this legacy warning once per client + if (in_array($args['@SecurityProfile'], self::$legacySecurityProfiles) + && $this->legacyWarningCount < 1 + ) { + $this->legacyWarningCount++; + trigger_error( + "This S3 Encryption Client operation is configured to" + . " read encrypted data with legacy encryption modes. If you" + . " don't have objects encrypted with these legacy modes," + . " you should disable support for them to enhance security. ", + E_USER_WARNING + ); + } + + $saveAs = null; + if (!empty($args['SaveAs'])) { + $saveAs = $args['SaveAs']; + } + + $promise = $this->client->getObjectAsync($args) + ->then( + function ($result) use ( + $provider, + $instructionFileSuffix, + $strategy, + $args + ) { + if ($strategy === null) { + $strategy = $this->determineGetObjectStrategy( + $result, + $instructionFileSuffix + ); + } + + $envelope = $strategy->load($args + [ + 'Metadata' => $result['Metadata'] + ]); + + $result['Body'] = $this->decrypt( + $result['Body'], + $provider, + $envelope, + $args + ); + return $result; + } + )->then( + function ($result) use ($saveAs) { + if (!empty($saveAs)) { + file_put_contents( + $saveAs, + (string)$result['Body'], + LOCK_EX + ); + } + return $result; + } + ); + + return $promise; + } + + /** + * Retrieves an object from S3 and decrypts the data in the 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'. + * - 'V2' indicates that only objects encrypted with S3EncryptionClientV2 + * content encryption and key wrap schemas are able to be decrypted. + * - 'V2_AND_LEGACY' indicates that objects encrypted with both + * S3EncryptionClientV2 and older legacy encryption clients are able + * to be decrypted. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * - @InstructionFileSuffix: (string|null) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler was detected. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with + * KMS materials for any KMS key ID, instead of needing the KMS key ID to + * be specified and provided to the decrypt operation. Ignored for non-KMS + * materials providers. Defaults to false. + * + * @return \Aws\Result GetObject call result with the 'Body' field + * wrapped in a decryption stream with its metadata + * information. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function getObject(array $args) + { + return $this->getObjectAsync($args)->wait(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php new file mode 100644 index 000000000..ddf1d2df9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php @@ -0,0 +1,169 @@ +appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $config['params'] = []; + if (!empty($config['bucket'])) { + $config['params']['Bucket'] = $config['bucket']; + } + if (!empty($config['key'])) { + $config['params']['Key'] = $config['key']; + } + + $this->provider = $this->getMaterialsProvider($config); + unset($config['@MaterialsProvider']); + + $this->instructionFileSuffix = $this->getInstructionFileSuffix($config); + unset($config['@InstructionFileSuffix']); + $this->strategy = $this->getMetadataStrategy( + $config, + $this->instructionFileSuffix + ); + if ($this->strategy === null) { + $this->strategy = self::getDefaultStrategy(); + } + unset($config['@MetadataStrategy']); + + $config['prepare_data_source'] = $this->getEncryptingDataPreparer(); + + parent::__construct($client, $source, $config); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + private function getEncryptingDataPreparer() + { + return function() { + // Defer encryption work until promise is executed + $envelope = new MetadataEnvelope(); + + list($this->source, $params) = Promise\Create::promiseFor($this->encrypt( + $this->source, + $this->config['@cipheroptions'] ?: [], + $this->provider, + $envelope + ))->then( + function ($bodyStream) use ($envelope) { + $params = $this->strategy->save( + $envelope, + $this->config['params'] + ); + return [$bodyStream, $params]; + } + )->wait(); + + $this->source->rewind(); + $this->config['params'] = $params; + }; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php new file mode 100644 index 000000000..1bdbccf37 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php @@ -0,0 +1,176 @@ +appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $config['params'] = []; + if (!empty($config['bucket'])) { + $config['params']['Bucket'] = $config['bucket']; + } + if (!empty($config['key'])) { + $config['params']['Key'] = $config['key']; + } + + $this->provider = $this->getMaterialsProvider($config); + unset($config['@MaterialsProvider']); + + $this->instructionFileSuffix = $this->getInstructionFileSuffix($config); + unset($config['@InstructionFileSuffix']); + $this->strategy = $this->getMetadataStrategy( + $config, + $this->instructionFileSuffix + ); + if ($this->strategy === null) { + $this->strategy = self::getDefaultStrategy(); + } + unset($config['@MetadataStrategy']); + + $config['prepare_data_source'] = $this->getEncryptingDataPreparer(); + + parent::__construct($client, $source, $config); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + private function getEncryptingDataPreparer() + { + return function() { + // Defer encryption work until promise is executed + $envelope = new MetadataEnvelope(); + + list($this->source, $params) = Promise\Create::promiseFor($this->encrypt( + $this->source, + $this->config ?: [], + $this->provider, + $envelope + ))->then( + function ($bodyStream) use ($envelope) { + $params = $this->strategy->save( + $envelope, + $this->config['params'] + ); + return [$bodyStream, $params]; + } + )->wait(); + + $this->source->rewind(); + $this->config['params'] = $params; + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php new file mode 100644 index 000000000..45662758c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php @@ -0,0 +1,31 @@ +getHandlerList(); + $list->appendBuild(Middleware::mapRequest( + function(RequestInterface $req) use ($agentString) { + if (!empty($req->getHeader('User-Agent')) + && !empty($req->getHeader('User-Agent')[0]) + ) { + $userAgent = $req->getHeader('User-Agent')[0]; + if (strpos($userAgent, $agentString) === false) { + $userAgent .= " {$agentString}"; + }; + } else { + $userAgent = $agentString; + } + + $req = $req->withHeader('User-Agent', $userAgent); + return $req; + } + )); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/EndpointRegionHelperTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/EndpointRegionHelperTrait.php new file mode 100644 index 000000000..3c35c4b97 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/EndpointRegionHelperTrait.php @@ -0,0 +1,106 @@ +getPartition( + $arn->getRegion(), + $arn->getService() + ); + return $partition->getDnsSuffix(); + } + + private function getSigningRegion( + $region, + $service, + PartitionEndpointProvider $provider + ) { + $partition = $provider->getPartition($region, $service); + $data = $partition->toArray(); + if (isset($data['services'][$service]['endpoints'][$region]['credentialScope']['region'])) { + return $data['services'][$service]['endpoints'][$region]['credentialScope']['region']; + } + return $region; + } + + private function isMatchingSigningRegion( + $arnRegion, + $clientRegion, + $service, + PartitionEndpointProvider $provider + ) { + $arnRegion = \Aws\strip_fips_pseudo_regions(strtolower($arnRegion)); + $clientRegion = strtolower($clientRegion); + if ($arnRegion === $clientRegion) { + return true; + } + if ($this->getSigningRegion($clientRegion, $service, $provider) === $arnRegion) { + return true; + } + return false; + } + + private function validateFipsConfigurations(ArnInterface $arn) + { + $useFipsEndpoint = !empty($this->config['use_fips_endpoint']); + if ($arn instanceof OutpostsArnInterface) { + if (empty($this->config['use_arn_region']) + || !($this->config['use_arn_region']->isUseArnRegion()) + ) { + $region = $this->region; + } else { + $region = $arn->getRegion(); + } + if (\Aws\is_fips_pseudo_region($region)) { + throw new InvalidRegionException( + 'Fips is currently not supported with S3 Outposts access' + . ' points. Please provide a non-fips region or do not supply an' + . ' access point ARN.'); + } + } + } + + private function validateMatchingRegion(ArnInterface $arn) + { + if (!($this->isMatchingSigningRegion( + $arn->getRegion(), + $this->region, + $this->service->getEndpointPrefix(), + $this->partitionProvider) + )) { + if (empty($this->config['use_arn_region']) + || !($this->config['use_arn_region']->isUseArnRegion()) + ) { + throw new InvalidRegionException('The region' + . " specified in the ARN (" . $arn->getRegion() + . ") does not match the client region (" + . "{$this->region})."); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/DeleteMultipleObjectsException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/DeleteMultipleObjectsException.php new file mode 100644 index 000000000..5b4c28903 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/DeleteMultipleObjectsException.php @@ -0,0 +1,68 @@ +deleted = array_values($deleted); + $this->errors = array_values($errors); + parent::__construct('Unable to delete certain keys when executing a' + . ' DeleteMultipleObjects request: ' + . self::createMessageFromErrors($errors)); + } + + /** + * Create a single error message from multiple errors. + * + * @param array $errors Errors encountered + * + * @return string + */ + public static function createMessageFromErrors(array $errors) + { + return "\n- " . implode("\n- ", array_map(function ($key) { + return json_encode($key); + }, $errors)); + } + + /** + * Get the errored objects + * + * @return array Returns an array of associative arrays, each containing + * a 'Code', 'Message', and 'Key' key. + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Get the successfully deleted objects + * + * @return array Returns an array of associative arrays, each containing + * a 'Key' and optionally 'DeleteMarker' and + * 'DeleterMarkerVersionId' + */ + public function getDeleted() + { + return $this->deleted; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/PermanentRedirectException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/PermanentRedirectException.php new file mode 100644 index 000000000..67d916e89 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Exception/PermanentRedirectException.php @@ -0,0 +1,4 @@ +collectPathInfo($error->getCommand()); + } elseif ($prev instanceof AwsException) { + $this->collectPathInfo($prev->getCommand()); + } + parent::__construct($state, $prev); + } + + /** + * Get the Bucket information of the transfer object + * + * @return string|null Returns null when 'Bucket' information + * is unavailable. + */ + public function getBucket() + { + return $this->bucket; + } + + /** + * Get the Key information of the transfer object + * + * @return string|null Returns null when 'Key' information + * is unavailable. + */ + public function getKey() + { + return $this->key; + } + + /** + * Get the source file name of the transfer object + * + * @return string|null Returns null when metadata of the stream + * wrapped in 'Body' parameter is unavailable. + */ + public function getSourceFileName() + { + return $this->filename; + } + + /** + * Collect file path information when accessible. (Bucket, Key) + * + * @param CommandInterface $cmd + */ + private function collectPathInfo(CommandInterface $cmd) + { + if (empty($this->bucket) && isset($cmd['Bucket'])) { + $this->bucket = $cmd['Bucket']; + } + if (empty($this->key) && isset($cmd['Key'])) { + $this->key = $cmd['Key']; + } + if (empty($this->filename) && isset($cmd['Body'])) { + $this->filename = $cmd['Body']->getMetadata('uri'); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ExpiresParsingMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ExpiresParsingMiddleware.php new file mode 100644 index 000000000..5bdb34a70 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ExpiresParsingMiddleware.php @@ -0,0 +1,56 @@ +nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, ?RequestInterface $request = null) + { + $next = $this->nextHandler; + return $next($command, $request)->then( + function (ResultInterface $result) { + if (empty($result['Expires']) && !empty($result['ExpiresString'])) { + trigger_error( + "Failed to parse the `expires` header as a timestamp due to " + . " an invalid timestamp format.\nPlease refer to `ExpiresString` " + . "for the unparsed string format of this header.\n" + , E_USER_WARNING + ); + } + return $result; + } + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/GetBucketLocationParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/GetBucketLocationParser.php new file mode 100644 index 000000000..94aee6967 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/GetBucketLocationParser.php @@ -0,0 +1,49 @@ +parser = $parser; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $fn = $this->parser; + $result = $fn($command, $response); + + if ($command->getName() === 'GetBucketLocation') { + $location = 'us-east-1'; + if (preg_match('/>(.+?)<\/LocationConstraint>/', $response->getBody(), $matches)) { + $location = $matches[1] === 'EU' ? 'eu-west-1' : $matches[1]; + } + $result['LocationConstraint'] = $location; + } + + return $result; + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartCopy.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartCopy.php new file mode 100644 index 000000000..6a7bc04dd --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartCopy.php @@ -0,0 +1,249 @@ +/). If the key contains a '?' + * character, instead pass an array of source_key, + * source_bucket, and source_version_id. + * @param array $config Configuration used to perform the upload. + */ + public function __construct( + S3ClientInterface $client, + $source, + array $config = [] + ) { + if (is_array($source)) { + $this->source = $source; + } else { + $this->source = $this->getInputSource($source); + } + + parent::__construct( + $client, + array_change_key_case($config) + ['source_metadata' => null] + ); + + if ($this->displayProgress) { + $this->getState()->setProgressThresholds( + $this->sourceMetadata["ContentLength"] + ); + } + } + + /** + * An alias of the self::upload method. + * + * @see self::upload + */ + public function copy() + { + return $this->upload(); + } + + protected function loadUploadWorkflowInfo() + { + return [ + 'command' => [ + 'initiate' => 'CreateMultipartUpload', + 'upload' => 'UploadPartCopy', + 'complete' => 'CompleteMultipartUpload', + ], + 'id' => [ + 'bucket' => 'Bucket', + 'key' => 'Key', + 'upload_id' => 'UploadId', + ], + 'part_num' => 'PartNumber', + ]; + } + + protected function getUploadCommands(callable $resultHandler) + { + $parts = ceil($this->getSourceSize() / $this->determinePartSize()); + + for ($partNumber = 1; $partNumber <= $parts; $partNumber++) { + // If we haven't already uploaded this part, yield a new part. + if (!$this->state->hasPartBeenUploaded($partNumber)) { + $command = $this->client->getCommand( + $this->info['command']['upload'], + $this->createPart($partNumber, $parts) + $this->getState()->getId() + ); + $command->getHandlerList()->appendSign($resultHandler, 'mup'); + yield $command; + } + } + } + + private function createPart($partNumber, $partsCount) + { + $data = []; + + // Apply custom params to UploadPartCopy data + $config = $this->getConfig(); + $params = isset($config['params']) ? $config['params'] : []; + foreach ($params as $k => $v) { + $data[$k] = $v; + } + // The source parameter here is usually a string, but can be overloaded as an array + // if the key contains a '?' character to specify where the query parameters start + if (is_array($this->source)) { + $key = str_replace('%2F', '/', rawurlencode($this->source['source_key'])); + $bucket = $this->source['source_bucket']; + } else { + list($bucket, $key) = explode('/', ltrim($this->source, '/'), 2); + $key = implode( + '/', + array_map( + 'urlencode', + explode('/', rawurldecode($key)) + ) + ); + } + + $uri = ArnParser::isArn($bucket) ? '' : '/'; + $uri .= $bucket . '/' . $key; + $data['CopySource'] = $uri; + $data['PartNumber'] = $partNumber; + if (!empty($this->sourceVersionId)) { + $data['CopySource'] .= "?versionId=" . $this->sourceVersionId; + } + + $defaultPartSize = $this->determinePartSize(); + $startByte = $defaultPartSize * ($partNumber - 1); + $data['ContentLength'] = $partNumber < $partsCount + ? $defaultPartSize + : $this->getSourceSize() - ($defaultPartSize * ($partsCount - 1)); + $endByte = $startByte + $data['ContentLength'] - 1; + $data['CopySourceRange'] = "bytes=$startByte-$endByte"; + + return $data; + } + + protected function extractETag(ResultInterface $result) + { + return $result->search('CopyPartResult.ETag'); + } + + protected function getSourceMimeType() + { + return $this->getSourceMetadata()['ContentType']; + } + + protected function getSourceSize() + { + return $this->getSourceMetadata()['ContentLength']; + } + + private function getSourceMetadata() + { + if (empty($this->sourceMetadata)) { + $this->sourceMetadata = $this->fetchSourceMetadata(); + } + + return $this->sourceMetadata; + } + + private function fetchSourceMetadata() + { + if ($this->config['source_metadata'] instanceof ResultInterface) { + return $this->config['source_metadata']; + } + //if the source variable was overloaded with an array, use the inputs for key and bucket + if (is_array($this->source)) { + $headParams = [ + 'Key' => $this->source['source_key'], + 'Bucket' => $this->source['source_bucket'] + ]; + if (isset($this->source['source_version_id'])) { + $this->sourceVersionId = $this->source['source_version_id']; + $headParams['VersionId'] = $this->sourceVersionId; + } + //otherwise, use the default source parsing behavior + } else { + list($bucket, $key) = explode('/', ltrim($this->source, '/'), 2); + $headParams = [ + 'Bucket' => $bucket, + 'Key' => $key, + ]; + if (strpos($key, '?')) { + list($key, $query) = explode('?', $key, 2); + $headParams['Key'] = $key; + $query = Psr7\Query::parse($query, false); + if (isset($query['versionId'])) { + $this->sourceVersionId = $query['versionId']; + $headParams['VersionId'] = $this->sourceVersionId; + } + } + } + return $this->client->headObject($headParams); + } + + /** + * Get the url decoded input source, starting with a slash if it is not an + * ARN to standardize the source location syntax. + * + * @param string $inputSource The source that was passed to the constructor + * @return string The source, starting with a slash if it's not an arn + */ + private function getInputSource($inputSource) + { + $sourceBuilder = ArnParser::isArn($inputSource) ? '' : '/'; + $sourceBuilder .= ltrim(rawurldecode($inputSource), '/'); + return $sourceBuilder; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploader.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploader.php new file mode 100644 index 000000000..b2bed2b60 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploader.php @@ -0,0 +1,181 @@ + null, + 'key' => null, + 'exception_class' => S3MultipartUploadException::class, + ]); + + if ($this->displayProgress) { + $this->getState()->setProgressThresholds($this->source->getSize()); + } + } + + protected function loadUploadWorkflowInfo() + { + return [ + 'command' => [ + 'initiate' => 'CreateMultipartUpload', + 'upload' => 'UploadPart', + 'complete' => 'CompleteMultipartUpload', + ], + 'id' => [ + 'bucket' => 'Bucket', + 'key' => 'Key', + 'upload_id' => 'UploadId', + ], + 'part_num' => 'PartNumber', + ]; + } + + protected function createPart($seekable, $number) + { + // Initialize the array of part data that will be returned. + $data = []; + + // Apply custom params to UploadPart data + $config = $this->getConfig(); + $params = isset($config['params']) ? $config['params'] : []; + foreach ($params as $k => $v) { + $data[$k] = $v; + } + + $data['PartNumber'] = $number; + + // Read from the source to create the body stream. + if ($seekable) { + // Case 1: Source is seekable, use lazy stream to defer work. + $body = $this->limitPartStream( + new Psr7\LazyOpenStream($this->source->getMetadata('uri'), 'r') + ); + } else { + // Case 2: Stream is not seekable; must store in temp stream. + $source = $this->limitPartStream($this->source); + $source = $this->decorateWithHashes($source, $data); + $body = Psr7\Utils::streamFor(); + Psr7\Utils::copyToStream($source, $body); + } + + $contentLength = $body->getSize(); + + // Do not create a part if the body size is zero. + if ($contentLength === 0) { + return false; + } + + $body->seek(0); + $data['Body'] = $body; + + if (isset($config['add_content_md5']) + && $config['add_content_md5'] === true + ) { + $data['AddContentMD5'] = true; + } + + $data['ContentLength'] = $contentLength; + + return $data; + } + + protected function extractETag(ResultInterface $result) + { + return $result['ETag']; + } + + protected function getSourceMimeType() + { + if ($uri = $this->source->getMetadata('uri')) { + return Psr7\MimeType::fromFilename($uri) + ?: 'application/octet-stream'; + } + } + + protected function getSourceSize() + { + return $this->source->getSize(); + } + + /** + * Decorates a stream with a sha256 linear hashing stream. + * + * @param Stream $stream Stream to decorate. + * @param array $data Part data to augment with the hash result. + * + * @return Stream + */ + private function decorateWithHashes(Stream $stream, array &$data) + { + // Decorate source with a hashing stream + $hash = new PhpHash('sha256'); + return new HashingStream($stream, $hash, function ($result) use (&$data) { + $data['ContentSHA256'] = bin2hex($result); + }); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploadingTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploadingTrait.php new file mode 100644 index 000000000..b98a2d795 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/MultipartUploadingTrait.php @@ -0,0 +1,151 @@ + $bucket, + 'Key' => $key, + 'UploadId' => $uploadId, + ]); + + foreach ($client->getPaginator('ListParts', $state->getId()) as $result) { + // Get the part size from the first part in the first result. + if (!$state->getPartSize()) { + $state->setPartSize($result->search('Parts[0].Size')); + } + // Mark all the parts returned by ListParts as uploaded. + foreach ($result['Parts'] as $part) { + $state->markPartAsUploaded($part['PartNumber'], [ + 'PartNumber' => $part['PartNumber'], + 'ETag' => $part['ETag'] + ]); + } + } + + $state->setStatus(UploadState::INITIATED); + + return $state; + } + + protected function handleResult(CommandInterface $command, ResultInterface $result) + { + $partData = []; + $partData['PartNumber'] = $command['PartNumber']; + $partData['ETag'] = $this->extractETag($result); + $commandName = $command->getName(); + $checksumResult = $commandName === 'UploadPart' + ? $result + : $result[$commandName . 'Result']; + + if (isset($command['ChecksumAlgorithm'])) { + $checksumMemberName = 'Checksum' . strtoupper($command['ChecksumAlgorithm']); + $partData[$checksumMemberName] = $checksumResult[$checksumMemberName] ?? null; + } + + $this->getState()->markPartAsUploaded($command['PartNumber'], $partData); + + // Updates counter for uploaded bytes. + $this->uploadedBytes += $command["ContentLength"]; + // Sends uploaded bytes to progress tracker if getDisplayProgress set + if ($this->displayProgress) { + $this->getState()->getDisplayProgress($this->uploadedBytes); + } + } + + abstract protected function extractETag(ResultInterface $result); + + protected function getCompleteParams() + { + $config = $this->getConfig(); + $params = isset($config['params']) ? $config['params'] : []; + + $params['MultipartUpload'] = [ + 'Parts' => $this->getState()->getUploadedParts() + ]; + + return $params; + } + + protected function determinePartSize() + { + // Make sure the part size is set. + $partSize = $this->getConfig()['part_size'] ?: MultipartUploader::PART_MIN_SIZE; + + // Adjust the part size to be larger for known, x-large uploads. + if ($sourceSize = $this->getSourceSize()) { + $partSize = (int) max( + $partSize, + ceil($sourceSize / MultipartUploader::PART_MAX_NUM) + ); + } + + // Ensure that the part size follows the rules: 5 MB <= size <= 5 GB. + if ($partSize < MultipartUploader::PART_MIN_SIZE || $partSize > MultipartUploader::PART_MAX_SIZE) { + throw new \InvalidArgumentException('The part size must be no less ' + . 'than 5 MB and no greater than 5 GB.'); + } + + return $partSize; + } + + protected function getInitiateParams() + { + $config = $this->getConfig(); + $params = isset($config['params']) ? $config['params'] : []; + + if (isset($config['acl'])) { + $params['ACL'] = $config['acl']; + } + + // Set the ContentType if not already present + if (empty($params['ContentType']) && $type = $this->getSourceMimeType()) { + $params['ContentType'] = $type; + } + + return $params; + } + + /** + * @return UploadState + */ + abstract protected function getState(); + + /** + * @return array + */ + abstract protected function getConfig(); + + /** + * @return int + */ + abstract protected function getSourceSize(); + + /** + * @return string|null + */ + abstract protected function getSourceMimeType(); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectCopier.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectCopier.php new file mode 100644 index 000000000..66e4446d9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectCopier.php @@ -0,0 +1,170 @@ + null, + 'before_upload' => null, + 'concurrency' => 5, + 'mup_threshold' => self::DEFAULT_MULTIPART_THRESHOLD, + 'params' => [], + 'part_size' => null, + 'version_id' => null, + ]; + + /** + * @param S3ClientInterface $client The S3 Client used to execute + * the copy command(s). + * @param array $source The object to copy, specified as + * an array with a 'Bucket' and + * 'Key' keys. Provide a + * 'VersionID' key to copy a + * specified version of an object. + * @param array $destination The bucket and key to which to + * copy the $source, specified as + * an array with a 'Bucket' and + * 'Key' keys. + * @param string $acl ACL to apply to the copy + * (default: private). + * @param array $options Options used to configure the + * copy process. Options passed in + * through 'params' are added to + * the sub commands. + * + * @throws InvalidArgumentException + */ + public function __construct( + S3ClientInterface $client, + array $source, + array $destination, + $acl = 'private', + array $options = [] + ) { + $this->validateLocation($source); + $this->validateLocation($destination); + + $this->client = $client; + $this->source = $source; + $this->destination = $destination; + $this->acl = $acl; + $this->options = $options + self::$defaults; + } + + /** + * Perform the configured copy asynchronously. Returns a promise that is + * fulfilled with the result of the CompleteMultipartUpload or CopyObject + * operation or rejected with an exception. + * + * @return Coroutine + */ + public function promise(): PromiseInterface + { + return Coroutine::of(function () { + $headObjectCommand = $this->client->getCommand( + 'HeadObject', + $this->options['params'] + $this->source + ); + if (is_callable($this->options['before_lookup'])) { + $this->options['before_lookup']($headObjectCommand); + } + $objectStats = (yield $this->client->executeAsync( + $headObjectCommand + )); + + if ($objectStats['ContentLength'] > $this->options['mup_threshold']) { + $mup = new MultipartCopy( + $this->client, + $this->getSourcePath(), + ['source_metadata' => $objectStats, 'acl' => $this->acl] + + $this->destination + + $this->options + ); + + yield $mup->promise(); + } else { + $defaults = [ + 'ACL' => $this->acl, + 'MetadataDirective' => 'COPY', + 'CopySource' => $this->getSourcePath(), + ]; + + $params = array_diff_key($this->options, self::$defaults) + + $this->destination + $defaults + $this->options['params']; + + yield $this->client->executeAsync( + $this->client->getCommand('CopyObject', $params) + ); + } + }); + } + + /** + * Perform the configured copy synchronously. Returns the result of the + * CompleteMultipartUpload or CopyObject operation. + * + * @return Result + * + * @throws S3Exception + * @throws MultipartUploadException + */ + public function copy() + { + return $this->promise()->wait(); + } + + private function validateLocation(array $location) + { + if (empty($location['Bucket']) || empty($location['Key'])) { + throw new \InvalidArgumentException('Locations provided to an' + . ' Aws\S3\ObjectCopier must have a non-empty Bucket and Key'); + } + } + + private function getSourcePath() + { + $path = "/{$this->source['Bucket']}/"; + if (ArnParser::isArn($this->source['Bucket'])) { + try { + new AccessPointArn($this->source['Bucket']); + $path = "{$this->source['Bucket']}/object/"; + } catch (\Exception $e) { + throw new \InvalidArgumentException( + 'Provided ARN was a not a valid S3 access point ARN (' + . $e->getMessage() . ')', + 0, + $e + ); + } + } + + $sourcePath = $path . rawurlencode($this->source['Key']); + if (isset($this->source['VersionId'])) { + $sourcePath .= "?versionId={$this->source['VersionId']}"; + } + + return $sourcePath; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectUploader.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectUploader.php new file mode 100644 index 000000000..b73b7b123 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/ObjectUploader.php @@ -0,0 +1,150 @@ + null, + 'concurrency' => 3, + 'mup_threshold' => self::DEFAULT_MULTIPART_THRESHOLD, + 'params' => [], + 'part_size' => null, + ]; + private $addContentMD5; + + /** + * @param S3ClientInterface $client The S3 Client used to execute + * the upload command(s). + * @param string $bucket Bucket to upload the object, or + * an S3 access point ARN. + * @param string $key Key of the object. + * @param mixed $body Object data to upload. Can be a + * StreamInterface, PHP stream + * resource, or a string of data to + * upload. + * @param string $acl ACL to apply to the copy + * (default: private). + * @param array $options Options used to configure the + * copy process. Options passed in + * through 'params' are added to + * the sub command(s). + */ + public function __construct( + S3ClientInterface $client, + $bucket, + $key, + $body, + $acl = 'private', + array $options = [] + ) { + $this->client = $client; + $this->bucket = $bucket; + $this->key = $key; + $this->body = Psr7\Utils::streamFor($body); + $this->acl = $acl; + $this->options = $options + self::$defaults; + // Handle "add_content_md5" option. + $this->addContentMD5 = isset($options['add_content_md5']) + && $options['add_content_md5'] === true; + } + + /** + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + /** @var int $mup_threshold */ + $mup_threshold = $this->options['mup_threshold']; + if ($this->requiresMultipart($this->body, $mup_threshold)) { + // Perform a multipart upload. + return (new MultipartUploader($this->client, $this->body, [ + 'bucket' => $this->bucket, + 'key' => $this->key, + 'acl' => $this->acl + ] + $this->options))->promise(); + } + + // Perform a regular PutObject operation. + $command = $this->client->getCommand('PutObject', [ + 'Bucket' => $this->bucket, + 'Key' => $this->key, + 'Body' => $this->body, + 'ACL' => $this->acl, + 'AddContentMD5' => $this->addContentMD5 + ] + $this->options['params']); + if (is_callable($this->options['before_upload'])) { + $this->options['before_upload']($command); + } + return $this->client->executeAsync($command); + } + + public function upload() + { + return $this->promise()->wait(); + } + + /** + * Determines if the body should be uploaded using PutObject or the + * Multipart Upload System. It also modifies the passed-in $body as needed + * to support the upload. + * + * @param StreamInterface $body Stream representing the body. + * @param integer $threshold Minimum bytes before using Multipart. + * + * @return bool + */ + private function requiresMultipart(StreamInterface &$body, $threshold) + { + // If body size known, compare to threshold to determine if Multipart. + if ($body->getSize() !== null) { + return $body->getSize() >= $threshold; + } + + /** + * Handle the situation where the body size is unknown. + * Read up to 5MB into a buffer to determine how to upload the body. + * @var StreamInterface $buffer + */ + $buffer = Psr7\Utils::streamFor(); + Psr7\Utils::copyToStream($body, $buffer, MultipartUploader::PART_MIN_SIZE); + + // If body < 5MB, use PutObject with the buffer. + if ($buffer->getSize() < MultipartUploader::PART_MIN_SIZE) { + $buffer->seek(0); + $body = $buffer; + return false; + } + + // If body >= 5 MB, then use multipart. [YES] + if ($body->isSeekable() && $body->getMetadata('uri') !== 'php://input') { + // If the body is seekable, just rewind the body. + $body->seek(0); + } else { + // If the body is non-seekable, stitch the rewind the buffer and + // the partially read body together into one stream. This avoids + // unnecessary disc usage and does not require seeking on the + // original stream. + $buffer->seek(0); + $body = new Psr7\AppendStream([$buffer, $body]); + } + + return true; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/GetBucketLocationResultMutator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/GetBucketLocationResultMutator.php new file mode 100644 index 000000000..2e8d1a1a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/GetBucketLocationResultMutator.php @@ -0,0 +1,42 @@ +getName() !== 'GetBucketLocation') { + return $result; + } + + $location = 'us-east-1'; + static $pattern = '/>(.+?)<\/LocationConstraint>/'; + if (preg_match($pattern, $response->getBody(), $matches)) { + $location = $matches[1] === 'EU' ? 'eu-west-1' : $matches[1]; + } + + $result['LocationConstraint'] = $location; + $response->getBody()->rewind(); + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3Parser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3Parser.php new file mode 100644 index 000000000..3f6f3541a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3Parser.php @@ -0,0 +1,275 @@ +protocolParser = $protocolParser; + $this->errorParser = $errorParser; + $this->exceptionClass = $exceptionClass; + $this->s3ResultMutators = []; + } + + /** + * Parses a S3 response. + * + * @param CommandInterface $command The command that originated the request. + * @param ResponseInterface $response The response received from the service. + * + * @return ResultInterface|null + */ + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ):? ResultInterface + { + // Check first if the response is an error + $this->parse200Error($command, $response); + + try { + $parseFn = $this->protocolParser; + $result = $parseFn($command, $response); + } catch (ParserException $e) { + // Parsing errors will be considered retryable. + throw new $this->exceptionClass( + "Error parsing response for {$command->getName()}:" + . " AWS parsing error: {$e->getMessage()}", + $command, + ['connection_error' => true, 'exception' => $e], + $e + ); + } + + return $this->executeS3ResultMutators($result, $command, $response); + } + + /** + * Tries to parse a 200 response as an error from S3. + * If the parsed result contains a code and message then that means an error + * was found, and hence an exception is thrown with that error. + * + * @param CommandInterface $command + * @param ResponseInterface $response + * + * @return void + */ + private function parse200Error( + CommandInterface $command, + ResponseInterface $response + ): void + { + // This error parsing should be just for 200 error responses + // and operations where its output shape does not have a streaming + // member and the body of the response is seekable. + if (200 !== $response->getStatusCode() + || !$this->shouldBeConsidered200Error($command->getName()) + || !$response->getBody()->isSeekable()) { + return; + } + + // To guarantee we try the error parsing just for an Error xml response. + if (!$this->isFirstRootElementError($response->getBody())) { + return; + } + + try { + $errorParserFn = $this->errorParser; + $parsedError = $errorParserFn($response, $command); + } catch (ParserException $e) { + // Parsing errors will be considered retryable. + $parsedError = [ + 'code' => 'ConnectionError', + 'message' => "An error connecting to the service occurred" + . " while performing the " . $command->getName() + . " operation." + ]; + } + + if (isset($parsedError['code']) && isset($parsedError['message'])) { + throw new $this->exceptionClass( + $parsedError['message'], + $command, + [ + 'connection_error' => true, + 'code' => $parsedError['code'], + 'message' => $parsedError['message'] + ] + ); + } + } + + /** + * Checks if a specific operation should be considered + * a s3 200 error. Operations where any of its output members + * has a streaming or httpPayload trait should be not considered. + * + * @param $commandName + * + * @return bool + */ + private function shouldBeConsidered200Error($commandName): bool + { + $operation = $this->api->getOperation($commandName); + $output = $operation->getOutput(); + foreach ($output->getMembers() as $_ => $memberProps) { + if (!empty($memberProps['eventstream']) || !empty($memberProps['streaming'])) { + return false; + } + } + + return true; + } + + /** + * Checks if the root element of the response body is "Error", which is + * when we should try to parse an error from a 200 response from s3. + * It is recommended to make sure the stream given is seekable, otherwise + * the rewind call will cause a user warning. + * + * @param StreamInterface $responseBody + * + * @return bool + */ + private function isFirstRootElementError(StreamInterface $responseBody): bool + { + static $pattern = '/<\?xml version="1\.0" encoding="UTF-8"\?>\s*/'; + // To avoid performance overhead in large streams + $reducedBodyContent = $responseBody->read(64); + $foundErrorElement = preg_match($pattern, $reducedBodyContent); + // A rewind is needed because the stream is partially or entirely consumed + // in the previous read operation. + $responseBody->rewind(); + + return $foundErrorElement; + } + + /** + * Execute mutator implementations over a result. + * Mutators are logics that modifies a result. + * + * @param ResultInterface $result + * @param CommandInterface $command + * @param ResponseInterface $response + * + * @return ResultInterface + */ + private function executeS3ResultMutators( + ResultInterface $result, + CommandInterface $command, + ResponseInterface $response + ): ResultInterface + { + foreach ($this->s3ResultMutators as $mutator) { + $result = $mutator($result, $command, $response); + } + + return $result; + } + + /** + * Adds a mutator into the list of mutators. + * + * @param string $mutatorName + * @param S3ResultMutator $s3ResultMutator + * @return void + */ + public function addS3ResultMutator( + string $mutatorName, + S3ResultMutator $s3ResultMutator + ): void + { + if (isset($this->s3ResultMutators[$mutatorName])) { + trigger_error( + "The S3 Result Mutator {$mutatorName} already exists!", + E_USER_WARNING + ); + + return; + } + + $this->s3ResultMutators[$mutatorName] = $s3ResultMutator; + } + + /** + * Removes a mutator from the mutator list. + * + * @param string $mutatorName + * @return void + */ + public function removeS3ResultMutator(string $mutatorName): void + { + if (!isset($this->s3ResultMutators[$mutatorName])) { + trigger_error( + "The S3 Result Mutator {$mutatorName} does not exist!", + E_USER_WARNING + ); + + return; + } + + unset($this->s3ResultMutators[$mutatorName]); + } + + /** + * Returns the list of result mutators available. + * + * @return array + */ + public function getS3ResultMutators(): array + { + return $this->s3ResultMutators; + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) + { + return $this->protocolParser->parseMemberFromStream( + $stream, + $member, + $response + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3ResultMutator.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3ResultMutator.php new file mode 100644 index 000000000..5119501fe --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Parser/S3ResultMutator.php @@ -0,0 +1,36 @@ +api = $api; + $this->config = $config; + } + + /** + * @param ResultInterface $result + * @param CommandInterface|null $command + * @param ResponseInterface|null $response + * + * @return ResultInterface + */ + public function __invoke( + ResultInterface $result, + ?CommandInterface $command = null, + ?ResponseInterface $response = null + ): ResultInterface + { + $operation = $this->api->getOperation($command->getName()); + + // Skip this middleware if the operation doesn't have an httpChecksum + $checksumInfo = $operation['httpChecksum'] ?? null; + if (is_null($checksumInfo)) { + return $result; + } + + $mode = $this->config['response_checksum_validation'] ?? self::DEFAULT_VALIDATION_MODE; + $checksumModeEnabledMember = $checksumInfo['requestValidationModeMember'] ?? ""; + $checksumModeEnabled = strtolower($command[$checksumModeEnabledMember] ?? ""); + $responseAlgorithms = $checksumInfo['responseAlgorithms'] ?? []; + $shouldSkipValidation = $this->shouldSkipValidation( + $mode, + $checksumModeEnabled, + $responseAlgorithms + ); + + if ($shouldSkipValidation) { + return $result; + } + + $checksumPriority = $this->getChecksumPriority(); + $checksumsToCheck = array_intersect($responseAlgorithms, array_map( + 'strtoupper', + array_keys($checksumPriority)) + ); + $checksumValidationInfo = $this->validateChecksum($checksumsToCheck, $response); + + if ($checksumValidationInfo['status'] === "SUCCEEDED") { + $result['ChecksumValidated'] = $checksumValidationInfo['checksum']; + } elseif ($checksumValidationInfo['status'] === "FAILED") { + if ($this->isMultipartGetObject($command, $checksumValidationInfo)) { + return $result; + } + throw new S3Exception( + "Calculated response checksum did not match the expected value", + $command + ); + } + + return $result; + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + * + * @return array + */ + private function validateChecksum( + $checksumPriority, + ResponseInterface $response + ): array + { + $checksumToValidate = $this->chooseChecksumHeaderToValidate( + $checksumPriority, + $response + ); + $validationStatus = "SKIPPED"; + $checksumHeaderValue = null; + if (!empty($checksumToValidate)) { + $checksumHeaderValue = $response->getHeaderLine( + 'x-amz-checksum-' . $checksumToValidate + ); + if (!empty($checksumHeaderValue)) { + $calculatedChecksumValue = $this->getEncodedValue( + $checksumToValidate, + $response->getBody() + ); + $validationStatus = $checksumHeaderValue == $calculatedChecksumValue + ? "SUCCEEDED" + : "FAILED"; + } + } + return [ + "status" => $validationStatus, + "checksum" => $checksumToValidate, + "checksumHeaderValue" => $checksumHeaderValue, + ]; + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + * + * @return string + */ + private function chooseChecksumHeaderToValidate( + $checksumPriority, + ResponseInterface $response + ):? string + { + foreach ($checksumPriority as $checksum) { + $checksumHeader = 'x-amz-checksum-' . $checksum; + if ($response->hasHeader($checksumHeader)) { + return $checksum; + } + } + + return null; + } + + /** + * @param string $mode + * @param string $checksumModeEnabled + * @param array $responseAlgorithms + * + * @return bool + */ + private function shouldSkipValidation( + string $mode, + string $checksumModeEnabled, + array $responseAlgorithms + ): bool + { + return empty($responseAlgorithms) + || ($mode === 'when_required' && $checksumModeEnabled !== 'enabled'); + } + + /** + * @return string[] + */ + private function getChecksumPriority(): array + { + return extension_loaded('awscrt') + ? self::$supportedAlgorithms + : array_slice(self::$supportedAlgorithms, 1); + } + + /** + * @param CommandInterface $command + * @param array $checksumValidationInfo + * + * @return bool + */ + private function isMultipartGetObject( + CommandInterface $command, + array $checksumValidationInfo + ): bool + { + if ($command->getName() !== "GetObject" + || empty($checksumValidationInfo['checksumHeaderValue']) + ) { + return false; + } + + $headerValue = $checksumValidationInfo['checksumHeaderValue']; + $lastDashPos = strrpos($headerValue, '-'); + $endOfChecksum = substr($headerValue, $lastDashPos + 1); + + return is_numeric($endOfChecksum) + && (int) $endOfChecksum > 1 + && (int) $endOfChecksum < 10000; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PermanentRedirectMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PermanentRedirectMiddleware.php new file mode 100644 index 000000000..36a0e683e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PermanentRedirectMiddleware.php @@ -0,0 +1,62 @@ +nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, ?RequestInterface $request = null) + { + $next = $this->nextHandler; + return $next($command, $request)->then( + function (ResultInterface $result) use ($command) { + $status = isset($result['@metadata']['statusCode']) + ? $result['@metadata']['statusCode'] + : null; + if ($status == 301) { + throw new PermanentRedirectException( + 'Encountered a permanent redirect while requesting ' + . $result->search('"@metadata".effectiveUri') . '. ' + . 'Are you sure you are using the correct region for ' + . 'this bucket?', + $command, + ['result' => $result] + ); + } + return $result; + } + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObject.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObject.php new file mode 100644 index 000000000..48913ea1e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObject.php @@ -0,0 +1,160 @@ +client = $client; + $this->bucket = $bucket; + + if (is_array($jsonPolicy)) { + $jsonPolicy = json_encode($jsonPolicy); + } + + $this->jsonPolicy = $jsonPolicy; + $this->formAttributes = [ + 'action' => $this->generateUri(), + 'method' => 'POST', + 'enctype' => 'multipart/form-data' + ]; + + $this->formInputs = $formInputs + ['key' => '${filename}']; + $credentials = $client->getCredentials()->wait(); + $this->formInputs += $this->getPolicyAndSignature($credentials); + } + + /** + * Gets the S3 client. + * + * @return S3ClientInterface + */ + public function getClient() + { + return $this->client; + } + + /** + * Gets the bucket name. + * + * @return string + */ + public function getBucket() + { + return $this->bucket; + } + + /** + * Gets the form attributes as an array. + * + * @return array + */ + public function getFormAttributes() + { + return $this->formAttributes; + } + + /** + * Set a form attribute. + * + * @param string $attribute Form attribute to set. + * @param string $value Value to set. + */ + public function setFormAttribute($attribute, $value) + { + $this->formAttributes[$attribute] = $value; + } + + /** + * Gets the form inputs as an array. + * + * @return array + */ + public function getFormInputs() + { + return $this->formInputs; + } + + /** + * Set a form input. + * + * @param string $field Field name to set + * @param string $value Value to set. + */ + public function setFormInput($field, $value) + { + $this->formInputs[$field] = $value; + } + + /** + * Gets the raw JSON policy. + * + * @return string + */ + public function getJsonPolicy() + { + return $this->jsonPolicy; + } + + private function generateUri() + { + $uri = new Uri($this->client->getEndpoint()); + + if ($this->client->getConfig('use_path_style_endpoint') === true + || ($uri->getScheme() === 'https' + && strpos($this->bucket, '.') !== false) + ) { + // Use path-style URLs + $uri = $uri->withPath("/{$this->bucket}"); + } else { + // Use virtual-style URLs + $uri = $uri->withHost($this->bucket . '.' . $uri->getHost()); + } + + return (string) $uri; + } + + protected function getPolicyAndSignature(CredentialsInterface $creds) + { + $jsonPolicy64 = base64_encode($this->jsonPolicy); + + return [ + 'AWSAccessKeyId' => $creds->getAccessKeyId(), + 'policy' => $jsonPolicy64, + 'signature' => base64_encode(hash_hmac( + 'sha1', + $jsonPolicy64, + $creds->getSecretKey(), + true + )) + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObjectV4.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObjectV4.php new file mode 100644 index 000000000..19763722f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PostObjectV4.php @@ -0,0 +1,195 @@ +client = $client; + $this->bucket = $bucket; + + // setup form attributes + $this->formAttributes = [ + 'action' => $this->generateUri(), + 'method' => 'POST', + 'enctype' => 'multipart/form-data' + ]; + + $credentials = $this->client->getCredentials()->wait(); + + if ($securityToken = $credentials->getSecurityToken()) { + $options [] = ['x-amz-security-token' => $securityToken]; + $formInputs['X-Amz-Security-Token'] = $securityToken; + } + + // setup basic policy + $policy = [ + 'expiration' => TimestampShape::format($expiration, 'iso8601'), + 'conditions' => $options, + ]; + + // setup basic formInputs + $this->formInputs = $formInputs + ['key' => '${filename}']; + + // finalize policy and signature + + $this->formInputs += $this->getPolicyAndSignature( + $credentials, + $policy + ); + } + + /** + * Gets the S3 client. + * + * @return S3ClientInterface + */ + public function getClient() + { + return $this->client; + } + + /** + * Gets the bucket name. + * + * @return string + */ + public function getBucket() + { + return $this->bucket; + } + + /** + * Gets the form attributes as an array. + * + * @return array + */ + public function getFormAttributes() + { + return $this->formAttributes; + } + + /** + * Set a form attribute. + * + * @param string $attribute Form attribute to set. + * @param string $value Value to set. + */ + public function setFormAttribute($attribute, $value) + { + $this->formAttributes[$attribute] = $value; + } + + /** + * Gets the form inputs as an array. + * + * @return array + */ + public function getFormInputs() + { + return $this->formInputs; + } + + /** + * Set a form input. + * + * @param string $field Field name to set + * @param string $value Value to set. + */ + public function setFormInput($field, $value) + { + $this->formInputs[$field] = $value; + } + + private function generateUri() + { + $uri = new Uri($this->client->getEndpoint()); + + if ($this->client->getConfig('use_path_style_endpoint') === true + || ($uri->getScheme() === 'https' + && strpos($this->bucket, '.') !== false) + ) { + // Use path-style URLs + $uri = $uri->withPath("/{$this->bucket}"); + } else { + // Use virtual-style URLs if haven't been set up already + if (strpos($uri->getHost(), $this->bucket . '.') !== 0) { + $uri = $uri->withHost($this->bucket . '.' . $uri->getHost()); + } + } + + return (string) $uri; + } + + protected function getPolicyAndSignature( + CredentialsInterface $credentials, + array $policy + ){ + $ldt = gmdate(SignatureV4::ISO8601_BASIC); + $sdt = substr($ldt, 0, 8); + $policy['conditions'][] = ['X-Amz-Date' => $ldt]; + + $region = $this->client->getRegion(); + $scope = $this->createScope($sdt, $region, 's3'); + $creds = "{$credentials->getAccessKeyId()}/$scope"; + $policy['conditions'][] = ['X-Amz-Credential' => $creds]; + + $policy['conditions'][] = ['X-Amz-Algorithm' => "AWS4-HMAC-SHA256"]; + + $jsonPolicy64 = base64_encode(json_encode($policy)); + $key = $this->getSigningKey( + $sdt, + $region, + 's3', + $credentials->getSecretKey() + ); + + return [ + 'X-Amz-Credential' => $creds, + 'X-Amz-Algorithm' => "AWS4-HMAC-SHA256", + 'X-Amz-Date' => $ldt, + 'Policy' => $jsonPolicy64, + 'X-Amz-Signature' => bin2hex( + hash_hmac('sha256', $jsonPolicy64, $key, true) + ), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PutObjectUrlMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PutObjectUrlMiddleware.php new file mode 100644 index 000000000..9b80406ec --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/PutObjectUrlMiddleware.php @@ -0,0 +1,59 @@ +nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, ?RequestInterface $request = null) + { + $next = $this->nextHandler; + return $next($command, $request)->then( + function (ResultInterface $result) use ($command) { + $name = $command->getName(); + switch ($name) { + case 'PutObject': + case 'CopyObject': + $result['ObjectURL'] = isset($result['@metadata']['effectiveUri']) + ? $result['@metadata']['effectiveUri'] + : null; + break; + case 'CompleteMultipartUpload': + $result['ObjectURL'] = urldecode($result['Location'] ?? ''); + break; + } + return $result; + } + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Configuration.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Configuration.php new file mode 100644 index 000000000..48dc63d78 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Configuration.php @@ -0,0 +1,42 @@ +endpointsType = strtolower($endpointsType); + $this->isFallback = $isFallback; + if (!in_array($this->endpointsType, ['legacy', 'regional'])) { + throw new \InvalidArgumentException( + "Configuration parameter must either be 'legacy' or 'regional'." + ); + } + } + + /** + * {@inheritdoc} + */ + public function getEndpointsType() + { + return $this->endpointsType; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'endpoints_type' => $this->getEndpointsType() + ]; + } + + public function isFallback() + { + return $this->isFallback; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/ConfigurationInterface.php new file mode 100644 index 000000000..10fbf9418 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/ConfigurationInterface.php @@ -0,0 +1,22 @@ + + * use Aws\S3\RegionalEndpoint\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see \Aws\S3\RegionalEndpoint\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const ENV_ENDPOINTS_TYPE = 'AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'; + const INI_ENDPOINTS_TYPE = 's3_us_east_1_regional_endpoint'; + const DEFAULT_ENDPOINTS_TYPE = 'legacy'; + + public static $cacheKey = 'aws_s3_us_east_1_regional_endpoint_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['s3_us_east_1_regional_endpoint']) + && $config['s3_us_east_1_regional_endpoint'] instanceof CacheInterface + ) { + return self::cache($memo, $config['s3_us_east_1_regional_endpoint'], self::$cacheKey); + } + + return $memo; + } + + public static function env() + { + return function () { + // Use config from environment variables, if available + $endpointsType = getenv(self::ENV_ENDPOINTS_TYPE); + if (!empty($endpointsType)) { + return Promise\Create::promiseFor( + new Configuration($endpointsType) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_ENDPOINTS_TYPE); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini( + $profile = null, + $filename = null + ) { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_ENDPOINTS_TYPE])) { + return self::reject("Required S3 regional endpoint config values + not present in INI profile '{$profile}' ({$filename})"); + } + + return Promise\Create::promiseFor( + new Configuration($data[$profile][self::INI_ENDPOINTS_TYPE]) + ); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function () { + return Promise\Create::promiseFor( + new Configuration(self::DEFAULT_ENDPOINTS_TYPE, true) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof Promise\PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } + if (is_string($config)) { + return new Configuration($config); + } + if (is_array($config) && isset($config['endpoints_type'])) { + return new Configuration($config['endpoints_type']); + } + + throw new \InvalidArgumentException('Not a valid S3 regional endpoint ' + . 'configuration argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Exception/ConfigurationException.php new file mode 100644 index 000000000..29e211f55 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/RegionalEndpoint/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +parser = $parser; + $this->exceptionClass = $exceptionClass; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $fn = $this->parser; + + try { + return $fn($command, $response); + } catch (ParserException $e) { + throw new $this->exceptionClass( + "Error parsing response for {$command->getName()}:" + . " AWS parsing error: {$e->getMessage()}", + $command, + ['connection_error' => true, 'exception' => $e], + $e + ); + } + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3Client.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3Client.php new file mode 100644 index 000000000..87315ecb9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3Client.php @@ -0,0 +1,1319 @@ + true, + 'when_required' => true + ]; + + public static function getArguments() + { + $args = parent::getArguments(); + $args['retries']['fn'] = [__CLASS__, '_applyRetryConfig']; + $args['api_provider']['fn'] = [__CLASS__, '_applyApiProvider']; + + return + [ + 'request_checksum_calculation' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.' + . ' `when_supported` results in checksum calculation when an operation has modeled checksum support.' + . ' `when_required` results in checksum calculation when an operation has modeled checksum support and' + . ' request checksums are modeled as required.', + 'fn' => [__CLASS__, '_apply_request_checksum_calculation'], + 'default' => [__CLASS__, '_default_request_checksum_calculation'], + ], + 'response_checksum_validation' => [ + 'type' => 'config', + 'valid' => ['string'], + 'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.' + . ' `when_supported` results in checksum validation when an operation has modeled checksum support.' + . ' `when_required` results in checksum validation when an operation has modeled checksum support and' + . ' `CheckSumMode` is set to `enabled`.', + 'fn' => [__CLASS__, '_apply_response_checksum_validation'], + 'default' => [__CLASS__, '_default_response_checksum_validation'], + ] + ] + + $args + [ + 'bucket_endpoint' => [ + 'type' => 'config', + 'valid' => ['bool'], + 'doc' => 'Set to true to send requests to a hardcoded ' + . 'bucket endpoint rather than create an endpoint as a ' + . 'result of injecting the bucket into the URL. This ' + . 'option is useful for interacting with CNAME endpoints.', + ], + 'use_arn_region' => [ + 'type' => 'config', + 'valid' => [ + 'bool', + Configuration::class, + CacheInterface::class, + 'callable' + ], + 'doc' => 'Set to true to allow passed in ARNs to override' + . ' client region. Accepts...', + 'fn' => [__CLASS__, '_apply_use_arn_region'], + 'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider'], + ], + 'use_accelerate_endpoint' => [ + 'type' => 'config', + 'valid' => ['bool'], + 'doc' => 'Set to true to send requests to an S3 Accelerate' + . ' endpoint by default. Can be enabled or disabled on' + . ' individual operations by setting' + . ' \'@use_accelerate_endpoint\' to true or false. Note:' + . ' you must enable S3 Accelerate on a bucket before it can' + . ' be accessed via an Accelerate endpoint.', + 'default' => false, + ], + 'use_path_style_endpoint' => [ + 'type' => 'config', + 'valid' => ['bool'], + 'doc' => 'Set to true to send requests to an S3 path style' + . ' endpoint by default.' + . ' Can be enabled or disabled on individual operations by setting' + . ' \'@use_path_style_endpoint\' to true or false.', + 'default' => false, + ], + 'disable_multiregion_access_points' => [ + 'type' => 'config', + 'valid' => ['bool'], + 'doc' => 'Set to true to disable the usage of' + . ' multi region access points. These are enabled by default.' + . ' Can be enabled or disabled on individual operations by setting' + . ' \'@disable_multiregion_access_points\' to true or false.', + 'default' => false, + ], + 'disable_express_session_auth' => [ + 'type' => 'config', + 'valid' => ['bool'], + 'doc' => 'Set to true to disable the usage of' + . ' s3 express session authentication. This is enabled by default.', + 'default' => [__CLASS__, '_default_disable_express_session_auth'], + ], + 's3_express_identity_provider' => [ + 'type' => 'config', + 'valid' => [ + 'bool', + 'callable' + ], + 'doc' => 'Specifies the provider used to generate identities to sign s3 express requests. ' + . 'Set to `false` to disable s3 express auth, or a callable provider used to create s3 express ' + . 'identities or return null.', + 'default' => [__CLASS__, '_default_s3_express_identity_provider'], + ], + ]; + } + + /** + * {@inheritdoc} + * + * In addition to the options available to + * {@see Aws\AwsClient::__construct}, S3Client accepts the following + * options: + * + * - bucket_endpoint: (bool) Set to true to send requests to a + * hardcoded bucket endpoint rather than create an endpoint as a result + * of injecting the bucket into the URL. This option is useful for + * interacting with CNAME endpoints. Note: if you are using version 2.243.0 + * and above and do not expect the bucket name to appear in the host, you will + * also need to set `use_path_style_endpoint` to `true`. + * - calculate_md5: (bool) Set to false to disable calculating an MD5 + * for all Amazon S3 signed uploads. + * - s3_us_east_1_regional_endpoint: + * (Aws\S3\RegionalEndpoint\ConfigurationInterface|Aws\CacheInterface\|callable|string|array) + * Specifies whether to use regional or legacy endpoints for the us-east-1 + * region. Provide an Aws\S3\RegionalEndpoint\ConfigurationInterface object, an + * instance of Aws\CacheInterface, a callable configuration provider used + * to create endpoint configuration, a string value of `legacy` or + * `regional`, or an associative array with the following keys: + * endpoint_types: (string) Set to `legacy` or `regional`, defaults to + * `legacy` + * - use_accelerate_endpoint: (bool) Set to true to send requests to an S3 + * Accelerate endpoint by default. Can be enabled or disabled on + * individual operations by setting '@use_accelerate_endpoint' to true or + * false. Note: you must enable S3 Accelerate on a bucket before it can be + * accessed via an Accelerate endpoint. + * - use_arn_region: (Aws\S3\UseArnRegion\ConfigurationInterface, + * Aws\CacheInterface, bool, callable) Set to true to enable the client + * to use the region from a supplied ARN argument instead of the client's + * region. Provide an instance of Aws\S3\UseArnRegion\ConfigurationInterface, + * an instance of Aws\CacheInterface, a callable that provides a promise for + * a Configuration object, or a boolean value. Defaults to false (i.e. + * the SDK will not follow the ARN region if it conflicts with the client + * region and instead throw an error). + * - use_dual_stack_endpoint: (bool) Set to true to send requests to an S3 + * Dual Stack endpoint by default, which enables IPv6 Protocol. + * Can be enabled or disabled on individual operations by setting + * '@use_dual_stack_endpoint\' to true or false. Note: + * you cannot use it together with an accelerate endpoint. + * - use_path_style_endpoint: (bool) Set to true to send requests to an S3 + * path style endpoint by default. + * Can be enabled or disabled on individual operations by setting + * '@use_path_style_endpoint\' to true or false. Note: + * you cannot use it together with an accelerate endpoint. + * - disable_multiregion_access_points: (bool) Set to true to disable + * sending multi region requests. They are enabled by default. + * Can be enabled or disabled on individual operations by setting + * '@disable_multiregion_access_points\' to true or false. Note: + * you cannot use it together with an accelerate or dualstack endpoint. + * + * @param array $args + */ + public function __construct(array $args) + { + if ( + !isset($args['s3_us_east_1_regional_endpoint']) + || $args['s3_us_east_1_regional_endpoint'] instanceof CacheInterface + ) { + $args['s3_us_east_1_regional_endpoint'] = ConfigurationProvider::defaultProvider($args); + } + $this->addBuiltIns($args); + parent::__construct($args); + $stack = $this->getHandlerList(); + $config = $this->getConfig(); + $stack->appendInit(SSECMiddleware::wrap($this->getEndpoint()->getScheme()), 's3.ssec'); + $stack->appendBuild( + ApplyChecksumMiddleware::wrap($this->getApi(), $this->getConfig()), + 's3.checksum' + ); + $stack->appendBuild( + Middleware::contentType(['PutObject', 'UploadPart']), + 's3.content_type' + ); + + if ($this->getConfig('bucket_endpoint')) { + $stack->appendBuild(BucketEndpointMiddleware::wrap( + $this->isUseEndpointV2(), $args['endpoint'] ?? null), 's3.bucket_endpoint' + ); + } elseif (!$this->isUseEndpointV2()) { + $stack->appendBuild( + S3EndpointMiddleware::wrap( + $this->getRegion(), + $this->getConfig('endpoint_provider'), + [ + 'accelerate' => $this->getConfig('use_accelerate_endpoint'), + 'path_style' => $this->getConfig('use_path_style_endpoint'), + 'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'), + 'dual_stack' => + $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(), + + ] + ), + 's3.endpoint_middleware' + ); + } + + $stack->appendBuild( + BucketEndpointArnMiddleware::wrap( + $this->getApi(), + $this->getRegion(), + [ + 'use_arn_region' => $this->getConfig('use_arn_region'), + 'accelerate' => $this->getConfig('use_accelerate_endpoint'), + 'path_style' => $this->getConfig('use_path_style_endpoint'), + 'dual_stack' => + $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(), + 'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'), + 'disable_multiregion_access_points' => + $this->getConfig('disable_multiregion_access_points'), + 'endpoint' => $args['endpoint'] ?? null + ], + $this->isUseEndpointV2() + ), + 's3.bucket_endpoint_arn' + ); + if ($this->getConfig('disable_express_session_auth')) { + $stack->prependSign( + $this->getDisableExpressSessionAuthMiddleware(), + 's3.disable_express_session_auth' + ); + } + + $stack->appendValidate( + InputValidationMiddleware::wrap($this->getApi(), self::$mandatoryAttributes), + 'input_validation_middleware' + ); + $stack->appendSign(ExpiresParsingMiddleware::wrap(), 's3.expires_parsing'); + $stack->appendSign(PutObjectUrlMiddleware::wrap(), 's3.put_object_url'); + $stack->appendSign(PermanentRedirectMiddleware::wrap(), 's3.permanent_redirect'); + $stack->appendInit(Middleware::sourceFile($this->getApi()), 's3.source_file'); + $stack->appendInit($this->getSaveAsParameter(), 's3.save_as'); + $stack->appendInit($this->getLocationConstraintMiddleware(), 's3.location'); + $stack->appendInit($this->getEncodingTypeMiddleware(), 's3.auto_encode'); + $stack->appendInit($this->getHeadObjectMiddleware(), 's3.head_object'); + $this->processModel($this->isUseEndpointV2()); + if ($this->isUseEndpointV2()) { + $stack->after('builder', + 's3.check_empty_path_with_query', + $this->getEmptyPathWithQuery()); + } + } + + /** + * Determine if a string is a valid name for a DNS compatible Amazon S3 + * bucket. + * + * DNS compatible bucket names can be used as a subdomain in a URL (e.g., + * ".s3.amazonaws.com"). + * + * @param string $bucket Bucket name to check. + * + * @return bool + */ + public static function isBucketDnsCompatible($bucket) + { + if (!is_string($bucket)) { + return false; + } + $bucketLen = strlen($bucket); + + return ($bucketLen >= 3 && $bucketLen <= 63) && + // Cannot look like an IP address + !filter_var($bucket, FILTER_VALIDATE_IP) && + preg_match('/^[a-z0-9]([a-z0-9\-\.]*[a-z0-9])?$/', $bucket); + } + + public static function _apply_use_arn_region($value, array &$args, HandlerList $list) + { + if ($value instanceof CacheInterface) { + $value = UseArnRegionConfigurationProvider::defaultProvider($args); + } + if (is_callable($value)) { + $value = $value(); + } + if ($value instanceof PromiseInterface) { + $value = $value->wait(); + } + if ($value instanceof ConfigurationInterface) { + $args['use_arn_region'] = $value; + } else { + // The Configuration class itself will validate other inputs + $args['use_arn_region'] = new Configuration($value); + } + } + + public static function _default_request_checksum_calculation(array $args): string + { + return ConfigurationResolver::resolve( + 'request_checksum_calculation', + ApplyChecksumMiddleware::DEFAULT_CALCULATION_MODE, + 'string', + $args + ); + } + + public static function _apply_request_checksum_calculation( + string $value, + array &$args + ): void + { + $value = strtolower($value); + if (array_key_exists($value, self::$checksumOptionEnum)) { + $args['request_checksum_calculation'] = $value; + } else { + $validValues = implode(' | ', array_keys(self::$checksumOptionEnum)); + throw new \InvalidArgumentException( + 'invalid value provided for `request_checksum_calculation`.' + . ' valid values are: ' . $validValues . '.' + ); + } + } + + public static function _default_response_checksum_validation(array $args): string + { + return ConfigurationResolver::resolve( + 'response_checksum_validation', + ValidateResponseChecksumResultMutator::DEFAULT_VALIDATION_MODE, + 'string', + $args + ); + } + + public static function _apply_response_checksum_validation( + $value, + array &$args + ): void + { + $value = strtolower($value); + if (array_key_exists($value, self::$checksumOptionEnum)) { + $args['response_checksum_validation'] = $value; + } else { + $validValues = implode(' | ', array_keys(self::$checksumOptionEnum)); + throw new \InvalidArgumentException( + 'invalid value provided for `response_checksum_validation`.' + . ' valid values are: ' . $validValues . '.' + ); + } + } + + public static function _default_disable_express_session_auth(array &$args) + { + return ConfigurationResolver::resolve( + 's3_disable_express_session_auth', + false, + 'bool', + $args + ); + } + + public static function _default_s3_express_identity_provider(array $args) + { + if ($args['config']['disable_express_session_auth']) { + return false; + } + return new S3ExpressIdentityProvider($args['region']); + } + + public function createPresignedRequest(CommandInterface $command, $expires, array $options = []) + { + $command = clone $command; + $list = $command->getHandlerList(); + $list->remove('signer'); + + //Removes checksum calculation behavior by default + if (empty($command['ChecksumAlgorithm']) + && empty($command['AddContentMD5']) + ) { + $list->remove('s3.checksum'); + } + + $request = \Aws\serialize($command); + + //Applies ContentSHA256 parameter, if provided and not applied + // by middleware + $commandName = $command->getName(); + if (!empty($command['ContentSHA256'] + && isset(ApplyChecksumMiddleware::$sha256[$commandName]) + && !$request->hasHeader('X-Amz-Content-Sha256') + )) { + $request = $request->withHeader( + 'X-Amz-Content-Sha256', + $command['ContentSHA256'] + ); + } + + $signing_name = $command['@context']['signing_service'] + ?? $this->getSigningName($request->getUri()->getHost()); + $signature_version = $this->getSignatureVersionFromCommand($command); + + /** @var \Aws\Signature\SignatureInterface $signer */ + $signer = call_user_func( + $this->getSignatureProvider(), + $signature_version, + $signing_name, + $this->getConfig('signing_region') + ); + if ($signature_version == 'v4-s3express') { + $provider = $this->getConfig('s3_express_identity_provider'); + $credentials = $provider($command)->wait(); + } else { + $credentials = $this->getCredentials()->wait(); + } + return $signer->presign( + $request, + $credentials, + $expires, + $options + ); + } + + /** + * Returns the URL to an object identified by its bucket and key. + * + * The URL returned by this method is not signed nor does it ensure that the + * bucket and key given to the method exist. If you need a signed URL, then + * use the {@see \Aws\S3\S3Client::createPresignedRequest} method and get + * the URI of the signed request. + * + * @param string $bucket The name of the bucket where the object is located + * @param string $key The key of the object + * + * @return string The URL to the object + */ + public function getObjectUrl($bucket, $key) + { + $command = $this->getCommand('GetObject', [ + 'Bucket' => $bucket, + 'Key' => $key + ]); + + return (string) \Aws\serialize($command)->getUri(); + } + + /** + * Raw URL encode a key and allow for '/' characters + * + * @param string $key Key to encode + * + * @return string Returns the encoded key + */ + public static function encodeKey($key) + { + return str_replace('%2F', '/', rawurlencode($key)); + } + + /** + * Provides a middleware that removes the need to specify LocationConstraint on CreateBucket. + * + * @return \Closure + */ + private function getLocationConstraintMiddleware() + { + $region = $this->getRegion(); + return static function (callable $handler) use ($region) { + return function (Command $command, $request = null) use ($handler, $region) { + if ($command->getName() === 'CreateBucket' + && !self::isDirectoryBucket($command['Bucket']) + ) { + $locationConstraint = $command['CreateBucketConfiguration']['LocationConstraint'] + ?? null; + + if ($locationConstraint === 'us-east-1') { + unset($command['CreateBucketConfiguration']); + } elseif ('us-east-1' !== $region && empty($locationConstraint)) { + if (isset($command['CreateBucketConfiguration'])) { + $command['CreateBucketConfiguration']['LocationConstraint'] = $region; + } else { + $command['CreateBucketConfiguration'] = ['LocationConstraint' => $region]; + } + } + } + + return $handler($command, $request); + }; + }; + } + + /** + * Provides a middleware that supports the `SaveAs` parameter. + * + * @return \Closure + */ + private function getSaveAsParameter() + { + return static function (callable $handler) { + return function (Command $command, $request = null) use ($handler) { + if ($command->getName() === 'GetObject' && isset($command['SaveAs'])) { + $command['@http']['sink'] = $command['SaveAs']; + unset($command['SaveAs']); + } + + return $handler($command, $request); + }; + }; + } + + /** + * Provides a middleware that disables content decoding on HeadObject + * commands. + * + * @return \Closure + */ + private function getHeadObjectMiddleware() + { + return static function (callable $handler) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler) { + if ($command->getName() === 'HeadObject' + && !isset($command['@http']['decode_content']) + ) { + $command['@http']['decode_content'] = false; + } + + return $handler($command, $request); + }; + }; + } + + /** + * Provides a middleware that autopopulates the EncodingType parameter on + * ListObjects commands. + * + * @return \Closure + */ + private function getEncodingTypeMiddleware() + { + return static function (callable $handler) { + return function (Command $command, $request = null) use ($handler) { + $autoSet = false; + if ($command->getName() === 'ListObjects' + && empty($command['EncodingType']) + ) { + $command['EncodingType'] = 'url'; + $autoSet = true; + } + + return $handler($command, $request) + ->then(function (ResultInterface $result) use ($autoSet) { + if ($result['EncodingType'] === 'url' && $autoSet) { + static $topLevel = [ + 'Delimiter', + 'Marker', + 'NextMarker', + 'Prefix', + ]; + static $nested = [ + ['Contents', 'Key'], + ['CommonPrefixes', 'Prefix'], + ]; + + foreach ($topLevel as $key) { + if (isset($result[$key])) { + $result[$key] = urldecode($result[$key]); + } + } + foreach ($nested as $steps) { + if (isset($result[$steps[0]])) { + foreach ($result[$steps[0]] as $key => $part) { + if (isset($part[$steps[1]])) { + $result[$steps[0]][$key][$steps[1]] + = urldecode($part[$steps[1]]); + } + } + } + } + + } + + return $result; + }); + }; + }; + } + + /** + * Provides a middleware that checks for an empty path and a + * non-empty query string. + * + * @return \Closure + */ + private function getEmptyPathWithQuery() + { + return static function (callable $handler) { + return function (Command $command, RequestInterface $request) use ($handler) { + $uri = $request->getUri(); + if (empty($uri->getPath()) && !empty($uri->getQuery())) { + $uri = $uri->withPath('/'); + $request = $request->withUri($uri); + } + + return $handler($command, $request); + }; + }; + } + + /** + * Provides a middleware that disables express session auth when + * customers opt out of it. + * + * @return \Closure + */ + private function getDisableExpressSessionAuthMiddleware() + { + return function (callable $handler) { + return function ( + CommandInterface $command, + ?RequestInterface $request = null + ) use ($handler) { + if (!empty($command['@context']['signature_version']) + && $command['@context']['signature_version'] === 'v4-s3express' + ) { + $command['@context']['signature_version'] = 's3v4'; + } + return $handler($command, $request); + }; + }; + } + + /** + * Special handling for when the service name is s3-object-lambda. + * So, if the host contains s3-object-lambda, then the service name + * returned is s3-object-lambda, otherwise the default signing service is returned. + * @param string $host The host to validate if is a s3-object-lambda URL. + * @return string returns the signing service name to be used + */ + private function getSigningName($host) + { + if (strpos( $host, 's3-object-lambda')) { + return 's3-object-lambda'; + } + + return $this->getConfig('signing_name'); + } + + /** + * If EndpointProviderV2 is used, removes `Bucket` from request URIs. + * This is now handled by the endpoint ruleset. + * + * Additionally adds a synthetic shape `ExpiresString` and modifies + * `Expires` type to ensure it remains set to `timestamp`. + * + * @param array $args + * @return void + * + * @internal + */ + private function processModel(bool $isUseEndpointV2): void + { + $definition = $this->getApi()->getDefinition(); + + if ($isUseEndpointV2) { + foreach($definition['operations'] as &$operation) { + if (isset($operation['http']['requestUri'])) { + $requestUri = $operation['http']['requestUri']; + if ($requestUri === "/{Bucket}") { + $requestUri = str_replace('/{Bucket}', '/', $requestUri); + } else { + $requestUri = str_replace('/{Bucket}', '', $requestUri); + // If we're left with just a query string, prepend '/' + if (str_starts_with($requestUri, '?')) { + $requestUri = '/' . $requestUri; + } + } + $operation['http']['requestUri'] = $requestUri; + } + } + } + + foreach ($definition['shapes'] as $key => &$value) { + $suffix = 'Output'; + if (str_ends_with($key, $suffix)) { + if (isset($value['members']['Expires'])) { + $value['members']['Expires']['deprecated'] = true; + $value['members']['ExpiresString'] = [ + 'shape' => 'ExpiresString', + 'location' => 'header', + 'locationName' => 'Expires' + ]; + } + } + } + $definition['shapes']['ExpiresString']['type'] = 'string'; + $definition['shapes']['Expires']['type'] = 'timestamp'; + + $this->getApi()->setDefinition($definition); + } + + /** + * Adds service-specific client built-in values + * + * @return void + */ + private function addBuiltIns($args) + { + if (isset($args['region']) + && $args['region'] !== 'us-east-1' + ) { + return false; + } + + if (!isset($args['region']) + && ConfigurationResolver::resolve('region', '', 'string') !== 'us-east-1' + ) { + return false; + } + + $key = 'AWS::S3::UseGlobalEndpoint'; + $result = $args['s3_us_east_1_regional_endpoint'] instanceof \Closure ? + $args['s3_us_east_1_regional_endpoint']()->wait() : $args['s3_us_east_1_regional_endpoint']; + + if (is_string($result)) { + if ($result === 'regional') { + $value = false; + } else if ($result === 'legacy') { + $value = true; + } else { + return; + } + } else { + if ($result->isFallback() + || $result->getEndpointsType() === 'legacy' + ) { + $value = true; + } else { + $value = false; + } + } + $this->clientBuiltIns[$key] = $value; + } + + /** + * Determines whether a bucket is a directory bucket. + * Only considers the availability zone/suffix format + * + * @param string $bucket + * @return bool + */ + public static function isDirectoryBucket(string $bucket): bool + { + return preg_match(self::DIRECTORY_BUCKET_REGEX, $bucket) === 1; + } + + /** @internal */ + public static function _applyRetryConfig($value, $args, HandlerList $list) + { + if ($value) { + $config = \Aws\Retry\ConfigurationProvider::unwrap($value); + + if ($config->getMode() === 'legacy') { + $maxRetries = $config->getMaxAttempts() - 1; + $decider = RetryMiddleware::createDefaultDecider($maxRetries); + $decider = function ($retries, $command, $request, $result, $error) use ($decider, $maxRetries) { + $maxRetries = $command['@retries'] ?? $maxRetries; + + if ($decider($retries, $command, $request, $result, $error)) { + return true; + } + + if ($error instanceof AwsException + && $retries < $maxRetries + ) { + if ($error->getResponse() + && $error->getResponse()->getStatusCode() >= 400 + ) { + return strpos( + $error->getResponse()->getBody(), + 'Your socket connection to the server' + ) !== false; + } + + if ($error->getPrevious() instanceof RequestException) { + // All commands except CompleteMultipartUpload are + // idempotent and may be retried without worry if a + // networking error has occurred. + return $command->getName() !== 'CompleteMultipartUpload'; + } + } + + return false; + }; + + $delay = [RetryMiddleware::class, 'exponentialDelay']; + $list->appendSign(Middleware::retry($decider, $delay), 'retry'); + } else { + $defaultDecider = RetryMiddlewareV2::createDefaultDecider( + new QuotaManager(), + $config->getMaxAttempts() + ); + + $list->appendSign( + RetryMiddlewareV2::wrap( + $config, + [ + 'collect_stats' => $args['stats']['retries'], + 'decider' => function( + $attempts, + CommandInterface $cmd, + $result + ) use ($defaultDecider, $config) { + $isRetryable = $defaultDecider($attempts, $cmd, $result); + if (!$isRetryable + && $result instanceof AwsException + && $attempts < $config->getMaxAttempts() + ) { + if (!empty($result->getResponse()) + && $result->getResponse()->getStatusCode() >= 400 + ) { + return strpos( + $result->getResponse()->getBody(), + 'Your socket connection to the server' + ) !== false; + } + + if ($result->getPrevious() instanceof RequestException + && $cmd->getName() !== 'CompleteMultipartUpload' + ) { + $isRetryable = true; + } + } + + return $isRetryable; + } + ] + ), + 'retry' + ); + } + } + } + + /** @internal */ + public static function _applyApiProvider($value, array &$args, HandlerList $list) + { + ClientResolver::_apply_api_provider($value, $args); + $s3Parser = new S3Parser( + $args['parser'], + $args['error_parser'], + $args['api'], + $args['exception_class'] + ); + $s3Parser->addS3ResultMutator( + 'get-bucket-location', + new GetBucketLocationResultMutator() + ); + $s3Parser->addS3ResultMutator( + 'validate-response-checksum', + new ValidateResponseChecksumResultMutator( + $args['api'], + ['response_checksum_validation' => $args['response_checksum_validation']] + ) + ); + $args['parser'] = $s3Parser; + } + + /** + * @internal + * @codeCoverageIgnore + */ + public static function applyDocFilters(array $api, array $docs) + { + $b64 = '
    This value will be base64 encoded on your behalf.
    '; + $opt = '
    This value will be computed for you it is not supplied.
    '; + + // Add a note on the CopyObject docs + $s3ExceptionRetryMessage = "

    Additional info on response behavior: if there is" + . " an internal error in S3 after the request was successfully recieved," + . " a 200 response will be returned with an S3Exception embedded" + . " in it; this will still be caught and retried by" + . " RetryMiddleware.

    "; + + $docs['operations']['CopyObject'] .= $s3ExceptionRetryMessage; + $docs['operations']['CompleteMultipartUpload'] .= $s3ExceptionRetryMessage; + $docs['operations']['UploadPartCopy'] .= $s3ExceptionRetryMessage; + $docs['operations']['UploadPart'] .= $s3ExceptionRetryMessage; + + // Add note about stream ownership in the putObject call + $guzzleStreamMessage = "

    Additional info on behavior of the stream" + . " parameters: Psr7 takes ownership of streams and will automatically close" + . " streams when this method is called with a stream as the Body" + . " parameter. To prevent this, set the Body using" + . " GuzzleHttp\Psr7\stream_for method with a is an instance of" + . " Psr\Http\Message\StreamInterface, and it will be returned" + . " unmodified. This will allow you to keep the stream in scope.

    "; + $docs['operations']['PutObject'] .= $guzzleStreamMessage; + + // Add the SourceFile parameter. + $docs['shapes']['SourceFile']['base'] = 'The path to a file on disk to use instead of the Body parameter.'; + $api['shapes']['SourceFile'] = ['type' => 'string']; + $api['shapes']['PutObjectRequest']['members']['SourceFile'] = ['shape' => 'SourceFile']; + $api['shapes']['UploadPartRequest']['members']['SourceFile'] = ['shape' => 'SourceFile']; + + // Add the ContentSHA256 parameter. + $docs['shapes']['ContentSHA256']['base'] = 'A SHA256 hash of the body content of the request.'; + $api['shapes']['ContentSHA256'] = ['type' => 'string']; + $api['shapes']['PutObjectRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256']; + $api['shapes']['UploadPartRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256']; + $docs['shapes']['ContentSHA256']['append'] = $opt; + + // Add the AddContentMD5 parameter. + $docs['shapes']['AddContentMD5']['base'] = 'Set to true to calculate the ContentMD5 for the upload.'; + $api['shapes']['AddContentMD5'] = ['type' => 'boolean']; + $api['shapes']['PutObjectRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5']; + $api['shapes']['UploadPartRequest']['members']['AddContentMD5'] = ['shape' => 'AddContentMD5']; + + // Add the SaveAs parameter. + $docs['shapes']['SaveAs']['base'] = 'The path to a file on disk to save the object data.'; + $api['shapes']['SaveAs'] = ['type' => 'string']; + $api['shapes']['GetObjectRequest']['members']['SaveAs'] = ['shape' => 'SaveAs']; + + // Several SSECustomerKey documentation updates. + $docs['shapes']['SSECustomerKey']['append'] = $b64; + $docs['shapes']['CopySourceSSECustomerKey']['append'] = $b64; + $docs['shapes']['SSECustomerKeyMd5']['append'] = $opt; + + // Add the ObjectURL to various output shapes and documentation. + $docs['shapes']['ObjectURL']['base'] = 'The URI of the created object.'; + $api['shapes']['ObjectURL'] = ['type' => 'string']; + $api['shapes']['PutObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL']; + $api['shapes']['CopyObjectOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL']; + $api['shapes']['CompleteMultipartUploadOutput']['members']['ObjectURL'] = ['shape' => 'ObjectURL']; + + // Fix references to Location Constraint. + unset($api['shapes']['CreateBucketRequest']['payload']); + $api['shapes']['BucketLocationConstraint']['enum'] = [ + "ap-northeast-1", + "ap-southeast-2", + "ap-southeast-1", + "cn-north-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-1", + "us-west-2", + "sa-east-1", + ]; + + // Add a note that the ContentMD5 is automatically computed, except for with PutObject and UploadPart + $docs['shapes']['ContentMD5']['append'] = '
    The value will be computed on ' + . 'your behalf.
    '; + $docs['shapes']['ContentMD5']['excludeAppend'] = ['PutObjectRequest', 'UploadPartRequest']; + + //Add a note to ContentMD5 for PutObject and UploadPart that specifies the value is required + // When uploading to a bucket with object lock enabled and that it is not computed automatically + $objectLock = '
    This value is required if uploading to a bucket ' + . 'which has Object Lock enabled. It will not be calculated for you automatically. If you wish to have ' + . 'the value calculated for you, use the `AddContentMD5` parameter.
    '; + $docs['shapes']['ContentMD5']['appendOnly'] = [ + 'message' => $objectLock, + 'shapes' => ['PutObjectRequest', 'UploadPartRequest'] + ]; + + // Add `ExpiresString` shape to output structures which contain `Expires` + // Deprecate existing `Expires` shapes in output structures + // Add/Update documentation for both `ExpiresString` and `Expires` + // Ensure `Expires` type remains timestamp + foreach ($api['shapes'] as $key => &$value) { + $suffix = 'Output'; + if (substr($key, -strlen($suffix)) === $suffix) { + if (isset($value['members']['Expires'])) { + $value['members']['Expires']['deprecated'] = true; + $value['members']['ExpiresString'] = [ + 'shape' => 'ExpiresString', + 'location' => 'header', + 'locationName' => 'Expires' + ]; + $docs['shapes']['Expires']['refs'][$key . '$Expires'] + .= '

    This output shape has been deprecated. Please refer to ExpiresString instead.

    .'; + } + } + } + $api['shapes']['ExpiresString']['type'] = 'string'; + $docs['shapes']['ExpiresString']['base'] = 'The unparsed string value of the Expires output member.'; + $api['shapes']['Expires']['type'] = 'timestamp'; + + return [ + new Service($api, ApiProvider::defaultProvider()), + new DocModel($docs) + ]; + } + + /** + * @internal + * @codeCoverageIgnore + */ + public static function addDocExamples($examples) + { + $getObjectExample = [ + 'input' => [ + 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint', + 'Key' => 'my-key' + ], + 'output' => [ + 'Body' => 'class GuzzleHttp\Psr7\Stream#208 (7) {...}', + 'ContentLength' => '11', + 'ContentType' => 'application/octet-stream', + ], + 'comments' => [ + 'input' => '', + 'output' => 'Simplified example output' + ], + 'description' => 'The following example retrieves an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.', + 'id' => '', + 'title' => 'To get an object via an S3 access point ARN' + ]; + if (isset($examples['GetObject'])) { + $examples['GetObject'] []= $getObjectExample; + } else { + $examples['GetObject'] = [$getObjectExample]; + } + + $putObjectExample = [ + 'input' => [ + 'Bucket' => 'arn:aws:s3:us-east-1:123456789012:accesspoint:myaccesspoint', + 'Key' => 'my-key', + 'Body' => 'my-body', + ], + 'output' => [ + 'ObjectURL' => 'https://my-bucket.s3.us-east-1.amazonaws.com/my-key' + ], + 'comments' => [ + 'input' => '', + 'output' => 'Simplified example output' + ], + 'description' => 'The following example uploads an object by referencing the bucket via an S3 accesss point ARN. Result output is simplified for the example.', + 'id' => '', + 'title' => 'To upload an object via an S3 access point ARN' + ]; + if (isset($examples['PutObject'])) { + $examples['PutObject'] []= $putObjectExample; + } else { + $examples['PutObject'] = [$putObjectExample]; + } + + return $examples; + } + + /** + * @param CommandInterface $command + * @return array|mixed|null + */ + private function getSignatureVersionFromCommand(CommandInterface $command) + { + return $command['@context']['signature_version'] + ?? $this->getConfig('signature_version'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3ClientInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3ClientInterface.php new file mode 100644 index 000000000..261d7dd3c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3ClientInterface.php @@ -0,0 +1,369 @@ +uploadAsync($bucket, $key, $body, $acl, $options) + ->wait(); + } + + /** + * @see S3ClientInterface::uploadAsync() + */ + public function uploadAsync( + $bucket, + $key, + $body, + $acl = 'private', + array $options = [] + ) { + return (new ObjectUploader($this, $bucket, $key, $body, $acl, $options)) + ->promise(); + } + + /** + * @see S3ClientInterface::copy() + */ + public function copy( + $fromB, + $fromK, + $destB, + $destK, + $acl = 'private', + array $opts = [] + ) { + return $this->copyAsync($fromB, $fromK, $destB, $destK, $acl, $opts) + ->wait(); + } + + /** + * @see S3ClientInterface::copyAsync() + */ + public function copyAsync( + $fromB, + $fromK, + $destB, + $destK, + $acl = 'private', + array $opts = [] + ) { + $source = [ + 'Bucket' => $fromB, + 'Key' => $fromK, + ]; + if (isset($opts['version_id'])) { + $source['VersionId'] = $opts['version_id']; + } + $destination = [ + 'Bucket' => $destB, + 'Key' => $destK + ]; + + return (new ObjectCopier($this, $source, $destination, $acl, $opts)) + ->promise(); + } + + /** + * @see S3ClientInterface::registerStreamWrapper() + */ + public function registerStreamWrapper() + { + StreamWrapper::register($this); + } + + /** + * @see S3ClientInterface::registerStreamWrapperV2() + */ + public function registerStreamWrapperV2() + { + StreamWrapper::register( + $this, + 's3', + null, + true + ); + } + + /** + * @see S3ClientInterface::deleteMatchingObjects() + */ + public function deleteMatchingObjects( + $bucket, + $prefix = '', + $regex = '', + array $options = [] + ) { + $this->deleteMatchingObjectsAsync($bucket, $prefix, $regex, $options) + ->wait(); + } + + /** + * @see S3ClientInterface::deleteMatchingObjectsAsync() + */ + public function deleteMatchingObjectsAsync( + $bucket, + $prefix = '', + $regex = '', + array $options = [] + ) { + if (!$prefix && !$regex) { + return new RejectedPromise( + new \RuntimeException('A prefix or regex is required.') + ); + } + + $params = ['Bucket' => $bucket, 'Prefix' => $prefix]; + $iter = $this->getIterator('ListObjects', $params); + + if ($regex) { + $iter = \Aws\filter($iter, function ($c) use ($regex) { + return preg_match($regex, $c['Key']); + }); + } + + return BatchDelete::fromIterator($this, $bucket, $iter, $options) + ->promise(); + } + + /** + * @see S3ClientInterface::uploadDirectory() + */ + public function uploadDirectory( + $directory, + $bucket, + $keyPrefix = null, + array $options = [] + ) { + $this->uploadDirectoryAsync($directory, $bucket, $keyPrefix, $options) + ->wait(); + } + + /** + * @see S3ClientInterface::uploadDirectoryAsync() + */ + public function uploadDirectoryAsync( + $directory, + $bucket, + $keyPrefix = null, + array $options = [] + ) { + $d = "s3://$bucket" . ($keyPrefix ? '/' . ltrim($keyPrefix, '/') : ''); + return (new Transfer($this, $directory, $d, $options))->promise(); + } + + /** + * @see S3ClientInterface::downloadBucket() + */ + public function downloadBucket( + $directory, + $bucket, + $keyPrefix = '', + array $options = [] + ) { + $this->downloadBucketAsync($directory, $bucket, $keyPrefix, $options) + ->wait(); + } + + /** + * @see S3ClientInterface::downloadBucketAsync() + */ + public function downloadBucketAsync( + $directory, + $bucket, + $keyPrefix = '', + array $options = [] + ) { + $s = "s3://$bucket" . ($keyPrefix ? '/' . ltrim($keyPrefix, '/') : ''); + return (new Transfer($this, $s, $directory, $options))->promise(); + } + + /** + * @see S3ClientInterface::determineBucketRegion() + */ + public function determineBucketRegion($bucketName) + { + return $this->determineBucketRegionAsync($bucketName)->wait(); + } + + /** + * @see S3ClientInterface::determineBucketRegionAsync() + * + * @param string $bucketName + * + * @return PromiseInterface + */ + public function determineBucketRegionAsync($bucketName) + { + $command = $this->getCommand('HeadBucket', ['Bucket' => $bucketName]); + $handlerList = clone $this->getHandlerList(); + $handlerList->remove('s3.permanent_redirect'); + $handlerList->remove('signer'); + $handler = $handlerList->resolve(); + + return $handler($command) + ->then(static function (ResultInterface $result) { + return $result['@metadata']['headers']['x-amz-bucket-region']; + }, function (AwsException $e) { + $response = $e->getResponse(); + if ($response === null) { + throw $e; + } + + if ($e->getAwsErrorCode() === 'AuthorizationHeaderMalformed') { + $region = $this->determineBucketRegionFromExceptionBody( + $response + ); + if (!empty($region)) { + return $region; + } + throw $e; + } + + return $response->getHeaderLine('x-amz-bucket-region'); + }); + } + + private function determineBucketRegionFromExceptionBody(ResponseInterface $response) + { + try { + $element = $this->parseXml($response->getBody(), $response); + if (!empty($element->Region)) { + return (string)$element->Region; + } + } catch (\Exception $e) { + // Fallthrough on exceptions from parsing + } + return false; + } + + /** + * @see S3ClientInterface::doesBucketExist() + */ + public function doesBucketExist($bucket) + { + return $this->checkExistenceWithCommand( + $this->getCommand('HeadBucket', ['Bucket' => $bucket]) + ); + } + + /** + * @see S3ClientInterface::doesBucketExistV2() + */ + public function doesBucketExistV2($bucket, $accept403 = false) + { + $command = $this->getCommand('HeadBucket', ['Bucket' => $bucket]); + + try { + $this->execute($command); + return true; + } catch (S3Exception $e) { + if ( + ($accept403 && $e->getStatusCode() === 403) + || $e instanceof PermanentRedirectException + ) { + return true; + } + if ($e->getStatusCode() === 404) { + return false; + } + throw $e; + } + } + + /** + * @see S3ClientInterface::doesObjectExist() + */ + public function doesObjectExist($bucket, $key, array $options = []) + { + return $this->checkExistenceWithCommand( + $this->getCommand('HeadObject', [ + 'Bucket' => $bucket, + 'Key' => $key + ] + $options) + ); + } + + /** + * @see S3ClientInterface::doesObjectExistV2() + */ + public function doesObjectExistV2( + $bucket, + $key, + $includeDeleteMarkers = false, + array $options = [] + ){ + $command = $this->getCommand('HeadObject', [ + 'Bucket' => $bucket, + 'Key' => $key + ] + $options + ); + + try { + $this->execute($command); + return true; + } catch (S3Exception $e) { + if ($includeDeleteMarkers + && $this->useDeleteMarkers($e) + ) { + return true; + } + if ($e->getStatusCode() === 404) { + return false; + } + throw $e; + } + } + + private function useDeleteMarkers($exception) + { + $response = $exception->getResponse(); + return !empty($response) + && $response->getHeader('x-amz-delete-marker'); + } + + /** + * Determines whether or not a resource exists using a command + * + * @param CommandInterface $command Command used to poll for the resource + * + * @return bool + * @throws S3Exception|\Exception if there is an unhandled exception + */ + private function checkExistenceWithCommand(CommandInterface $command) + { + try { + $this->execute($command); + return true; + } catch (S3Exception $e) { + if ($e->getAwsErrorCode() == 'AccessDenied') { + return true; + } + if ($e->getStatusCode() >= 500) { + throw $e; + } + return false; + } + } + + /** + * @see S3ClientInterface::execute() + */ + abstract public function execute(CommandInterface $command); + + /** + * @see S3ClientInterface::getCommand() + */ + abstract public function getCommand($name, array $args = []); + + /** + * @see S3ClientInterface::getHandlerList() + * + * @return HandlerList + */ + abstract public function getHandlerList(); + + /** + * @see S3ClientInterface::getIterator() + * + * @return \Iterator + */ + abstract public function getIterator($name, array $args = []); +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php new file mode 100644 index 000000000..c8dd00703 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3EndpointMiddleware.php @@ -0,0 +1,343 @@ + true, + 'DeleteBucket' => true, + 'ListBuckets' => true, + ]; + + const NO_PATTERN = 0; + const DUALSTACK = 1; + const ACCELERATE = 2; + const ACCELERATE_DUALSTACK = 3; + const PATH_STYLE = 4; + const HOST_STYLE = 5; + + /** @var bool */ + private $accelerateByDefault; + /** @var bool */ + private $dualStackByDefault; + /** @var bool */ + private $pathStyleByDefault; + /** @var string */ + private $region; + /** @var callable */ + private $endpointProvider; + /** @var callable */ + private $nextHandler; + /** @var string */ + private $endpoint; + + /** + * Create a middleware wrapper function + * + * @param string $region + * @param EndpointProvider $endpointProvider + * @param array $options + * + * @return callable + */ + public static function wrap($region, $endpointProvider, array $options) + { + return function (callable $handler) use ($region, $endpointProvider, $options) { + return new self($handler, $region, $options, $endpointProvider); + }; + } + + public function __construct( + callable $nextHandler, + $region, + array $options, + $endpointProvider = null + ) { + $this->pathStyleByDefault = isset($options['path_style']) + ? (bool) $options['path_style'] : false; + $this->dualStackByDefault = isset($options['dual_stack']) + ? (bool) $options['dual_stack'] : false; + $this->accelerateByDefault = isset($options['accelerate']) + ? (bool) $options['accelerate'] : false; + $this->region = (string) $region; + $this->endpoint = isset($options['endpoint']) + ? $options['endpoint'] : ""; + $this->endpointProvider = is_null($endpointProvider) + ? PartitionEndpointProvider::defaultProvider() + : $endpointProvider; + $this->nextHandler = $nextHandler; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + if (!empty($this->endpoint)) { + $request = $this->applyEndpoint($command, $request); + } else { + switch ($this->endpointPatternDecider($command, $request)) { + case self::HOST_STYLE: + $request = $this->applyHostStyleEndpoint($command, $request); + break; + case self::NO_PATTERN: + break; + case self::PATH_STYLE: + $request = $this->applyPathStyleEndpointCustomizations($command, $request); + break; + case self::DUALSTACK: + $request = $this->applyDualStackEndpoint($command, $request); + break; + case self::ACCELERATE: + $request = $this->applyAccelerateEndpoint( + $command, + $request, + 's3-accelerate' + ); + break; + case self::ACCELERATE_DUALSTACK: + $request = $this->applyAccelerateEndpoint( + $command, + $request, + 's3-accelerate.dualstack' + ); + break; + } + } + $nextHandler = $this->nextHandler; + return $nextHandler($command, $request); + } + + private static function isRequestHostStyleCompatible( + CommandInterface $command, + RequestInterface $request + ) { + return S3Client::isBucketDnsCompatible($command['Bucket']) + && ( + $request->getUri()->getScheme() === 'http' + || strpos($command['Bucket'], '.') === false + ) + && filter_var($request->getUri()->getHost(), FILTER_VALIDATE_IP) === false; + } + + private function endpointPatternDecider( + CommandInterface $command, + RequestInterface $request + ) { + $accelerate = isset($command['@use_accelerate_endpoint']) + ? $command['@use_accelerate_endpoint'] : $this->accelerateByDefault; + $dualStack = isset($command['@use_dual_stack_endpoint']) + ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault; + $pathStyle = isset($command['@use_path_style_endpoint']) + ? $command['@use_path_style_endpoint'] : $this->pathStyleByDefault; + + if ($accelerate && $dualStack) { + // When try to enable both for operations excluded from s3-accelerate, + // only dualstack endpoints will be enabled. + return $this->canAccelerate($command) + ? self::ACCELERATE_DUALSTACK + : self::DUALSTACK; + } + + if ($accelerate && $this->canAccelerate($command)) { + return self::ACCELERATE; + } + + if ($dualStack) { + return self::DUALSTACK; + } + + if (!$pathStyle + && self::isRequestHostStyleCompatible($command, $request) + ) { + return self::HOST_STYLE; + } + + return self::PATH_STYLE; + } + + private function canAccelerate(CommandInterface $command) + { + return empty(self::$exclusions[$command->getName()]) + && S3Client::isBucketDnsCompatible($command['Bucket']); + } + + private function getBucketStyleHost(CommandInterface $command, $host) + { + // For operations on the base host (e.g. ListBuckets) + if (!isset($command['Bucket'])) { + return $host; + } + + return "{$command['Bucket']}.{$host}"; + } + + private function applyHostStyleEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $uri = $request->getUri(); + $request = $request->withUri( + $uri->withHost($this->getBucketStyleHost( + $command, + $uri->getHost() + )) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + return $request; + } + + private function applyPathStyleEndpointCustomizations( + CommandInterface $command, + RequestInterface $request + ) { + if ($command->getName() == 'WriteGetObjectResponse') { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + $fips = \Aws\is_fips_pseudo_region($this->region) ? "-fips" : ""; + $region = \Aws\strip_fips_pseudo_regions($this->region); + $host = + "{$command['RequestRoute']}.s3-object-lambda{$fips}.{$region}.{$dnsSuffix}"; + + $uri = $request->getUri(); + $request = $request->withUri( + $uri->withHost($host) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + } + return $request; + } + + + private function applyDualStackEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $request = $request->withUri( + $request->getUri()->withHost($this->getDualStackHost()) + ); + + if (empty($command['@use_path_style_endpoint']) + && !$this->pathStyleByDefault + && self::isRequestHostStyleCompatible($command, $request) + ) { + $request = $this->applyHostStyleEndpoint($command, $request); + } + return $request; + } + + private function getDualStackHost() + { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + return "s3.dualstack.{$this->region}.{$dnsSuffix}"; + } + + private function applyAccelerateEndpoint( + CommandInterface $command, + RequestInterface $request, + $pattern + ) { + $request = $request->withUri( + $request->getUri() + ->withHost($this->getAccelerateHost($command, $pattern)) + ->withPath($this->getBucketlessPath( + $request->getUri()->getPath(), + $command + )) + ); + return $request; + } + + private function getAccelerateHost(CommandInterface $command, $pattern) + { + $dnsSuffix = $this->endpointProvider + ->getPartition($this->region, 's3') + ->getDnsSuffix(); + return "{$command['Bucket']}.{$pattern}.{$dnsSuffix}"; + } + + private function getBucketlessPath($path, CommandInterface $command) + { + $pattern = '/^\\/' . preg_quote($command['Bucket'], '/') . '/'; + $path = preg_replace($pattern, '', $path) ?: '/'; + if (substr($path, 0 , 1) !== '/') { + $path = '/' . $path; + } + return $path; + } + + private function applyEndpoint( + CommandInterface $command, + RequestInterface $request + ) { + $dualStack = isset($command['@use_dual_stack_endpoint']) + ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault; + if (ArnParser::isArn($command['Bucket'])) { + $arn = ArnParser::parse($command['Bucket']); + $outpost = $arn->getService() == 's3-outposts'; + if ($outpost && $dualStack) { + throw new InvalidArgumentException("Outposts + dualstack is not supported"); + } + if ($arn instanceof ObjectLambdaAccessPointArn) { + return $request; + } + } + if ($dualStack) { + throw new InvalidArgumentException("Custom Endpoint + Dualstack not supported"); + } + if ($command->getName() == 'WriteGetObjectResponse') { + $host = "{$command['RequestRoute']}.{$this->endpoint}"; + $uri = $request->getUri(); + return $request = $request->withUri( + $uri->withHost($host) + ->withPath($this->getBucketlessPath( + $uri->getPath(), + $command + )) + ); + } + $host = ($this->pathStyleByDefault) ? + $this->endpoint : + $this->getBucketStyleHost( + $command, + $this->endpoint + ); + $uri = $request->getUri(); + $scheme = $uri->getScheme(); + if(empty($scheme)){ + $request = $request->withUri( + $uri->withHost($host) + ); + } else { + $request = $request->withUri($uri); + } + + return $request; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3MultiRegionClient.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3MultiRegionClient.php new file mode 100644 index 000000000..3fb1470a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3MultiRegionClient.php @@ -0,0 +1,380 @@ + function (array &$args) { + $availableRegions = array_keys($args['partition']['regions']); + return end($availableRegions); + }]; + unset($args['region']); + + return $args + [ + 'bucket_region_cache' => [ + 'type' => 'config', + 'valid' => [CacheInterface::class], + 'doc' => 'Cache of regions in which given buckets are located.', + 'default' => function () { return new LruArrayCache; }, + ], + 'region' => $regionDef, + ]; + } + + public function __construct(array $args) + { + parent::__construct($args); + $this->cache = $this->getConfig('bucket_region_cache'); + + $this->getHandlerList()->prependInit( + $this->determineRegionMiddleware(), + 'determine_region' + ); + } + + private function determineRegionMiddleware() + { + return function (callable $handler) { + return function (CommandInterface $command) use ($handler) { + $cacheKey = $this->getCacheKey($command['Bucket']); + if ( + empty($command['@region']) && + $region = $this->cache->get($cacheKey) + ) { + $command['@region'] = $region; + } + + return Promise\Coroutine::of(function () use ( + $handler, + $command, + $cacheKey + ) { + try { + yield $handler($command); + } catch (PermanentRedirectException $e) { + if (empty($command['Bucket'])) { + throw $e; + } + $result = $e->getResult(); + $region = null; + if (isset($result['@metadata']['headers']['x-amz-bucket-region'])) { + $region = $result['@metadata']['headers']['x-amz-bucket-region']; + $this->cache->set($cacheKey, $region); + } else { + $region = (yield $this->determineBucketRegionAsync( + $command['Bucket'] + )); + } + + $command['@region'] = $region; + yield $handler($command); + } catch (AwsException $e) { + if ($e->getAwsErrorCode() === 'AuthorizationHeaderMalformed') { + $region = $this->determineBucketRegionFromExceptionBody( + $e->getResponse() + ); + if (!empty($region)) { + $this->cache->set($cacheKey, $region); + + $command['@region'] = $region; + yield $handler($command); + } else { + throw $e; + } + } else { + throw $e; + } + } + }); + }; + }; + } + + public function createPresignedRequest(CommandInterface $command, $expires, array $options = []) + { + if (empty($command['Bucket'])) { + throw new \InvalidArgumentException('The S3\\MultiRegionClient' + . ' cannot create presigned requests for commands without a' + . ' specified bucket.'); + } + + /** @var S3ClientInterface $client */ + $client = $this->getClientFromPool( + $this->determineBucketRegion($command['Bucket']) + ); + return $client->createPresignedRequest( + $client->getCommand($command->getName(), $command->toArray()), + $expires, + $options + ); + } + + public function getObjectUrl($bucket, $key) + { + /** @var S3Client $regionalClient */ + $regionalClient = $this->getClientFromPool( + $this->determineBucketRegion($bucket) + ); + + return $regionalClient->getObjectUrl($bucket, $key); + } + + public function determineBucketRegionAsync($bucketName) + { + $cacheKey = $this->getCacheKey($bucketName); + if ($cached = $this->cache->get($cacheKey)) { + return Promise\Create::promiseFor($cached); + } + + /** @var S3ClientInterface $regionalClient */ + $regionalClient = $this->getClientFromPool(); + return $regionalClient->determineBucketRegionAsync($bucketName) + ->then( + function ($region) use ($cacheKey) { + $this->cache->set($cacheKey, $region); + + return $region; + } + ); + } + + private function getCacheKey($bucketName) + { + return "aws:s3:{$bucketName}:location"; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3UriParser.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3UriParser.php new file mode 100644 index 000000000..508bff14c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/S3UriParser.php @@ -0,0 +1,163 @@ + true, + 'bucket' => null, + 'key' => null, + 'region' => null + ]; + + /** + * Parses a URL or S3 StreamWrapper Uri (s3://) into an associative array + * of Amazon S3 data including: + * + * - bucket: The Amazon S3 bucket (null if none) + * - key: The Amazon S3 key (null if none) + * - path_style: Set to true if using path style, or false if not + * - region: Set to a string if a non-class endpoint is used or null. + * + * @param string|UriInterface $uri + * + * @return array + * @throws \InvalidArgumentException|InvalidArnException + */ + public function parse($uri) + { + // Attempt to parse host component of uri as an ARN + $components = $this->parseS3UrlComponents($uri); + if (!empty($components)) { + if (ArnParser::isArn($components['host'])) { + $arn = new AccessPointArn($components['host']); + return [ + 'bucket' => $components['host'], + 'key' => $components['path'], + 'path_style' => false, + 'region' => $arn->getRegion() + ]; + } + } + + $url = Psr7\Utils::uriFor($uri); + + if ($url->getScheme() == $this->streamWrapperScheme) { + return $this->parseStreamWrapper($url); + } + + if (!$url->getHost()) { + throw new \InvalidArgumentException('No hostname found in URI: ' + . $uri); + } + + if (!preg_match($this->pattern, $url->getHost(), $matches)) { + return $this->parseCustomEndpoint($url); + } + + // Parse the URI based on the matched format (path / virtual) + $result = empty($matches[1]) + ? $this->parsePathStyle($url) + : $this->parseVirtualHosted($url, $matches); + + // Add the region if one was found and not the classic endpoint + $result['region'] = $matches[2] == 'amazonaws' ? null : $matches[2]; + + return $result; + } + + private function parseS3UrlComponents($uri) + { + preg_match("/^([a-zA-Z0-9]*):\/\/([a-zA-Z0-9:-]*)\/(.*)/", $uri, $components); + if (empty($components)) { + return []; + } + return [ + 'scheme' => $components[1], + 'host' => $components[2], + 'path' => $components[3], + ]; + } + + private function parseStreamWrapper(UriInterface $url) + { + $result = self::$defaultResult; + $result['path_style'] = false; + + $result['bucket'] = $url->getHost(); + if ($url->getPath()) { + $key = ltrim($url->getPath(), '/ '); + if (!empty($key)) { + $result['key'] = $key; + } + } + + return $result; + } + + private function parseCustomEndpoint(UriInterface $url) + { + $result = self::$defaultResult; + $path = ltrim($url->getPath(), '/ '); + $segments = explode('/', $path, 2); + + if (isset($segments[0])) { + $result['bucket'] = $segments[0]; + if (isset($segments[1])) { + $result['key'] = $segments[1]; + } + } + + return $result; + } + + private function parsePathStyle(UriInterface $url) + { + $result = self::$defaultResult; + + if ($url->getPath() != '/') { + $path = ltrim($url->getPath(), '/'); + if ($path) { + $pathPos = strpos($path, '/'); + if ($pathPos === false) { + // https://s3.amazonaws.com/bucket + $result['bucket'] = $path; + } elseif ($pathPos == strlen($path) - 1) { + // https://s3.amazonaws.com/bucket/ + $result['bucket'] = substr($path, 0, -1); + } else { + // https://s3.amazonaws.com/bucket/key + $result['bucket'] = substr($path, 0, $pathPos); + $result['key'] = substr($path, $pathPos + 1) ?: null; + } + } + } + + return $result; + } + + private function parseVirtualHosted(UriInterface $url, array $matches) + { + $result = self::$defaultResult; + $result['path_style'] = false; + // Remove trailing "." from the prefix to get the bucket + $result['bucket'] = substr($matches[1], 0, -1); + $path = $url->getPath(); + // Check if a key was present, and if so, removing the leading "/" + $result['key'] = !$path || $path == '/' ? null : substr($path, 1); + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/SSECMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/SSECMiddleware.php new file mode 100644 index 000000000..628ddef15 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/SSECMiddleware.php @@ -0,0 +1,75 @@ +nextHandler = $nextHandler; + $this->endpointScheme = $endpointScheme; + } + + public function __invoke( + CommandInterface $command, + ?RequestInterface $request = null + ) { + // Allows only HTTPS connections when using SSE-C + if (($command['SSECustomerKey'] || $command['CopySourceSSECustomerKey']) + && $this->endpointScheme !== 'https' + ) { + throw new \RuntimeException('You must configure your S3 client to ' + . 'use HTTPS in order to use the SSE-C features.'); + } + + // Prepare the normal SSE-CPK headers + if ($command['SSECustomerKey']) { + $this->prepareSseParams($command); + } + + // If it's a copy operation, prepare the SSE-CPK headers for the source. + if ($command['CopySourceSSECustomerKey']) { + $this->prepareSseParams($command, 'CopySource'); + } + + $f = $this->nextHandler; + return $f($command, $request); + } + + private function prepareSseParams(CommandInterface $command, $prefix = '') + { + // Base64 encode the provided key + $key = $command[$prefix . 'SSECustomerKey']; + $command[$prefix . 'SSECustomerKey'] = base64_encode($key); + + // Base64 the provided MD5 or, generate an MD5 if not provided + if ($md5 = $command[$prefix . 'SSECustomerKeyMD5']) { + $command[$prefix . 'SSECustomerKeyMD5'] = base64_encode($md5); + } else { + $command[$prefix . 'SSECustomerKeyMD5'] = base64_encode(md5($key, true)); + } + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/StreamWrapper.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/StreamWrapper.php new file mode 100644 index 000000000..af7d22907 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/StreamWrapper.php @@ -0,0 +1,1005 @@ +/" files with PHP + * streams, supporting "r", "w", "a", "x". + * + * # Opening "r" (read only) streams: + * + * Read only streams are truly streaming by default and will not allow you to + * seek. This is because data read from the stream is not kept in memory or on + * the local filesystem. You can force a "r" stream to be seekable by setting + * the "seekable" stream context option true. This will allow true streaming of + * data from Amazon S3, but will maintain a buffer of previously read bytes in + * a 'php://temp' stream to allow seeking to previously read bytes from the + * stream. + * + * You may pass any GetObject parameters as 's3' stream context options. These + * options will affect how the data is downloaded from Amazon S3. + * + * # Opening "w" and "x" (write only) streams: + * + * Because Amazon S3 requires a Content-Length header, write only streams will + * maintain a 'php://temp' stream to buffer data written to the stream until + * the stream is flushed (usually by closing the stream with fclose). + * + * You may pass any PutObject parameters as 's3' stream context options. These + * options will affect how the data is uploaded to Amazon S3. + * + * When opening an "x" stream, the file must exist on Amazon S3 for the stream + * to open successfully. + * + * # Opening "a" (write only append) streams: + * + * Similar to "w" streams, opening append streams requires that the data be + * buffered in a "php://temp" stream. Append streams will attempt to download + * the contents of an object in Amazon S3, seek to the end of the object, then + * allow you to append to the contents of the object. The data will then be + * uploaded using a PutObject operation when the stream is flushed (usually + * with fclose). + * + * You may pass any GetObject and/or PutObject parameters as 's3' stream + * context options. These options will affect how the data is downloaded and + * uploaded from Amazon S3. + * + * Stream context options: + * + * - "seekable": Set to true to create a seekable "r" (read only) stream by + * using a php://temp stream buffer + * - For "unlink" only: Any option that can be passed to the DeleteObject + * operation + */ +class StreamWrapper +{ + /** @var resource|null Stream context (this is set by PHP) */ + public $context; + + /** @var StreamInterface Underlying stream resource */ + private $body; + + /** @var int Size of the body that is opened */ + private $size; + + /** @var array Hash of opened stream parameters */ + private $params = []; + + /** @var string Mode in which the stream was opened */ + private $mode; + + /** @var \Iterator Iterator used with opendir() related calls */ + private $objectIterator; + + /** @var string The bucket that was opened when opendir() was called */ + private $openedBucket; + + /** @var string The prefix of the bucket that was opened with opendir() */ + private $openedBucketPrefix; + + /** @var string Opened bucket path */ + private $openedPath; + + /** @var CacheInterface Cache for object and dir lookups */ + private $cache; + + /** @var string The opened protocol (e.g., "s3") */ + private $protocol = 's3'; + + /** @var bool Keeps track of whether stream has been flushed since opening */ + private $isFlushed = false; + + /** @var bool Whether or not to use V2 bucket and object existence methods */ + private static $useV2Existence = false; + + /** + * Register the 's3://' stream wrapper + * + * @param S3ClientInterface $client Client to use with the stream wrapper + * @param string $protocol Protocol to register as. + * @param CacheInterface $cache Default cache for the protocol. + */ + public static function register( + S3ClientInterface $client, + $protocol = 's3', + ?CacheInterface $cache = null, + $v2Existence = false + ) { + self::$useV2Existence = $v2Existence; + if (in_array($protocol, stream_get_wrappers())) { + stream_wrapper_unregister($protocol); + } + + // Set the client passed in as the default stream context client + stream_wrapper_register($protocol, get_called_class(), STREAM_IS_URL); + $default = stream_context_get_options(stream_context_get_default()); + $default[$protocol]['client'] = $client; + + if ($cache) { + $default[$protocol]['cache'] = $cache; + } elseif (!isset($default[$protocol]['cache'])) { + // Set a default cache adapter. + $default[$protocol]['cache'] = new LruArrayCache(); + } + + stream_context_set_default($default); + } + + public function stream_close() + { + if (!$this->isFlushed + && empty($this->body->getSize()) + && $this->mode !== 'r' + ) { + $this->stream_flush(); + } + $this->body = $this->cache = null; + } + + public function stream_open($path, $mode, $options, &$opened_path) + { + $this->initProtocol($path); + $this->isFlushed = false; + $this->params = $this->getBucketKey($path); + $this->mode = rtrim($mode, 'bt'); + + if ($errors = $this->validate($path, $this->mode)) { + return $this->triggerError($errors); + } + + return $this->boolCall(function() { + switch ($this->mode) { + case 'r': return $this->openReadStream(); + case 'a': return $this->openAppendStream(); + default: return $this->openWriteStream(); + } + }); + } + + public function stream_eof() + { + return $this->body->eof(); + } + + public function stream_flush() + { + // Check if stream body size has been + // calculated via a flush or close + if($this->body->getSize() === null && $this->mode !== 'r') { + return $this->triggerError( + "Unable to determine stream size. Did you forget to close or flush the stream?" + ); + } + + $this->isFlushed = true; + if ($this->mode == 'r') { + return false; + } + + if ($this->body->isSeekable()) { + $this->body->seek(0); + } + $params = $this->getOptions(true); + $params['Body'] = $this->body; + + // Attempt to guess the ContentType of the upload based on the + // file extension of the key + if (!isset($params['ContentType']) && + ($type = Psr7\MimeType::fromFilename($params['Key'])) + ) { + $params['ContentType'] = $type; + } + + $this->clearCacheKey("{$this->protocol}://{$params['Bucket']}/{$params['Key']}"); + return $this->boolCall(function () use ($params) { + return (bool) $this->getClient()->putObject($params); + }); + } + + public function stream_read($count) + { + return $this->body->read($count); + } + + public function stream_seek($offset, $whence = SEEK_SET) + { + return !$this->body->isSeekable() + ? false + : $this->boolCall(function () use ($offset, $whence) { + $this->body->seek($offset, $whence); + return true; + }); + } + + public function stream_tell() + { + return $this->boolCall(function() { return $this->body->tell(); }); + } + + public function stream_write($data) + { + return $this->body->write($data); + } + + public function unlink($path) + { + $this->initProtocol($path); + + return $this->boolCall(function () use ($path) { + $this->clearCacheKey($path); + $this->getClient()->deleteObject($this->withPath($path)); + return true; + }); + } + + public function stream_stat() + { + $stat = $this->getStatTemplate(); + $stat[7] = $stat['size'] = $this->getSize(); + $stat[2] = $stat['mode'] = $this->mode; + + return $stat; + } + + /** + * Provides information for is_dir, is_file, filesize, etc. Works on + * buckets, keys, and prefixes. + * @link http://www.php.net/manual/en/streamwrapper.url-stat.php + */ + public function url_stat($path, $flags) + { + $this->initProtocol($path); + + // Some paths come through as S3:// for some reason. + $split = explode('://', $path, 2); + $path = strtolower($split[0]) . '://' . $split[1]; + + // Check if this path is in the url_stat cache + if ($value = $this->getCacheStorage()->get($path)) { + return $value; + } + + $stat = $this->createStat($path, $flags); + + if (is_array($stat)) { + $this->getCacheStorage()->set($path, $stat); + } + + return $stat; + } + + /** + * Parse the protocol out of the given path. + * + * @param $path + */ + private function initProtocol($path) + { + $parts = explode('://', $path, 2); + $this->protocol = $parts[0] ?: 's3'; + } + + private function createStat($path, $flags) + { + $this->initProtocol($path); + $parts = $this->withPath($path); + + if (!$parts['Key']) { + return $this->statDirectory($parts, $path, $flags); + } + + return $this->boolCall(function () use ($parts, $path) { + try { + $result = $this->getClient()->headObject($parts); + if (substr($parts['Key'], -1, 1) == '/' && + $result['ContentLength'] == 0 + ) { + // Return as if it is a bucket to account for console + // bucket objects (e.g., zero-byte object "foo/") + return $this->formatUrlStat($path); + } + + // Attempt to stat and cache regular object + return $this->formatUrlStat($result->toArray()); + } catch (S3Exception $e) { + // Maybe this isn't an actual key, but a prefix. Do a prefix + // listing of objects to determine. + $result = $this->getClient()->listObjects([ + 'Bucket' => $parts['Bucket'], + 'Prefix' => rtrim($parts['Key'], '/') . '/', + 'MaxKeys' => 1 + ]); + if (!$result['Contents'] && !$result['CommonPrefixes']) { + throw new \Exception("File or directory not found: $path"); + } + return $this->formatUrlStat($path); + } + }, $flags); + } + + private function statDirectory($parts, $path, $flags) + { + // Stat "directories": buckets, or "s3://" + $method = self::$useV2Existence ? 'doesBucketExistV2' : 'doesBucketExist'; + + if (!$parts['Bucket'] || + $this->getClient()->$method($parts['Bucket']) + ) { + return $this->formatUrlStat($path); + } + + return $this->triggerError("File or directory not found: $path", $flags); + } + + /** + * Support for mkdir(). + * + * @param string $path Directory which should be created. + * @param int $mode Permissions. 700-range permissions map to + * ACL_PUBLIC. 600-range permissions map to + * ACL_AUTH_READ. All other permissions map to + * ACL_PRIVATE. Expects octal form. + * @param int $options A bitwise mask of values, such as + * STREAM_MKDIR_RECURSIVE. + * + * @return bool + * @link http://www.php.net/manual/en/streamwrapper.mkdir.php + */ + public function mkdir($path, $mode, $options) + { + $this->initProtocol($path); + $params = $this->withPath($path); + $this->clearCacheKey($path); + if (!$params['Bucket']) { + return false; + } + + if (!isset($params['ACL'])) { + $params['ACL'] = $this->determineAcl($mode); + } + + return empty($params['Key']) + ? $this->createBucket($path, $params) + : $this->createSubfolder($path, $params); + } + + public function rmdir($path, $options) + { + $this->initProtocol($path); + $this->clearCacheKey($path); + $params = $this->withPath($path); + $client = $this->getClient(); + + if (!$params['Bucket']) { + return $this->triggerError('You must specify a bucket'); + } + + return $this->boolCall(function () use ($params, $path, $client) { + if (!$params['Key']) { + $client->deleteBucket(['Bucket' => $params['Bucket']]); + return true; + } + return $this->deleteSubfolder($path, $params); + }); + } + + /** + * Support for opendir(). + * + * The opendir() method of the Amazon S3 stream wrapper supports a stream + * context option of "listFilter". listFilter must be a callable that + * accepts an associative array of object data and returns true if the + * object should be yielded when iterating the keys in a bucket. + * + * @param string $path The path to the directory + * (e.g. "s3://dir[]") + * @param string $options Unused option variable + * + * @return bool true on success + * @see http://www.php.net/manual/en/function.opendir.php + */ + public function dir_opendir($path, $options) + { + $this->initProtocol($path); + $this->openedPath = $path; + $params = $this->withPath($path); + $delimiter = $this->getOption('delimiter'); + /** @var callable $filterFn */ + $filterFn = $this->getOption('listFilter'); + $op = ['Bucket' => $params['Bucket']]; + $this->openedBucket = $params['Bucket']; + + if ($delimiter === null) { + $delimiter = '/'; + } + + if ($delimiter) { + $op['Delimiter'] = $delimiter; + } + + if ($params['Key']) { + $params['Key'] = rtrim($params['Key'], $delimiter) . $delimiter; + $op['Prefix'] = $params['Key']; + } + + $this->openedBucketPrefix = $params['Key']; + + // Filter our "/" keys added by the console as directories, and ensure + // that if a filter function is provided that it passes the filter. + $this->objectIterator = \Aws\flatmap( + $this->getClient()->getPaginator('ListObjects', $op), + function (Result $result) use ($filterFn) { + $contentsAndPrefixes = $result->search('[Contents[], CommonPrefixes[]][]'); + // Filter out dir place holder keys and use the filter fn. + return array_filter( + $contentsAndPrefixes, + function ($key) use ($filterFn) { + return (!$filterFn || call_user_func($filterFn, $key)) + && (!isset($key['Key']) || substr($key['Key'], -1, 1) !== '/'); + } + ); + } + ); + + return true; + } + + /** + * Close the directory listing handles + * + * @return bool true on success + */ + public function dir_closedir() + { + $this->objectIterator = null; + gc_collect_cycles(); + + return true; + } + + /** + * This method is called in response to rewinddir() + * + * @return boolean true on success + */ + public function dir_rewinddir() + { + return $this->boolCall(function() { + $this->objectIterator = null; + $this->dir_opendir($this->openedPath, null); + return true; + }); + } + + /** + * This method is called in response to readdir() + * + * @return string Should return a string representing the next filename, or + * false if there is no next file. + * @link http://www.php.net/manual/en/function.readdir.php + */ + public function dir_readdir() + { + // Skip empty result keys + if (!$this->objectIterator->valid()) { + return false; + } + + // First we need to create a cache key. This key is the full path to + // then object in s3: protocol://bucket/key. + // Next we need to create a result value. The result value is the + // current value of the iterator without the opened bucket prefix to + // emulate how readdir() works on directories. + // The cache key and result value will depend on if this is a prefix + // or a key. + $cur = $this->objectIterator->current(); + if (isset($cur['Prefix'])) { + // Include "directories". Be sure to strip a trailing "/" + // on prefixes. + $result = rtrim($cur['Prefix'], '/'); + $key = $this->formatKey($result); + $stat = $this->formatUrlStat($key); + } else { + $result = $cur['Key']; + $key = $this->formatKey($cur['Key']); + $stat = $this->formatUrlStat($cur); + } + + // Cache the object data for quick url_stat lookups used with + // RecursiveDirectoryIterator. + $this->getCacheStorage()->set($key, $stat); + $this->objectIterator->next(); + + // Remove the prefix from the result to emulate other stream wrappers. + return $this->openedBucketPrefix + ? substr($result, strlen($this->openedBucketPrefix)) + : $result; + } + + private function formatKey($key) + { + $protocol = explode('://', $this->openedPath)[0]; + return "{$protocol}://{$this->openedBucket}/{$key}"; + } + + /** + * Called in response to rename() to rename a file or directory. Currently + * only supports renaming objects. + * + * @param string $path_from the path to the file to rename + * @param string $path_to the new path to the file + * + * @return bool true if file was successfully renamed + * @link http://www.php.net/manual/en/function.rename.php + */ + public function rename($path_from, $path_to) + { + // PHP will not allow rename across wrapper types, so we can safely + // assume $path_from and $path_to have the same protocol + $this->initProtocol($path_from); + $partsFrom = $this->withPath($path_from); + $partsTo = $this->withPath($path_to); + $this->clearCacheKey($path_from); + $this->clearCacheKey($path_to); + + if (!$partsFrom['Key'] || !$partsTo['Key']) { + return $this->triggerError('The Amazon S3 stream wrapper only ' + . 'supports copying objects'); + } + + return $this->boolCall(function () use ($partsFrom, $partsTo) { + $options = $this->getOptions(true); + // Copy the object and allow overriding default parameters if + // desired, but by default copy metadata + $this->getClient()->copy( + $partsFrom['Bucket'], + $partsFrom['Key'], + $partsTo['Bucket'], + $partsTo['Key'], + isset($options['acl']) ? $options['acl'] : 'private', + $options + ); + // Delete the original object + $this->getClient()->deleteObject([ + 'Bucket' => $partsFrom['Bucket'], + 'Key' => $partsFrom['Key'] + ] + $options); + return true; + }); + } + + public function stream_cast($cast_as) + { + return false; + } + + public function stream_set_option($option, $arg1, $arg2) + { + return false; + } + + public function stream_metadata($path, $option, $value) + { + return false; + } + + public function stream_lock($operation) + { + trigger_error( + 'stream_lock() is not supported by the Amazon S3 stream wrapper', + E_USER_WARNING + ); + return false; + } + + public function stream_truncate($new_size) + { + return false; + } + + /** + * Validates the provided stream arguments for fopen and returns an array + * of errors. + */ + private function validate($path, $mode) + { + $errors = []; + + if (!$this->getOption('Key')) { + $errors[] = 'Cannot open a bucket. You must specify a path in the ' + . 'form of s3://bucket/key'; + } + + if (!in_array($mode, ['r', 'w', 'a', 'x'])) { + $errors[] = "Mode not supported: {$mode}. " + . "Use one 'r', 'w', 'a', or 'x'."; + } + + if ($mode === 'x') { + $method = self::$useV2Existence ? 'doesObjectExistV2' : 'doesObjectExist'; + + if ($this->getClient()->$method( + $this->getOption('Bucket'), + $this->getOption('Key'), + $this->getOptions(true) + )) { + $errors[] = "{$path} already exists on Amazon S3"; + } + } + + return $errors; + } + + /** + * Get the stream context options available to the current stream + * + * @param bool $removeContextData Set to true to remove contextual kvp's + * like 'client' from the result. + * + * @return array + */ + private function getOptions($removeContextData = false) + { + // Context is not set when doing things like stat + if ($this->context === null) { + $options = []; + } else { + $options = stream_context_get_options($this->context); + $options = isset($options[$this->protocol]) + ? $options[$this->protocol] + : []; + } + + $default = stream_context_get_options(stream_context_get_default()); + $default = isset($default[$this->protocol]) + ? $default[$this->protocol] + : []; + $result = $this->params + $options + $default; + + if ($removeContextData) { + unset($result['client'], $result['seekable'], $result['cache']); + } + + return $result; + } + + /** + * Get a specific stream context option + * + * @param string $name Name of the option to retrieve + * + * @return mixed|null + */ + private function getOption($name) + { + $options = $this->getOptions(); + + return isset($options[$name]) ? $options[$name] : null; + } + + /** + * Gets the client from the stream context + * + * @return S3ClientInterface + * @throws \RuntimeException if no client has been configured + */ + private function getClient() + { + if (!$client = $this->getOption('client')) { + throw new \RuntimeException('No client in stream context'); + } + + return $client; + } + + private function getBucketKey($path) + { + // Remove the protocol + $parts = explode('://', $path, 2); + // Get the bucket, key + $parts = explode('/', $parts[1], 2); + + return [ + 'Bucket' => $parts[0], + 'Key' => isset($parts[1]) ? $parts[1] : null + ]; + } + + /** + * Get the bucket and key from the passed path (e.g. s3://bucket/key) + * + * @param string $path Path passed to the stream wrapper + * + * @return array Hash of 'Bucket', 'Key', and custom params from the context + */ + private function withPath($path) + { + $params = $this->getOptions(true); + + return $this->getBucketKey($path) + $params; + } + + private function openReadStream() + { + $client = $this->getClient(); + $command = $client->getCommand('GetObject', $this->getOptions(true)); + $command['@http']['stream'] = true; + $result = $client->execute($command); + $this->size = $result['ContentLength']; + $this->body = $result['Body']; + + // Wrap the body in a caching entity body if seeking is allowed + if ($this->getOption('seekable') && !$this->body->isSeekable()) { + $this->body = new CachingStream($this->body); + } + + return true; + } + + private function openWriteStream() + { + $this->body = new Stream(fopen('php://temp', 'r+')); + return true; + } + + private function openAppendStream() + { + try { + // Get the body of the object and seek to the end of the stream + $client = $this->getClient(); + $this->body = $client->getObject($this->getOptions(true))['Body']; + $this->body->seek(0, SEEK_END); + return true; + } catch (S3Exception $e) { + // The object does not exist, so use a simple write stream + return $this->openWriteStream(); + } + } + + /** + * Trigger one or more errors + * + * @param string|array $errors Errors to trigger + * @param mixed $flags If set to STREAM_URL_STAT_QUIET, then no + * error or exception occurs + * + * @return bool Returns false + * @throws \RuntimeException if throw_errors is true + */ + private function triggerError($errors, $flags = null) + { + // This is triggered with things like file_exists() + if ($flags & STREAM_URL_STAT_QUIET) { + return $flags & STREAM_URL_STAT_LINK + // This is triggered for things like is_link() + ? $this->formatUrlStat(false) + : false; + } + + // This is triggered when doing things like lstat() or stat() + trigger_error(implode("\n", (array) $errors), E_USER_WARNING); + + return false; + } + + /** + * Prepare a url_stat result array + * + * @param string|array $result Data to add + * + * @return array Returns the modified url_stat result + */ + private function formatUrlStat($result = null) + { + $stat = $this->getStatTemplate(); + switch (gettype($result)) { + case 'NULL': + case 'string': + // Directory with 0777 access - see "man 2 stat". + $stat['mode'] = $stat[2] = 0040777; + break; + case 'array': + // Regular file with 0777 access - see "man 2 stat". + $stat['mode'] = $stat[2] = 0100777; + // Pluck the content-length if available. + if (isset($result['ContentLength'])) { + $stat['size'] = $stat[7] = $result['ContentLength']; + } elseif (isset($result['Size'])) { + $stat['size'] = $stat[7] = $result['Size']; + } + if (isset($result['LastModified'])) { + // ListObjects or HeadObject result + $stat['mtime'] = $stat[9] = $stat['ctime'] = $stat[10] + = strtotime($result['LastModified']); + } + } + + return $stat; + } + + /** + * Creates a bucket for the given parameters. + * + * @param string $path Stream wrapper path + * @param array $params A result of StreamWrapper::withPath() + * + * @return bool Returns true on success or false on failure + */ + private function createBucket($path, array $params) + { + $method = self::$useV2Existence ? 'doesBucketExistV2' : 'doesBucketExist'; + + if ($this->getClient()->$method($params['Bucket'])) { + return $this->triggerError("Bucket already exists: {$path}"); + } + + unset($params['ACL']); + return $this->boolCall(function () use ($params, $path) { + $this->getClient()->createBucket($params); + $this->clearCacheKey($path); + return true; + }); + } + + /** + * Creates a pseudo-folder by creating an empty "/" suffixed key + * + * @param string $path Stream wrapper path + * @param array $params A result of StreamWrapper::withPath() + * + * @return bool + */ + private function createSubfolder($path, array $params) + { + // Ensure the path ends in "/" and the body is empty. + $params['Key'] = rtrim($params['Key'], '/') . '/'; + $params['Body'] = ''; + + // Fail if this pseudo directory key already exists + $method = self::$useV2Existence ? 'doesObjectExistV2' : 'doesObjectExist'; + + if ($this->getClient()->$method( + $params['Bucket'], + $params['Key'] + )) { + return $this->triggerError("Subfolder already exists: {$path}"); + } + + return $this->boolCall(function () use ($params, $path) { + $this->getClient()->putObject($params); + $this->clearCacheKey($path); + return true; + }); + } + + /** + * Deletes a nested subfolder if it is empty. + * + * @param string $path Path that is being deleted (e.g., 's3://a/b/c') + * @param array $params A result of StreamWrapper::withPath() + * + * @return bool + */ + private function deleteSubfolder($path, $params) + { + // Use a key that adds a trailing slash if needed. + $prefix = rtrim($params['Key'], '/') . '/'; + $result = $this->getClient()->listObjects([ + 'Bucket' => $params['Bucket'], + 'Prefix' => $prefix, + 'MaxKeys' => 1 + ]); + + // Check if the bucket contains keys other than the placeholder + if ($contents = $result['Contents']) { + return (count($contents) > 1 || $contents[0]['Key'] != $prefix) + ? $this->triggerError('Subfolder is not empty') + : $this->unlink(rtrim($path, '/') . '/'); + } + + return $result['CommonPrefixes'] + ? $this->triggerError('Subfolder contains nested folders') + : true; + } + + /** + * Determine the most appropriate ACL based on a file mode. + * + * @param int $mode File mode + * + * @return string + */ + private function determineAcl($mode) + { + switch (substr(decoct($mode), 0, 1)) { + case '7': return 'public-read'; + case '6': return 'authenticated-read'; + default: return 'private'; + } + } + + /** + * Gets a URL stat template with default values + * + * @return array + */ + private function getStatTemplate() + { + return [ + 0 => 0, 'dev' => 0, + 1 => 0, 'ino' => 0, + 2 => 0, 'mode' => 0, + 3 => 0, 'nlink' => 0, + 4 => 0, 'uid' => 0, + 5 => 0, 'gid' => 0, + 6 => -1, 'rdev' => -1, + 7 => 0, 'size' => 0, + 8 => 0, 'atime' => 0, + 9 => 0, 'mtime' => 0, + 10 => 0, 'ctime' => 0, + 11 => -1, 'blksize' => -1, + 12 => -1, 'blocks' => -1, + ]; + } + + /** + * Invokes a callable and triggers an error if an exception occurs while + * calling the function. + * + * @param callable $fn + * @param int $flags + * + * @return bool + */ + private function boolCall(callable $fn, $flags = null) + { + try { + return $fn(); + } catch (\Exception $e) { + return $this->triggerError($e->getMessage(), $flags); + } + } + + /** + * @return LruArrayCache + */ + private function getCacheStorage() + { + if (!$this->cache) { + $this->cache = $this->getOption('cache') ?: new LruArrayCache(); + } + + return $this->cache; + } + + /** + * Clears a specific stat cache value from the stat cache and LRU cache. + * + * @param string $key S3 path (s3://bucket/key). + */ + private function clearCacheKey($key) + { + clearstatcache(true, $key); + $this->getCacheStorage()->remove($key); + } + + /** + * Returns the size of the opened object body. + * + * @return int|null + */ + private function getSize() + { + $size = $this->body->getSize(); + + return !empty($size) ? $size : $this->size; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Transfer.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Transfer.php new file mode 100644 index 000000000..7679950b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/Transfer.php @@ -0,0 +1,456 @@ +client = $client; + + // Prepare the destination. + $this->destination = $this->prepareTarget($dest); + if ($this->destination['scheme'] === 's3') { + $this->s3Args = $this->getS3Args($this->destination['path']); + } + + // Prepare the source. + if (is_string($source)) { + $this->sourceMetadata = $this->prepareTarget($source); + $this->source = $source; + } elseif ($source instanceof Iterator) { + if (empty($options['base_dir'])) { + throw new \InvalidArgumentException('You must provide the source' + . ' argument as a string or provide the "base_dir" option.'); + } + + $this->sourceMetadata = $this->prepareTarget($options['base_dir']); + $this->source = $source; + } else { + throw new \InvalidArgumentException('source must be the path to a ' + . 'directory or an iterator that yields file names.'); + } + + // Validate schemes. + if ($this->sourceMetadata['scheme'] === $this->destination['scheme']) { + throw new \InvalidArgumentException("You cannot copy from" + . " {$this->sourceMetadata['scheme']} to" + . " {$this->destination['scheme']}." + ); + } + + // Handle multipart-related options. + $this->concurrency = isset($options['concurrency']) + ? $options['concurrency'] + : MultipartUploader::DEFAULT_CONCURRENCY; + $this->mupThreshold = isset($options['mup_threshold']) + ? $options['mup_threshold'] + : 16777216; + if ($this->mupThreshold < MultipartUploader::PART_MIN_SIZE) { + throw new \InvalidArgumentException('mup_threshold must be >= 5MB'); + } + + // Handle "before" callback option. + if (isset($options['before'])) { + $this->before = $options['before']; + if (!is_callable($this->before)) { + throw new \InvalidArgumentException('before must be a callable.'); + } + } + + // Handle "after" callback option. + if (isset($options['after'])) { + $this->after = $options['after']; + if (!is_callable($this->after)) { + throw new \InvalidArgumentException('after must be a callable.'); + } + } + + // Handle "debug" option. + if (isset($options['debug'])) { + if ($options['debug'] === true) { + $options['debug'] = fopen('php://output', 'w'); + } + if (is_resource($options['debug'])) { + $this->addDebugToBefore($options['debug']); + } + } + + // Handle "add_content_md5" option. + $this->addContentMD5 = isset($options['add_content_md5']) + && $options['add_content_md5'] === true; + MetricsBuilder::appendMetricsCaptureMiddleware( + $this->client->getHandlerList(), + MetricsBuilder::S3_TRANSFER + ); + } + + /** + * Transfers the files. + * + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + // If the promise has been created, just return it. + if (!$this->promise) { + // Create an upload/download promise for the transfer. + $this->promise = $this->sourceMetadata['scheme'] === 'file' + ? $this->createUploadPromise() + : $this->createDownloadPromise(); + } + + return $this->promise; + } + + /** + * Transfers the files synchronously. + */ + public function transfer() + { + $this->promise()->wait(); + } + + private function prepareTarget($targetPath) + { + $target = [ + 'path' => $this->normalizePath($targetPath), + 'scheme' => $this->determineScheme($targetPath), + ]; + + if ($target['scheme'] !== 's3' && $target['scheme'] !== 'file') { + throw new \InvalidArgumentException('Scheme must be "s3" or "file".'); + } + + return $target; + } + + /** + * Creates an array that contains Bucket and Key by parsing the filename. + * + * @param string $path Path to parse. + * + * @return array + */ + private function getS3Args($path) + { + $parts = explode('/', str_replace('s3://', '', $path), 2); + $args = ['Bucket' => $parts[0]]; + if (isset($parts[1])) { + $args['Key'] = $parts[1]; + } + + return $args; + } + + /** + * Parses the scheme from a filename. + * + * @param string $path Path to parse. + * + * @return string + */ + private function determineScheme($path) + { + return !strpos($path, '://') ? 'file' : explode('://', $path)[0]; + } + + /** + * Normalize a path so that it has UNIX-style directory separators and no trailing / + * + * @param string $path + * + * @return string + */ + private function normalizePath($path) + { + return rtrim(str_replace('\\', '/', $path), '/'); + } + + private function resolvesOutsideTargetDirectory($sink, $objectKey) + { + $resolved = []; + $sections = explode('/', $sink); + $targetSectionsLength = count(explode('/', $objectKey)); + $targetSections = array_slice($sections, -($targetSectionsLength + 1)); + $targetDirectory = $targetSections[0]; + + foreach ($targetSections as $section) { + if ($section === '.' || $section === '') { + continue; + } + if ($section === '..') { + array_pop($resolved); + if (empty($resolved) || $resolved[0] !== $targetDirectory) { + return true; + } + } else { + $resolved []= $section; + } + } + return false; + } + + private function createDownloadPromise() + { + $parts = $this->getS3Args($this->sourceMetadata['path']); + $prefix = "s3://{$parts['Bucket']}/" + . (isset($parts['Key']) ? $parts['Key'] . '/' : ''); + + $commands = []; + foreach ($this->getDownloadsIterator() as $object) { + // Prepare the sink. + $objectKey = preg_replace('/^' . preg_quote($prefix, '/') . '/', '', $object); + $sink = $this->destination['path'] . '/' . $objectKey; + + $command = $this->client->getCommand( + 'GetObject', + $this->getS3Args($object) + ['@http' => ['sink' => $sink]] + ); + + if ($this->resolvesOutsideTargetDirectory($sink, $objectKey)) { + throw new AwsException( + 'Cannot download key ' . $objectKey + . ', its relative path resolves outside the' + . ' parent directory', $command); + } + + // Create the directory if needed. + $dir = dirname($sink); + if (!is_dir($dir) && !mkdir($dir, 0777, true)) { + throw new \RuntimeException("Could not create dir: {$dir}"); + } + + // Create the command. + $commands []= $command; + } + + // Create a GetObject command pool and return the promise. + return (new Aws\CommandPool($this->client, $commands, [ + 'concurrency' => $this->concurrency, + 'before' => $this->before, + 'fulfill' => $this->after, + 'rejected' => function ($reason, $idx, Promise\PromiseInterface $p) { + $p->reject($reason); + } + ]))->promise(); + } + + private function createUploadPromise() + { + // Map each file into a promise that performs the actual transfer. + $files = \Aws\map($this->getUploadsIterator(), function ($file) { + return (filesize($file) >= $this->mupThreshold) + ? $this->uploadMultipart($file) + : $this->upload($file); + }); + + // Create an EachPromise, that will concurrently handle the upload + // operations' yielded promises from the iterator. + return Promise\Each::ofLimitAll($files, $this->concurrency, $this->after); + } + + /** @return Iterator */ + private function getUploadsIterator() + { + if (is_string($this->source)) { + return Aws\filter( + Aws\recursive_dir_iterator($this->sourceMetadata['path']), + function ($file) { return !is_dir($file); } + ); + } + + return $this->source; + } + + /** @return Iterator */ + private function getDownloadsIterator() + { + if (is_string($this->source)) { + $listArgs = $this->getS3Args($this->sourceMetadata['path']); + if (isset($listArgs['Key'])) { + $listArgs['Prefix'] = $listArgs['Key'] . '/'; + unset($listArgs['Key']); + } + + $files = $this->client + ->getPaginator('ListObjects', $listArgs) + ->search('Contents[].Key'); + $files = Aws\map($files, function ($key) use ($listArgs) { + return "s3://{$listArgs['Bucket']}/$key"; + }); + return Aws\filter($files, function ($key) { + return substr($key, -1, 1) !== '/'; + }); + } + + return $this->source; + } + + private function upload($filename) + { + $args = $this->s3Args; + $args['SourceFile'] = $filename; + $args['Key'] = $this->createS3Key($filename); + $args['AddContentMD5'] = $this->addContentMD5; + $command = $this->client->getCommand('PutObject', $args); + $this->before and call_user_func($this->before, $command); + + return $this->client->executeAsync($command); + } + + private function uploadMultipart($filename) + { + $args = $this->s3Args; + $args['Key'] = $this->createS3Key($filename); + $filename = $filename instanceof \SplFileInfo ? $filename->getPathname() : $filename; + + return (new MultipartUploader($this->client, $filename, [ + 'bucket' => $args['Bucket'], + 'key' => $args['Key'], + 'before_initiate' => $this->before, + 'before_upload' => $this->before, + 'before_complete' => $this->before, + 'concurrency' => $this->concurrency, + 'add_content_md5' => $this->addContentMD5 + ]))->promise(); + } + + private function createS3Key($filename) + { + $filename = $this->normalizePath($filename); + $relative_file_path = ltrim( + preg_replace('#^' . preg_quote($this->sourceMetadata['path']) . '#', '', $filename), + '/\\' + ); + + if (isset($this->s3Args['Key'])) { + return rtrim($this->s3Args['Key'], '/').'/'.$relative_file_path; + } + + return $relative_file_path; + } + + private function addDebugToBefore($debug) + { + $before = $this->before; + $sourcePath = $this->sourceMetadata['path']; + $s3Args = $this->s3Args; + + $this->before = static function ( + CommandInterface $command + ) use ($before, $debug, $sourcePath, $s3Args) { + // Call the composed before function. + $before and $before($command); + + // Determine the source and dest values based on operation. + switch ($operation = $command->getName()) { + case 'GetObject': + $source = "s3://{$command['Bucket']}/{$command['Key']}"; + $dest = $command['@http']['sink']; + break; + case 'PutObject': + $source = $command['SourceFile']; + $dest = "s3://{$command['Bucket']}/{$command['Key']}"; + break; + case 'UploadPart': + $part = $command['PartNumber']; + case 'CreateMultipartUpload': + case 'CompleteMultipartUpload': + $sourceKey = $command['Key']; + if (isset($s3Args['Key']) && strpos($sourceKey, $s3Args['Key']) === 0) { + $sourceKey = substr($sourceKey, strlen($s3Args['Key']) + 1); + } + $source = "{$sourcePath}/{$sourceKey}"; + $dest = "s3://{$command['Bucket']}/{$command['Key']}"; + break; + default: + throw new \UnexpectedValueException( + "Transfer encountered an unexpected operation: {$operation}." + ); + } + + // Print the debugging message. + $context = sprintf('%s -> %s (%s)', $source, $dest, $operation); + if (isset($part)) { + $context .= " : Part={$part}"; + } + fwrite($debug, "Transferring {$context}\n"); + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Configuration.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Configuration.php new file mode 100644 index 000000000..91277d61e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Configuration.php @@ -0,0 +1,37 @@ +useArnRegion = Aws\boolean_value($useArnRegion); + if (is_null($this->useArnRegion)) { + throw new ConfigurationException("'use_arn_region' config option" + . " must be a boolean value."); + } + } + + /** + * {@inheritdoc} + */ + public function isUseArnRegion() + { + return $this->useArnRegion; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'use_arn_region' => $this->isUseArnRegion(), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/ConfigurationInterface.php new file mode 100644 index 000000000..c7f3b24d9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/ConfigurationInterface.php @@ -0,0 +1,19 @@ + + * use Aws\S3\UseArnRegion\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see Aws\S3\UseArnRegion\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const ENV_USE_ARN_REGION = 'AWS_S3_USE_ARN_REGION'; + const INI_USE_ARN_REGION = 's3_use_arn_region'; + const DEFAULT_USE_ARN_REGION = true; + + public static $cacheKey = 'aws_s3_use_arn_region_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['use_arn_region']) + && $config['use_arn_region'] instanceof CacheInterface + ) { + return self::cache($memo, $config['use_arn_region'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use config from environment variables, if available + $useArnRegion = getenv(self::ENV_USE_ARN_REGION); + if (!empty($useArnRegion)) { + return Promise\Create::promiseFor( + new Configuration($useArnRegion) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_USE_ARN_REGION); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini($profile = null, $filename = null) + { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + + // Use INI_SCANNER_NORMAL instead of INI_SCANNER_TYPED for PHP 5.5 compatibility + $data = \Aws\parse_ini_file($filename, true, INI_SCANNER_NORMAL); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_USE_ARN_REGION])) { + return self::reject("Required S3 Use Arn Region config values + not present in INI profile '{$profile}' ({$filename})"); + } + + // INI_SCANNER_NORMAL parses false-y values as an empty string + if ($data[$profile][self::INI_USE_ARN_REGION] === "") { + $data[$profile][self::INI_USE_ARN_REGION] = false; + } + + return Promise\Create::promiseFor( + new Configuration($data[$profile][self::INI_USE_ARN_REGION]) + ); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function () { + return Promise\Create::promiseFor( + new Configuration(self::DEFAULT_USE_ARN_REGION) + ); + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Exception/ConfigurationException.php new file mode 100644 index 000000000..15d06a9c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/S3/UseArnRegion/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +api = $api; + $this->parser = $parser; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $fn = $this->parser; + $result = $fn($command, $response); + + //Skip this middleware if the operation doesn't have an httpChecksum + $op = $this->api->getOperation($command->getName()); + $checksumInfo = isset($op['httpChecksum']) + ? $op['httpChecksum'] + : []; + if (empty($checksumInfo)) { + return $result; + } + + //Skip this middleware if the operation doesn't send back a checksum, or the user doesn't opt in + $checksumModeEnabledMember = isset($checksumInfo['requestValidationModeMember']) + ? $checksumInfo['requestValidationModeMember'] + : ""; + $checksumModeEnabled = isset($command[$checksumModeEnabledMember]) + ? $command[$checksumModeEnabledMember] + : ""; + $responseAlgorithms = isset($checksumInfo['responseAlgorithms']) + ? $checksumInfo['responseAlgorithms'] + : []; + if (empty($responseAlgorithms) + || strtolower($checksumModeEnabled) !== "enabled" + ) { + return $result; + } + + if (extension_loaded('awscrt')) { + $checksumPriority = ['CRC32C', 'CRC32', 'SHA1', 'SHA256']; + } else { + $checksumPriority = ['CRC32', 'SHA1', 'SHA256']; + } + $checksumsToCheck = array_intersect($responseAlgorithms, $checksumPriority); + $checksumValidationInfo = $this->validateChecksum($checksumsToCheck, $response); + + if ($checksumValidationInfo['status'] == "SUCCEEDED") { + $result['ChecksumValidated'] = $checksumValidationInfo['checksum']; + } else if ($checksumValidationInfo['status'] == "FAILED"){ + //Ignore failed validations on GetObject if it's a multipart get which returned a full multipart object + if ($command->getName() == "GetObject" + && !empty($checksumValidationInfo['checksumHeaderValue']) + ) { + $headerValue = $checksumValidationInfo['checksumHeaderValue']; + $lastDashPos = strrpos($headerValue, '-'); + $endOfChecksum = substr($headerValue, $lastDashPos + 1); + if (is_numeric($endOfChecksum) + && intval($endOfChecksum) > 1 + && intval($endOfChecksum) < 10000) { + return $result; + } + } + throw new S3Exception( + "Calculated response checksum did not match the expected value", + $command + ); + } + return $result; + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + */ + public function validateChecksum($checksumPriority, ResponseInterface $response) + { + $checksumToValidate = $this->chooseChecksumHeaderToValidate( + $checksumPriority, + $response + ); + $validationStatus = "SKIPPED"; + $checksumHeaderValue = null; + if (!empty($checksumToValidate)) { + $checksumHeaderValue = $response->getHeader( + 'x-amz-checksum-' . $checksumToValidate + ); + if (isset($checksumHeaderValue)) { + $checksumHeaderValue = $checksumHeaderValue[0]; + $calculatedChecksumValue = $this->getEncodedValue( + $checksumToValidate, + $response->getBody() + ); + $validationStatus = $checksumHeaderValue == $calculatedChecksumValue + ? "SUCCEEDED" + : "FAILED"; + } + } + return [ + "status" => $validationStatus, + "checksum" => $checksumToValidate, + "checksumHeaderValue" => $checksumHeaderValue, + ]; + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + */ + public function chooseChecksumHeaderToValidate( + $checksumPriority, + ResponseInterface $response + ) { + foreach ($checksumPriority as $checksum) { + $checksumHeader = 'x-amz-checksum-' . $checksum; + if ($response->hasHeader($checksumHeader)) { + return $checksum; + } + } + return null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/SSO/Exception/SSOException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/SSO/Exception/SSOException.php new file mode 100644 index 000000000..6392a3f05 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/SSO/Exception/SSOException.php @@ -0,0 +1,9 @@ +isDevMode()){ + return; + } + + $composer = $event->getComposer(); + $extra = $composer->getPackage()->getExtra(); + $listedServices = isset($extra['aws/aws-sdk-php']) + ? $extra['aws/aws-sdk-php'] + : []; + + if ($listedServices) { + $serviceMapping = self::buildServiceMapping(); + self::verifyListedServices($serviceMapping, $listedServices); + $filesystem = $filesystem ?: new Filesystem(); + $vendorPath = $composer->getConfig()->get('vendor-dir'); + self::removeServiceDirs( + $event, + $filesystem, + $serviceMapping, + $listedServices, + $vendorPath + ); + } else { + throw new \InvalidArgumentException( + 'There are no services listed. Did you intend to use this script?' + ); + } + } + + public static function buildServiceMapping() + { + $serviceMapping = []; + $manifest = require(__DIR__ . '/../../data/manifest.json.php'); + + foreach ($manifest as $service => $attributes) { + $serviceMapping[$attributes['namespace']] = $service; + } + + return $serviceMapping; + } + + private static function verifyListedServices($serviceMapping, $listedServices) + { + foreach ($listedServices as $serviceToKeep) { + if (!isset($serviceMapping[$serviceToKeep])) { + throw new \InvalidArgumentException( + "'$serviceToKeep' is not a valid AWS service namespace. Please check spelling and casing." + ); + } + } + } + + private static function removeServiceDirs( + $event, + $filesystem, + $serviceMapping, + $listedServices, + $vendorPath + ) { + $unsafeForDeletion = ['Kms', 'S3', 'SSO', 'SSOOIDC', 'Sts']; + if (in_array('DynamoDbStreams', $listedServices)) { + $unsafeForDeletion[] = 'DynamoDb'; + } + + $clientPath = $vendorPath . '/aws/aws-sdk-php/src/'; + $modelPath = $clientPath . 'data/'; + $deleteCount = 0; + + foreach ($serviceMapping as $clientName => $modelName) { + if (!in_array($clientName, $listedServices) && + !in_array($clientName, $unsafeForDeletion) + ) { + $clientDir = $clientPath . $clientName; + $modelDir = $modelPath . $modelName; + + if ($filesystem->exists([$clientDir, $modelDir])) { + $attempts = 3; + $delay = 2; + + while ($attempts) { + try { + $filesystem->remove([$clientDir, $modelDir]); + $deleteCount++; + break; + } catch (IOException $e) { + $attempts--; + + if (!$attempts) { + throw new IOException( + "Removal failed after several attempts. Last error: " . $e->getMessage() + ); + } else { + sleep($delay); + $event->getIO()->write( + "Error encountered: " . $e->getMessage() . ". Retrying..." + ); + $delay += 2; + } + } + } + + } + } + } + $event->getIO()->write( + "Removed $deleteCount AWS service" . ($deleteCount === 1 ? '' : 's') + ); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sdk.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sdk.php new file mode 100644 index 000000000..8b13ff0f8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sdk.php @@ -0,0 +1,948 @@ +args = $args; + + if (!isset($args['handler']) && !isset($args['http_handler'])) { + $this->args['http_handler'] = default_http_handler(); + } + } + + public function __call($name, array $args) + { + $args = isset($args[0]) ? $args[0] : []; + if (strpos($name, 'createMultiRegion') === 0) { + return $this->createMultiRegionClient(substr($name, 17), $args); + } + + if (strpos($name, 'create') === 0) { + return $this->createClient(substr($name, 6), $args); + } + + throw new \BadMethodCallException("Unknown method: {$name}."); + } + + /** + * Get a client by name using an array of constructor options. + * + * @param string $name Service name or namespace (e.g., DynamoDb, s3). + * @param array $args Arguments to configure the client. + * + * @return AwsClientInterface + * @throws \InvalidArgumentException if any required options are missing or + * the service is not supported. + * @see Aws\AwsClient::__construct for a list of available options for args. + */ + public function createClient($name, array $args = []) + { + // Get information about the service from the manifest file. + $service = manifest($name); + $namespace = $service['namespace']; + + // Instantiate the client class. + $client = "Aws\\{$namespace}\\{$namespace}Client"; + return new $client($this->mergeArgs($namespace, $service, $args)); + } + + public function createMultiRegionClient($name, array $args = []) + { + // Get information about the service from the manifest file. + $service = manifest($name); + $namespace = $service['namespace']; + + $klass = "Aws\\{$namespace}\\{$namespace}MultiRegionClient"; + $klass = class_exists($klass) ? $klass : MultiRegionClient::class; + + return new $klass($this->mergeArgs($namespace, $service, $args)); + } + + /** + * Clone existing SDK instance with ability to pass an associative array + * of extra client settings. + * + * @param array $args + * + * @return self + */ + public function copy(array $args = []) + { + return new self($args + $this->args); + } + + private function mergeArgs($namespace, array $manifest, array $args = []) + { + // Merge provided args with stored, service-specific args. + if (isset($this->args[$namespace])) { + $args += $this->args[$namespace]; + } + + // Provide the endpoint prefix in the args. + if (!isset($args['service'])) { + $args['service'] = $manifest['endpoint']; + } + + return $args + $this->args; + } + + /** + * Determine the endpoint prefix from a client namespace. + * + * @param string $name Namespace name + * + * @return string + * @internal + * @deprecated Use the `\Aws\manifest()` function instead. + */ + public static function getEndpointPrefix($name) + { + return manifest($name)['endpoint']; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/AnonymousSignature.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/AnonymousSignature.php new file mode 100644 index 000000000..9ccc8df61 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/AnonymousSignature.php @@ -0,0 +1,33 @@ +modifyTokenHeaders($request, $credentials); + $credentials = $this->getSigningCredentials($credentials); + return parent::signRequest($request, $credentials, $signingService); + } + + public function presign(RequestInterface $request, CredentialsInterface $credentials, $expires, array $options = []) + { + $request = $this->modifyTokenHeaders($request, $credentials); + $credentials = $this->getSigningCredentials($credentials); + return parent::presign($request, $credentials, $expires, $options); + } + + private function modifyTokenHeaders( + RequestInterface $request, + CredentialsInterface $credentials + ) { + //The x-amz-security-token header is not supported by s3 express + $request = $request->withoutHeader('X-Amz-Security-Token'); + return $request->withHeader( + 'x-amz-s3session-token', + $credentials->getSecurityToken() + ); + } + + private function getSigningCredentials(CredentialsInterface $credentials) + { + return new Credentials( + $credentials->getAccessKeyId(), + $credentials->getSecretKey() + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/S3SignatureV4.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/S3SignatureV4.php new file mode 100644 index 000000000..c99b281cf --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/S3SignatureV4.php @@ -0,0 +1,125 @@ +hasHeader('x-amz-content-sha256')) { + $request = $request->withHeader( + 'x-amz-content-sha256', + $this->getPayload($request) + ); + } + $useCrt = + strpos($request->getUri()->getHost(), "accesspoint.s3-global") + !== false; + if (!$useCrt) { + if (strpos($request->getUri()->getHost(), "s3-object-lambda")) { + return parent::signRequest($request, $credentials, "s3-object-lambda"); + } + return parent::signRequest($request, $credentials); + } + $signingService = $signingService ?: 's3'; + return $this->signWithV4a($credentials, $request, $signingService); + } + + /** + * @param CredentialsInterface $credentials + * @param RequestInterface $request + * @param $signingService + * @param SigningConfigAWS|null $signingConfig + * @return RequestInterface + * + * Instantiates a separate sigv4a signing config. All services except S3 + * use double encoding. All services except S3 require path normalization. + */ + protected function signWithV4a( + CredentialsInterface $credentials, + RequestInterface $request, + $signingService, + ?SigningConfigAWS $signingConfig = null + ){ + $this->verifyCRTLoaded(); + $credentials_provider = $this->createCRTStaticCredentialsProvider($credentials); + $signingConfig = new SigningConfigAWS([ + 'algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => $credentials_provider, + 'signed_body_value' => $this->getPayload($request), + 'region' => $this->region, + 'should_normalize_uri_path' => false, + 'use_double_uri_encode' => false, + 'service' => $signingService, + 'date' => time(), + ]); + + return parent::signWithV4a($credentials, $request, $signingService, $signingConfig); + } + + /** + * Always add a x-amz-content-sha-256 for data integrity. + * + * {@inheritdoc} + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ) { + if (!$request->hasHeader('x-amz-content-sha256')) { + $request = $request->withHeader( + 'X-Amz-Content-Sha256', + $this->getPresignedPayload($request) + ); + } + + if (strpos($request->getUri()->getHost(), "accesspoint.s3-global")) { + $request = $request->withHeader("x-amz-region-set", "*"); + } + + return parent::presign($request, $credentials, $expires, $options); + } + + /** + * Override used to allow pre-signed URLs to be created for an + * in-determinate request payload. + */ + protected function getPresignedPayload(RequestInterface $request) + { + return SignatureV4::UNSIGNED_PAYLOAD; + } + + /** + * Amazon S3 does not double-encode the path component in the canonical request + */ + protected function createCanonicalizedPath($path) + { + // Only remove one slash in case of keys that have a preceding slash + if (substr($path, 0, 1) === '/') { + $path = substr($path, 1); + } + return '/' . $path; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureInterface.php new file mode 100644 index 000000000..cedfc45e8 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureInterface.php @@ -0,0 +1,45 @@ + true, + 's3control' => true, + 's3-outposts' => true, + 's3-object-lambda' => true, + 's3express' => true + ]; + + /** + * Resolves and signature provider and ensures a non-null return value. + * + * @param callable $provider Provider function to invoke. + * @param string $version Signature version. + * @param string $service Service name. + * @param string $region Region name. + * + * @return SignatureInterface + * @throws UnresolvedSignatureException + */ + public static function resolve(callable $provider, $version, $service, $region) + { + $result = $provider($version, $service, $region); + if ($result instanceof SignatureInterface + || $result instanceof BearerTokenAuthorization + ) { + return $result; + } + + throw new UnresolvedSignatureException( + "Unable to resolve a signature for $version/$service/$region.\n" + . "Valid signature versions include v4 and anonymous." + ); + } + + /** + * Default SDK signature provider. + * + * @return callable + */ + public static function defaultProvider() + { + return self::memoize(self::version()); + } + + /** + * Creates a signature provider that caches previously created signature + * objects. The computed cache key is the concatenation of the version, + * service, and region. + * + * @param callable $provider Signature provider to wrap. + * + * @return callable + */ + public static function memoize(callable $provider) + { + $cache = []; + return function ($version, $service, $region) use (&$cache, $provider) { + $key = "($version)($service)($region)"; + if (!isset($cache[$key])) { + $cache[$key] = $provider($version, $service, $region); + } + return $cache[$key]; + }; + } + + /** + * Creates signature objects from known signature versions. + * + * This provider currently recognizes the following signature versions: + * + * - v4: Signature version 4. + * - anonymous: Does not sign requests. + * + * @return callable + */ + public static function version() + { + return function ($version, $service, $region) { + switch ($version) { + case 'v4-s3express': + return new S3ExpressSignature($service, $region); + case 's3v4': + case 'v4': + return !empty(self::$s3v4SignedServices[$service]) + ? new S3SignatureV4($service, $region) + : new SignatureV4($service, $region); + case 'v4a': + return !empty(self::$s3v4SignedServices[$service]) + ? new S3SignatureV4($service, $region, ['use_v4a' => true]) + : new SignatureV4($service, $region, ['use_v4a' => true]); + case 'v4-unsigned-body': + return !empty(self::$s3v4SignedServices[$service]) + ? new S3SignatureV4($service, $region, ['unsigned-body' => 'true']) + : new SignatureV4($service, $region, ['unsigned-body' => 'true']); + case 'bearer': + return new BearerTokenAuthorization(); + case 'anonymous': + return new AnonymousSignature(); + default: + return null; + } + }; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureTrait.php new file mode 100644 index 000000000..5dcfe9dfa --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureTrait.php @@ -0,0 +1,48 @@ +cache[$k])) { + // Clear the cache when it reaches 50 entries + if (++$this->cacheSize > 50) { + $this->cache = []; + $this->cacheSize = 0; + } + + $dateKey = hash_hmac( + 'sha256', + $shortDate, + "AWS4{$secretKey}", + true + ); + $regionKey = hash_hmac('sha256', $region, $dateKey, true); + $serviceKey = hash_hmac('sha256', $service, $regionKey, true); + $this->cache[$k] = hash_hmac( + 'sha256', + 'aws4_request', + $serviceKey, + true + ); + } + return $this->cache[$k]; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureV4.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureV4.php new file mode 100644 index 000000000..74c3940fc --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Signature/SignatureV4.php @@ -0,0 +1,584 @@ + true, + 'content-type' => true, + 'content-length' => true, + 'expect' => true, + 'max-forwards' => true, + 'pragma' => true, + 'range' => true, + 'te' => true, + 'if-match' => true, + 'if-none-match' => true, + 'if-modified-since' => true, + 'if-unmodified-since' => true, + 'if-range' => true, + 'accept' => true, + 'authorization' => true, + 'proxy-authorization' => true, + 'from' => true, + 'referer' => true, + 'user-agent' => true, + 'X-Amz-User-Agent' => true, + 'x-amzn-trace-id' => true, + 'aws-sdk-invocation-id' => true, + 'aws-sdk-retry' => true, + ]; + } + + /** + * @param string $service Service name to use when signing + * @param string $region Region name to use when signing + * @param array $options Array of configuration options used when signing + * - unsigned-body: Flag to make request have unsigned payload. + * Unsigned body is used primarily for streaming requests. + */ + public function __construct($service, $region, array $options = []) + { + $this->service = $service; + $this->region = $region; + $this->unsigned = isset($options['unsigned-body']) ? $options['unsigned-body'] : false; + $this->useV4a = isset($options['use_v4a']) && $options['use_v4a'] === true; + } + + /** + * {@inheritdoc} + */ + public function signRequest( + RequestInterface $request, + CredentialsInterface $credentials, + $signingService = null + ) { + $ldt = gmdate(self::ISO8601_BASIC); + $sdt = substr($ldt, 0, 8); + $parsed = $this->parseRequest($request); + $parsed['headers']['X-Amz-Date'] = [$ldt]; + + if ($token = $credentials->getSecurityToken()) { + $parsed['headers']['X-Amz-Security-Token'] = [$token]; + } + $service = isset($signingService) ? $signingService : $this->service; + + if ($this->useV4a) { + return $this->signWithV4a($credentials, $request, $service); + } + + $cs = $this->createScope($sdt, $this->region, $service); + $payload = $this->getPayload($request); + + if ($payload == self::UNSIGNED_PAYLOAD) { + $parsed['headers'][self::AMZ_CONTENT_SHA256_HEADER] = [$payload]; + } + + $context = $this->createContext($parsed, $payload); + $toSign = $this->createStringToSign($ldt, $cs, $context['creq']); + $signingKey = $this->getSigningKey( + $sdt, + $this->region, + $service, + $credentials->getSecretKey() + ); + $signature = hash_hmac('sha256', $toSign, $signingKey); + $parsed['headers']['Authorization'] = [ + "AWS4-HMAC-SHA256 " + . "Credential={$credentials->getAccessKeyId()}/{$cs}, " + . "SignedHeaders={$context['headers']}, Signature={$signature}" + ]; + + return $this->buildRequest($parsed); + } + + /** + * Get the headers that were used to pre-sign the request. + * Used for the X-Amz-SignedHeaders header. + * + * @param array $headers + * @return array + */ + private function getPresignHeaders(array $headers) + { + $presignHeaders = []; + $blacklist = $this->getHeaderBlacklist(); + foreach ($headers as $name => $value) { + $lName = strtolower($name); + if (!isset($blacklist[$lName]) + && $name !== self::AMZ_CONTENT_SHA256_HEADER + ) { + $presignHeaders[] = $lName; + } + } + return $presignHeaders; + } + + /** + * {@inheritdoc} + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ) { + $startTimestamp = isset($options['start_time']) + ? $this->convertToTimestamp($options['start_time'], null) + : time(); + $expiresTimestamp = $this->convertToTimestamp($expires, $startTimestamp); + + if ($this->useV4a) { + return $this->presignWithV4a( + $request, + $credentials, + $this->convertExpires($expiresTimestamp, $startTimestamp) + ); + } + + $parsed = $this->createPresignedRequest($request, $credentials); + + $payload = $this->getPresignedPayload($request); + $httpDate = gmdate(self::ISO8601_BASIC, $startTimestamp); + $shortDate = substr($httpDate, 0, 8); + $scope = $this->createScope($shortDate, $this->region, $this->service); + $credential = $credentials->getAccessKeyId() . '/' . $scope; + if ($credentials->getSecurityToken()) { + unset($parsed['headers']['X-Amz-Security-Token']); + } + $parsed['query']['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'; + $parsed['query']['X-Amz-Credential'] = $credential; + $parsed['query']['X-Amz-Date'] = gmdate('Ymd\THis\Z', $startTimestamp); + $parsed['query']['X-Amz-SignedHeaders'] = implode(';', $this->getPresignHeaders($parsed['headers'])); + $parsed['query']['X-Amz-Expires'] = $this->convertExpires($expiresTimestamp, $startTimestamp); + $context = $this->createContext($parsed, $payload); + $stringToSign = $this->createStringToSign($httpDate, $scope, $context['creq']); + $key = $this->getSigningKey( + $shortDate, + $this->region, + $this->service, + $credentials->getSecretKey() + ); + $parsed['query']['X-Amz-Signature'] = hash_hmac('sha256', $stringToSign, $key); + + return $this->buildRequest($parsed); + } + + /** + * Converts a POST request to a GET request by moving POST fields into the + * query string. + * + * Useful for pre-signing query protocol requests. + * + * @param RequestInterface $request Request to clone + * + * @return RequestInterface + * @throws \InvalidArgumentException if the method is not POST + */ + public static function convertPostToGet(RequestInterface $request, $additionalQueryParams = "") + { + if ($request->getMethod() !== 'POST') { + throw new \InvalidArgumentException('Expected a POST request but ' + . 'received a ' . $request->getMethod() . ' request.'); + } + + $sr = $request->withMethod('GET') + ->withBody(Psr7\Utils::streamFor('')) + ->withoutHeader('Content-Type') + ->withoutHeader('Content-Length'); + + // Move POST fields to the query if they are present + if ($request->getHeaderLine('Content-Type') === 'application/x-www-form-urlencoded') { + $body = (string) $request->getBody() . $additionalQueryParams; + $sr = $sr->withUri($sr->getUri()->withQuery($body)); + } + + return $sr; + } + + protected function getPayload(RequestInterface $request) + { + if ($this->unsigned && $request->getUri()->getScheme() == 'https') { + return self::UNSIGNED_PAYLOAD; + } + // Calculate the request signature payload + if ($request->hasHeader(self::AMZ_CONTENT_SHA256_HEADER)) { + // Handle streaming operations (e.g. Glacier.UploadArchive) + return $request->getHeaderLine(self::AMZ_CONTENT_SHA256_HEADER); + } + + if (!$request->getBody()->isSeekable()) { + throw new CouldNotCreateChecksumException('sha256'); + } + + try { + return Psr7\Utils::hash($request->getBody(), 'sha256'); + } catch (\Exception $e) { + throw new CouldNotCreateChecksumException('sha256', $e); + } + } + + protected function getPresignedPayload(RequestInterface $request) + { + return $this->getPayload($request); + } + + protected function createCanonicalizedPath($path) + { + $doubleEncoded = rawurlencode(ltrim($path, '/')); + + return '/' . str_replace('%2F', '/', $doubleEncoded); + } + + private function createStringToSign($longDate, $credentialScope, $creq) + { + $hash = hash('sha256', $creq); + + return "AWS4-HMAC-SHA256\n{$longDate}\n{$credentialScope}\n{$hash}"; + } + + private function createPresignedRequest( + RequestInterface $request, + CredentialsInterface $credentials + ) { + $parsedRequest = $this->parseRequest($request); + + // Make sure to handle temporary credentials + if ($token = $credentials->getSecurityToken()) { + $parsedRequest['headers']['X-Amz-Security-Token'] = [$token]; + } + + return $this->moveHeadersToQuery($parsedRequest); + } + + /** + * @param array $parsedRequest + * @param string $payload Hash of the request payload + * @return array Returns an array of context information + */ + private function createContext(array $parsedRequest, $payload) + { + $blacklist = $this->getHeaderBlacklist(); + + // Normalize the path as required by SigV4 + $canon = $parsedRequest['method'] . "\n" + . $this->createCanonicalizedPath($parsedRequest['path']) . "\n" + . $this->getCanonicalizedQuery($parsedRequest['query']) . "\n"; + + // Case-insensitively aggregate all of the headers. + $aggregate = []; + foreach ($parsedRequest['headers'] as $key => $values) { + $key = strtolower($key); + if (!isset($blacklist[$key])) { + foreach ($values as $v) { + $aggregate[$key][] = $v; + } + } + } + + ksort($aggregate); + $canonHeaders = []; + foreach ($aggregate as $k => $v) { + if (count($v) > 0) { + sort($v); + } + $canonHeaders[] = $k . ':' . preg_replace('/\s+/', ' ', implode(',', $v)); + } + + $signedHeadersString = implode(';', array_keys($aggregate)); + $canon .= implode("\n", $canonHeaders) . "\n\n" + . $signedHeadersString . "\n" + . $payload; + + return ['creq' => $canon, 'headers' => $signedHeadersString]; + } + + private function getCanonicalizedQuery(array $query) + { + unset($query['X-Amz-Signature']); + + if (!$query) { + return ''; + } + + $qs = ''; + ksort($query); + foreach ($query as $k => $v) { + if (!is_array($v)) { + $qs .= rawurlencode($k) . '=' . rawurlencode($v !== null ? $v : '') . '&'; + } else { + sort($v); + foreach ($v as $value) { + $qs .= rawurlencode($k) . '=' . rawurlencode($value !== null ? $value : '') . '&'; + } + } + } + + return substr($qs, 0, -1); + } + + private function convertToTimestamp($dateValue, $relativeTimeBase = null) + { + if ($dateValue instanceof \DateTimeInterface) { + $timestamp = $dateValue->getTimestamp(); + } elseif (!is_numeric($dateValue)) { + $timestamp = strtotime($dateValue, + $relativeTimeBase === null ? time() : $relativeTimeBase + ); + } else { + $timestamp = $dateValue; + } + + return $timestamp; + } + + private function convertExpires($expiresTimestamp, $startTimestamp) + { + $duration = $expiresTimestamp - $startTimestamp; + + // Ensure that the duration of the signature is not longer than a week + if ($duration > 604800) { + throw new \InvalidArgumentException('The expiration date of a ' + . 'signature version 4 presigned URL must be less than one ' + . 'week'); + } + + return $duration; + } + + private function moveHeadersToQuery(array $parsedRequest) + { + //x-amz-user-agent shouldn't be put in a query param + unset($parsedRequest['headers']['X-Amz-User-Agent']); + + foreach ($parsedRequest['headers'] as $name => $header) { + $lname = strtolower($name); + if (substr($lname, 0, 5) == 'x-amz') { + $parsedRequest['query'][$name] = $header; + } + $blacklist = $this->getHeaderBlacklist(); + if (isset($blacklist[$lname]) + || $lname === strtolower(self::AMZ_CONTENT_SHA256_HEADER) + ) { + unset($parsedRequest['headers'][$name]); + } + } + + return $parsedRequest; + } + + private function parseRequest(RequestInterface $request) + { + // Clean up any previously set headers. + /** @var RequestInterface $request */ + $request = $request + ->withoutHeader('X-Amz-Date') + ->withoutHeader('Date') + ->withoutHeader('Authorization'); + $uri = $request->getUri(); + + return [ + 'method' => $request->getMethod(), + 'path' => $uri->getPath(), + 'query' => Psr7\Query::parse($uri->getQuery()), + 'uri' => $uri, + 'headers' => $request->getHeaders(), + 'body' => $request->getBody(), + 'version' => $request->getProtocolVersion() + ]; + } + + private function buildRequest(array $req) + { + if ($req['query']) { + $req['uri'] = $req['uri']->withQuery(Psr7\Query::build($req['query'])); + } + + return new Psr7\Request( + $req['method'], + $req['uri'], + $req['headers'], + $req['body'], + $req['version'] + ); + } + + protected function verifyCRTLoaded() + { + if (!extension_loaded('awscrt')) { + throw new CommonRuntimeException( + "AWS Common Runtime for PHP is required to use Signature V4A" + . ". Please install it using the instructions found at" + . " https://github.com/aws/aws-sdk-php/blob/master/CRT_INSTRUCTIONS.md" + ); + } + } + + protected function createCRTStaticCredentialsProvider($credentials) + { + return new StaticCredentialsProvider([ + 'access_key_id' => $credentials->getAccessKeyId(), + 'secret_access_key' => $credentials->getSecretKey(), + 'session_token' => $credentials->getSecurityToken(), + ]); + } + + private function removeIllegalV4aHeaders(&$request) + { + static $illegalV4aHeaders = [ + self::AMZ_CONTENT_SHA256_HEADER, + 'aws-sdk-invocation-id', + 'aws-sdk-retry', + 'x-amz-region-set', + 'transfer-encoding' + ]; + $storedHeaders = []; + + foreach ($illegalV4aHeaders as $header) { + if ($request->hasHeader($header)) { + $storedHeaders[$header] = $request->getHeader($header); + $request = $request->withoutHeader($header); + } + } + + return $storedHeaders; + } + + private function CRTRequestFromGuzzleRequest($request) + { + return new Request( + $request->getMethod(), + (string) $request->getUri(), + [], //leave empty as the query is parsed from the uri object + array_map(function ($header) {return $header[0];}, $request->getHeaders()) + ); + } + + /** + * @param CredentialsInterface $credentials + * @param RequestInterface $request + * @param $signingService + * @param SigningConfigAWS|null $signingConfig + * @return RequestInterface + */ + protected function signWithV4a( + CredentialsInterface $credentials, + RequestInterface $request, + $signingService, + ?SigningConfigAWS $signingConfig = null + ){ + $this->verifyCRTLoaded(); + $signingConfig = $signingConfig ?? new SigningConfigAWS([ + 'algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => $this->createCRTStaticCredentialsProvider($credentials), + 'signed_body_value' => $this->getPayload($request), + 'should_normalize_uri_path' => true, + 'use_double_uri_encode' => true, + 'region' => $this->region, + 'service' => $signingService, + 'date' => time(), + ]); + + $removedIllegalHeaders = $this->removeIllegalV4aHeaders($request); + $http_request = $this->CRTRequestFromGuzzleRequest($request); + + Signing::signRequestAws( + Signable::fromHttpRequest($http_request), + $signingConfig, function ($signing_result, $error_code) use (&$http_request) { + $signing_result->applyToHttpRequest($http_request); + }); + foreach ($removedIllegalHeaders as $header => $value) { + $request = $request->withHeader($header, $value); + } + + $sigV4AHeaders = $http_request->headers(); + foreach ($sigV4AHeaders->toArray() as $h => $v) { + $request = $request->withHeader($h, $v); + } + + return $request; + } + + protected function presignWithV4a( + RequestInterface $request, + CredentialsInterface $credentials, + $expires + ) + { + $this->verifyCRTLoaded(); + $credentials_provider = $this->createCRTStaticCredentialsProvider($credentials); + $signingConfig = new SigningConfigAWS([ + 'algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, + 'signature_type' => SignatureType::HTTP_REQUEST_QUERY_PARAMS, + 'credentials_provider' => $credentials_provider, + 'signed_body_value' => $this->getPresignedPayload($request), + 'region' => "*", + 'service' => $this->service, + 'date' => time(), + 'expiration_in_seconds' => $expires + ]); + + $this->removeIllegalV4aHeaders($request); + foreach ($this->getHeaderBlacklist() as $headerName => $headerValue) { + if ($request->hasHeader($headerName)) { + $request = $request->withoutHeader($headerName); + } + } + + $http_request = $this->CRTRequestFromGuzzleRequest($request); + Signing::signRequestAws( + Signable::fromHttpRequest($http_request), + $signingConfig, function ($signing_result, $error_code) use (&$http_request) { + $signing_result->applyToHttpRequest($http_request); + }); + + return $request->withUri( + new Psr7\Uri($http_request->pathAndQuery()) + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sns/Exception/SnsException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sns/Exception/SnsException.php new file mode 100644 index 000000000..cc2c245ce --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sns/Exception/SnsException.php @@ -0,0 +1,9 @@ +nextHandler = $nextHandler; + $this->service = $service; + } + + public function __invoke(CommandInterface $command, RequestInterface $request) + { + $nextHandler = $this->nextHandler; + + $operation = $this->service->getOperation($command->getName()); + $contentLength = $request->getHeader('content-length'); + $hasStreaming = false; + $requiresLength = false; + + // Check if any present input member is a stream and requires the + // content length + foreach ($operation->getInput()->getMembers() as $name => $member) { + if (!empty($member['streaming']) && isset($command[$name])) { + $hasStreaming = true; + if (!empty($member['requiresLength'])) { + $requiresLength = true; + } + } + } + + if ($hasStreaming) { + + // Add 'transfer-encoding' header if payload size not required to + // to be calculated and not already known + if (empty($requiresLength) + && empty($contentLength) + && isset($operation['authtype']) + && $operation['authtype'] == 'v4-unsigned-body' + ) { + $request = $request->withHeader('transfer-encoding', 'chunked'); + + // Otherwise, make sure 'content-length' header is added + } else { + if (empty($contentLength)) { + $size = $request->getBody()->getSize(); + if (is_null($size)) { + throw new IncalculablePayloadException('Payload' + . ' content length is required and can not be' + . ' calculated.'); + } + $request = $request->withHeader( + 'Content-Length', + $size + ); + } + } + } + + return $nextHandler($command, $request); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/Exception/StsException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/Exception/StsException.php new file mode 100644 index 000000000..81cff402e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/Exception/StsException.php @@ -0,0 +1,9 @@ +endpointsType = strtolower($endpointsType); + $this->isFallback = $isFallback; + if (!in_array($this->endpointsType, ['legacy', 'regional'])) { + throw new \InvalidArgumentException( + "Configuration parameter must either be 'legacy' or 'regional'." + ); + } + } + + /** + * {@inheritdoc} + */ + public function getEndpointsType() + { + return $this->endpointsType; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return [ + 'endpoints_type' => $this->getEndpointsType() + ]; + } + + public function isFallback() + { + return $this->isFallback; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/ConfigurationInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/ConfigurationInterface.php new file mode 100644 index 000000000..41d543b8c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/ConfigurationInterface.php @@ -0,0 +1,22 @@ + + * use Aws\Sts\RegionalEndpoints\ConfigurationProvider; + * $provider = ConfigurationProvider::defaultProvider(); + * // Returns a ConfigurationInterface or throws. + * $config = $provider()->wait(); + * + * + * Configuration providers can be composed to create configuration using + * conditional logic that can create different configurations in different + * environments. You can compose multiple providers into a single provider using + * {@see \Aws\Sts\RegionalEndpoints\ConfigurationProvider::chain}. This function + * accepts providers as variadic arguments and returns a new function that will + * invoke each provider until a successful configuration is returned. + * + * + * // First try an INI file at this location. + * $a = ConfigurationProvider::ini(null, '/path/to/file.ini'); + * // Then try an INI file at this location. + * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini'); + * // Then try loading from environment variables. + * $c = ConfigurationProvider::env(); + * // Combine the three providers together. + * $composed = ConfigurationProvider::chain($a, $b, $c); + * // Returns a promise that is fulfilled with a configuration or throws. + * $promise = $composed(); + * // Wait on the configuration to resolve. + * $config = $promise->wait(); + * + */ +class ConfigurationProvider extends AbstractConfigurationProvider + implements ConfigurationProviderInterface +{ + const DEFAULT_ENDPOINTS_TYPE = 'regional'; + const ENV_ENDPOINTS_TYPE = 'AWS_STS_REGIONAL_ENDPOINTS'; + const ENV_PROFILE = 'AWS_PROFILE'; + const INI_ENDPOINTS_TYPE = 'sts_regional_endpoints'; + + public static $cacheKey = 'aws_sts_regional_endpoints_config'; + + protected static $interfaceClass = ConfigurationInterface::class; + protected static $exceptionClass = ConfigurationException::class; + + /** + * Create a default config provider that first checks for environment + * variables, then checks for a specified profile in the environment-defined + * config file location (env variable is 'AWS_CONFIG_FILE', file location + * defaults to ~/.aws/config), then checks for the "default" profile in the + * environment-defined config file location, and failing those uses a default + * fallback set of configuration options. + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided config options. + * + * @param array $config + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $configProviders = [self::env()]; + if ( + !isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] != false + ) { + $configProviders[] = self::ini(); + } + $configProviders[] = self::fallback(); + + $memo = self::memoize( + call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders) + ); + + if (isset($config['sts_regional_endpoints']) + && $config['sts_regional_endpoints'] instanceof CacheInterface + ) { + return self::cache($memo, $config['sts_regional_endpoints'], self::$cacheKey); + } + + return $memo; + } + + /** + * Provider that creates config from environment variables. + * + * @return callable + */ + public static function env() + { + return function () { + // Use config from environment variables, if available + $endpointsType = getenv(self::ENV_ENDPOINTS_TYPE); + if (!empty($endpointsType)) { + return Promise\Create::promiseFor( + new Configuration($endpointsType) + ); + } + + return self::reject('Could not find environment variable config' + . ' in ' . self::ENV_ENDPOINTS_TYPE); + }; + } + + /** + * Fallback config options when other sources are not set. + * + * @return callable + */ + public static function fallback() + { + return function () { + return Promise\Create::promiseFor( + new Configuration(self::DEFAULT_ENDPOINTS_TYPE, true) + ); + }; + } + + /** + * Config provider that creates config using a config file whose location + * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to + * ~/.aws/config if not specified + * + * @param string|null $profile Profile to use. If not specified will use + * the "default" profile. + * @param string|null $filename If provided, uses a custom filename rather + * than looking in the default directory. + * + * @return callable + */ + public static function ini( + $profile = null, + $filename = null + ) { + $filename = $filename ?: (self::getDefaultConfigFilename()); + $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default'); + + return function () use ($profile, $filename) { + if (!@is_readable($filename)) { + return self::reject("Cannot read configuration from $filename"); + } + $data = \Aws\parse_ini_file($filename, true); + if ($data === false) { + return self::reject("Invalid config file: $filename"); + } + if (!isset($data[$profile])) { + return self::reject("'$profile' not found in config file"); + } + if (!isset($data[$profile][self::INI_ENDPOINTS_TYPE])) { + return self::reject("Required STS regional endpoints config values + not present in INI profile '{$profile}' ({$filename})"); + } + + return Promise\Create::promiseFor( + new Configuration($data[$profile][self::INI_ENDPOINTS_TYPE]) + ); + }; + } + + /** + * Unwraps a configuration object in whatever valid form it is in, + * always returning a ConfigurationInterface object. + * + * @param mixed $config + * @return ConfigurationInterface + * @throws \InvalidArgumentException + */ + public static function unwrap($config) + { + if (is_callable($config)) { + $config = $config(); + } + if ($config instanceof PromiseInterface) { + $config = $config->wait(); + } + if ($config instanceof ConfigurationInterface) { + return $config; + } + if (is_string($config)) { + return new Configuration($config); + } + if (is_array($config) && isset($config['endpoints_type'])) { + return new Configuration($config['endpoints_type']); + } + + throw new \InvalidArgumentException('Not a valid STS regional endpoints ' + . 'configuration argument.'); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/Exception/ConfigurationException.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/Exception/ConfigurationException.php new file mode 100644 index 000000000..668426672 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Sts/RegionalEndpoints/Exception/ConfigurationException.php @@ -0,0 +1,14 @@ +addBuiltIns($args); + parent::__construct($args); + } + + /** + * Creates credentials from the result of an STS operations + * + * @param Result $result Result of an STS operation + * + * @return Credentials + * @throws \InvalidArgumentException if the result contains no credentials + */ + public function createCredentials(Result $result, $source=null) + { + if (!$result->hasKey('Credentials')) { + throw new \InvalidArgumentException('Result contains no credentials'); + } + + $accountId = null; + if ($result->hasKey('AssumedRoleUser')) { + $parsedArn = ArnParser::parse($result->get('AssumedRoleUser')['Arn']); + $accountId = $parsedArn->getAccountId(); + } elseif ($result->hasKey('FederatedUser')) { + $parsedArn = ArnParser::parse($result->get('FederatedUser')['Arn']); + $accountId = $parsedArn->getAccountId(); + } + + $credentials = $result['Credentials']; + $expiration = isset($credentials['Expiration']) && $credentials['Expiration'] instanceof \DateTimeInterface + ? (int) $credentials['Expiration']->format('U') + : null; + + return new Credentials( + $credentials['AccessKeyId'], + $credentials['SecretAccessKey'], + isset($credentials['SessionToken']) ? $credentials['SessionToken'] : null, + $expiration, + $accountId, + $source + ); + } + + /** + * Adds service-specific client built-in value + * + * @return void + */ + private function addBuiltIns($args) + { + $key = 'AWS::STS::UseGlobalEndpoint'; + $result = $args['sts_regional_endpoints'] instanceof \Closure ? + $args['sts_regional_endpoints']()->wait() : $args['sts_regional_endpoints']; + + if (is_string($result)) { + if ($result === 'regional') { + $value = false; + } else if ($result === 'legacy') { + $value = true; + } else { + return; + } + } else { + if ($result->getEndpointsType() === 'regional') { + $value = false; + } else { + $value = true; + } + } + + $this->clientBuiltIns[$key] = $value; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BearerTokenAuthorization.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BearerTokenAuthorization.php new file mode 100644 index 000000000..7d830f3b2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BearerTokenAuthorization.php @@ -0,0 +1,33 @@ +getToken())) { + throw new InvalidArgumentException( + "Cannot authorize a request with an empty token" + ); + } + $accessToken = $token->getToken(); + return $request->withHeader('Authorization', "Bearer {$accessToken}"); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BedrockTokenProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BedrockTokenProvider.php new file mode 100644 index 000000000..3539abace --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/BedrockTokenProvider.php @@ -0,0 +1,102 @@ + self::env(self::TOKEN_ENV_KEY)]; + + return self::memoize( + call_user_func_array( + [TokenProvider::class, 'chain'], + array_values($defaultChain) + ) + ); + } + + /** + * Token provider that creates a token from an environment variable. + * + * @param string $configKey The configuration key that will be transformed + * to an environment variable name by ConfigurationResolver + * + * @return callable + */ + public static function env(string $configKey): callable + { + return static function () use ($configKey) { + $tokenValue = ConfigurationResolver::env($configKey); + if (empty($tokenValue)) { + return Promise\Create::rejectionFor( + new TokenException( + "No token found in environment variable " . + ConfigurationResolver::$envPrefix . strtoupper($configKey) + ) + ); + } + + return Promise\Create::promiseFor(new Token($tokenValue)); + }; + } + + /** + * Create a token provider from a raw token value string. + * Bedrock bearer tokens sourced from env do not have an expiration + * + * @param string $tokenValue The bearer token value + * + * @return callable + */ + public static function fromTokenValue(string $tokenValue): callable + { + $token = new Token($tokenValue); + return self::fromToken($token); + } + + /** + * Create a Bedrock token provider if the service is 'bedrock' and a token is available. + * Sets auth scheme preference to `bearer` auth. + * + * @param array $args Configuration arguments containing 'config' array + * + * @return callable|null Returns a token provider if conditions are met, null otherwise + */ + public static function createIfAvailable(array &$args): ?callable + { + $tokenValue = ConfigurationResolver::env(self::TOKEN_ENV_KEY); + + if ($tokenValue) { + $authSchemePreference = $args['config']['auth_scheme_preference'] ?? []; + array_unshift($authSchemePreference, self::BEARER_AUTH); + $args['config']['auth_scheme_preference'] = $authSchemePreference; + + return self::fromTokenValue($tokenValue); + } + + return null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/ParsesIniTrait.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/ParsesIniTrait.php new file mode 100644 index 000000000..b96a6d97b --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/ParsesIniTrait.php @@ -0,0 +1,44 @@ + $profile) { + // standardize config profile names + $name = str_replace('profile ', '', $name); + $profileData[$name] = $profile; + } + + return $profileData; + } + + /** + * Gets the environment's HOME directory if available. + * + * @return null|string + */ + private static function getHomeDir() + { + // On Linux/Unix-like systems, use the HOME environment variable + if ($homeDir = getenv('HOME')) { + return $homeDir; + } + + // Get the HOMEDRIVE and HOMEPATH values for Windows hosts + $homeDrive = getenv('HOMEDRIVE'); + $homePath = getenv('HOMEPATH'); + + return ($homeDrive && $homePath) ? $homeDrive . $homePath : null; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/RefreshableTokenProviderInterface.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/RefreshableTokenProviderInterface.php new file mode 100644 index 000000000..4c88f3f02 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/RefreshableTokenProviderInterface.php @@ -0,0 +1,23 @@ +refreshToken = $refreshToken; + $this->clientId = $clientId; + $this->clientSecret = $clientSecret; + $this->registrationExpiresAt = $registrationExpiresAt; + $this->region = $region; + $this->startUrl = $startUrl; + } + + /** + * @return bool + */ + public function isExpired() + { + if (isset($this->registrationExpiresAt) + && time() >= $this->registrationExpiresAt + ) { + return false; + } + return $this->expires !== null && time() >= $this->expires; + } + + /** + * @return string|null + */ + public function getRefreshToken() + { + return $this->refreshToken; + } + + /** + * @return string|null + */ + public function getClientId() + { + return $this->clientId; + } + + /** + * @return string|null + */ + public function getClientSecret() + { + return $this->clientSecret; + } + + /** + * @return int|null + */ + public function getRegistrationExpiresAt() + { + return $this->registrationExpiresAt; + } + + /** + * @return string|null + */ + public function getRegion() + { + return $this->region; + } + + /** + * @return string|null + */ + public function getStartUrl() + { + return $this->startUrl; + } + + /** + * Creates an instance of SsoToken from a token data. + * + * @param $tokenData + * + * @return SsoToken + */ + public static function fromTokenData($tokenData): SsoToken + { + return new SsoToken( + $tokenData['accessToken'], + \strtotime($tokenData['expiresAt']), + isset($tokenData['refreshToken']) ? $tokenData['refreshToken'] : null, + isset($tokenData['clientId']) ? $tokenData['clientId'] : null, + isset($tokenData['clientSecret']) ? $tokenData['clientSecret'] : null, + isset($tokenData['registrationExpiresAt']) ? $tokenData['registrationExpiresAt'] : null, + isset($tokenData['region']) ? $tokenData['region'] : null, + isset($tokenData['startUrl']) ? $tokenData['startUrl'] : null + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/SsoTokenProvider.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/SsoTokenProvider.php new file mode 100644 index 000000000..13345a7cd --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/SsoTokenProvider.php @@ -0,0 +1,280 @@ +profileName = $this->resolveProfileName($profileName); + $this->configFilePath = $this->resolveConfigFile($configFilePath); + $this->ssoOidcClient = $ssoOidcClient; + } + + /** + * This method resolves the profile name to be used. The + * profile provided as instantiation argument takes precedence, + * followed by AWS_PROFILE env variable, otherwise `default` is + * used. + * + * @param string|null $argProfileName The profile provided as argument. + * + * @return string + */ + private function resolveProfileName($argProfileName): string + { + if (empty($argProfileName)) { + return getenv(self::ENV_PROFILE) ?: 'default'; + } else { + return $argProfileName; + } + } + + /** + * This method resolves the config file from where the profiles + * are going to be loaded from. If $argFileName is not empty then, + * it takes precedence over the default config file location. + * + * @param string|null $argConfigFilePath The config path provided as argument. + * + * @return string + */ + private function resolveConfigFile($argConfigFilePath): string + { + if (empty($argConfigFilePath)) { + return self::getHomeDir() . '/.aws/config'; + } else{ + return $argConfigFilePath; + } + } + + /** + * Loads cached sso credentials. + * + * @return Promise\PromiseInterface + */ + public function __invoke() + { + return Promise\Coroutine::of(function () { + if (empty($this->configFilePath) || !is_readable($this->configFilePath)) { + throw new TokenException("Cannot read profiles from {$this->configFilePath}"); + } + + $profiles = self::loadProfiles($this->configFilePath); + if (!isset($profiles[$this->profileName])) { + throw new TokenException("Profile `{$this->profileName}` does not exist in {$this->configFilePath}."); + } + + $profile = $profiles[$this->profileName]; + if (empty($profile['sso_session'])) { + throw new TokenException( + "Profile `{$this->profileName}` in {$this->configFilePath} must contain an sso_session." + ); + } + + $ssoSessionName = $profile['sso_session']; + $this->ssoSessionName = $ssoSessionName; + $profileSsoSession = 'sso-session ' . $ssoSessionName; + if (empty($profiles[$profileSsoSession])) { + throw new TokenException( + "Sso session `{$ssoSessionName}` does not exist in {$this->configFilePath}" + ); + } + + $sessionProfileData = $profiles[$profileSsoSession]; + foreach (['sso_start_url', 'sso_region'] as $requiredProp) { + if (empty($sessionProfileData[$requiredProp])) { + throw new TokenException( + "Sso session `{$ssoSessionName}` in {$this->configFilePath} is missing the required property `{$requiredProp}`" + ); + } + } + + $tokenData = $this->refresh(); + $tokenLocation = self::getTokenLocation($ssoSessionName); + $this->validateTokenData($tokenLocation, $tokenData); + $ssoToken = SsoToken::fromTokenData($tokenData); + // To make sure the token is not expired + if ($ssoToken->isExpired()) { + throw new TokenException("Cached SSO token returned an expired token."); + } + + yield $ssoToken; + }); + } + + /** + * This method attempt to refresh when possible. + * If a refresh is not possible then it just returns + * the current token data as it is. + * + * @return array + * @throws TokenException + */ + public function refresh(): array + { + $tokenLocation = self::getTokenLocation($this->ssoSessionName); + $tokenData = $this->getTokenData($tokenLocation); + if (!$this->shouldAttemptRefresh()) { + return $tokenData; + } + + if (null === $this->ssoOidcClient) { + throw new TokenException( + "Cannot refresh this token without an 'ssooidcClient' " + ); + } + + foreach (['clientId', 'clientSecret', 'refreshToken'] as $requiredProp) { + if (empty($tokenData[$requiredProp])) { + throw new TokenException( + "Cannot refresh this token without `{$requiredProp}` being set" + ); + } + } + + $response = $this->ssoOidcClient->createToken([ + 'clientId' => $tokenData['clientId'], + 'clientSecret' => $tokenData['clientSecret'], + 'grantType' => 'refresh_token', // REQUIRED + 'refreshToken' => $tokenData['refreshToken'], + ]); + if ($response['@metadata']['statusCode'] !== 200) { + throw new TokenException('Unable to create a new sso token'); + } + + $tokenData['accessToken'] = $response['accessToken']; + $tokenData['expiresAt'] = time () + $response['expiresIn']; + $tokenData['refreshToken'] = $response['refreshToken']; + + return $this->writeNewTokenDataToDisk($tokenData, $tokenLocation); + } + + /** + * This method checks for whether a token refresh should happen. + * It will return true just if more than 30 seconds has happened + * since last refresh, and if the expiration is within a 5-minutes + * window from the current time. + * + * @return bool + */ + public function shouldAttemptRefresh(): bool + { + $tokenLocation = self::getTokenLocation($this->ssoSessionName); + $tokenData = $this->getTokenData($tokenLocation); + if (empty($tokenData['expiresAt'])) { + throw new TokenException( + "Token file at $tokenLocation must contain an expiration date" + ); + } + + $tokenExpiresAt = strtotime($tokenData['expiresAt']); + $lastRefreshAt = filemtime($tokenLocation); + $now = \time(); + + // If last refresh happened after 30 seconds + // and if the token expiration is in the 5 minutes window + return ($now - $lastRefreshAt) > self::REFRESH_ATTEMPT_WINDOW_IN_SECS + && ($tokenExpiresAt - $now) < self::REFRESH_WINDOW_IN_SECS; + } + + /** + * @param $sso_session + * @return string + */ + public static function getTokenLocation($sso_session): string + { + return self::getHomeDir() + . '/.aws/sso/cache/' + . mb_convert_encoding(sha1($sso_session), "UTF-8") + . ".json"; + } + + /** + * @param $tokenLocation + * @return array + */ + function getTokenData($tokenLocation): array + { + if (empty($tokenLocation) || !is_readable($tokenLocation)) { + throw new TokenException("Unable to read token file at {$tokenLocation}"); + } + + return json_decode(file_get_contents($tokenLocation), true); + } + + /** + * @param $tokenData + * @param $tokenLocation + * @return mixed + */ + private function validateTokenData($tokenLocation, $tokenData) + { + foreach (['accessToken', 'expiresAt'] as $requiredProp) { + if (empty($tokenData[$requiredProp])) { + throw new TokenException( + "Token file at {$tokenLocation} must contain the required property `{$requiredProp}`" + ); + } + } + + $expiration = strtotime($tokenData['expiresAt']); + if ($expiration === false) { + throw new TokenException("Cached SSO token returned an invalid expiration"); + } elseif ($expiration < time()) { + throw new TokenException("Cached SSO token returned an expired token"); + } + + return $tokenData; + } + + /** + * @param array $tokenData + * @param string $tokenLocation + * + * @return array + */ + private function writeNewTokenDataToDisk(array $tokenData, $tokenLocation): array + { + $tokenData['expiresAt'] = gmdate( + 'Y-m-d\TH:i:s\Z', + $tokenData['expiresAt'] + ); + file_put_contents($tokenLocation, json_encode(array_filter($tokenData))); + + return $tokenData; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/Token.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/Token.php new file mode 100644 index 000000000..aef5cbb45 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/Token.php @@ -0,0 +1,110 @@ +token = $token; + $this->expires = $expires; + } + + /** + * Sets the state of a token object + * + * @param array $state array containing 'token' and 'expires' + */ + public static function __set_state(array $state) + { + return new self( + $state['token'], + $state['expires'] + ); + } + + /** + * @return string + */ + public function getToken() + { + return $this->token; + } + + /** + * @return int + */ + public function getExpiration() + { + return $this->expires; + } + + /** + * @return bool + */ + public function isExpired() + { + return $this->expires !== null && time() >= $this->expires; + } + + /** + * @return array + */ + public function toArray() + { + return [ + 'token' => $this->token, + 'expires' => $this->expires + ]; + } + + /** + * @return string + */ + public function serialize() + { + return json_encode($this->__serialize()); + } + + /** + * Sets the state of the object from serialized json data + */ + public function unserialize($serialized) + { + $data = json_decode($serialized, true); + + $this->__unserialize($data); + } + + /** + * @return array + */ + public function __serialize() + { + return $this->toArray(); + } + + /** + * Sets the state of this object from an array + */ + public function __unserialize($data) + { + $this->token = $data['token']; + $this->expires = $data['expires']; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/TokenAuthorization.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/TokenAuthorization.php new file mode 100644 index 000000000..3fab516fd --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Token/TokenAuthorization.php @@ -0,0 +1,24 @@ + + * use Aws\Token\TokenProvider; + * $provider = TokenProvider::defaultProvider(); + * // Returns a TokenInterface or throws. + * $token = $provider()->wait(); + * + * + * Token providers can be composed to create a token using conditional + * logic that can create different tokens in different environments. You + * can compose multiple providers into a single provider using + * {@see Aws\Token\TokenProvider::chain}. This function accepts + * providers as variadic arguments and returns a new function that will invoke + * each provider until a token is successfully returned. + */ +class TokenProvider +{ + const ENV_PROFILE = 'AWS_PROFILE'; + + use ParsesIniTrait; + + /** + * Create a default token provider tha checks for cached a SSO token from + * the CLI + * + * This provider is automatically wrapped in a memoize function that caches + * previously provided tokens. + * + * @param array $config Optional array of token provider options. + * + * @return callable + */ + public static function defaultProvider(array $config = []) + { + $cacheable = [ + 'sso', + ]; + + $defaultChain = []; + + if (!isset($config['use_aws_shared_config_files']) + || $config['use_aws_shared_config_files'] !== false + ) { + $profileName = getenv(self::ENV_PROFILE) ?: 'default'; + $defaultChain['sso'] = self::sso( + $profileName, + self::getHomeDir() . '/.aws/config', + $config + ); + } + + if (isset($config['token']) + && $config['token'] instanceof CacheInterface + ) { + foreach ($cacheable as $provider) { + if (isset($defaultChain[$provider])) { + $defaultChain[$provider] = self::cache( + $defaultChain[$provider], + $config['token'], + 'aws_cached_' . $provider . '_token' + ); + } + } + } + + return self::memoize( + call_user_func_array( + [__CLASS__, 'chain'], + array_values($defaultChain) + ) + ); + } + + /** + * Create a token provider function from a static token. + * + * @param TokenInterface $token + * + * @return callable + */ + public static function fromToken(TokenInterface $token) + { + $promise = Promise\Create::promiseFor($token); + + return static function () use ($promise) { + return $promise; + }; + } + + /** + * Creates an aggregate token provider that invokes the provided + * variadic providers one after the other until a provider returns + * a token. + * + * @return callable + */ + public static function chain() + { + $links = func_get_args(); + //Common use case for when aws_shared_config_files is false + if (empty($links)) { + return static function () { + return Promise\Create::promiseFor(false); + }; + } + + return static function () use ($links) { + /** @var callable $parent */ + $parent = array_shift($links); + $promise = $parent(); + while ($next = array_shift($links)) { + $promise = $promise->otherwise($next); + } + return $promise; + }; + } + + /** + * Wraps a token provider and caches a previously provided token. + * Ensures that cached tokens are refreshed when they expire. + * + * @param callable $provider Token provider function to wrap. + * @return callable + */ + public static function memoize(callable $provider) + { + return static function () use ($provider) { + static $result; + static $isConstant; + + // Constant tokens will be returned constantly. + if ($isConstant) { + return $result; + } + + // Create the initial promise that will be used as the cached value + // until it expires. + if (null === $result) { + $result = $provider(); + } + + // Return a token that could expire and refresh when needed. + return $result + ->then(function (TokenInterface $token) use ($provider, &$isConstant, &$result) { + // Determine if the token is constant. + if (!$token->getExpiration()) { + $isConstant = true; + return $token; + } + + if (!$token->isExpired()) { + return $token; + } + return $result = $provider(); + }) + ->otherwise(function($reason) use (&$result) { + // Cleanup rejected promise. + $result = null; + return Promise\Create::promiseFor(null); + }); + }; + } + + /** + * Wraps a token provider and saves provided token in an + * instance of Aws\CacheInterface. Forwards calls when no token found + * in cache and updates cache with the results. + * + * @param callable $provider Token provider function to wrap + * @param CacheInterface $cache Cache to store the token + * @param string|null $cacheKey (optional) Cache key to use + * + * @return callable + */ + public static function cache( + callable $provider, + CacheInterface $cache, + $cacheKey = null + ){ + $cacheKey = $cacheKey ?: 'aws_cached_token'; + + return static function () use ($provider, $cache, $cacheKey) { + $found = $cache->get($cacheKey); + if (is_array($found) && isset($found['token'])) { + $foundToken = $found['token']; + if ($foundToken instanceof TokenInterface) { + if (!$foundToken->isExpired()) { + return Promise\Create::promiseFor($foundToken); + } + if (isset($found['refreshMethod']) && is_callable($found['refreshMethod'])) { + return Promise\Create::promiseFor($found['refreshMethod']()); + } + } + } + + return $provider() + ->then(function (TokenInterface $token) use ( + $cache, + $cacheKey + ) { + $cache->set( + $cacheKey, + ['token' => $token], + null === $token->getExpiration() ? + 0 : $token->getExpiration() - time() + ); + + return $token; + }); + }; + } + + /** + * Gets profiles from the ~/.aws/config ini file + */ + private static function loadDefaultProfiles() + { + $profiles = []; + $configFile = self::getHomeDir() . '/.aws/config'; + + if (file_exists($configFile)) { + $configProfileData = \Aws\parse_ini_file($configFile, true, INI_SCANNER_RAW); + foreach ($configProfileData as $name => $profile) { + // standardize config profile names + $name = str_replace('profile ', '', $name); + if (!isset($profiles[$name])) { + $profiles[$name] = $profile; + } + } + } + + return $profiles; + } + + private static function reject($msg) + { + return new Promise\RejectedPromise(new TokenException($msg)); + } + + /** + * Token provider that creates a token from cached sso credentials + * + * @param string $profileName the name of the ini profile name + * @param string $filename the location of the ini file + * @param array $config configuration options + * + * @return SsoTokenProvider + * @see Aws\Token\SsoTokenProvider for $config details. + */ + public static function sso( + $profileName, + $filename, + $config = [] + ){ + $ssoClient = $config['ssoClient'] ?? null; + + return new SsoTokenProvider($profileName, $filename, $ssoClient); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/TraceMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/TraceMiddleware.php new file mode 100644 index 000000000..032043b8e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/TraceMiddleware.php @@ -0,0 +1,360 @@ + '[TOKEN]', + ]; + + private static $authStrings = [ + // S3Signature + '/AWSAccessKeyId=[A-Z0-9]{20}&/i' => 'AWSAccessKeyId=[KEY]&', + // SignatureV4 Signature and S3Signature + '/Signature=.+/i' => 'Signature=[SIGNATURE]', + // SignatureV4 access key ID + '/Credential=[A-Z0-9]{20}\//i' => 'Credential=[KEY]/', + // S3 signatures + '/AWS [A-Z0-9]{20}:.+/' => 'AWS AKI[KEY]:[SIGNATURE]', + // STS Presigned URLs + '/X-Amz-Security-Token=[^&]+/i' => 'X-Amz-Security-Token=[TOKEN]', + // Crypto *Stream Keys + '/\["key.{27,36}Stream.{9}\]=>\s+.{7}\d{2}\) "\X{16,64}"/U' => '["key":[CONTENT KEY]]', + ]; + + /** + * Configuration array can contain the following key value pairs. + * + * - logfn: (callable) Function that is invoked with log messages. By + * default, PHP's "echo" function will be utilized. + * - stream_size: (int) When the size of a stream is greater than this + * number, the stream data will not be logged. Set to "0" to not log any + * stream data. + * - scrub_auth: (bool) Set to false to disable the scrubbing of auth data + * from the logged messages. + * - http: (bool) Set to false to disable the "debug" feature of lower + * level HTTP adapters (e.g., verbose curl output). + * - auth_strings: (array) A mapping of authentication string regular + * expressions to scrubbed strings. These mappings are passed directly to + * preg_replace (e.g., preg_replace($key, $value, $debugOutput) if + * "scrub_auth" is set to true. + * - auth_headers: (array) A mapping of header names known to contain + * sensitive data to what the scrubbed value should be. The value of any + * headers contained in this array will be replaced with the if + * "scrub_auth" is set to true. + */ + public function __construct(array $config = [], ?Service $service = null) + { + $this->config = $config + [ + 'logfn' => function ($value) { echo $value; }, + 'stream_size' => 524288, + 'scrub_auth' => true, + 'http' => true, + 'auth_strings' => [], + 'auth_headers' => [], + ]; + + $this->config['auth_strings'] += self::$authStrings; + $this->config['auth_headers'] += self::$authHeaders; + $this->service = $service; + } + + public function __invoke($step, $name) + { + $this->prevOutput = $this->prevInput = []; + + return function (callable $next) use ($step, $name) { + return function ( + CommandInterface $command, + $request = null + ) use ($next, $step, $name) { + $this->createHttpDebug($command); + $start = microtime(true); + $this->stepInput([ + 'step' => $step, + 'name' => $name, + 'request' => $this->requestArray($request), + 'command' => $this->commandArray($command) + ]); + + return $next($command, $request)->then( + function ($value) use ($step, $name, $command, $start) { + $this->flushHttpDebug($command); + $this->stepOutput($start, [ + 'step' => $step, + 'name' => $name, + 'result' => $this->resultArray($value), + 'error' => null + ]); + return $value; + }, + function ($reason) use ($step, $name, $start, $command) { + $this->flushHttpDebug($command); + $this->stepOutput($start, [ + 'step' => $step, + 'name' => $name, + 'result' => null, + 'error' => $this->exceptionArray($reason) + ]); + return new RejectedPromise($reason); + } + ); + }; + }; + } + + private function stepInput($entry) + { + static $keys = ['command', 'request']; + $this->compareStep($this->prevInput, $entry, '-> Entering', $keys); + $this->write("\n"); + $this->prevInput = $entry; + } + + private function stepOutput($start, $entry) + { + static $keys = ['result', 'error']; + $this->compareStep($this->prevOutput, $entry, '<- Leaving', $keys); + $totalTime = microtime(true) - $start; + $this->write(" Inclusive step time: " . $totalTime . "\n\n"); + $this->prevOutput = $entry; + } + + private function compareStep(array $a, array $b, $title, array $keys) + { + $changes = []; + foreach ($keys as $key) { + $av = isset($a[$key]) ? $a[$key] : null; + $bv = isset($b[$key]) ? $b[$key] : null; + $this->compareArray($av, $bv, $key, $changes); + } + $str = "\n{$title} step {$b['step']}, name '{$b['name']}'"; + $str .= "\n" . str_repeat('-', strlen($str) - 1) . "\n\n "; + $str .= $changes + ? implode("\n ", str_replace("\n", "\n ", $changes)) + : 'no changes'; + $this->write($str . "\n"); + } + + private function commandArray(CommandInterface $cmd) + { + return [ + 'instance' => spl_object_hash($cmd), + 'name' => $cmd->getName(), + 'params' => $this->getRedactedArray($cmd) + ]; + } + + private function requestArray($request = null) + { + return !$request instanceof RequestInterface + ? [] + : array_filter([ + 'instance' => spl_object_hash($request), + 'method' => $request->getMethod(), + 'headers' => $this->redactHeaders($request->getHeaders()), + 'body' => $this->streamStr($request->getBody()), + 'scheme' => $request->getUri()->getScheme(), + 'port' => $request->getUri()->getPort(), + 'path' => $request->getUri()->getPath(), + 'query' => $request->getUri()->getQuery(), + ]); + } + + private function responseArray(?ResponseInterface $response = null) + { + return !$response ? [] : [ + 'instance' => spl_object_hash($response), + 'statusCode' => $response->getStatusCode(), + 'headers' => $this->redactHeaders($response->getHeaders()), + 'body' => $this->streamStr($response->getBody()) + ]; + } + + private function resultArray($value) + { + return $value instanceof ResultInterface + ? [ + 'instance' => spl_object_hash($value), + 'data' => $value->toArray() + ] : $value; + } + + private function exceptionArray($e) + { + if (!($e instanceof \Exception)) { + return $e; + } + + $result = [ + 'instance' => spl_object_hash($e), + 'class' => get_class($e), + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'trace' => $e->getTraceAsString(), + ]; + + if ($e instanceof AwsException) { + $result += [ + 'type' => $e->getAwsErrorType(), + 'code' => $e->getAwsErrorCode(), + 'requestId' => $e->getAwsRequestId(), + 'statusCode' => $e->getStatusCode(), + 'result' => $this->resultArray($e->getResult()), + 'request' => $this->requestArray($e->getRequest()), + 'response' => $this->responseArray($e->getResponse()), + ]; + } + + return $result; + } + + private function compareArray($a, $b, $path, array &$diff) + { + if ($a === $b) { + return; + } + + if (is_array($a)) { + $b = (array) $b; + $keys = array_unique(array_merge(array_keys($a), array_keys($b))); + foreach ($keys as $k) { + if (!array_key_exists($k, $a)) { + $this->compareArray(null, $b[$k], "{$path}.{$k}", $diff); + } elseif (!array_key_exists($k, $b)) { + $this->compareArray($a[$k], null, "{$path}.{$k}", $diff); + } else { + $this->compareArray($a[$k], $b[$k], "{$path}.{$k}", $diff); + } + } + } elseif ($a !== null && $b === null) { + $diff[] = "{$path} was unset"; + } elseif ($a === null && $b !== null) { + $diff[] = sprintf("%s was set to %s", $path, $this->str($b)); + } else { + $diff[] = sprintf("%s changed from %s to %s", $path, $this->str($a), $this->str($b)); + } + } + + private function str($value) + { + if (is_scalar($value)) { + return (string) $value; + } + + if ($value instanceof \Exception) { + $value = $this->exceptionArray($value); + } + + ob_start(); + var_dump($value); + return ob_get_clean(); + } + + private function streamStr(StreamInterface $body) + { + return $body->getSize() < $this->config['stream_size'] + ? (string) $body + : 'stream(size=' . $body->getSize() . ')'; + } + + private function createHttpDebug(CommandInterface $command) + { + if ($this->config['http'] && !isset($command['@http']['debug'])) { + $command['@http']['debug'] = fopen('php://temp', 'w+'); + } + } + + private function flushHttpDebug(CommandInterface $command) + { + if ($res = $command['@http']['debug']) { + if (is_resource($res)) { + rewind($res); + $this->write(stream_get_contents($res)); + fclose($res); + } + $command['@http']['debug'] = null; + } + } + + private function write($value) + { + if ($this->config['scrub_auth']) { + foreach ($this->config['auth_strings'] as $pattern => $replacement) { + $value = preg_replace_callback( + $pattern, + function ($matches) use ($replacement) { + return $replacement; + }, + $value + ); + } + } + + call_user_func($this->config['logfn'], $value); + } + + private function redactHeaders(array $headers) + { + if ($this->config['scrub_auth']) { + $headers = $this->config['auth_headers'] + $headers; + } + + return $headers; + } + + /** + * @param CommandInterface $cmd + * @return array + */ + private function getRedactedArray(CommandInterface $cmd) + { + if (!isset($this->service["shapes"])) { + return $cmd->toArray(); + } + $shapes = $this->service["shapes"]; + $cmdArray = $cmd->toArray(); + $iterator = new RecursiveIteratorIterator( + new RecursiveArrayIterator($cmdArray), + RecursiveIteratorIterator::SELF_FIRST + ); + foreach ($iterator as $parameter => $value) { + if (isset($shapes[$parameter]['sensitive']) && + $shapes[$parameter]['sensitive'] === true + ) { + $redactedValue = is_string($value) ? "[{$parameter}]" : ["[{$parameter}]"]; + $currentDepth = $iterator->getDepth(); + for ($subDepth = $currentDepth; $subDepth >= 0; $subDepth--) { + $subIterator = $iterator->getSubIterator($subDepth); + $subIterator->offsetSet( + $subIterator->key(), + ($subDepth === $currentDepth + ? $redactedValue + : $iterator->getSubIterator(($subDepth+1))->getArrayCopy() + ) + ); + } + } + } + return $iterator->getArrayCopy(); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/UserAgentMiddleware.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/UserAgentMiddleware.php new file mode 100644 index 000000000..afccc9781 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/UserAgentMiddleware.php @@ -0,0 +1,265 @@ +nextHandler = $nextHandler; + $this->args = $args; + } + + /** + * When invoked, its injects the user agent header into the + * request headers. + * + * @param CommandInterface $command + * @param RequestInterface $request + * + * @return mixed + */ + public function __invoke(CommandInterface $command, RequestInterface $request) + { + $handler = $this->nextHandler; + $this->metricsBuilder = MetricsBuilder::fromCommand($command); + $request = $this->requestWithUserAgentHeader($request); + + return $handler($command, $request); + } + + /** + * Builds the user agent header value, and injects it into the request + * headers. Then, it returns the mutated request. + * + * @param RequestInterface $request + * + * @return RequestInterface + */ + private function requestWithUserAgentHeader(RequestInterface $request): RequestInterface + { + $uaAppend = $this->args['ua_append'] ?? []; + $userAgentValue = array_merge( + $this->buildUserAgentValue(), + $uaAppend + ); + // It includes the user agent values just for the User-Agent header. + // The reason is that the SEP does not mention appending the + // metrics into the X-Amz-User-Agent header. + return $request->withHeader( + 'User-Agent', + implode(' ', array_merge( + $userAgentValue, + $request->getHeader('User-Agent') + )) + ); + } + + /** + * Builds the different user agent values. + * + * @return array + */ + private function buildUserAgentValue(): array + { + $userAgentValue = []; + foreach (self::$userAgentFnList as $fn) { + $val = $this->{$fn}(); + if (!empty($val)) { + $userAgentValue[] = $val; + } + } + + return $userAgentValue; + } + + /** + * Returns the user agent value for SDK version. + * + * @return string + */ + private function getSdkVersion(): string + { + return 'aws-sdk-php/' . Sdk::VERSION; + } + + /** + * Returns the user agent value for the agent version. + * + * @return string + */ + private function getUserAgentVersion(): string + { + return 'ua/' . self::AGENT_VERSION; + } + + /** + * Returns the user agent value for the hhvm version, but just + * when it is defined. + * + * @return string + */ + private function getHhvmVersion(): string + { + if (defined('HHVM_VERSION')) { + return 'HHVM/' . HHVM_VERSION; + } + + return ""; + } + + /** + * Returns the user agent value for the os version. + * + * @return string + */ + private function getOsName(): string + { + $disabledFunctions = explode(',', ini_get('disable_functions')); + if (function_exists('php_uname') + && !in_array('php_uname', $disabledFunctions, true) + ) { + $osName = "OS/" . php_uname('s') . '#' . php_uname('r'); + if (!empty($osName)) { + return $osName; + } + } + + return ""; + } + + /** + * Returns the user agent value for the php language used. + * + * @return string + */ + private function getLangVersion(): string + { + return 'lang/php#' . phpversion(); + } + + /** + * Returns the user agent value for the execution env. + * + * @return string + */ + private function getExecEnv(): string + { + if ($executionEnvironment = getenv('AWS_EXECUTION_ENV')) { + return $executionEnvironment; + } + + return ""; + } + + /** + * Returns the user agent value for endpoint discovery as cfg. + * This feature is deprecated. + * + * @return string + */ + private function getEndpointDiscovery(): string + { + $args = $this->args; + if (isset($args['endpoint_discovery'])) { + if (($args['endpoint_discovery'] instanceof Configuration + && $args['endpoint_discovery']->isEnabled()) + ) { + return 'cfg/endpoint-discovery'; + } elseif (is_array($args['endpoint_discovery']) + && isset($args['endpoint_discovery']['enabled']) + && $args['endpoint_discovery']['enabled'] + ) { + return 'cfg/endpoint-discovery'; + } + } + + return ""; + } + + /** + * Returns the user agent value for app id, but just when an + * app id was provided as a client argument. + * + * @return string + */ + private function getAppId(): string + { + if (empty($this->args['app_id'])) { + return ""; + } + + return 'app/' . $this->args['app_id']; + } + + /** + * Returns the user agent value for metrics. + * + * @return string + */ + private function getMetrics(): string + { + // Resolve first metrics related to client arguments. + $this->metricsBuilder->resolveAndAppendFromArgs($this->args); + // Build the metrics. + $metricsEncoded = $this->metricsBuilder->build(); + if (empty($metricsEncoded)) { + return ""; + } + + return "m/" . $metricsEncoded; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Waiter.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Waiter.php new file mode 100644 index 000000000..59abdcca5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/Waiter.php @@ -0,0 +1,285 @@ + 0, 'before' => null]; + + /** @var array Required configuration options. */ + private static $required = [ + 'acceptors', + 'delay', + 'maxAttempts', + 'operation', + ]; + + /** + * The array of configuration options include: + * + * - acceptors: (array) Array of acceptor options + * - delay: (int) Number of seconds to delay between attempts + * - maxAttempts: (int) Maximum number of attempts before failing + * - operation: (string) Name of the API operation to use for polling + * - before: (callable) Invoked before attempts. Accepts command and tries. + * + * @param AwsClientInterface $client Client used to execute commands. + * @param string $name Waiter name. + * @param array $args Command arguments. + * @param array $config Waiter config that overrides defaults. + * + * @throws \InvalidArgumentException if the configuration is incomplete. + */ + public function __construct( + AwsClientInterface $client, + $name, + array $args = [], + array $config = [] + ) { + $this->client = $client; + $this->name = $name; + $this->args = $args; + + // Prepare and validate config. + $this->config = $config + self::$defaults; + foreach (self::$required as $key) { + if (!isset($this->config[$key])) { + throw new \InvalidArgumentException( + 'The provided waiter configuration was incomplete.' + ); + } + } + if ($this->config['before'] && !is_callable($this->config['before'])) { + throw new \InvalidArgumentException( + 'The provided "before" callback is not callable.' + ); + } + MetricsBuilder::appendMetricsCaptureMiddleware( + $this->client->getHandlerList(), + MetricsBuilder::WAITER + ); + } + + /** + * @return Coroutine + */ + public function promise(): PromiseInterface + { + return Coroutine::of(function () { + $name = $this->config['operation']; + for ($state = 'retry', $attempt = 1; $state === 'retry'; $attempt++) { + // Execute the operation. + $args = $this->getArgsForAttempt($attempt); + $command = $this->client->getCommand($name, $args); + try { + if ($this->config['before']) { + $this->config['before']($command, $attempt); + } + $result = (yield $this->client->executeAsync($command)); + } catch (AwsException $e) { + $result = $e; + } + + // Determine the waiter's state and what to do next. + $state = $this->determineState($result); + if ($state === 'success') { + yield $command; + } elseif ($state === 'failed') { + $msg = "The {$this->name} waiter entered a failure state."; + if ($result instanceof \Exception) { + $msg .= ' Reason: ' . $result->getMessage(); + } + yield new RejectedPromise(new \RuntimeException($msg)); + } elseif ($state === 'retry' + && $attempt >= $this->config['maxAttempts'] + ) { + $state = 'failed'; + yield new RejectedPromise(new \RuntimeException( + "The {$this->name} waiter failed after attempt #{$attempt}." + )); + } + } + }); + } + + /** + * Gets the operation arguments for the attempt, including the delay. + * + * @param $attempt Number of the current attempt. + * + * @return mixed integer + */ + private function getArgsForAttempt($attempt) + { + $args = $this->args; + + // Determine the delay. + $delay = ($attempt === 1) + ? $this->config['initDelay'] + : $this->config['delay']; + if (is_callable($delay)) { + $delay = $delay($attempt); + } + + // Set the delay. (Note: handlers except delay in milliseconds.) + if (!isset($args['@http'])) { + $args['@http'] = []; + } + $args['@http']['delay'] = $delay * 1000; + + return $args; + } + + /** + * Determines the state of the waiter attempt, based on the result of + * polling the resource. A waiter can have the state of "success", "failed", + * or "retry". + * + * @param mixed $result + * + * @return string Will be "success", "failed", or "retry" + */ + private function determineState($result) + { + foreach ($this->config['acceptors'] as $acceptor) { + $matcher = 'matches' . ucfirst($acceptor['matcher']); + if ($this->{$matcher}($result, $acceptor)) { + return $acceptor['state']; + } + } + + return $result instanceof \Exception ? 'failed' : 'retry'; + } + + /** + * @param Result $result Result or exception. + * @param array $acceptor Acceptor configuration being checked. + * + * @return bool + */ + private function matchesPath($result, array $acceptor) + { + return $result instanceof ResultInterface + && $acceptor['expected'] === $result->search($acceptor['argument']); + } + + /** + * @param Result $result Result or exception. + * @param array $acceptor Acceptor configuration being checked. + * + * @return bool + */ + private function matchesPathAll($result, array $acceptor) + { + if (!($result instanceof ResultInterface)) { + return false; + } + + $actuals = $result->search($acceptor['argument']) ?: []; + // If is empty or not evaluates to an array it must return false. + if (empty($actuals) || !is_array($actuals)) { + return false; + } + + foreach ($actuals as $actual) { + if ($actual != $acceptor['expected']) { + return false; + } + } + + return true; + } + + /** + * @param Result $result Result or exception. + * @param array $acceptor Acceptor configuration being checked. + * + * @return bool + */ + private function matchesPathAny($result, array $acceptor) + { + if (!($result instanceof ResultInterface)) { + return false; + } + + $actuals = $result->search($acceptor['argument']) ?: []; + // If is empty or not evaluates to an array it must return false. + if (empty($actuals) || !is_array($actuals)) { + return false; + } + + return in_array($acceptor['expected'], $actuals); + } + + /** + * @param Result $result Result or exception. + * @param array $acceptor Acceptor configuration being checked. + * + * @return bool + */ + private function matchesStatus($result, array $acceptor) + { + if ($result instanceof ResultInterface) { + return $acceptor['expected'] == $result['@metadata']['statusCode']; + } + + if ($result instanceof AwsException && $response = $result->getResponse()) { + return $acceptor['expected'] == $response->getStatusCode(); + } + + return false; + } + + /** + * @param Result $result Result or exception. + * @param array $acceptor Acceptor configuration being checked. + * + * @return bool + */ + private function matchesError($result, array $acceptor) + { + // If expected is true then the $result should be an instance of + // AwsException, otherwise it should not. + if (isset($acceptor['expected']) && is_bool($acceptor['expected'])) { + return $acceptor['expected'] === ($result instanceof AwsException); + } + + if ($result instanceof AwsException) { + return $result->isConnectionError() + || $result->getAwsErrorCode() == $acceptor['expected']; + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/WrappedHttpHandler.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/WrappedHttpHandler.php new file mode 100644 index 000000000..1c602de49 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/WrappedHttpHandler.php @@ -0,0 +1,208 @@ +httpHandler = $httpHandler; + $this->parser = $parser; + $this->errorParser = $errorParser; + $this->exceptionClass = $exceptionClass; + $this->collectStats = $collectStats; + } + + /** + * Calls the simpler HTTP specific handler and wraps the returned promise + * with AWS specific values (e.g., a result object or AWS exception). + * + * @param CommandInterface $command Command being executed. + * @param RequestInterface $request Request to send. + * + * @return Promise\PromiseInterface + */ + public function __invoke( + CommandInterface $command, + RequestInterface $request + ) { + $fn = $this->httpHandler; + $options = $command['@http'] ?: []; + $stats = []; + if ($this->collectStats || !empty($options['collect_stats'])) { + $options['http_stats_receiver'] = static function ( + array $transferStats + ) use (&$stats) { + $stats = $transferStats; + }; + } elseif (isset($options['http_stats_receiver'])) { + throw new \InvalidArgumentException('Providing a custom HTTP stats' + . ' receiver to Aws\WrappedHttpHandler is not supported.'); + } + + return Promise\Create::promiseFor($fn($request, $options)) + ->then( + function ( + ResponseInterface $res + ) use ($command, $request, &$stats) { + return $this->parseResponse($command, $request, $res, $stats); + }, + function ($err) use ($request, $command, &$stats) { + if (is_array($err)) { + $err = $this->parseError( + $err, + $request, + $command, + $stats + ); + } + return new Promise\RejectedPromise($err); + } + ); + } + + /** + * @param CommandInterface $command + * @param RequestInterface $request + * @param ResponseInterface $response + * @param array $stats + * + * @return ResultInterface + */ + private function parseResponse( + CommandInterface $command, + RequestInterface $request, + ResponseInterface $response, + array $stats + ) { + $parser = $this->parser; + $status = $response->getStatusCode(); + $result = $status < 300 + ? $parser($command, $response) + : new Result(); + + $metadata = [ + 'statusCode' => $status, + 'effectiveUri' => (string) $request->getUri(), + 'headers' => [], + 'transferStats' => [], + ]; + if (!empty($stats)) { + $metadata['transferStats']['http'] = [$stats]; + } + + // Bring headers into the metadata array. + foreach ($response->getHeaders() as $name => $values) { + $metadata['headers'][strtolower($name)] = $values[0]; + } + + $result['@metadata'] = $metadata; + + return $result; + } + + /** + * Parses a rejection into an AWS error. + * + * @param array $err Rejection error array. + * @param RequestInterface $request Request that was sent. + * @param CommandInterface $command Command being sent. + * @param array $stats Transfer statistics + * + * @return \Exception + */ + private function parseError( + array $err, + RequestInterface $request, + CommandInterface $command, + array $stats + ) { + if (!isset($err['exception'])) { + throw new \RuntimeException('The HTTP handler was rejected without an "exception" key value pair.'); + } + + $serviceError = "AWS HTTP error: " . $err['exception']->getMessage(); + + if (!isset($err['response'])) { + $parts = ['response' => null]; + } else { + try { + $parts = call_user_func( + $this->errorParser, + $err['response'], + $command + ); + $serviceError .= " {$parts['code']} ({$parts['type']}): " + . "{$parts['message']} - " . $err['response']->getBody(); + } catch (ParserException $e) { + $parts = []; + $serviceError .= ' Unable to parse error information from ' + . "response - {$e->getMessage()}"; + } + + $parts['response'] = $err['response']; + } + + $parts['exception'] = $err['exception']; + $parts['request'] = $request; + $parts['connection_error'] = !empty($err['connection_error']); + $parts['transfer_stats'] = $stats; + + return new $this->exceptionClass( + sprintf( + 'Error executing "%s" on "%s"; %s', + $command->getName(), + $request->getUri(), + $serviceError + ), + $command, + $parts, + $err['exception'] + ); + } +} diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/aliases.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/aliases.json.php new file mode 100644 index 000000000..b6270471d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/aliases.json.php @@ -0,0 +1,3 @@ + [ 'ApiGatewayV2' => [ '2018-11-29' => [ 'GetApi' => 'GetApiResource', ], ], 'CloudHSM' => [ '2014-05-30' => [ 'GetConfig' => 'GetConfigFiles', ], ], 'GroundStation' => [ '2019-05-23' => [ 'GetConfig' => 'GetMissionProfileConfig', ], ], 'Pinpoint' => [ '2016-12-01' => [ 'GetEndpoint' => 'GetUserEndpoint', 'UpdateEndpoint' => 'UpdateUserEndpoint', 'UpdateEndpointsBatch' => 'UpdateUserEndpointsBatch', ], ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints.json.php new file mode 100644 index 000000000..2733a9842 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints.json.php @@ -0,0 +1,3 @@ + [ [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'dnsSuffix' => 'amazonaws.com', 'partition' => 'aws', 'partitionName' => 'AWS Standard', 'regionRegex' => '^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$', 'regions' => [ 'af-south-1' => [ 'description' => 'Africa (Cape Town)', ], 'ap-east-1' => [ 'description' => 'Asia Pacific (Hong Kong)', ], 'ap-east-2' => [ 'description' => 'Asia Pacific (Taipei)', ], 'ap-northeast-1' => [ 'description' => 'Asia Pacific (Tokyo)', ], 'ap-northeast-2' => [ 'description' => 'Asia Pacific (Seoul)', ], 'ap-northeast-3' => [ 'description' => 'Asia Pacific (Osaka)', ], 'ap-south-1' => [ 'description' => 'Asia Pacific (Mumbai)', ], 'ap-south-2' => [ 'description' => 'Asia Pacific (Hyderabad)', ], 'ap-southeast-1' => [ 'description' => 'Asia Pacific (Singapore)', ], 'ap-southeast-2' => [ 'description' => 'Asia Pacific (Sydney)', ], 'ap-southeast-3' => [ 'description' => 'Asia Pacific (Jakarta)', ], 'ap-southeast-4' => [ 'description' => 'Asia Pacific (Melbourne)', ], 'ap-southeast-5' => [ 'description' => 'Asia Pacific (Malaysia)', ], 'ap-southeast-6' => [ 'description' => 'Asia Pacific (New Zealand)', ], 'ap-southeast-7' => [ 'description' => 'Asia Pacific (Thailand)', ], 'ca-central-1' => [ 'description' => 'Canada (Central)', ], 'ca-west-1' => [ 'description' => 'Canada West (Calgary)', ], 'eu-central-1' => [ 'description' => 'Europe (Frankfurt)', ], 'eu-central-2' => [ 'description' => 'Europe (Zurich)', ], 'eu-north-1' => [ 'description' => 'Europe (Stockholm)', ], 'eu-south-1' => [ 'description' => 'Europe (Milan)', ], 'eu-south-2' => [ 'description' => 'Europe (Spain)', ], 'eu-west-1' => [ 'description' => 'Europe (Ireland)', ], 'eu-west-2' => [ 'description' => 'Europe (London)', ], 'eu-west-3' => [ 'description' => 'Europe (Paris)', ], 'il-central-1' => [ 'description' => 'Israel (Tel Aviv)', ], 'me-central-1' => [ 'description' => 'Middle East (UAE)', ], 'me-south-1' => [ 'description' => 'Middle East (Bahrain)', ], 'mx-central-1' => [ 'description' => 'Mexico (Central)', ], 'sa-east-1' => [ 'description' => 'South America (Sao Paulo)', ], 'us-east-1' => [ 'description' => 'US East (N. Virginia)', ], 'us-east-2' => [ 'description' => 'US East (Ohio)', ], 'us-west-1' => [ 'description' => 'US West (N. California)', ], 'us-west-2' => [ 'description' => 'US West (Oregon)', ], ], 'services' => [ 'access-analyzer' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'access-analyzer-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'access-analyzer-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'access-analyzer.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'account' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'account.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'acm' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'acm-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'acm-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'acm-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'acm-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'acm-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'acm-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'acm-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'acm-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'acm-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'acm-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'acm-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'acm-fips.us-west-2.amazonaws.com', ], ], ], 'acm-pca' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'acm-pca-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'acm-pca-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'agreement-marketplace' => [ 'endpoints' => [ 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'agreement-marketplace.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'airflow' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'amplify' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'amplifybackend' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'amplifyuibuilder' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'aoss' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'api.detective' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'detective.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'detective.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'detective.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'detective.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'detective.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'detective.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'detective.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'detective.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'detective.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'detective.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'detective.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'detective.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'detective.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'detective.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'detective.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'detective.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-west-2.amazonaws.com', ], ], ], 'api.ecr' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'ecr-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'api.ecr.af-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'api.ecr.ap-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'api.ecr.ap-northeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'api.ecr.ap-northeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'api.ecr.ap-northeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'api.ecr.ap-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'api.ecr.ap-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'api.ecr.ap-southeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'api.ecr.ap-southeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'api.ecr.ap-southeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'api.ecr.ap-southeast-4.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'hostname' => 'api.ecr.ap-southeast-5.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'credentialScope' => [ 'region' => 'ap-southeast-7', ], 'hostname' => 'api.ecr.ap-southeast-7.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'api.ecr.ca-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'hostname' => 'api.ecr.ca-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'dkr-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dkr-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dkr-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dkr-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'api.ecr.eu-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'api.ecr.eu-central-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'api.ecr.eu-north-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'api.ecr.eu-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'api.ecr.eu-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'api.ecr.eu-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'api.ecr.eu-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'api.ecr.eu-west-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-dkr-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-east-1.amazonaws.com', ], 'fips-dkr-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-east-2.amazonaws.com', ], 'fips-dkr-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-west-1.amazonaws.com', ], 'fips-dkr-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-west-2.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'api.ecr.il-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'api.ecr.me-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'api.ecr.me-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'credentialScope' => [ 'region' => 'mx-central-1', ], 'hostname' => 'api.ecr.mx-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'api.ecr.sa-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.ecr.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'api.ecr.us-east-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'api.ecr.us-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.ecr.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'api.ecr-public' => [ 'endpoints' => [ 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.ecr-public.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-public.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.ecr-public.us-west-2.amazonaws.com', ], ], ], 'api.fleethub.iot' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'api.fleethub.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'api.fleethub.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'api.fleethub.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'api.fleethub.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'api.fleethub.iot-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'api.fleethub.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'api.fleethub.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'api.fleethub.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'api.iotdeviceadvisor' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'api.iotdeviceadvisor.ap-northeast-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'api.iotdeviceadvisor.eu-west-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.iotdeviceadvisor.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.iotdeviceadvisor.us-west-2.amazonaws.com', ], ], ], 'api.iotwireless' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'api.iotwireless.ap-northeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'api.iotwireless.ap-southeast-2.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'api.iotwireless.eu-central-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'api.iotwireless.eu-west-1.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'api.iotwireless.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.iotwireless.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.iotwireless.us-west-2.amazonaws.com', ], ], ], 'api.mediatailor' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-3' => [], 'me-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'ap-south-1' => [], 'eu-central-1' => [], 'us-east-1' => [], ], ], 'api.sagemaker' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-west-2.amazonaws.com', ], ], ], 'api.tunneling.iot' => [ 'defaults' => [ 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => 'api.tunneling.iot-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => 'api.iot-tunneling-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => 'api.iot-tunneling.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'apigateway' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'apigateway-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'apigateway-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'app-integrations' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'appflow' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'appflow-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'appflow-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'appflow-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'appflow-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'appflow-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'appflow-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'appflow-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'appflow-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'applicationinsights' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'appmesh' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'appmesh.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'appmesh-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'appmesh-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'appmesh.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'appmesh-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'appmesh.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'appmesh-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'appmesh-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'appmesh.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'appmesh-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'appmesh-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'appmesh-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'appmesh.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'appmesh-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'appmesh-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'appmesh-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'appmesh.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'appmesh-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'appmesh-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'appmesh-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'appmesh.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'appmesh-fips.us-west-2.amazonaws.com', ], ], ], 'apprunner' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'apprunner-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'apprunner-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'apprunner-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'apprunner-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'apprunner-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'apprunner-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'appstream2' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'appstream', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'appstream2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'appstream2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-west-2.amazonaws.com', ], ], ], 'appsync' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'appsync.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'appsync.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'appsync.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'appsync.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'appsync.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'appsync.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'appsync.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'appsync.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'appsync.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'appsync.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'appsync.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'appsync.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'apptest' => [ 'endpoints' => [ 'ap-southeast-2' => [], 'eu-central-1' => [], 'fips-us-east-1' => [ 'deprecated' => true, ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'aps' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'deprecated' => true, ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'deprecated' => true, ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'deprecated' => true, ], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'athena' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'athena.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'athena.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'athena.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'athena.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'athena.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'athena.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'athena.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'athena.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'athena.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'athena.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'athena.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'athena.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'athena.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'athena.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'athena.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'athena.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'athena.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'athena.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'athena.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'athena.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'athena.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'athena.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'athena.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'athena.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'auditmanager' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'auditmanager-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'auditmanager-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'auditmanager-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'auditmanager-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'auditmanager-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'auditmanager-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'auditmanager-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'auditmanager-fips.us-west-2.amazonaws.com', ], ], ], 'autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'autoscaling-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'autoscaling-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'autoscaling-plans' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'backup' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'backup-gateway' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'batch' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'fips.batch.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fips.batch.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fips.batch.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fips.batch.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fips.batch.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'fips.batch.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'fips.batch.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'fips.batch.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'fips.batch.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'bedrock' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'bedrock-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'bedrock.ap-northeast-1.amazonaws.com', ], 'bedrock-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'bedrock.ap-northeast-2.amazonaws.com', ], 'bedrock-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'bedrock.ap-northeast-3.amazonaws.com', ], 'bedrock-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'bedrock.ap-south-1.amazonaws.com', ], 'bedrock-ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'bedrock.ap-south-2.amazonaws.com', ], 'bedrock-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'bedrock.ap-southeast-1.amazonaws.com', ], 'bedrock-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'bedrock.ap-southeast-2.amazonaws.com', ], 'bedrock-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'bedrock.ca-central-1.amazonaws.com', ], 'bedrock-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'bedrock.eu-central-1.amazonaws.com', ], 'bedrock-eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'bedrock.eu-central-2.amazonaws.com', ], 'bedrock-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'bedrock.eu-north-1.amazonaws.com', ], 'bedrock-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'bedrock.eu-south-1.amazonaws.com', ], 'bedrock-eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'bedrock.eu-south-2.amazonaws.com', ], 'bedrock-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'bedrock.eu-west-1.amazonaws.com', ], 'bedrock-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'bedrock.eu-west-2.amazonaws.com', ], 'bedrock-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'bedrock.eu-west-3.amazonaws.com', ], 'bedrock-fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'bedrock-fips.ca-central-1.amazonaws.com', ], 'bedrock-fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'bedrock-fips.us-east-1.amazonaws.com', ], 'bedrock-fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'bedrock-fips.us-east-2.amazonaws.com', ], 'bedrock-fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'bedrock-fips.us-west-2.amazonaws.com', ], 'bedrock-runtime-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'bedrock-runtime.ap-northeast-1.amazonaws.com', ], 'bedrock-runtime-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'bedrock-runtime.ap-northeast-2.amazonaws.com', ], 'bedrock-runtime-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'bedrock-runtime.ap-northeast-3.amazonaws.com', ], 'bedrock-runtime-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'bedrock-runtime.ap-south-1.amazonaws.com', ], 'bedrock-runtime-ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'bedrock-runtime.ap-south-2.amazonaws.com', ], 'bedrock-runtime-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'bedrock-runtime.ap-southeast-1.amazonaws.com', ], 'bedrock-runtime-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'bedrock-runtime.ap-southeast-2.amazonaws.com', ], 'bedrock-runtime-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'bedrock-runtime.ca-central-1.amazonaws.com', ], 'bedrock-runtime-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'bedrock-runtime.eu-central-1.amazonaws.com', ], 'bedrock-runtime-eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'bedrock-runtime.eu-central-2.amazonaws.com', ], 'bedrock-runtime-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'bedrock-runtime.eu-north-1.amazonaws.com', ], 'bedrock-runtime-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'bedrock-runtime.eu-south-1.amazonaws.com', ], 'bedrock-runtime-eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'bedrock-runtime.eu-south-2.amazonaws.com', ], 'bedrock-runtime-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'bedrock-runtime.eu-west-1.amazonaws.com', ], 'bedrock-runtime-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'bedrock-runtime.eu-west-2.amazonaws.com', ], 'bedrock-runtime-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'bedrock-runtime.eu-west-3.amazonaws.com', ], 'bedrock-runtime-fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'bedrock-runtime-fips.ca-central-1.amazonaws.com', ], 'bedrock-runtime-fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'bedrock-runtime-fips.us-east-1.amazonaws.com', ], 'bedrock-runtime-fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'bedrock-runtime-fips.us-east-2.amazonaws.com', ], 'bedrock-runtime-fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'bedrock-runtime-fips.us-west-2.amazonaws.com', ], 'bedrock-runtime-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'bedrock-runtime.sa-east-1.amazonaws.com', ], 'bedrock-runtime-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'bedrock-runtime.us-east-1.amazonaws.com', ], 'bedrock-runtime-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'bedrock-runtime.us-east-2.amazonaws.com', ], 'bedrock-runtime-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'bedrock-runtime.us-west-2.amazonaws.com', ], 'bedrock-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'bedrock.sa-east-1.amazonaws.com', ], 'bedrock-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'bedrock.us-east-1.amazonaws.com', ], 'bedrock-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'bedrock.us-east-2.amazonaws.com', ], 'bedrock-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'bedrock.us-west-2.amazonaws.com', ], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'billingconductor' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'billingconductor.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'braket' => [ 'endpoints' => [ 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'braket.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'braket.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'braket.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'braket.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'braket.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'budgets' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'budgets.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'cases' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'deprecated' => true, ], 'fips-us-west-2' => [ 'deprecated' => true, ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'cassandra' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cassandra-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cassandra-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cassandra-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cassandra-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'catalog.marketplace' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'ce' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'ce.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'chime' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'chime.us-east-1.amazonaws.com', 'protocols' => [ 'https', ], ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'cleanrooms' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'cleanrooms.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cleanrooms-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cleanrooms-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cleanrooms-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cleanrooms-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cleanrooms-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cleanrooms.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cleanrooms-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cleanrooms-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cleanrooms.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cleanrooms-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cleanrooms-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cleanrooms.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cloud9' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'cloud9-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloud9-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'cloud9-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cloud9-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cloud9-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cloud9-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cloud9-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'cloud9-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloud9-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'cloud9-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloud9-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'cloud9-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloud9-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'cloud9-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloud9-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'cloudcontrolapi' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'clouddirectory' => [ 'endpoints' => [ 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'cloudformation' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudformation-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cloudformation-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cloudformation-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cloudformation-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudformation-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cloudformation-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudformation-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cloudformation-fips.us-west-2.amazonaws.com', ], ], ], 'cloudfront' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'cloudfront.amazonaws.com', 'protocols' => [ 'http', 'https', ], ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'cloudhsm' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'cloudhsmv2' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'cloudhsm', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cloudsearch' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'cloudtrail' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'cloudtrail-data' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'codeartifact' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'codebuild' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-west-2.amazonaws.com', ], ], ], 'codecatalyst' => [ 'endpoints' => [ 'aws-global' => [ 'hostname' => 'codecatalyst.global.api.aws', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'codecommit' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.ca-central-1.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-west-2.amazonaws.com', ], ], ], 'codedeploy' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-west-2.amazonaws.com', ], ], ], 'codeguru-profiler' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'codeguru-reviewer' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'codepipeline' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'codestar-connections' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'codestar-notifications' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'cognito-identity' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.af-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-northeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-northeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-northeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-southeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-southeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-southeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-southeast-4.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ap-southeast-5.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-central-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-north-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.eu-west-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cognito-identity-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cognito-identity-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cognito-identity-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cognito-identity-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.il-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.me-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.me-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.sa-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity-fips.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-identity-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-identity.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity-fips.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-identity-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-identity.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity-fips.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-identity-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-identity.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cognito-identity-fips.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-identity-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-identity.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cognito-idp' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.af-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-northeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-northeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-northeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-southeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-southeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-southeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-southeast-4.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ap-southeast-5.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-central-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-north-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.eu-west-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'cognito-idp-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'cognito-idp-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'cognito-idp-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'cognito-idp-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.il-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.me-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.me-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.sa-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp-fips.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-idp-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-idp.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp-fips.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-idp-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-idp.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp-fips.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-idp-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-idp.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'cognito-idp-fips.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-idp-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-idp.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cognito-sync' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'comprehend' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'comprehend.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'comprehend.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'comprehend.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'comprehend.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'comprehend.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'comprehend-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'comprehend.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'comprehend.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'comprehend.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'comprehend.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'comprehend-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'comprehend.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'comprehend-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'comprehend.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'comprehend-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'comprehend.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'comprehendmedical' => [ 'endpoints' => [ 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'comprehendmedical-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'comprehendmedical-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'comprehendmedical-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'comprehendmedical-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'comprehendmedical-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'comprehendmedical-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'comprehendmedical-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'comprehendmedical-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'compute-optimizer' => [ 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'compute-optimizer.af-south-1.amazonaws.com', ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'compute-optimizer.ap-east-1.amazonaws.com', ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'compute-optimizer.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'compute-optimizer.ap-northeast-2.amazonaws.com', ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'compute-optimizer.ap-northeast-3.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'compute-optimizer.ap-south-1.amazonaws.com', ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'compute-optimizer.ap-south-2.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'compute-optimizer.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'compute-optimizer.ap-southeast-2.amazonaws.com', ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'compute-optimizer.ap-southeast-3.amazonaws.com', ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'compute-optimizer.ap-southeast-4.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'compute-optimizer.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'compute-optimizer.eu-central-1.amazonaws.com', ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'compute-optimizer.eu-central-2.amazonaws.com', ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'compute-optimizer.eu-north-1.amazonaws.com', ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'compute-optimizer.eu-south-1.amazonaws.com', ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'compute-optimizer.eu-south-2.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'compute-optimizer.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'compute-optimizer.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'compute-optimizer.eu-west-3.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'compute-optimizer.il-central-1.amazonaws.com', ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'compute-optimizer.me-central-1.amazonaws.com', ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'compute-optimizer.me-south-1.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'compute-optimizer.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'compute-optimizer.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'compute-optimizer.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'compute-optimizer.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'compute-optimizer.us-west-2.amazonaws.com', ], ], ], 'config' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'config-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'config-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'config-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'config-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'connect' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'connect-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'connect-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'connect-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'connect-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'connect-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'connect-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'connect-campaigns' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'connect-campaigns-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'connect-campaigns-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'connect-campaigns-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'connect-campaigns-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'contact-lens' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'controltower' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-west-2.amazonaws.com', ], ], ], 'cost-optimization-hub' => [ 'endpoints' => [ 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'cost-optimization-hub.us-east-1.amazonaws.com', ], ], ], 'cur' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'data-ats.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'data.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'data.jobs.iot' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'data.mediastore' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'databrew' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'databrew-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'databrew-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'databrew-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'databrew-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'databrew-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'databrew-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'databrew-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'databrew-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'dataexchange' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'datapipeline' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'datasync' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'datasync.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'datasync.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'datasync.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'datasync.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'datasync.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'datasync.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'datasync.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'datasync.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'datazone' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'datazone.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'datazone.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'datazone.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'datazone.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'datazone.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'datazone.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'datazone.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'datazone.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'datazone.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'datazone.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'datazone.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'datazone.ca-central-1.api.aws', 'variants' => [ [ 'hostname' => 'datazone-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'hostname' => 'datazone.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'datazone.eu-central-1.api.aws', ], 'eu-north-1' => [ 'hostname' => 'datazone.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'datazone.eu-south-1.api.aws', ], 'eu-west-1' => [ 'hostname' => 'datazone.eu-west-1.api.aws', ], 'eu-west-2' => [ 'hostname' => 'datazone.eu-west-2.api.aws', ], 'eu-west-3' => [ 'hostname' => 'datazone.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'datazone.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'datazone.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'datazone.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'datazone.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'datazone.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'datazone.us-east-1.api.aws', 'variants' => [ [ 'hostname' => 'datazone-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'hostname' => 'datazone.us-east-2.api.aws', 'variants' => [ [ 'hostname' => 'datazone-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'hostname' => 'datazone.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'datazone.us-west-2.api.aws', 'variants' => [ [ 'hostname' => 'datazone-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'dax' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'devicefarm' => [ 'endpoints' => [ 'us-west-2' => [], ], ], 'devops-guru' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'devops-guru-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'devops-guru-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'devops-guru-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'devops-guru-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'devops-guru-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'devops-guru-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'devops-guru-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'devops-guru-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'devops-guru-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'devops-guru-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'directconnect' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'discovery' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'dlm' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'dlm.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'dlm.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'dlm.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'dlm.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'dlm.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'dlm.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'dlm.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'dlm.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'dms' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'dms' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'dms-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dms-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'dms-fips.us-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'dms-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'dms-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'dms-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'dms-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'dms-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'dms-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'dms-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'dms-fips.us-west-2.amazonaws.com', ], ], ], 'docdb' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'rds.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'rds.ap-northeast-2.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'rds.ap-south-1.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'rds.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'rds.ap-southeast-2.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'rds.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'rds.eu-central-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'rds.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'rds.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'rds.eu-west-3.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'rds.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'rds.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'rds.us-east-2.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'rds.us-west-2.amazonaws.com', ], ], ], 'drs' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ds' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'dynamodb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'local' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'localhost:8000', 'protocols' => [ 'http', ], ], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-west-2.amazonaws.com', ], ], ], 'ebs' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ebs-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'ebs-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ebs-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ebs-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ebs-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ebs-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ebs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ec2' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'ec2.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'ec2.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ec2.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'ec2.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ec2-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'ec2-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ec2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ec2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ec2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ec2-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'ec2.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'ec2.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ec2.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ec2.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ec2.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ec2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ec2.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'ecs' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'edge.sagemaker' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'fips.eks.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fips.eks.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fips.eks.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fips.eks.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fips.eks.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'fips.eks.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'fips.eks.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'fips.eks.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'fips.eks.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'eks-auth' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'eks-auth.af-south-1.api.aws', ], 'ap-east-1' => [ 'hostname' => 'eks-auth.ap-east-1.api.aws', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'eks-auth.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'eks-auth.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'eks-auth.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'eks-auth.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'eks-auth.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'eks-auth.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'eks-auth.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'eks-auth.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'eks-auth.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'eks-auth.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'eks-auth.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'eks-auth.ca-central-1.api.aws', ], 'ca-west-1' => [ 'hostname' => 'eks-auth.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'eks-auth.eu-central-1.api.aws', ], 'eu-central-2' => [ 'hostname' => 'eks-auth.eu-central-2.api.aws', ], 'eu-north-1' => [ 'hostname' => 'eks-auth.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'eks-auth.eu-south-1.api.aws', ], 'eu-south-2' => [ 'hostname' => 'eks-auth.eu-south-2.api.aws', ], 'eu-west-1' => [ 'hostname' => 'eks-auth.eu-west-1.api.aws', ], 'eu-west-2' => [ 'hostname' => 'eks-auth.eu-west-2.api.aws', ], 'eu-west-3' => [ 'hostname' => 'eks-auth.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'eks-auth.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'eks-auth.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'eks-auth.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'eks-auth.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'eks-auth.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'eks-auth.us-east-1.api.aws', ], 'us-east-2' => [ 'hostname' => 'eks-auth.us-east-2.api.aws', ], 'us-west-1' => [ 'hostname' => 'eks-auth.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'eks-auth.us-west-2.api.aws', ], ], ], 'elasticache' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticache-fips.us-west-1.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticache-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'elasticache-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'elasticache-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'elasticache-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticache-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticache-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticache-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'elasticache-fips.us-west-2.amazonaws.com', ], ], ], 'elasticbeanstalk' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-northeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-4.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-5.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ap-southeast-7.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-central-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-north-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.af-south-1.amazonaws.com', ], 'fips-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-east-1.amazonaws.com', ], 'fips-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-northeast-1.amazonaws.com', ], 'fips-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-northeast-2.amazonaws.com', ], 'fips-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-northeast-3.amazonaws.com', ], 'fips-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-south-1.amazonaws.com', ], 'fips-ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-south-2.amazonaws.com', ], 'fips-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-1.amazonaws.com', ], 'fips-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-2.amazonaws.com', ], 'fips-ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-3.amazonaws.com', ], 'fips-ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-4.amazonaws.com', ], 'fips-ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-5.amazonaws.com', ], 'fips-ap-southeast-7' => [ 'credentialScope' => [ 'region' => 'ap-southeast-7', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ap-southeast-7.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.ca-west-1.amazonaws.com', ], 'fips-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-central-1.amazonaws.com', ], 'fips-eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-central-2.amazonaws.com', ], 'fips-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-north-1.amazonaws.com', ], 'fips-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-south-1.amazonaws.com', ], 'fips-eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-south-2.amazonaws.com', ], 'fips-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-west-1.amazonaws.com', ], 'fips-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-west-2.amazonaws.com', ], 'fips-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-west-3.amazonaws.com', ], 'fips-il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.il-central-1.amazonaws.com', ], 'fips-me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.me-central-1.amazonaws.com', ], 'fips-me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.me-south-1.amazonaws.com', ], 'fips-mx-central-1' => [ 'credentialScope' => [ 'region' => 'mx-central-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.mx-central-1.amazonaws.com', ], 'fips-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.sa-east-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.il-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.me-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.me-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.mx-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticloadbalancing' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticmapreduce' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'sslCommonName' => '{region}.{service}.{dnsSuffix}', ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'sslCommonName' => '{service}.{region}.{dnsSuffix}', ], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'sslCommonName' => '{service}.{region}.{dnsSuffix}', 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticmapreduce.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'elastictranscoder' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'email' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'email-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'email-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'email-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'email-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'email-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'email-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'emr-containers' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'emr-containers-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'emr-containers-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'emr-containers-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'emr-containers-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'emr-containers-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'emr-containers-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'emr-containers-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'emr-containers-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'emr-containers-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'emr-containers-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'emr-serverless' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'emr-serverless-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'emr-serverless-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'emr-serverless-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'emr-serverless-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'emr-serverless-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'emr-serverless-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'emr-serverless-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'emr-serverless-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'emr-serverless-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'emr-serverless-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'entitlement.marketplace' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'aws-marketplace', ], ], 'endpoints' => [ 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'entitlement-marketplace.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'es' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'aos.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'aos.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'aos.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'aos.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'aos.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'aos.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'aos.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'aos.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'aos.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'aos.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'aos.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'aos.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'aos.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'aos.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'aos.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'aos.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'aos.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'aos.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-west-1.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'aos.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'aos.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'aos.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'aos.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'aos.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'aos.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'aos.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'es-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'aos.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'aos.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'es-fips.us-west-2.amazonaws.com', ], ], ], 'events' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'events.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'events.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'events.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'events.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'events.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'events.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'events.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'events.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'events.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'events.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'events.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'events.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'events.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'events.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'events.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'events.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'events.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'events.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'events-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'events-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'events-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'events-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'events.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'events.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'events.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'events.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'events.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'events-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'events-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'events.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'events-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'events-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'events.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'events-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'events-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'events.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'events-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'events-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'events.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'evidently' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'hostname' => 'evidently.ap-northeast-1.amazonaws.com', ], 'ap-southeast-1' => [ 'hostname' => 'evidently.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'hostname' => 'evidently.ap-southeast-2.amazonaws.com', ], 'eu-central-1' => [ 'hostname' => 'evidently.eu-central-1.amazonaws.com', ], 'eu-north-1' => [ 'hostname' => 'evidently.eu-north-1.amazonaws.com', ], 'eu-west-1' => [ 'hostname' => 'evidently.eu-west-1.amazonaws.com', ], 'us-east-1' => [ 'hostname' => 'evidently.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'hostname' => 'evidently.us-east-2.amazonaws.com', ], 'us-west-2' => [ 'hostname' => 'evidently.us-west-2.amazonaws.com', ], ], ], 'finspace' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'finspace-api' => [ 'endpoints' => [ 'ca-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'firehose' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'firehose.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'firehose.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'firehose.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'firehose.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'firehose.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'firehose.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'firehose.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'firehose.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'firehose.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'firehose-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'firehose.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'firehose-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'firehose.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'firehose-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'firehose.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'firehose-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'firehose.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'fms' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-3' => [], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-2' => [], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-2' => [], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'fms-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'fms-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.af-south-1.amazonaws.com', ], 'fips-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-east-1.amazonaws.com', ], 'fips-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-northeast-1.amazonaws.com', ], 'fips-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-northeast-2.amazonaws.com', ], 'fips-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-south-1.amazonaws.com', ], 'fips-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-southeast-1.amazonaws.com', ], 'fips-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'fms-fips.ap-southeast-2.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.ca-west-1.amazonaws.com', ], 'fips-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.eu-central-1.amazonaws.com', ], 'fips-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.eu-south-1.amazonaws.com', ], 'fips-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.eu-west-1.amazonaws.com', ], 'fips-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'fms-fips.eu-west-2.amazonaws.com', ], 'fips-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'fms-fips.eu-west-3.amazonaws.com', ], 'fips-me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.me-south-1.amazonaws.com', ], 'fips-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.sa-east-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.me-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'forecast' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'forecast-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'forecast-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'forecast-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'forecast-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'forecast-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'forecast-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'forecastquery' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'forecastquery-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'forecastquery-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'forecastquery-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'forecastquery-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'forecastquery-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'forecastquery-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'frauddetector' => [ 'endpoints' => [ 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'fsx' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.ca-west-1.amazonaws.com', ], 'fips-prod-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.ca-central-1.amazonaws.com', ], 'fips-prod-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.ca-west-1.amazonaws.com', ], 'fips-prod-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-east-1.amazonaws.com', ], 'fips-prod-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-east-2.amazonaws.com', ], 'fips-prod-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-west-1.amazonaws.com', ], 'fips-prod-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-west-2.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'prod-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'gamelift' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'gameliftstreams' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'gameliftstreams.af-south-1.api.aws', ], 'ap-east-1' => [ 'hostname' => 'gameliftstreams.ap-east-1.api.aws', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'gameliftstreams.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'gameliftstreams.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'gameliftstreams.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'gameliftstreams.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'gameliftstreams.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'gameliftstreams.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'gameliftstreams.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'gameliftstreams.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'gameliftstreams.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'gameliftstreams.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'gameliftstreams.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'gameliftstreams.ca-central-1.api.aws', ], 'ca-west-1' => [ 'hostname' => 'gameliftstreams.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'gameliftstreams.eu-central-1.api.aws', ], 'eu-central-2' => [ 'hostname' => 'gameliftstreams.eu-central-2.api.aws', ], 'eu-north-1' => [ 'hostname' => 'gameliftstreams.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'gameliftstreams.eu-south-1.api.aws', ], 'eu-south-2' => [ 'hostname' => 'gameliftstreams.eu-south-2.api.aws', ], 'eu-west-1' => [ 'hostname' => 'gameliftstreams.eu-west-1.api.aws', ], 'eu-west-2' => [ 'hostname' => 'gameliftstreams.eu-west-2.api.aws', ], 'eu-west-3' => [ 'hostname' => 'gameliftstreams.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'gameliftstreams.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'gameliftstreams.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'gameliftstreams.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'gameliftstreams.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'gameliftstreams.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'gameliftstreams.us-east-1.api.aws', ], 'us-east-2' => [ 'hostname' => 'gameliftstreams.us-east-2.api.aws', ], 'us-west-1' => [ 'hostname' => 'gameliftstreams.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'gameliftstreams.us-west-2.api.aws', ], ], ], 'geo' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'glacier' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'globalaccelerator' => [ 'endpoints' => [ 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'globalaccelerator-fips.us-west-2.amazonaws.com', ], ], ], 'glue' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'glue.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'glue.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'glue.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'glue.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'glue.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'glue.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'glue.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'glue.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'glue.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'glue.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'glue.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'glue.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'glue.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'glue.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'glue.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'glue.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'glue.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'glue.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'glue.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'glue.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'glue.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'glue.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'glue.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'grafana' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'grafana.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'grafana.ap-northeast-2.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'grafana.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'grafana.ap-southeast-2.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'grafana.eu-central-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'grafana.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'grafana.eu-west-2.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'grafana.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'grafana.us-east-2.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'grafana.us-west-2.amazonaws.com', ], ], ], 'greengrass' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'greengrass-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'greengrass-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'greengrass-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'greengrass-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'greengrass-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'greengrass-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'greengrass-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'greengrass-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], 'isRegionalized' => true, ], 'groundstation' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'groundstation-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'groundstation-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'groundstation-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'groundstation-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'groundstation-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'groundstation-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'groundstation-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'groundstation-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'groundstation-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'guardduty' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'guardduty-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'guardduty-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'guardduty-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'guardduty-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'guardduty-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'guardduty-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'guardduty-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'guardduty-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'guardduty-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'guardduty-fips.us-west-2.amazonaws.com', ], ], 'isRegionalized' => true, ], 'health' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'sslCommonName' => 'health.us-east-1.amazonaws.com', ], 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'global.health.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'health-fips.us-east-2.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'health-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'healthlake' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-south-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'iam' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'iam.amazonaws.com', 'variants' => [ [ 'hostname' => 'iam-fips.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'iam.global.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'aws-global-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'iam-fips.amazonaws.com', ], 'iam' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'iam-fips.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'iam-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'iam-fips.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'identity-chime' => [ 'endpoints' => [ 'eu-central-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'identity-chime-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'identity-chime-fips.us-east-1.amazonaws.com', ], ], ], 'identitystore' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'importexport' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', 'service' => 'IngestionService', ], 'hostname' => 'importexport.amazonaws.com', 'signatureVersions' => [ 'v2', 'v4', ], ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'ingest.timestream' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'ingest-fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ingest.timestream-fips.us-east-1.amazonaws.com', ], 'ingest-fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ingest.timestream-fips.us-east-2.amazonaws.com', ], 'ingest-fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ingest.timestream-fips.us-west-2.amazonaws.com', ], 'ingest-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ingest.timestream-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ingest-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ingest.timestream-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ingest-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ingest.timestream-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'inspector' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'inspector2' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'internetmonitor' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'internetmonitor.af-south-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'hostname' => 'internetmonitor.ap-east-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'internetmonitor.ap-northeast-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'hostname' => 'internetmonitor.ap-northeast-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'hostname' => 'internetmonitor.ap-northeast-3.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'hostname' => 'internetmonitor.ap-south-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'hostname' => 'internetmonitor.ap-south-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'hostname' => 'internetmonitor.ap-southeast-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'hostname' => 'internetmonitor.ap-southeast-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'hostname' => 'internetmonitor.ap-southeast-3.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'hostname' => 'internetmonitor.ap-southeast-4.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'hostname' => 'internetmonitor.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'internetmonitor.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'internetmonitor.ca-central-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'internetmonitor-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'internetmonitor.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'hostname' => 'internetmonitor.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'internetmonitor.eu-central-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'hostname' => 'internetmonitor.eu-central-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'hostname' => 'internetmonitor.eu-north-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'hostname' => 'internetmonitor.eu-south-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'hostname' => 'internetmonitor.eu-south-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'hostname' => 'internetmonitor.eu-west-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'hostname' => 'internetmonitor.eu-west-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'hostname' => 'internetmonitor.eu-west-3.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'hostname' => 'internetmonitor.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'internetmonitor.me-central-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'hostname' => 'internetmonitor.me-south-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'hostname' => 'internetmonitor.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'internetmonitor.sa-east-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'hostname' => 'internetmonitor.us-east-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'internetmonitor-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'internetmonitor.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'hostname' => 'internetmonitor.us-east-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'internetmonitor-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'internetmonitor.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'hostname' => 'internetmonitor.us-west-1.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'internetmonitor-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'internetmonitor.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'hostname' => 'internetmonitor.us-west-2.api.aws', 'variants' => [ [ 'hostname' => 'internetmonitor-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'internetmonitor-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'internetmonitor.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'iot' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'deprecated' => true, 'hostname' => 'iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotanalytics' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'iotevents' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'iotevents-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'iotevents-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'iotevents-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'iotevents-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'iotevents-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'iotevents-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'iotevents-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'iotevents-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ioteventsdata' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'data.iotevents.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'data.iotevents.ap-northeast-2.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'data.iotevents.ap-south-1.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'data.iotevents.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'data.iotevents.ap-southeast-2.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'data.iotevents.ca-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'data.iotevents-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'data.iotevents.eu-central-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'data.iotevents.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'data.iotevents.eu-west-2.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'data.iotevents-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'data.iotevents-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'data.iotevents-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'data.iotevents-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'data.iotevents.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'data.iotevents-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'data.iotevents.us-east-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'data.iotevents-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'data.iotevents.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'data.iotevents-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotfleetwise' => [ 'endpoints' => [ 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], ], ], 'iotsecuredtunneling' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotsitewise' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'iotsitewise-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-1' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'iotsitewise-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'iotsitewise-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'iotsitewise-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'iotsitewise-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'iotsitewise-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'iotsitewise-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'iotsitewise-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotthingsgraph' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotthingsgraph', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'iottwinmaker' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'api-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'api.iottwinmaker.ap-northeast-1.amazonaws.com', ], 'api-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'api.iottwinmaker.ap-northeast-2.amazonaws.com', ], 'api-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'api.iottwinmaker.ap-south-1.amazonaws.com', ], 'api-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'api.iottwinmaker.ap-southeast-1.amazonaws.com', ], 'api-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'api.iottwinmaker.ap-southeast-2.amazonaws.com', ], 'api-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'api.iottwinmaker.eu-central-1.amazonaws.com', ], 'api-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'api.iottwinmaker.eu-west-1.amazonaws.com', ], 'api-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.iottwinmaker.us-east-1.amazonaws.com', ], 'api-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.iottwinmaker.us-west-2.amazonaws.com', ], 'data-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'data.iottwinmaker.ap-northeast-1.amazonaws.com', ], 'data-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'data.iottwinmaker.ap-northeast-2.amazonaws.com', ], 'data-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'data.iottwinmaker.ap-south-1.amazonaws.com', ], 'data-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'data.iottwinmaker.ap-southeast-1.amazonaws.com', ], 'data-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'data.iottwinmaker.ap-southeast-2.amazonaws.com', ], 'data-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'data.iottwinmaker.eu-central-1.amazonaws.com', ], 'data-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'data.iottwinmaker.eu-west-1.amazonaws.com', ], 'data-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'data.iottwinmaker.us-east-1.amazonaws.com', ], 'data-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'data.iottwinmaker.us-west-2.amazonaws.com', ], 'eu-central-1' => [], 'eu-west-1' => [], 'fips-api-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.iottwinmaker-fips.us-east-1.amazonaws.com', ], 'fips-api-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.iottwinmaker-fips.us-west-2.amazonaws.com', ], 'fips-data-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'data.iottwinmaker-fips.us-east-1.amazonaws.com', ], 'fips-data-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'data.iottwinmaker-fips.us-west-2.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'iottwinmaker-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'iottwinmaker-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'iottwinmaker-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'iottwinmaker-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotwireless' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'api.iotwireless.ap-northeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'api.iotwireless.ap-southeast-2.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'api.iotwireless.eu-west-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'api.iotwireless.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'api.iotwireless.us-west-2.amazonaws.com', ], ], ], 'ivs' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'ivschat' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'ivsrealtime' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'kafka' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'kafka-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'kafka-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'kafka-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'kafka-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'kafka-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'kafka-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'kafka-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kafkaconnect' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'kendra' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'kendra-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'kendra-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'kendra-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'kendra-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'kendra-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'kendra-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'kendra-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'kendra-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kendra-ranking' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'kendra-ranking.af-south-1.api.aws', ], 'ap-east-1' => [ 'hostname' => 'kendra-ranking.ap-east-1.api.aws', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'kendra-ranking.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'kendra-ranking.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'kendra-ranking.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'kendra-ranking.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'kendra-ranking.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'kendra-ranking.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'kendra-ranking.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'kendra-ranking.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'kendra-ranking.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'kendra-ranking.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'kendra-ranking.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'kendra-ranking.ca-central-1.api.aws', 'variants' => [ [ 'hostname' => 'kendra-ranking-fips.ca-central-1.api.aws', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'hostname' => 'kendra-ranking.ca-west-1.api.aws', ], 'eu-central-2' => [ 'hostname' => 'kendra-ranking.eu-central-2.api.aws', ], 'eu-north-1' => [ 'hostname' => 'kendra-ranking.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'kendra-ranking.eu-south-1.api.aws', ], 'eu-south-2' => [ 'hostname' => 'kendra-ranking.eu-south-2.api.aws', ], 'eu-west-1' => [ 'hostname' => 'kendra-ranking.eu-west-1.api.aws', ], 'eu-west-3' => [ 'hostname' => 'kendra-ranking.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'kendra-ranking.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'kendra-ranking.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'kendra-ranking.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'kendra-ranking.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'kendra-ranking.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'kendra-ranking.us-east-1.api.aws', 'variants' => [ [ 'hostname' => 'kendra-ranking-fips.us-east-1.api.aws', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'hostname' => 'kendra-ranking.us-east-2.api.aws', 'variants' => [ [ 'hostname' => 'kendra-ranking-fips.us-east-2.api.aws', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'hostname' => 'kendra-ranking.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'kendra-ranking.us-west-2.api.aws', 'variants' => [ [ 'hostname' => 'kendra-ranking-fips.us-west-2.api.aws', 'tags' => [ 'fips', ], ], ], ], ], ], 'kinesis' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'kinesis-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'kinesis-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'kinesis-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'kinesis-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'kinesis-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'kinesis-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'kinesis-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'kinesis-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kinesisanalytics' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kinesisvideo' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-5' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-central-2.amazonaws.com', ], 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'af-south-1-fips' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.af-south-1.amazonaws.com', ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-1-fips' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-east-1.amazonaws.com', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-1-fips' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-2-fips' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-northeast-2.amazonaws.com', ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-northeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-3-fips' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-northeast-3.amazonaws.com', ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-1-fips' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-south-1.amazonaws.com', ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-2-fips' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-south-2.amazonaws.com', ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-1-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-2-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-2.amazonaws.com', ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-3-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-3.amazonaws.com', ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-4.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-4-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-4.amazonaws.com', ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-5.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-5-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-5.amazonaws.com', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ap-southeast-7.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-7-fips' => [ 'credentialScope' => [ 'region' => 'ap-southeast-7', ], 'deprecated' => true, 'hostname' => 'kms-fips.ap-southeast-7.amazonaws.com', ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1-fips' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-central-1.amazonaws.com', ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-central-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-2-fips' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-central-2.amazonaws.com', ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-north-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-north-1-fips' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-north-1.amazonaws.com', ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-1-fips' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-south-1.amazonaws.com', ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-2-fips' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-south-2.amazonaws.com', ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1-fips' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-2-fips' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-3-fips' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-west-3.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.il-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'il-central-1-fips' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.il-central-1.amazonaws.com', ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.me-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-central-1-fips' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.me-central-1.amazonaws.com', ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.me-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-south-1-fips' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.me-south-1.amazonaws.com', ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.mx-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'mx-central-1-fips' => [ 'credentialScope' => [ 'region' => 'mx-central-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.mx-central-1.amazonaws.com', ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1-fips' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-west-2.amazonaws.com', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'lakeformation.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'lambda' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'lambda.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'lambda.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'lambda.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'lambda.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'lambda.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'lambda.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'lambda.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'lambda.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'license-manager' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'license-manager-linux-subscriptions' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'license-manager-linux-subscriptions-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'license-manager-linux-subscriptions-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'license-manager-linux-subscriptions-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'license-manager-linux-subscriptions-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-linux-subscriptions-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-linux-subscriptions-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-linux-subscriptions-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-linux-subscriptions-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'license-manager-user-subscriptions' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'license-manager-user-subscriptions-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'license-manager-user-subscriptions-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'license-manager-user-subscriptions-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'license-manager-user-subscriptions-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-user-subscriptions-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-user-subscriptions-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-user-subscriptions-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'license-manager-user-subscriptions-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'lightsail' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'logs' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'logs.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'logs.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'logs.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'logs.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'logs.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'logs.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'logs.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'logs.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'logs.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'logs.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'logs.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'logs-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'logs-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'logs.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'logs.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'logs.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'logs.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'logs.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'logs.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'logs.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'logs.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'logs-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'logs-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'logs-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'logs-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'logs-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'logs-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'logs.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'logs.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'logs.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'logs.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'logs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'logs-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'logs-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'logs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'lookoutequipment' => [ 'endpoints' => [ 'ap-northeast-2' => [], 'eu-west-1' => [], 'us-east-1' => [], ], ], 'lookoutmetrics' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'lookoutvision' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'm2' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'deprecated' => true, ], 'fips-us-east-1' => [ 'deprecated' => true, ], 'fips-us-east-2' => [ 'deprecated' => true, ], 'fips-us-west-1' => [ 'deprecated' => true, ], 'fips-us-west-2' => [ 'deprecated' => true, ], 'il-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'machinelearning' => [ 'endpoints' => [ 'eu-west-1' => [], 'us-east-1' => [], ], ], 'macie2' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'macie2.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'macie2.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'macie2.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'macie2.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'macie2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'macie2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'macie2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'macie2-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'macie2.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'macie2.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'macie2.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'macie2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'macie2-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'macie2.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'macie2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'macie2-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'macie2.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'macie2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'macie2-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'macie2.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'macie2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'macie2-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'macie2.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'managedblockchain' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], ], ], 'managedblockchain-query' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'marketplacecommerceanalytics' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'media-pipelines-chime' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'media-pipelines-chime-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'media-pipelines-chime-fips.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'media-pipelines-chime-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'media-pipelines-chime-fips.us-west-2.amazonaws.com', ], ], ], 'mediaconnect' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'mediaconvert' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'mediaconvert.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'mediaconvert-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'mediaconvert-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'mediaconvert-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'mediaconvert-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'mediaconvert-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'mediaconvert.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'mediaconvert-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'mediaconvert.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'mediaconvert.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'mediaconvert-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'mediaconvert.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'medialive' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'medialive-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'medialive-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'medialive-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'medialive-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'medialive-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'medialive-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'mediapackage' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'mediapackage-vod' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'mediapackagev2' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-4' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'mediapackagev2-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'mediapackagev2-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'mediapackagev2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'mediapackagev2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'mediapackagev2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'mediapackagev2-fips.us-west-2.amazonaws.com', ], 'me-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'mediapackagev2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'mediapackagev2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'mediapackagev2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'mediapackagev2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'mediastore' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'meetings-chime' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'meetings-chime-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'meetings-chime-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-west-2' => [], 'il-central-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'meetings-chime-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'meetings-chime-fips.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'meetings-chime-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'meetings-chime-fips.us-west-2.amazonaws.com', ], ], ], 'memory-db' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'memory-db-fips.us-west-1.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'messaging-chime' => [ 'endpoints' => [ 'eu-central-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'messaging-chime-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'messaging-chime-fips.us-east-1.amazonaws.com', ], ], ], 'metering.marketplace' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'aws-marketplace', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'metrics-fips.sagemaker.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'metrics-fips.sagemaker.us-west-2.amazonaws.com', ], ], ], 'mgh' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'mgn' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'migrationhub-orchestrator' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'migrationhub-strategy' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'mobileanalytics' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'models-v2-lex' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'models.lex' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'lex', ], 'variants' => [ [ 'hostname' => 'models-fips.lex.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'models-fips.lex.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'models-fips.lex.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'models-fips.lex.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'models-fips.lex.us-west-2.amazonaws.com', ], ], ], 'monitoring' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'monitoring-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'monitoring-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'monitoring-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'monitoring-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'monitoring-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'monitoring-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'monitoring-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'monitoring-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'mq' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'mturk-requester' => [ 'endpoints' => [ 'sandbox' => [ 'hostname' => 'mturk-requester-sandbox.us-east-1.amazonaws.com', ], 'us-east-1' => [], ], 'isRegionalized' => false, ], 'neptune' => [ 'endpoints' => [ 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'rds.ap-east-1.amazonaws.com', ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'rds.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'rds.ap-northeast-2.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'rds.ap-south-1.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'rds.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'rds.ap-southeast-2.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'rds.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'rds.eu-central-1.amazonaws.com', ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'rds.eu-north-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'rds.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'rds.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'rds.eu-west-3.amazonaws.com', ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'rds.me-south-1.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'rds.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'rds.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'rds.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'rds.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'rds.us-west-2.amazonaws.com', ], ], ], 'network-firewall' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'networkmanager' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'networkmanager.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'networkmanager-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'networkmanager-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'networkmanager.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-aws-global' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'networkmanager-fips.us-west-2.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'notifications' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'notifications.af-south-1.api.aws', ], 'ap-east-1' => [ 'hostname' => 'notifications.ap-east-1.api.aws', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'notifications.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'notifications.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'notifications.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'notifications.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'notifications.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'notifications.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'notifications.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'notifications.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'notifications.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'notifications.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'notifications.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'notifications.ca-central-1.api.aws', ], 'ca-west-1' => [ 'hostname' => 'notifications.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'notifications.eu-central-1.api.aws', ], 'eu-central-2' => [ 'hostname' => 'notifications.eu-central-2.api.aws', ], 'eu-north-1' => [ 'hostname' => 'notifications.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'notifications.eu-south-1.api.aws', ], 'eu-south-2' => [ 'hostname' => 'notifications.eu-south-2.api.aws', ], 'eu-west-1' => [ 'hostname' => 'notifications.eu-west-1.api.aws', ], 'eu-west-2' => [ 'hostname' => 'notifications.eu-west-2.api.aws', ], 'eu-west-3' => [ 'hostname' => 'notifications.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'notifications.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'notifications.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'notifications.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'notifications.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'notifications.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'notifications.us-east-1.api.aws', ], 'us-east-2' => [ 'hostname' => 'notifications.us-east-2.api.aws', ], 'us-west-1' => [ 'hostname' => 'notifications.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'notifications.us-west-2.api.aws', ], ], ], 'notifications-contacts' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'notifications-contacts.us-east-1.api.aws', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'oam' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'oidc' => [ 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'oidc.af-south-1.amazonaws.com', ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'oidc.ap-east-1.amazonaws.com', ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'oidc.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'oidc.ap-northeast-2.amazonaws.com', ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'oidc.ap-northeast-3.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'oidc.ap-south-1.amazonaws.com', ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'oidc.ap-south-2.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'oidc.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'oidc.ap-southeast-2.amazonaws.com', ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'oidc.ap-southeast-3.amazonaws.com', ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'oidc.ap-southeast-4.amazonaws.com', ], 'ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'hostname' => 'oidc.ap-southeast-5.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'oidc.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'hostname' => 'oidc.ca-west-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'oidc.eu-central-1.amazonaws.com', ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'oidc.eu-central-2.amazonaws.com', ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'oidc.eu-north-1.amazonaws.com', ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'oidc.eu-south-1.amazonaws.com', ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'oidc.eu-south-2.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'oidc.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'oidc.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'oidc.eu-west-3.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'oidc.il-central-1.amazonaws.com', ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'oidc.me-central-1.amazonaws.com', ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'oidc.me-south-1.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'oidc.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'oidc.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'oidc.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'oidc.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'oidc.us-west-2.amazonaws.com', ], ], ], 'omics' => [ 'endpoints' => [ 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'omics.ap-southeast-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'omics.eu-central-1.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'omics.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'omics.eu-west-2.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'omics-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'omics-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'omics.il-central-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'omics.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'omics-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'omics.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'omics-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'organizations' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'organizations.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'organizations-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'organizations-fips.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'osis' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'outposts' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'outposts-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'outposts-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'outposts-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'outposts-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'outposts-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'outposts-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'outposts-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'outposts-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'outposts-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'outposts-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'participant.connect' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'participant.connect-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'participant.connect-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'participant.connect-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'participant.connect-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'personalize' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'pi' => [ 'endpoints' => [ 'af-south-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'pinpoint' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'mobiletargeting', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'pinpoint.ca-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'pinpoint-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'pinpoint-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'pinpoint-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'pinpoint-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'pinpoint-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'pinpoint.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'pinpoint-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'pinpoint.us-east-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'pinpoint-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'pinpoint.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'pinpoint-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'pipes' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'polly' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'polly.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'polly.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'polly.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'polly.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'polly.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'polly.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'polly.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'polly.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'polly.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'polly-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'polly.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'polly.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'polly.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'polly.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'polly.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'polly.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'polly-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'polly-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'polly-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'polly-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'polly-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'polly.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'polly.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'polly-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'polly-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'polly-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'polly-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'portal.sso' => [ 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'portal.sso.af-south-1.amazonaws.com', ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'portal.sso.ap-east-1.amazonaws.com', ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'portal.sso.ap-northeast-1.amazonaws.com', ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'portal.sso.ap-northeast-2.amazonaws.com', ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'portal.sso.ap-northeast-3.amazonaws.com', ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'portal.sso.ap-south-1.amazonaws.com', ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'portal.sso.ap-south-2.amazonaws.com', ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'portal.sso.ap-southeast-1.amazonaws.com', ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'portal.sso.ap-southeast-2.amazonaws.com', ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'portal.sso.ap-southeast-3.amazonaws.com', ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'portal.sso.ap-southeast-4.amazonaws.com', ], 'ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'hostname' => 'portal.sso.ap-southeast-5.amazonaws.com', ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'portal.sso.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'hostname' => 'portal.sso.ca-west-1.amazonaws.com', ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'portal.sso.eu-central-1.amazonaws.com', ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'portal.sso.eu-central-2.amazonaws.com', ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'portal.sso.eu-north-1.amazonaws.com', ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'portal.sso.eu-south-1.amazonaws.com', ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'portal.sso.eu-south-2.amazonaws.com', ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'portal.sso.eu-west-1.amazonaws.com', ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'portal.sso.eu-west-2.amazonaws.com', ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'portal.sso.eu-west-3.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'portal.sso.il-central-1.amazonaws.com', ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'portal.sso.me-central-1.amazonaws.com', ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'portal.sso.me-south-1.amazonaws.com', ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'portal.sso.sa-east-1.amazonaws.com', ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'portal.sso.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'portal.sso.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'portal.sso.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'portal.sso.us-west-2.amazonaws.com', ], ], ], 'profile' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'profile-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'profile-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'profile-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'profile-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'profile-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'profile-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'proton' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'qbusiness' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'hostname' => 'qbusiness.af-south-1.api.aws', ], 'ap-east-1' => [ 'hostname' => 'qbusiness.ap-east-1.api.aws', ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 'qbusiness.ap-northeast-1.api.aws', ], 'ap-northeast-2' => [ 'hostname' => 'qbusiness.ap-northeast-2.api.aws', ], 'ap-northeast-3' => [ 'hostname' => 'qbusiness.ap-northeast-3.api.aws', ], 'ap-south-1' => [ 'hostname' => 'qbusiness.ap-south-1.api.aws', ], 'ap-south-2' => [ 'hostname' => 'qbusiness.ap-south-2.api.aws', ], 'ap-southeast-1' => [ 'hostname' => 'qbusiness.ap-southeast-1.api.aws', ], 'ap-southeast-2' => [ 'hostname' => 'qbusiness.ap-southeast-2.api.aws', ], 'ap-southeast-3' => [ 'hostname' => 'qbusiness.ap-southeast-3.api.aws', ], 'ap-southeast-4' => [ 'hostname' => 'qbusiness.ap-southeast-4.api.aws', ], 'ap-southeast-5' => [ 'hostname' => 'qbusiness.ap-southeast-5.api.aws', ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'hostname' => 'qbusiness.ap-southeast-7.api.aws', ], 'ca-central-1' => [ 'hostname' => 'qbusiness.ca-central-1.api.aws', ], 'ca-west-1' => [ 'hostname' => 'qbusiness.ca-west-1.api.aws', ], 'eu-central-1' => [ 'hostname' => 'qbusiness.eu-central-1.api.aws', ], 'eu-central-2' => [ 'hostname' => 'qbusiness.eu-central-2.api.aws', ], 'eu-north-1' => [ 'hostname' => 'qbusiness.eu-north-1.api.aws', ], 'eu-south-1' => [ 'hostname' => 'qbusiness.eu-south-1.api.aws', ], 'eu-south-2' => [ 'hostname' => 'qbusiness.eu-south-2.api.aws', ], 'eu-west-1' => [ 'hostname' => 'qbusiness.eu-west-1.api.aws', ], 'eu-west-2' => [ 'hostname' => 'qbusiness.eu-west-2.api.aws', ], 'eu-west-3' => [ 'hostname' => 'qbusiness.eu-west-3.api.aws', ], 'il-central-1' => [ 'hostname' => 'qbusiness.il-central-1.api.aws', ], 'me-central-1' => [ 'hostname' => 'qbusiness.me-central-1.api.aws', ], 'me-south-1' => [ 'hostname' => 'qbusiness.me-south-1.api.aws', ], 'mx-central-1' => [ 'hostname' => 'qbusiness.mx-central-1.api.aws', ], 'sa-east-1' => [ 'hostname' => 'qbusiness.sa-east-1.api.aws', ], 'us-east-1' => [ 'hostname' => 'qbusiness.us-east-1.api.aws', ], 'us-east-2' => [ 'hostname' => 'qbusiness.us-east-2.api.aws', ], 'us-west-1' => [ 'hostname' => 'qbusiness.us-west-1.api.aws', ], 'us-west-2' => [ 'hostname' => 'qbusiness.us-west-2.api.aws', ], ], ], 'qldb' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'qldb-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'qldb-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'qldb-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'qldb-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'qldb-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'qldb-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'qldb-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'qldb-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'query.timestream' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'quicksight' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'ram' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ram-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'ram-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ram-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ram-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ram-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ram-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ram-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'rbin' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'rbin.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'rbin.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'rbin.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'rbin.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'rbin.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'rbin.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'rds' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'rds-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'rds-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'rds-fips.ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.ca-central-1.amazonaws.com', ], 'rds-fips.ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.ca-west-1.amazonaws.com', ], 'rds-fips.us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-east-1.amazonaws.com', ], 'rds-fips.us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-east-2.amazonaws.com', ], 'rds-fips.us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-west-1.amazonaws.com', ], 'rds-fips.us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-west-2.amazonaws.com', ], 'rds.ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rds.ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rds.us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rds.us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rds.us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rds.us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rds-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1' => [], 'us-east-1' => [ 'sslCommonName' => '{service}.{dnsSuffix}', 'variants' => [ [ 'hostname' => 'rds-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'rds-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'rds-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'rds-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rds-fips.us-west-2.amazonaws.com', ], ], ], 'rds-data' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rds-data-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rds-data-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rds-data-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rds-data-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'rds-data-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'rds-data-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'rds-data-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'rds-data-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'redshift' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'redshift-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'redshift-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'redshift-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'redshift-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'redshift-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'redshift-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'redshift-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'redshift-serverless' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'rekognition' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'rekognition.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'rekognition.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'rekognition.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'rekognition.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'rekognition.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'rekognition-fips.ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.ca-central-1.amazonaws.com', ], 'rekognition-fips.us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-east-1.amazonaws.com', ], 'rekognition-fips.us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-east-2.amazonaws.com', ], 'rekognition-fips.us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-west-1.amazonaws.com', ], 'rekognition-fips.us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-west-2.amazonaws.com', ], 'rekognition.ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rekognition.us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rekognition.us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rekognition.us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'rekognition.us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-west-2.amazonaws.com', ], ], ], 'resiliencehub' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'resiliencehub.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'resource-explorer-2' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'resource-explorer-2-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'resource-explorer-2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resource-explorer-2-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'resource-groups' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'resource-groups-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'resource-groups-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'resource-groups-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'resource-groups-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'resource-groups-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'resource-groups-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'resource-groups-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'resource-groups-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'robomaker' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'rolesanywhere' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'route53' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'route53.amazonaws.com', 'variants' => [ [ 'hostname' => 'route53-fips.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'route53-fips.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'route53-recovery-control-config' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'route53-recovery-control-config.us-west-2.amazonaws.com', ], ], ], 'route53domains' => [ 'endpoints' => [ 'us-east-1' => [], ], ], 'route53profiles' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'route53profiles.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'route53profiles.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'route53resolver' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'route53resolver.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'route53resolver.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'route53resolver-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53resolver.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'route53resolver-fips.us-west-2.amazonaws.com', ], ], ], 'rum' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'runtime-v2-lex' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'runtime.lex' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'lex', ], 'variants' => [ [ 'hostname' => 'runtime-fips.lex.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.lex.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'runtime-fips.lex.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.lex.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'runtime-fips.lex.us-west-2.amazonaws.com', ], ], ], 'runtime.sagemaker' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.sagemaker.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.sagemaker.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'runtime-fips.sagemaker.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.sagemaker.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'runtime-fips.sagemaker.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.sagemaker.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'runtime-fips.sagemaker.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.sagemaker.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'runtime-fips.sagemaker.us-west-2.amazonaws.com', ], ], ], 's3' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.af-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'hostname' => 's3.ap-northeast-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3.dualstack.ap-northeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-northeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-northeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'hostname' => 's3.ap-southeast-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'hostname' => 's3.ap-southeast-2.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-4.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-5.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.ap-southeast-7.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 's3.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 's3-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-fips.dualstack.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3.dualstack.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 's3-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-fips.dualstack.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3.dualstack.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-central-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-north-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'hostname' => 's3.eu-west-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3.dualstack.eu-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.eu-west-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 's3-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 's3-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 's3-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 's3-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.il-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.me-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.me-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.mx-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 's3-external-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 's3-external-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], ], 'sa-east-1' => [ 'hostname' => 's3.sa-east-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3.dualstack.sa-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'hostname' => 's3.us-east-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'hostname' => 's3.us-west-1.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'hostname' => 's3.us-west-2.amazonaws.com', 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], 'isRegionalized' => true, 'partitionEndpoint' => 'aws-global', ], 's3-control' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 's3-control.af-south-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.af-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 's3-control.ap-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 's3-control.ap-northeast-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-northeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 's3-control.ap-northeast-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-northeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 's3-control.ap-northeast-3.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-northeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 's3-control.ap-south-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 's3-control.ap-south-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 's3-control.ap-southeast-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-southeast-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 's3-control.ap-southeast-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-southeast-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 's3-control.ap-southeast-3.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-southeast-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 's3-control.ap-southeast-4.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.ap-southeast-4.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 's3-control.ca-central-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control-fips.dualstack.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control.dualstack.ca-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.ca-central-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'hostname' => 's3-control.ca-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control-fips.dualstack.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control.dualstack.ca-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.ca-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 's3-control.eu-central-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 's3-control.eu-central-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-central-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 's3-control.eu-north-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-north-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 's3-control.eu-south-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 's3-control.eu-south-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-south-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 's3-control.eu-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 's3-control.eu-west-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 's3-control.eu-west-3.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.eu-west-3.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 's3-control.il-central-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.il-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 's3-control.me-central-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.me-central-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 's3-control.me-south-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.me-south-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 's3-control.sa-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.sa-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 's3-control.us-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 's3-control.us-east-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-east-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-east-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 's3-control.us-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 's3-control.us-west-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-west-2.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-west-2.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], ], ], 's3-outposts' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'deprecated' => true, ], 'fips-us-east-1' => [ 'deprecated' => true, ], 'fips-us-east-2' => [ 'deprecated' => true, ], 'fips-us-west-1' => [ 'deprecated' => true, ], 'fips-us-west-2' => [ 'deprecated' => true, ], 'il-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], ], ], 'sagemaker-geospatial' => [ 'endpoints' => [ 'us-west-2' => [], ], ], 'savingsplans' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'savingsplans.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'scheduler' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'schemas' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'sdb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 'v2', ], ], 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'hostname' => 'sdb.amazonaws.com', ], 'us-west-1' => [], 'us-west-2' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'deprecated' => true, ], 'ca-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'deprecated' => true, ], 'eu-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'deprecated' => true, ], 'us-east-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'deprecated' => true, ], 'us-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'deprecated' => true, ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'deprecated' => true, ], ], ], 'securityhub' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'securityhub.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'securityhub.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'securityhub.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'securitylake' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'securitylake-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'securitylake-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'securitylake-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'securitylake-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'securitylake-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'securitylake-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'securitylake-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'securitylake-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'serverlessrepo' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-east-1' => [ 'protocols' => [ 'https', ], ], 'ap-northeast-1' => [ 'protocols' => [ 'https', ], ], 'ap-northeast-2' => [ 'protocols' => [ 'https', ], ], 'ap-south-1' => [ 'protocols' => [ 'https', ], ], 'ap-southeast-1' => [ 'protocols' => [ 'https', ], ], 'ap-southeast-2' => [ 'protocols' => [ 'https', ], ], 'ca-central-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'serverlessrepo-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [ 'protocols' => [ 'https', ], ], 'eu-north-1' => [ 'protocols' => [ 'https', ], ], 'eu-west-1' => [ 'protocols' => [ 'https', ], ], 'eu-west-2' => [ 'protocols' => [ 'https', ], ], 'eu-west-3' => [ 'protocols' => [ 'https', ], ], 'me-south-1' => [ 'protocols' => [ 'https', ], ], 'sa-east-1' => [ 'protocols' => [ 'https', ], ], 'us-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'serverlessrepo-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'serverlessrepo-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'serverlessrepo-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'serverlessrepo-fips.us-west-2.amazonaws.com', ], ], ], 'servicecatalog' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-west-2.amazonaws.com', ], ], ], 'servicecatalog-appregistry' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-appregistry-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-appregistry-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'servicecatalog-appregistry-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-appregistry-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'servicecatalog-appregistry-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'servicediscovery' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-west-2.amazonaws.com', ], ], ], 'servicequotas' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'session.qldb' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'session.qldb-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'session.qldb-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'session.qldb-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'session.qldb-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'session.qldb-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'session.qldb-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'shield' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'sslCommonName' => 'shield.us-east-1.amazonaws.com', ], 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'shield.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'shield-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'shield-fips.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'signer' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-west-2.amazonaws.com', ], 'fips-verification-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'verification.signer-fips.us-east-1.amazonaws.com', ], 'fips-verification-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'verification.signer-fips.us-east-2.amazonaws.com', ], 'fips-verification-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'verification.signer-fips.us-west-1.amazonaws.com', ], 'fips-verification-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'verification.signer-fips.us-west-2.amazonaws.com', ], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'verification-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'verification.signer.af-south-1.amazonaws.com', ], 'verification-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'verification.signer.ap-east-1.amazonaws.com', ], 'verification-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'verification.signer.ap-northeast-1.amazonaws.com', ], 'verification-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'verification.signer.ap-northeast-2.amazonaws.com', ], 'verification-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'verification.signer.ap-south-1.amazonaws.com', ], 'verification-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'verification.signer.ap-southeast-1.amazonaws.com', ], 'verification-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'verification.signer.ap-southeast-2.amazonaws.com', ], 'verification-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'verification.signer.ca-central-1.amazonaws.com', ], 'verification-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'verification.signer.eu-central-1.amazonaws.com', ], 'verification-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'verification.signer.eu-north-1.amazonaws.com', ], 'verification-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'verification.signer.eu-south-1.amazonaws.com', ], 'verification-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'verification.signer.eu-west-1.amazonaws.com', ], 'verification-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'verification.signer.eu-west-2.amazonaws.com', ], 'verification-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'verification.signer.eu-west-3.amazonaws.com', ], 'verification-me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'verification.signer.me-south-1.amazonaws.com', ], 'verification-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'verification.signer.sa-east-1.amazonaws.com', ], 'verification-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'verification.signer.us-east-1.amazonaws.com', ], 'verification-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'verification.signer.us-east-2.amazonaws.com', ], 'verification-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'verification.signer.us-west-1.amazonaws.com', ], 'verification-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'verification.signer.us-west-2.amazonaws.com', ], ], ], 'simspaceweaver' => [ 'endpoints' => [ 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'sms' => [ 'endpoints' => [ 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'sms-fips.us-west-2.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'sms-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'sms-voice' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'sms-voice.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'sms-voice.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'snowball' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.af-south-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-northeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-south-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ap-southeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-north-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-north-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-south-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.eu-west-3.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.af-south-1.amazonaws.com', ], 'fips-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-east-1.amazonaws.com', ], 'fips-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-northeast-1.amazonaws.com', ], 'fips-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-northeast-2.amazonaws.com', ], 'fips-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-northeast-3.amazonaws.com', ], 'fips-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-south-1.amazonaws.com', ], 'fips-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-southeast-1.amazonaws.com', ], 'fips-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-southeast-2.amazonaws.com', ], 'fips-ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ap-southeast-3.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.ca-central-1.amazonaws.com', ], 'fips-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-central-1.amazonaws.com', ], 'fips-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-north-1.amazonaws.com', ], 'fips-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-south-1.amazonaws.com', ], 'fips-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-west-1.amazonaws.com', ], 'fips-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-west-2.amazonaws.com', ], 'fips-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'snowball-fips.eu-west-3.amazonaws.com', ], 'fips-il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.il-central-1.amazonaws.com', ], 'fips-me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.me-central-1.amazonaws.com', ], 'fips-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.sa-east-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.il-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.il-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.me-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.me-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.sa-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'sns' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'sns.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'sns.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'sns.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'sns.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'sns.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'sns.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'sns.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'sns.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'sns.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'sns-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sns.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'sns.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'sns.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'sns.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'sns.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'sns.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'sns.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'sns.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'sns.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'sns-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'sns-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'sns-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'sns-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'sns-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'sns.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'sns.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'sns.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'sns.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'sns.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'sns-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sns.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'sns-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sns.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'sns-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sns.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'sns-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sns.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'sqs' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'sqs.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'sqs.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'sqs-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'sqs-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'sqs.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'sqs-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'sqs-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'sqs-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'sqs-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'sqs-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'sqs-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'sqs.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'sqs.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'sqs.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'sqs.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'sqs.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'sslCommonName' => 'queue.{dnsSuffix}', 'variants' => [ [ 'hostname' => 'sqs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'sqs-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'sqs-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'sqs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sqs.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'ssm' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ssm-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ssm-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ssm-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ssm-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm-contacts' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ssm-contacts-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ssm-contacts-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-contacts-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ssm-contacts-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-contacts-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ssm-contacts-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-contacts-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-contacts-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm-incidents' => [ 'endpoints' => [ 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-incidents-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-incidents.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ssm-incidents-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ssm-incidents-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ssm-incidents-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-incidents-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ssm-incidents-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-incidents-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-incidents.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-incidents-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-incidents.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-incidents-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-incidents.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-incidents-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-incidents-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-incidents.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'ssm-quicksetup' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-quicksetup-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ssm-quicksetup-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ssm-quicksetup-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ssm-quicksetup-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-quicksetup-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ssm-quicksetup-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-quicksetup-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ssm-quicksetup-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-quicksetup-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-quicksetup-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm-sap' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-sap-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-sap.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'ssm-sap-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'ssm-sap-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'ssm-sap-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'ssm-sap-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'ssm-sap-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-sap-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-sap.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-sap-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-sap.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm-sap-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-sap-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-sap.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'ssm-sap-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ssm-sap-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ssm-sap.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'sso' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'states' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'states-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'states-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'states-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'states-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'storagegateway' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.ca-central-1.amazonaws.com', ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.ca-west-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-west-2.amazonaws.com', ], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'local' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'localhost:8000', 'protocols' => [ 'http', ], ], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'sts' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'sts.amazonaws.com', ], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'sts-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'sts-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'sts-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'sts-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'sts-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'sts-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'sts-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'sts-fips.us-west-2.amazonaws.com', ], ], 'partitionEndpoint' => 'aws-global', ], 'support' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'support.us-east-1.amazonaws.com', ], ], 'partitionEndpoint' => 'aws-global', ], 'supportapp' => [ 'endpoints' => [ 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'swf' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'synthetics' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-2' => [], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-3' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-northeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-3' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-4' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-4.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-5' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-5.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-6' => [], 'ap-southeast-7' => [ 'variants' => [ [ 'hostname' => 'synthetics.ap-southeast-7.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.ca-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.ca-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-central-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'synthetics.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.il-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-central-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.me-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'mx-central-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.mx-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'tagging' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'tax' => [ 'endpoints' => [ 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'tax.us-east-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'textract' => [ 'endpoints' => [ 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'textract.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'textract.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'textract.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'textract.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'textract-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'textract.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-south-2' => [ 'variants' => [ [ 'hostname' => 'textract.eu-south-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'textract.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'textract.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'textract.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'textract-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'thinclient' => [ 'endpoints' => [ 'ap-south-1' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'tnb' => [ 'endpoints' => [ 'ap-northeast-2' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-south-2' => [], 'eu-west-3' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'transcribe' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'fips.transcribe.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'transcribe.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'transcribe.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'transcribe.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-west-2.amazonaws.com', ], 'me-south-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.me-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'transcribe.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transcribestreaming' => [ 'endpoints' => [ 'af-south-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.af-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.ca-central-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.us-east-2.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.us-west-2.amazonaws.com', ], 'sa-east-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.sa-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transfer' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'translate' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'ap-east-1' => [ 'variants' => [ [ 'hostname' => 'translate.ap-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-1' => [ 'variants' => [ [ 'hostname' => 'translate.ap-northeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-northeast-2' => [ 'variants' => [ [ 'hostname' => 'translate.ap-northeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-south-1' => [ 'variants' => [ [ 'hostname' => 'translate.ap-south-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-1' => [ 'variants' => [ [ 'hostname' => 'translate.ap-southeast-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ap-southeast-2' => [ 'variants' => [ [ 'hostname' => 'translate.ap-southeast-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'translate.ca-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-central-1' => [ 'variants' => [ [ 'hostname' => 'translate.eu-central-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-north-1' => [ 'variants' => [ [ 'hostname' => 'translate.eu-north-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-1' => [ 'variants' => [ [ 'hostname' => 'translate.eu-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-2' => [ 'variants' => [ [ 'hostname' => 'translate.eu-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'eu-west-3' => [ 'variants' => [ [ 'hostname' => 'translate.eu-west-3.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'translate-fips.us-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'translate.us-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-east-1.amazonaws.com', ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'translate-fips.us-east-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'translate.us-east-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-east-2-fips' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-east-2.amazonaws.com', ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'translate-fips.us-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'translate.us-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-west-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'translate-fips.us-west-2.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'translate.us-west-2.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-west-2.amazonaws.com', ], ], ], 'trustedadvisor' => [ 'endpoints' => [ 'ap-northeast-2' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'trustedadvisor-fips.us-east-1.api.aws', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'trustedadvisor-fips.us-east-2.api.aws', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'trustedadvisor-fips.us-west-2.api.aws', ], 'us-east-1' => [], 'us-east-2' => [], 'us-west-2' => [], ], ], 'verifiedpermissions' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-7' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.ca-west-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'voice-chime' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'voice-chime-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1-fips' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'voice-chime-fips.ca-central-1.amazonaws.com', ], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'voice-chime-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'voice-chime-fips.us-east-1.amazonaws.com', ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'voice-chime-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2-fips' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'voice-chime-fips.us-west-2.amazonaws.com', ], ], ], 'voiceid' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'hostname' => 'voiceid-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'voiceid-fips.ca-central-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'voiceid-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'voiceid-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'voiceid-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'voiceid-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'vpc-lattice' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-central-1' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'waf' => [ 'endpoints' => [ 'aws' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'waf-fips.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'aws-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'waf-fips.amazonaws.com', ], 'aws-global' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'waf.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-fips.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'aws-global-fips' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'waf-fips.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-global', ], 'waf-regional' => [ 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'waf-regional.af-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'waf-regional.ap-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'waf-regional.ap-northeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'waf-regional.ap-northeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'waf-regional.ap-northeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-northeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'waf-regional.ap-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'waf-regional.ap-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'waf-regional.ap-southeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'waf-regional.ap-southeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'waf-regional.ap-southeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-southeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'waf-regional.ap-southeast-4.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ap-southeast-4.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'waf-regional.ca-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'waf-regional.eu-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'waf-regional.eu-central-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-central-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'waf-regional.eu-north-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-north-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'waf-regional.eu-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'waf-regional.eu-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'waf-regional.eu-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'waf-regional.eu-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'waf-regional.eu-west-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.af-south-1.amazonaws.com', ], 'fips-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-east-1.amazonaws.com', ], 'fips-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-northeast-1.amazonaws.com', ], 'fips-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-northeast-2.amazonaws.com', ], 'fips-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-northeast-3.amazonaws.com', ], 'fips-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-south-1.amazonaws.com', ], 'fips-ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-south-2.amazonaws.com', ], 'fips-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-southeast-1.amazonaws.com', ], 'fips-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-southeast-2.amazonaws.com', ], 'fips-ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-southeast-3.amazonaws.com', ], 'fips-ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ap-southeast-4.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.ca-central-1.amazonaws.com', ], 'fips-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-central-1.amazonaws.com', ], 'fips-eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-central-2.amazonaws.com', ], 'fips-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-north-1.amazonaws.com', ], 'fips-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-south-1.amazonaws.com', ], 'fips-eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-south-2.amazonaws.com', ], 'fips-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-west-1.amazonaws.com', ], 'fips-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-west-2.amazonaws.com', ], 'fips-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.eu-west-3.amazonaws.com', ], 'fips-il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.il-central-1.amazonaws.com', ], 'fips-me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.me-central-1.amazonaws.com', ], 'fips-me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.me-south-1.amazonaws.com', ], 'fips-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.sa-east-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'waf-regional.il-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.il-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'waf-regional.me-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.me-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'waf-regional.me-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.me-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'waf-regional.sa-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'waf-regional.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'waf-regional.us-east-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'waf-regional.us-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'waf-regional.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'wafv2' => [ 'endpoints' => [ 'af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'hostname' => 'wafv2.af-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.af-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'hostname' => 'wafv2.ap-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'hostname' => 'wafv2.ap-northeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-northeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'hostname' => 'wafv2.ap-northeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-northeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'hostname' => 'wafv2.ap-northeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-northeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'hostname' => 'wafv2.ap-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'hostname' => 'wafv2.ap-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'hostname' => 'wafv2.ap-southeast-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'hostname' => 'wafv2.ap-southeast-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'hostname' => 'wafv2.ap-southeast-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'hostname' => 'wafv2.ap-southeast-4.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-4.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'hostname' => 'wafv2.ap-southeast-5.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-5.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ap-southeast-7' => [ 'credentialScope' => [ 'region' => 'ap-southeast-7', ], 'hostname' => 'wafv2.ap-southeast-7.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ap-southeast-7.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'hostname' => 'wafv2.ca-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ca-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'hostname' => 'wafv2.ca-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.ca-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'hostname' => 'wafv2.eu-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'hostname' => 'wafv2.eu-central-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-central-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'hostname' => 'wafv2.eu-north-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-north-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'hostname' => 'wafv2.eu-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'hostname' => 'wafv2.eu-south-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-south-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'hostname' => 'wafv2.eu-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'hostname' => 'wafv2.eu-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'hostname' => 'wafv2.eu-west-3.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.eu-west-3.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-af-south-1' => [ 'credentialScope' => [ 'region' => 'af-south-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.af-south-1.amazonaws.com', ], 'fips-ap-east-1' => [ 'credentialScope' => [ 'region' => 'ap-east-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-east-1.amazonaws.com', ], 'fips-ap-northeast-1' => [ 'credentialScope' => [ 'region' => 'ap-northeast-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-northeast-1.amazonaws.com', ], 'fips-ap-northeast-2' => [ 'credentialScope' => [ 'region' => 'ap-northeast-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-northeast-2.amazonaws.com', ], 'fips-ap-northeast-3' => [ 'credentialScope' => [ 'region' => 'ap-northeast-3', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-northeast-3.amazonaws.com', ], 'fips-ap-south-1' => [ 'credentialScope' => [ 'region' => 'ap-south-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-south-1.amazonaws.com', ], 'fips-ap-south-2' => [ 'credentialScope' => [ 'region' => 'ap-south-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-south-2.amazonaws.com', ], 'fips-ap-southeast-1' => [ 'credentialScope' => [ 'region' => 'ap-southeast-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-1.amazonaws.com', ], 'fips-ap-southeast-2' => [ 'credentialScope' => [ 'region' => 'ap-southeast-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-2.amazonaws.com', ], 'fips-ap-southeast-3' => [ 'credentialScope' => [ 'region' => 'ap-southeast-3', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-3.amazonaws.com', ], 'fips-ap-southeast-4' => [ 'credentialScope' => [ 'region' => 'ap-southeast-4', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-4.amazonaws.com', ], 'fips-ap-southeast-5' => [ 'credentialScope' => [ 'region' => 'ap-southeast-5', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-5.amazonaws.com', ], 'fips-ap-southeast-7' => [ 'credentialScope' => [ 'region' => 'ap-southeast-7', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ap-southeast-7.amazonaws.com', ], 'fips-ca-central-1' => [ 'credentialScope' => [ 'region' => 'ca-central-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ca-central-1.amazonaws.com', ], 'fips-ca-west-1' => [ 'credentialScope' => [ 'region' => 'ca-west-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.ca-west-1.amazonaws.com', ], 'fips-eu-central-1' => [ 'credentialScope' => [ 'region' => 'eu-central-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-central-1.amazonaws.com', ], 'fips-eu-central-2' => [ 'credentialScope' => [ 'region' => 'eu-central-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-central-2.amazonaws.com', ], 'fips-eu-north-1' => [ 'credentialScope' => [ 'region' => 'eu-north-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-north-1.amazonaws.com', ], 'fips-eu-south-1' => [ 'credentialScope' => [ 'region' => 'eu-south-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-south-1.amazonaws.com', ], 'fips-eu-south-2' => [ 'credentialScope' => [ 'region' => 'eu-south-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-south-2.amazonaws.com', ], 'fips-eu-west-1' => [ 'credentialScope' => [ 'region' => 'eu-west-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-west-1.amazonaws.com', ], 'fips-eu-west-2' => [ 'credentialScope' => [ 'region' => 'eu-west-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-west-2.amazonaws.com', ], 'fips-eu-west-3' => [ 'credentialScope' => [ 'region' => 'eu-west-3', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.eu-west-3.amazonaws.com', ], 'fips-il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.il-central-1.amazonaws.com', ], 'fips-me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.me-central-1.amazonaws.com', ], 'fips-me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.me-south-1.amazonaws.com', ], 'fips-mx-central-1' => [ 'credentialScope' => [ 'region' => 'mx-central-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.mx-central-1.amazonaws.com', ], 'fips-sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.sa-east-1.amazonaws.com', ], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [ 'credentialScope' => [ 'region' => 'il-central-1', ], 'hostname' => 'wafv2.il-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.il-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-central-1' => [ 'credentialScope' => [ 'region' => 'me-central-1', ], 'hostname' => 'wafv2.me-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.me-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'me-south-1' => [ 'credentialScope' => [ 'region' => 'me-south-1', ], 'hostname' => 'wafv2.me-south-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.me-south-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'mx-central-1' => [ 'credentialScope' => [ 'region' => 'mx-central-1', ], 'hostname' => 'wafv2.mx-central-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.mx-central-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'sa-east-1' => [ 'credentialScope' => [ 'region' => 'sa-east-1', ], 'hostname' => 'wafv2.sa-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.sa-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'hostname' => 'wafv2.us-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'hostname' => 'wafv2.us-east-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'hostname' => 'wafv2.us-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'hostname' => 'wafv2.us-west-2.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'wellarchitected' => [ 'endpoints' => [ 'ap-east-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-north-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'me-south-1' => [], 'sa-east-1' => [], 'us-east-1' => [], 'us-east-2' => [], 'us-west-1' => [], 'us-west-2' => [], ], ], 'wisdom' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'eu-central-1' => [], 'eu-west-2' => [], 'fips-ca-central-1' => [ 'deprecated' => true, ], 'fips-us-east-1' => [ 'deprecated' => true, ], 'fips-us-west-2' => [ 'deprecated' => true, ], 'ui-ap-northeast-1' => [], 'ui-ap-northeast-2' => [], 'ui-ap-southeast-1' => [], 'ui-ap-southeast-2' => [], 'ui-ca-central-1' => [], 'ui-eu-central-1' => [], 'ui-eu-west-2' => [], 'ui-us-east-1' => [], 'ui-us-west-2' => [], 'us-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'workdocs' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'eu-west-1' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'workdocs-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'workdocs-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'workdocs-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'workdocs-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'workmail' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'eu-west-1' => [], 'us-east-1' => [], 'us-west-2' => [], ], ], 'workspaces' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'workspaces-web' => [ 'endpoints' => [ 'ap-northeast-1' => [], 'ap-south-1' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ca-central-1' => [], 'eu-central-1' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'workspaces-web-fips.us-east-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'workspaces-web-fips.us-west-2.amazonaws.com', ], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-web-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'workspaces-web-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'xray' => [ 'endpoints' => [ 'af-south-1' => [], 'ap-east-1' => [], 'ap-east-2' => [], 'ap-northeast-1' => [], 'ap-northeast-2' => [], 'ap-northeast-3' => [], 'ap-south-1' => [], 'ap-south-2' => [], 'ap-southeast-1' => [], 'ap-southeast-2' => [], 'ap-southeast-3' => [], 'ap-southeast-4' => [], 'ap-southeast-5' => [], 'ap-southeast-6' => [], 'ap-southeast-7' => [], 'ca-central-1' => [], 'ca-west-1' => [], 'eu-central-1' => [], 'eu-central-2' => [], 'eu-north-1' => [], 'eu-south-1' => [], 'eu-south-2' => [], 'eu-west-1' => [], 'eu-west-2' => [], 'eu-west-3' => [], 'fips-us-east-1' => [ 'credentialScope' => [ 'region' => 'us-east-1', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-east-1.amazonaws.com', ], 'fips-us-east-2' => [ 'credentialScope' => [ 'region' => 'us-east-2', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-east-2.amazonaws.com', ], 'fips-us-west-1' => [ 'credentialScope' => [ 'region' => 'us-west-1', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-west-1.amazonaws.com', ], 'fips-us-west-2' => [ 'credentialScope' => [ 'region' => 'us-west-2', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-west-2.amazonaws.com', ], 'il-central-1' => [], 'me-central-1' => [], 'me-south-1' => [], 'mx-central-1' => [], 'sa-east-1' => [], 'us-east-1' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-east-2' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-east-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-1' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-west-2' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-west-2.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'dnsSuffix' => 'amazonaws.com.cn', 'partition' => 'aws-cn', 'partitionName' => 'AWS China', 'regionRegex' => '^cn\\-\\w+\\-\\d+$', 'regions' => [ 'cn-north-1' => [ 'description' => 'China (Beijing)', ], 'cn-northwest-1' => [ 'description' => 'China (Ningxia)', ], ], 'services' => [ 'access-analyzer' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'account' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'account.cn-northwest-1.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'acm' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'acm-pca' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'airflow' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'api.ecr' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'api.ecr.cn-north-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'ecr.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'api.ecr.cn-northwest-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'ecr.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'cn-northwest-1' => [], ], ], 'api.sagemaker' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'api.tunneling.iot' => [ 'defaults' => [ 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com.cn', 'hostname' => 'api.tunneling.iot-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => 'api.iot-tunneling-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => 'api.iot-tunneling.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'apigateway' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'applicationinsights' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'appmesh' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'appmesh.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'appsync' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'appsync.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'appsync.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'athena.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'athena.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'autoscaling-plans' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'backup' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'batch' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'budgets' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'budgets.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'cassandra' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'ce' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'ce.cn-northwest-1.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'cloudcontrolapi' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cloudformation' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'cloudfront' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'cloudfront.cn-northwest-1.amazonaws.com.cn', 'protocols' => [ 'http', 'https', ], ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'cloudtrail' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'codebuild' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'codecommit' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'codedeploy' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'codepipeline' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'cognito-identity' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.cn-north-1.amazonaws.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'compute-optimizer' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'compute-optimizer.cn-north-1.amazonaws.com.cn', ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'compute-optimizer.cn-northwest-1.amazonaws.com.cn', ], ], ], 'config' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'cur' => [ 'endpoints' => [ 'cn-northwest-1' => [], ], ], 'data-ats.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'data.ats.iot.cn-north-1.amazonaws.com.cn', 'protocols' => [ 'https', ], ], 'cn-northwest-1' => [], ], ], 'data.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'data.jobs.iot' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'databrew' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'datasync' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'datasync.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'datasync.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'datazone' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'datazone.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'datazone.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'dax' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'directconnect' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'dlm' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'dlm.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'dlm.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'dms' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'docdb' => [ 'endpoints' => [ 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'rds.cn-northwest-1.amazonaws.com.cn', ], ], ], 'ds' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'dynamodb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'ebs' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'ec2' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'ecs' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'eks-auth' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'eks-auth.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'eks-auth.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'elasticache' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'elasticbeanstalk' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'elasticbeanstalk.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.cn-north-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'fips-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.cn-north-1.amazonaws.com.cn', ], 'fips-cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.cn-northwest-1.amazonaws.com.cn', ], ], ], 'elasticloadbalancing' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'elasticmapreduce' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'emr-containers' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'emr-serverless' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'entitlement.marketplace' => [ 'endpoints' => [ 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'entitlement-marketplace.cn-northwest-1.amazonaws.com.cn', 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'entitlement-marketplace.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'es' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'aos.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'aos.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'events' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'events.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'events.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'firehose' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'firehose.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'firehose.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'fms' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'fsx' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'gamelift' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'gameliftstreams' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'gameliftstreams.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'gameliftstreams.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'glacier' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'glue' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'glue.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'glue.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'greengrass' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], ], 'isRegionalized' => true, ], 'guardduty' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], 'isRegionalized' => true, ], 'health' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'sslCommonName' => 'health.cn-northwest-1.amazonaws.com.cn', ], 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'global.health.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'iam' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'iam.cn-north-1.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'identitystore' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'inspector2' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'internetmonitor' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'internetmonitor.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'internetmonitor.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'iot' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'iotanalytics' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'iotevents' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'ioteventsdata' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'data.iotevents.cn-north-1.amazonaws.com.cn', ], ], ], 'iotsecuredtunneling' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'iotsitewise' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'iottwinmaker' => [ 'endpoints' => [ 'api-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'api.iottwinmaker.cn-north-1.amazonaws.com.cn', ], 'cn-north-1' => [], 'data-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'data.iottwinmaker.cn-north-1.amazonaws.com.cn', ], ], ], 'kafka' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'kafkaconnect' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'kendra-ranking' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'kendra-ranking.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'kendra-ranking.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'kinesis' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'kinesisanalytics' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'kinesisvideo' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'kms' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'lakeformation' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'lambda' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'lambda.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'lambda.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'license-manager' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'license-manager-linux-subscriptions' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'logs.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'logs.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'mediaconvert' => [ 'endpoints' => [ 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'memory-db' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'metering.marketplace' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'aws-marketplace', ], ], 'endpoints' => [ 'cn-northwest-1' => [], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'monitoring' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'mq' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'neptune' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'rds.cn-north-1.amazonaws.com.cn', ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'rds.cn-northwest-1.amazonaws.com.cn', ], ], ], 'network-firewall' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'notifications' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'notifications.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'notifications.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'oam' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'oidc' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'oidc.cn-north-1.amazonaws.com.cn', ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'oidc.cn-northwest-1.amazonaws.com.cn', ], ], ], 'organizations' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'organizations.cn-northwest-1.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'personalize' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'pi' => [ 'endpoints' => [ 'cn-north-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'pipes' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'polly' => [ 'endpoints' => [ 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'polly.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'portal.sso' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'portal.sso.cn-north-1.amazonaws.com.cn', ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'portal.sso.cn-northwest-1.amazonaws.com.cn', ], ], ], 'qbusiness' => [ 'defaults' => [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'variants' => [ [ 'dnsSuffix' => 'api.amazonwebservices.com.cn', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'hostname' => 'qbusiness.cn-north-1.api.amazonwebservices.com.cn', ], 'cn-northwest-1' => [ 'hostname' => 'qbusiness.cn-northwest-1.api.amazonwebservices.com.cn', ], ], ], 'quicksight' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'ram' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], ], ], 'rbin' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'rbin.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'rbin.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'rds' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'redshift' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'redshift-serverless' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'resource-groups' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'rolesanywhere' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'route53' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'route53.amazonaws.com.cn', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-cn-global', ], 'route53profiles' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'route53resolver' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'runtime.sagemaker' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 's3' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com.cn', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.cn-north-1.amazonaws.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 's3.dualstack.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 's3-control' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com.cn', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 's3-control.cn-north-1.amazonaws.com.cn', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.cn-north-1.amazonaws.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 's3-control.cn-northwest-1.amazonaws.com.cn', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control.dualstack.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'savingsplans' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'savingsplans.cn-north-1.amazonaws.com.cn', ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'savingsplans.cn-northwest-1.amazonaws.com.cn', ], ], 'isRegionalized' => true, ], 'scheduler' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'schemas' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], ], ], ], ], 'securityhub' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'serverlessrepo' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'protocols' => [ 'https', ], ], 'cn-northwest-1' => [ 'protocols' => [ 'https', ], ], ], ], 'servicecatalog' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'servicequotas' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'signer' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], 'verification-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'verification.signer.cn-north-1.amazonaws.com.cn', ], 'verification-cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'verification.signer.cn-northwest-1.amazonaws.com.cn', ], ], ], 'sms' => [ 'endpoints' => [ 'cn-north-1' => [], ], ], 'snowball' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.cn-north-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'fips-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.cn-north-1.amazonaws.com.cn', ], 'fips-cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.cn-northwest-1.amazonaws.com.cn', ], ], ], 'sns' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'sns.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'sns.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'sqs' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', ], 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'sqs.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'sqs.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'ssm' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'sso' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'states' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'states.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'states.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'storagegateway' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'sts' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'support' => [ 'endpoints' => [ 'aws-cn-global' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'support.cn-north-1.amazonaws.com.cn', ], ], 'partitionEndpoint' => 'aws-cn-global', ], 'swf' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'synthetics' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'synthetics.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'tagging' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'transcribe' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'cn.transcribe.cn-north-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'transcribe.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'cn.transcribe.cn-northwest-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'transcribe.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transcribestreaming' => [ 'endpoints' => [ 'cn-north-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.cn-north-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], 'cn-northwest-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming.cn-northwest-1.api.amazonwebservices.com.cn', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transfer' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], 'waf-regional' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'waf-regional.cn-north-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'waf-regional-fips.cn-north-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'waf-regional.cn-northwest-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'waf-regional-fips.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'fips-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.cn-north-1.amazonaws.com.cn', ], 'fips-cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.cn-northwest-1.amazonaws.com.cn', ], ], ], 'wafv2' => [ 'endpoints' => [ 'cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'hostname' => 'wafv2.cn-north-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'wafv2-fips.cn-north-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'hostname' => 'wafv2.cn-northwest-1.amazonaws.com.cn', 'variants' => [ [ 'hostname' => 'wafv2-fips.cn-northwest-1.amazonaws.com.cn', 'tags' => [ 'fips', ], ], ], ], 'fips-cn-north-1' => [ 'credentialScope' => [ 'region' => 'cn-north-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.cn-north-1.amazonaws.com.cn', ], 'fips-cn-northwest-1' => [ 'credentialScope' => [ 'region' => 'cn-northwest-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.cn-northwest-1.amazonaws.com.cn', ], ], ], 'workspaces' => [ 'endpoints' => [ 'cn-northwest-1' => [], ], ], 'xray' => [ 'endpoints' => [ 'cn-north-1' => [], 'cn-northwest-1' => [], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'dnsSuffix' => 'amazonaws.com', 'partition' => 'aws-us-gov', 'partitionName' => 'AWS GovCloud (US)', 'regionRegex' => '^us\\-gov\\-\\w+\\-\\d+$', 'regions' => [ 'us-gov-east-1' => [ 'description' => 'AWS GovCloud (US-East)', ], 'us-gov-west-1' => [ 'description' => 'AWS GovCloud (US-West)', ], ], 'services' => [ 'access-analyzer' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'access-analyzer.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'access-analyzer.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'access-analyzer.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'access-analyzer.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'access-analyzer.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'access-analyzer.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'access-analyzer.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'access-analyzer.us-gov-west-1.amazonaws.com', ], ], ], 'acm' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'acm.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'acm.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'acm.us-gov-west-1.amazonaws.com', ], ], ], 'acm-pca' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'acm-pca.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'acm-pca.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'acm-pca.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'acm-pca.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'aoss' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'api.detective' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'api.detective-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'detective-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'detective.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'api.detective-fips.us-gov-west-1.amazonaws.com', ], ], ], 'api.ecr' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'ecr-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'dkr-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dkr-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'ecr-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-dkr-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-gov-east-1.amazonaws.com', ], 'fips-dkr-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-gov-west-1.amazonaws.com', ], 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ecr-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'api.ecr.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'api.ecr.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ecr-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ecr-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'ecr.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'api.sagemaker' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'api-fips.sagemaker.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'api-fips.sagemaker.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1-fips-secondary' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'api.sagemaker.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1-secondary' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'api.sagemaker.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'api.tunneling.iot' => [ 'defaults' => [ 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => 'api.tunneling.iot-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => 'api.iot-tunneling-fips.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'api.aws', 'hostname' => 'api.iot-tunneling.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'api.iot-tunneling-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'api.iot-tunneling.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'api.tunneling.iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'apigateway' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'appconfig.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'appconfig.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'appconfig.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'appconfig.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'appconfigdata' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'appconfigdata.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'appconfigdata.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'appconfigdata.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'appconfigdata.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'application-autoscaling.us-gov-east-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'application-autoscaling.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'deprecated' => true, 'hostname' => 'application-autoscaling.us-gov-east-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], ], 'us-gov-west-1' => [ 'hostname' => 'application-autoscaling.us-gov-west-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'application-autoscaling.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'deprecated' => true, 'hostname' => 'application-autoscaling.us-gov-west-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], ], ], ], 'applicationinsights' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'applicationinsights-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'applicationinsights-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'applicationinsights-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'applicationinsights.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'appstream2' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'appstream', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'appstream2-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'appstream2-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'appstream2-fips.us-gov-west-1.amazonaws.com', ], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'athena-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'athena-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'athena-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'athena.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'autoscaling' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'autoscaling.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'protocols' => [ 'http', 'https', ], ], 'us-gov-west-1' => [ 'protocols' => [ 'http', 'https', ], ], ], ], 'autoscaling-plans' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-plans.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'deprecated' => true, 'hostname' => 'autoscaling-plans.us-gov-east-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'autoscaling-plans.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'deprecated' => true, 'hostname' => 'autoscaling-plans.us-gov-west-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], ], ], ], 'backup' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'backup-gateway' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'batch' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'batch.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'batch.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'batch.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'batch.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'batch.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'bedrock' => [ 'endpoints' => [ 'bedrock-fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'bedrock-fips.us-gov-east-1.amazonaws.com', ], 'bedrock-fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'bedrock-fips.us-gov-west-1.amazonaws.com', ], 'bedrock-runtime-fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'bedrock-runtime-fips.us-gov-east-1.amazonaws.com', ], 'bedrock-runtime-fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'bedrock-runtime-fips.us-gov-west-1.amazonaws.com', ], 'bedrock-runtime-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'bedrock-runtime.us-gov-east-1.amazonaws.com', ], 'bedrock-runtime-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'bedrock-runtime.us-gov-west-1.amazonaws.com', ], 'bedrock-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'bedrock.us-gov-east-1.amazonaws.com', ], 'bedrock-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'bedrock.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'cassandra' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'cassandra.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'cassandra.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'cassandra.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'cassandra.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'cassandra.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cassandra.us-gov-west-1.amazonaws.com', ], ], ], 'cloudcontrolapi' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cloudcontrolapi-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudcontrolapi-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cloudcontrolapi-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cloudcontrolapi.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'clouddirectory' => [ 'endpoints' => [ 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'clouddirectory.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'clouddirectory.us-gov-west-1.amazonaws.com', ], ], ], 'cloudformation' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'cloudformation.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'cloudformation.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'cloudformation.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'cloudformation.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'cloudformation.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cloudformation.us-gov-west-1.amazonaws.com', ], ], ], 'cloudhsm' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'cloudhsmv2' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'cloudhsm', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudhsmv2.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cloudtrail' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'cloudtrail.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'codebuild' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'codebuild-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'codebuild-fips.us-gov-west-1.amazonaws.com', ], ], ], 'codecommit' => [ 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'codecommit-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'codecommit-fips.us-gov-west-1.amazonaws.com', ], ], ], 'codedeploy' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'codedeploy-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'codedeploy-fips.us-gov-west-1.amazonaws.com', ], ], ], 'codepipeline' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'codepipeline-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'codepipeline-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'codestar-connections' => [ 'endpoints' => [ 'us-gov-east-1' => [], ], ], 'cognito-identity' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cognito-identity-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity.us-gov-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-identity-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-identity-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-identity.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'cognito-idp' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'cognito-idp-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp.us-gov-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'cognito-idp-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'cognito-idp-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'cognito-idp.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'comprehend' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'comprehend-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'comprehend.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'comprehendmedical' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'comprehendmedical-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'comprehendmedical-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'compute-optimizer' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'compute-optimizer-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'compute-optimizer-fips.us-gov-west-1.amazonaws.com', ], ], ], 'config' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'config.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'config.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'config.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'config.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'config.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'connect' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'connect.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'connect.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'controltower' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'controltower-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'controltower-fips.us-gov-west-1.amazonaws.com', ], ], ], 'data-ats.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'data.iot' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'service' => 'iotdata', ], 'deprecated' => true, 'hostname' => 'data.iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'data.iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'data.jobs.iot' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'data.jobs.iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'data.jobs.iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'databrew' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'databrew.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'databrew.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'datasync' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'datasync-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'datasync.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'datazone' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'datazone.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'datazone.us-gov-west-1.api.aws', ], ], ], 'directconnect' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'directconnect-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'directconnect-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'dlm' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'dlm.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'dlm.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'dlm-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'dlm.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'dlm.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'dlm.us-gov-west-1.amazonaws.com', ], ], ], 'dms' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'dms.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'dms' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'dms.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'dms-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'dms.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'dms.us-gov-west-1.amazonaws.com', ], ], ], 'docdb' => [ 'endpoints' => [ 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'rds.us-gov-west-1.amazonaws.com', ], ], ], 'drs' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'drs-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'drs-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ds' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'dynamodb' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'dynamodb.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'dynamodb-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'dynamodb-fips.us-gov-west-1.amazonaws.com', ], ], ], 'ebs' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'ec2' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'ec2.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'ec2.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ec2.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'ec2.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'ec2.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'ecs' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ecs-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'ecs-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'eks.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'eks.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'eks.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'eks.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'eks.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'eks-auth' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'eks-auth.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'eks-auth.us-gov-west-1.api.aws', ], ], ], 'elasticache' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'elasticache.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticache.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticache.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticache.us-gov-west-1.amazonaws.com', ], ], ], 'elasticbeanstalk' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'elasticbeanstalk.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'elasticbeanstalk.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'elasticbeanstalk.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'elasticbeanstalk.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticbeanstalk.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticbeanstalk.us-gov-west-1.amazonaws.com', ], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticloadbalancing' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticloadbalancing.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticloadbalancing.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'elasticloadbalancing.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticmapreduce' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticmapreduce.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'elasticmapreduce.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'elasticmapreduce.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'email' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'email-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'email-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'email-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'emr-containers' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'emr-containers.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'emr-containers.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'emr-containers.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'emr-containers.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'emr-serverless' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'emr-serverless.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'emr-serverless.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'emr-serverless.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'emr-serverless.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'es' => [ 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'aos.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'aos.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'es-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'es-fips.us-gov-west-1.amazonaws.com', ], ], ], 'events' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'events.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'events.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'events.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'events.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'firehose' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'firehose-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'firehose-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'fms' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'fms-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'fms-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'fsx' => [ 'endpoints' => [ 'fips-prod-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-gov-east-1.amazonaws.com', ], 'fips-prod-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-gov-west-1.amazonaws.com', ], 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-gov-west-1.amazonaws.com', ], 'prod-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'prod-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'gameliftstreams' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'gameliftstreams.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'gameliftstreams.us-gov-west-1.api.aws', ], ], ], 'geo' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'geo-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'geo-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'glacier' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'glacier.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'glacier.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'glacier.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'glacier.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'glue' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'glue-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'glue-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'glue-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'glue.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'greengrass' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'dataplane-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'greengrass-ats.iot.us-gov-east-1.amazonaws.com', ], 'dataplane-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'greengrass-ats.iot.us-gov-west-1.amazonaws.com', ], 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'greengrass.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'greengrass.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'greengrass.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'greengrass.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], 'isRegionalized' => true, ], 'guardduty' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'guardduty.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'guardduty.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'guardduty.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'guardduty.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'guardduty.us-gov-west-1.amazonaws.com', ], ], 'isRegionalized' => true, ], 'health' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'sslCommonName' => 'health.us-gov-west-1.amazonaws.com', ], 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'global.health.us-gov.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'health-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'health-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iam' => [ 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'iam.us-gov.amazonaws.com', 'variants' => [ [ 'hostname' => 'iam.us-gov.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'aws-us-gov-global-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'iam.us-gov.amazonaws.com', ], 'iam-govcloud' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'iam.us-gov.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'iam-govcloud-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'iam.us-gov.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-us-gov-global', ], 'identitystore' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'identitystore.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'identitystore.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'identitystore.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'identitystore.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'identitystore.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ingest.timestream' => [ 'endpoints' => [ 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'ingest.timestream.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ingest.timestream.us-gov-west-1.amazonaws.com', ], ], ], 'inspector' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'inspector-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'inspector-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'inspector2' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'inspector2-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'inspector2-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'internetmonitor' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'internetmonitor.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'internetmonitor.us-gov-west-1.api.aws', ], ], ], 'iot' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'deprecated' => true, 'hostname' => 'iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotevents' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'iotevents-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'iotevents-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ioteventsdata' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'data.iotevents-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'data.iotevents.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'data.iotevents-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotsecuredtunneling' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'api.tunneling.iot-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'api.tunneling.iot-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iotsitewise' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'iotsitewise-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'iotsitewise-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'iottwinmaker' => [ 'endpoints' => [ 'api-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'api.iottwinmaker.us-gov-west-1.amazonaws.com', ], 'data-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'data.iottwinmaker.us-gov-west-1.amazonaws.com', ], 'fips-api-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'api.iottwinmaker-fips.us-gov-west-1.amazonaws.com', ], 'fips-data-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'data.iottwinmaker-fips.us-gov-west-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'iottwinmaker-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'iottwinmaker-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kafka' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'kafka.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kafka.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'kafka.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'kafka.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kafka.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kafka.us-gov-west-1.amazonaws.com', ], ], ], 'kendra' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kendra-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'kendra-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kendra-ranking' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'kendra-ranking.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'kendra-ranking.us-gov-west-1.api.aws', ], ], ], 'kinesis' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'kinesis.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kinesis.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'kinesis.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kinesis.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'kinesis.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kinesis.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kinesisanalytics' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kinesisanalytics-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'kinesisanalytics-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kinesisvideo' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'kinesisvideo-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kinesisvideo-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'kinesisvideo-fips.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kinesisvideo-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'kinesisvideo-fips.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'kinesisvideo-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-gov-west-1.amazonaws.com', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'lakeformation-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'lakeformation-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lakeformation-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'lakeformation.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'lambda' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'lambda-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'lambda-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'lambda.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'license-manager' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'license-manager-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'license-manager-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'license-manager-linux-subscriptions' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'license-manager-user-subscriptions' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'logs.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'logs.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'logs.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'logs.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'logs.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'm2' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'deprecated' => true, ], 'fips-us-gov-west-1' => [ 'deprecated' => true, ], 'us-gov-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'managedblockchain' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'mediaconvert' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'mediaconvert.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'mediaconvert.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'mediaconvert.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'mediaconvert.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], ], ], 'meetings-chime' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'meetings-chime-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'meetings-chime-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'meetings-chime-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'meetings-chime-fips.us-gov-west-1.amazonaws.com', ], ], ], 'memory-db' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'metering.marketplace' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'aws-marketplace', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'metering-marketplace.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'mgn' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'mgn-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'mgn-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'models-v2-lex' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'models.lex' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'lex', ], 'variants' => [ [ 'hostname' => 'models-fips.lex.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'models-fips.lex.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'models-fips.lex.us-gov-west-1.amazonaws.com', ], ], ], 'monitoring' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'monitoring.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'monitoring.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'monitoring.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'monitoring.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'monitoring.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'mq' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'mq-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'mq-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'neptune' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'rds.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'rds.us-gov-west-1.amazonaws.com', ], ], ], 'network-firewall' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'network-firewall-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'network-firewall-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'networkmanager' => [ 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'networkmanager.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'networkmanager.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'networkmanager.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'networkmanager.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'fips-aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'networkmanager.us-gov-west-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-us-gov-global', ], 'notifications' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'notifications.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'notifications.us-gov-west-1.api.aws', ], ], ], 'oam' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'oidc' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'oidc.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'oidc.us-gov-west-1.amazonaws.com', ], ], ], 'organizations' => [ 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'organizations.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'organizations.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'organizations.us-gov-west-1.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-us-gov-global', ], 'outposts' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'outposts.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'outposts.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'outposts.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'outposts.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'participant.connect' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'participant.connect.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'participant.connect.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'pi' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'pi-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'pi-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'pi-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'pi.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'pinpoint' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'mobiletargeting', ], ], 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'pinpoint-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'pinpoint.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'pinpoint-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'polly' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'polly-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'polly-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'polly-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'polly.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'portal.sso' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'portal.sso.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'portal.sso.us-gov-west-1.amazonaws.com', ], ], ], 'qbusiness' => [ 'defaults' => [ 'dnsSuffix' => 'api.aws', 'variants' => [ [ 'dnsSuffix' => 'api.aws', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'hostname' => 'qbusiness.us-gov-east-1.api.aws', ], 'us-gov-west-1' => [ 'hostname' => 'qbusiness.us-gov-west-1.api.aws', ], ], ], 'query.timestream' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'quicksight' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'ram' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'ram.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ramus-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ram.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'ram.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'ram.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'ramus-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ram.us-gov-west-1.amazonaws.com', ], ], ], 'rbin' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rbin-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rbin.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'rds' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'rds.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'rds.us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-gov-east-1.amazonaws.com', ], 'rds.us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rds.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'rds.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'rds.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rds.us-gov-west-1.amazonaws.com', ], ], ], 'redshift' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'redshift.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'redshift.us-gov-west-1.amazonaws.com', ], ], ], 'redshift-serverless' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'redshift-serverless-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'redshift-serverless-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'rekognition' => [ 'endpoints' => [ 'rekognition-fips.us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-gov-west-1.amazonaws.com', ], 'rekognition.us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'rekognition-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'rekognition-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'rekognition-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'rekognition.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rekognition-fips.us-gov-west-1.amazonaws.com', ], ], ], 'resiliencehub' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'resiliencehub-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'resiliencehub-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resiliencehub-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'resiliencehub.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'resiliencehub-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'resiliencehub-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'resiliencehub.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'resource-groups' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'resource-groups.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'resource-groups.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'resource-groups.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'resource-groups.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'resource-groups.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'robomaker' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'rolesanywhere' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'rolesanywhere-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'rolesanywhere-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'route53' => [ 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'route53.us-gov.amazonaws.com', 'variants' => [ [ 'hostname' => 'route53.us-gov.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'fips-aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'route53.us-gov.amazonaws.com', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-us-gov-global', ], 'route53profiles' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'route53profiles-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'route53profiles.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'route53resolver' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'route53resolver.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'deprecated' => true, 'hostname' => 'route53resolver.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'route53resolver.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'route53resolver.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], [ 'hostname' => 'route53resolver.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'deprecated' => true, 'hostname' => 'route53resolver.us-gov-west-1.amazonaws.com', ], ], ], 'rum' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'runtime-v2-lex' => [ 'endpoints' => [ 'us-gov-west-1' => [], ], ], 'runtime.lex' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'lex', ], 'variants' => [ [ 'hostname' => 'runtime-fips.lex.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'runtime-fips.lex.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'runtime-fips.lex.us-gov-west-1.amazonaws.com', ], ], ], 'runtime.sagemaker' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'runtime.sagemaker.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'runtime.sagemaker.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'runtime.sagemaker.us-gov-west-1.amazonaws.com', ], ], ], 's3' => [ 'defaults' => [ 'signatureVersions' => [ 's3', 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'hostname' => 's3.us-gov-east-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 's3-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-gov-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'hostname' => 's3.us-gov-west-1.amazonaws.com', 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 's3-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3.dualstack.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], ], ], 's3-control' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}-fips.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', 'fips', ], ], [ 'dnsSuffix' => 'amazonaws.com', 'hostname' => '{service}.dualstack.{region}.{dnsSuffix}', 'tags' => [ 'dualstack', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 's3-control.us-gov-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-gov-east-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-gov-east-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-gov-east-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 's3-control.us-gov-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-gov-west-1.amazonaws.com', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-gov-west-1.amazonaws.com', 'signatureVersions' => [ 's3v4', ], ], ], ], 's3-outposts' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'deprecated' => true, ], 'fips-us-gov-west-1' => [ 'deprecated' => true, ], 'us-gov-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], ], ], 'scheduler' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'schemas' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'deprecated' => true, ], 'us-gov-west-1' => [ 'variants' => [ [ 'tags' => [ 'dualstack', ], ], [ 'tags' => [ 'dualstack', 'fips', ], ], [ 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'deprecated' => true, ], ], ], 'securityhub' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'securityhub-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'securityhub-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securityhub.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'securitylake' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'securitylake.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'securitylake.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'securitylake.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'securitylake.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'securitylake.us-gov-west-1.amazonaws.com', ], ], ], 'serverlessrepo' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'serverlessrepo.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'serverlessrepo.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'serverlessrepo.us-gov-west-1.amazonaws.com', ], ], ], 'servicecatalog' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'servicecatalog-fips.us-gov-west-1.amazonaws.com', ], ], ], 'servicecatalog-appregistry' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'servicecatalog-appregistry.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'servicediscovery' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'servicediscovery-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'servicediscovery-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'servicediscovery-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'servicediscovery.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'servicediscovery-fips.us-gov-west-1.amazonaws.com', ], ], ], 'servicequotas' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'servicequotas.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'servicequotas.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'servicequotas.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'servicequotas.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'servicequotas.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'signer' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'signer-fips.us-gov-west-1.amazonaws.com', ], 'fips-verification-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'verification.signer-fips.us-gov-east-1.amazonaws.com', ], 'fips-verification-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'verification.signer-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'signer-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'verification-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'verification.signer.us-gov-east-1.amazonaws.com', ], 'verification-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'verification.signer.us-gov-west-1.amazonaws.com', ], ], ], 'simspaceweaver' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'simspaceweaver.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'simspaceweaver.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'simspaceweaver.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'simspaceweaver.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'sms' => [ 'endpoints' => [ 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sms-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'sms-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'sms-voice' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sms-voice-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'sms-voice-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'sms-voice-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'sms-voice.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'snowball' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'snowball-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'snowball-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'snowball-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'snowball.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'sns' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'sns.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sns.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'sns.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'sns.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'sqs' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'sqs.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'sqs.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', 'variants' => [ [ 'hostname' => 'sqs.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'ssm.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'ssm.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'ssm.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'ssm.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'ssm.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'sso' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'sso.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'sso.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'sso.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'sso.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'sso.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sso.us-gov-west-1.amazonaws.com', ], ], ], 'states' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'states.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'states.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'storagegateway' => [ 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-gov-west-1.amazonaws.com', ], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'variants' => [ [ 'hostname' => 'streams.dynamodb.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'sts' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'sts.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'sts.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'sts.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'sts.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'sts.us-gov-west-1.amazonaws.com', ], ], ], 'support' => [ 'endpoints' => [ 'aws-us-gov-global' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'support.us-gov-west-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'support.us-gov-west-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'support.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], 'partitionEndpoint' => 'aws-us-gov-global', ], 'swf' => [ 'endpoints' => [ 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'swf.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'swf.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'swf.us-gov-east-1.amazonaws.com', ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'swf.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'swf.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'swf.us-gov-west-1.amazonaws.com', ], ], ], 'synthetics' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'synthetics-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'synthetics-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'synthetics-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'synthetics.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'tagging' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'textract' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'textract-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'textract-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'textract-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'textract.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transcribe' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'fips.transcribe.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribe-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribe.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transcribestreaming' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'transcribestreaming-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.us-gov-east-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'transcribestreaming-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'transcribestreaming-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'transcribestreaming.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'transfer' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'transfer-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'transfer-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'translate' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], [ 'hostname' => 'translate-fips.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 'translate.us-gov-west-1.api.aws', 'tags' => [ 'dualstack', ], ], ], ], 'us-gov-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-gov-west-1.amazonaws.com', ], ], ], 'verifiedpermissions' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'verifiedpermissions-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'verifiedpermissions-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'waf-regional' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'waf-regional-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'waf-regional.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'waf-regional.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'waf-regional-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'wafv2' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'wafv2-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'hostname' => 'wafv2.us-gov-east-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'hostname' => 'wafv2.us-gov-west-1.amazonaws.com', 'variants' => [ [ 'hostname' => 'wafv2-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'wellarchitected' => [ 'endpoints' => [ 'us-gov-east-1' => [], 'us-gov-west-1' => [], ], ], 'workspaces' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], 'xray' => [ 'endpoints' => [ 'fips-us-gov-east-1' => [ 'credentialScope' => [ 'region' => 'us-gov-east-1', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-gov-east-1.amazonaws.com', ], 'fips-us-gov-west-1' => [ 'credentialScope' => [ 'region' => 'us-gov-west-1', ], 'deprecated' => true, 'hostname' => 'xray-fips.us-gov-west-1.amazonaws.com', ], 'us-gov-east-1' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-gov-east-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], 'us-gov-west-1' => [ 'variants' => [ [ 'hostname' => 'xray-fips.us-gov-west-1.amazonaws.com', 'tags' => [ 'fips', ], ], ], ], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'c2s.ic.gov', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'dnsSuffix' => 'c2s.ic.gov', 'partition' => 'aws-iso', 'partitionName' => 'AWS ISO (US)', 'regionRegex' => '^us\\-iso\\-\\w+\\-\\d+$', 'regions' => [ 'us-iso-east-1' => [ 'description' => 'US ISO East', ], 'us-iso-west-1' => [ 'description' => 'US ISO WEST', ], ], 'services' => [ 'agreement-marketplace' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'agreement-marketplace-fips.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'agreement-marketplace-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'api.ecr' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'api.ecr.us-iso-east-1.c2s.ic.gov', ], 'us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'hostname' => 'api.ecr.us-iso-west-1.c2s.ic.gov', ], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'api.sagemaker' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'apigateway' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'autoscaling' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], ], 'us-iso-west-1' => [], ], ], 'backup' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'batch' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'bedrock' => [ 'endpoints' => [ 'bedrock-runtime-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'bedrock-runtime.us-iso-east-1.c2s.ic.gov', ], 'bedrock-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'bedrock.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [], ], ], 'budgets' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'budgets.c2s.ic.gov', ], 'us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'budgets.c2s.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-global', ], 'ce' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'ce.us-iso-east-1.c2s.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-global', ], 'cloudcontrolapi' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'cloudformation' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'cloudtrail' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'codebuild' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'codedeploy' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'comprehend' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'comprehend-fips.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'comprehend-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'config' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'config-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'config-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'datapipeline' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'datasync' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'datasync-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'datasync-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'directconnect' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'dlm' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'dms' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'dms.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'dms' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'dms.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'dms-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-iso-east-1.c2s.ic.gov', ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'dms.us-iso-west-1.c2s.ic.gov', ], ], ], 'ds' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'dynamodb' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], ], 'us-iso-west-1' => [], ], ], 'ebs' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'ec2' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'ecs' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'elasticache' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticloadbalancing' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], ], 'us-iso-west-1' => [], ], ], 'elasticmapreduce' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'protocols' => [ 'https', ], 'variants' => [ [ 'hostname' => 'elasticmapreduce.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'es' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'events' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'firehose' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'fsx' => [ 'endpoints' => [ 'fips-prod-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'fsx-fips.us-iso-east-1.c2s.ic.gov', ], 'prod-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'fsx-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'fsx-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [], ], ], 'glacier' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'glacier-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'glue' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'guardduty' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-iso-east-1' => [], ], 'isRegionalized' => true, ], 'health' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'iam' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'iam.us-iso-east-1.c2s.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-global', ], 'kinesis' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'kinesisanalytics' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-iso-east-1.c2s.ic.gov', ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-iso-west-1.c2s.ic.gov', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'lambda' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'license-manager' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'medialive' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'medialive-fips.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'medialive-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'mediapackage' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'monitoring' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'network-firewall' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'oam' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'organizations' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'organizations.us-iso-east-1.c2s.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-global', ], 'outposts' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'pi' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'protocols' => [ 'https', ], ], 'us-iso-west-1' => [ 'protocols' => [ 'https', ], ], ], ], 'ram' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'rbin' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'rds' => [ 'endpoints' => [ 'rds.us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-iso-east-1.c2s.ic.gov', ], 'rds.us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'rds.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'rds.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-iso-east-1.c2s.ic.gov', ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'rds.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'rds.us-iso-west-1.c2s.ic.gov', ], ], ], 'redshift' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'redshift.us-iso-east-1.c2s.ic.gov', ], 'us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'hostname' => 'redshift.us-iso-west-1.c2s.ic.gov', ], ], ], 'resource-groups' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'route53' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'route53.c2s.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-global', ], 'route53resolver' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'runtime.sagemaker' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 's3' => [ 'defaults' => [ 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 's3-control' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 's3-control.us-iso-east-1.c2s.ic.gov', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], 'us-iso-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-iso-east-1.c2s.ic.gov', 'signatureVersions' => [ 's3v4', ], ], 'us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'hostname' => 's3-control.us-iso-west-1.c2s.ic.gov', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], 'us-iso-west-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-iso-west-1.c2s.ic.gov', 'signatureVersions' => [ 's3v4', ], ], ], ], 's3-outposts' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'deprecated' => true, ], 'us-iso-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'scheduler' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1-fips' => [ 'deprecated' => true, ], 'us-iso-west-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1-fips' => [ 'deprecated' => true, ], ], ], 'securityhub' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'servicequotas' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'snowball' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'sns' => [ 'endpoints' => [ 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], ], 'us-iso-west-1' => [], ], ], 'sqs' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'protocols' => [ 'http', 'https', ], 'variants' => [ [ 'hostname' => 'sqs.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'sqs.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'states' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'storagegateway' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], ], 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'sts' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'support' => [ 'endpoints' => [ 'aws-iso-global' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'hostname' => 'support.us-iso-east-1.c2s.ic.gov', ], ], 'partitionEndpoint' => 'aws-iso-global', ], 'swf' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'synthetics' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'tagging' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], 'textract' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'transcribe' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'fips.transcribe.us-iso-east-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'fips.transcribe.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'transcribestreaming' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'translate' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'translate-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'translate-fips.us-iso-east-1.c2s.ic.gov', ], ], ], 'wafv2' => [ 'endpoints' => [ 'us-iso-east-1' => [], ], ], 'workspaces' => [ 'endpoints' => [ 'fips-us-iso-east-1' => [ 'credentialScope' => [ 'region' => 'us-iso-east-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-iso-east-1.c2s.ic.gov', ], 'fips-us-iso-west-1' => [ 'credentialScope' => [ 'region' => 'us-iso-west-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-iso-west-1.c2s.ic.gov', ], 'us-iso-east-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-iso-east-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-iso-west-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-iso-west-1.c2s.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'xray' => [ 'endpoints' => [ 'us-iso-east-1' => [], 'us-iso-west-1' => [], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'sc2s.sgov.gov', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'dnsSuffix' => 'sc2s.sgov.gov', 'partition' => 'aws-iso-b', 'partitionName' => 'AWS ISOB (US)', 'regionRegex' => '^us\\-isob\\-\\w+\\-\\d+$', 'regions' => [ 'us-isob-east-1' => [ 'description' => 'US ISOB East (Ohio)', ], ], 'services' => [ 'api.ecr' => [ 'endpoints' => [ 'us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'api.ecr.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'api.sagemaker' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'apigateway' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'backup' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'batch' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'budgets' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'budgets.global.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'budgets.global.sc2s.sgov.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-b-global', ], 'ce' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'ce.us-isob-east-1.sc2s.sgov.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-b-global', ], 'cloudcontrolapi' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'cloudformation' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'cloudtrail' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'cloudtrail-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'cloudtrail-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'codebuild' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'codedeploy' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'config' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'config-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'config-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'datasync' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'directconnect' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'dlm' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'dms' => [ 'defaults' => [ 'variants' => [ [ 'hostname' => 'dms.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'endpoints' => [ 'dms' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'dms.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], 'dms-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isob-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'ds' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'ds-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'ds-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'dynamodb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'ebs' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'ec2' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'ecs' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'elasticache' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticloadbalancing' => [ 'endpoints' => [ 'us-isob-east-1' => [ 'protocols' => [ 'https', ], ], ], ], 'elasticmapreduce' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'elasticmapreduce.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticmapreduce.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'es' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'events' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'firehose' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'fsx' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'glacier' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'glacier-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'glacier-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'glue' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'guardduty' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'health' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'iam' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'iam.us-isob-east-1.sc2s.sgov.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-b-global', ], 'kinesis' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'kinesisanalytics' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isob-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'lambda' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'license-manager' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'medialive' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'medialive-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'medialive-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'mediapackage' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'metering.marketplace' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'aws-marketplace', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'monitoring' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'network-firewall' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'oam' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'organizations' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'organizations.us-isob-east-1.sc2s.sgov.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-b-global', ], 'outposts' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'pi' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'ram' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'rbin' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'rbin-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'rbin-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'rds' => [ 'endpoints' => [ 'rds.us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'rds.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isob-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'rds.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'redshift' => [ 'endpoints' => [ 'us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'redshift.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'resource-groups' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'route53' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'route53.sc2s.sgov.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-b-global', ], 'route53resolver' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'runtime.sagemaker' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 's3' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 's3-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 's3-fips.dualstack.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 's3-control' => [ 'defaults' => [ 'protocols' => [ 'https', ], 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 's3-control.us-isob-east-1.sc2s.sgov.gov', 'signatureVersions' => [ 's3v4', ], 'variants' => [ [ 'hostname' => 's3-control-fips.dualstack.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'dualstack', 'fips', ], ], [ 'hostname' => 's3-control-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], [ 'hostname' => 's3-control.dualstack.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'dualstack', ], ], ], ], 'us-isob-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 's3-control-fips.us-isob-east-1.sc2s.sgov.gov', 'signatureVersions' => [ 's3v4', ], ], ], ], 's3-outposts' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'deprecated' => true, ], 'us-isob-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], ], ], 'scheduler' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'us-isob-east-1' => [ 'variants' => [ [ 'tags' => [ 'fips', ], ], ], ], 'us-isob-east-1-fips' => [ 'deprecated' => true, ], ], ], 'securityhub' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'servicequotas' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'snowball' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'sns' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'sqs' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', ], 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'sqs.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'states' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'states-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'states-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'storagegateway' => [ 'endpoints' => [ 'fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'storagegateway-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isob-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'storagegateway-fips.us-isob-east-1.sc2s.sgov.gov', ], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'sts' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'support' => [ 'endpoints' => [ 'aws-iso-b-global' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'hostname' => 'support.us-isob-east-1.sc2s.sgov.gov', ], ], 'partitionEndpoint' => 'aws-iso-b-global', ], 'swf' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'swf-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'swf-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'synthetics' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'tagging' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'wafv2' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], 'workspaces' => [ 'endpoints' => [ 'fips-us-isob-east-1' => [ 'credentialScope' => [ 'region' => 'us-isob-east-1', ], 'deprecated' => true, 'hostname' => 'workspaces-fips.us-isob-east-1.sc2s.sgov.gov', ], 'us-isob-east-1' => [ 'variants' => [ [ 'hostname' => 'workspaces-fips.us-isob-east-1.sc2s.sgov.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'xray' => [ 'endpoints' => [ 'us-isob-east-1' => [], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'cloud.adc-e.uk', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'dnsSuffix' => 'cloud.adc-e.uk', 'partition' => 'aws-iso-e', 'partitionName' => 'AWS ISOE (Europe)', 'regionRegex' => '^eu\\-isoe\\-\\w+\\-\\d+$', 'regions' => [ 'eu-isoe-west-1' => [ 'description' => 'EU ISOE West', ], ], 'services' => [ 'access-analyzer' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.eu-isoe-west-1.api.cloud-aws.adc-e.uk', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'acm' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'acm-pca' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'api.ecr' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'api.ecr.eu-isoe-west-1.cloud.adc-e.uk', ], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'batch' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'budgets' => [ 'endpoints' => [ 'aws-iso-e-global' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'budgets.global.cloud.adc-e.uk', ], 'eu-isoe-west-1' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'budgets.global.cloud.adc-e.uk', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-e-global', ], 'cloudcontrolapi' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'cloudformation' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'cloudtrail' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'cloudtrail-data' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'codedeploy' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'compute-optimizer' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'compute-optimizer.eu-isoe-west-1.cloud.adc-e.uk', ], ], ], 'config' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'cost-optimization-hub' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'cost-optimization-hub.eu-isoe-west-1.cloud.adc-e.uk', ], ], ], 'directconnect' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'dlm' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'dms' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ds' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'dynamodb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ebs' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ec2' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ecs' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'elasticache' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.eu-isoe-west-1.cloud.adc-e.uk', 'tags' => [ 'fips', ], ], ], ], 'fips-eu-isoe-west-1' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.eu-isoe-west-1.cloud.adc-e.uk', ], ], ], 'elasticloadbalancing' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'elasticmapreduce' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'emr-serverless' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'es' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'events' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'firehose' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'glue' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'kinesis' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-isoe-west-1.cloud.adc-e.uk', ], 'eu-isoe-west-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.eu-isoe-west-1.cloud.adc-e.uk', 'tags' => [ 'fips', ], ], ], ], 'eu-isoe-west-1-fips' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.eu-isoe-west-1.cloud.adc-e.uk', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'lambda' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'variants' => [ [ 'hostname' => 'lambda.eu-isoe-west-1.api.cloud-aws.adc-e.uk', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'license-manager' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'monitoring' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'oam' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'organizations' => [ 'endpoints' => [ 'aws-iso-e-global' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'organizations.eu-isoe-west-1.cloud.adc-e.uk', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-e-global', ], 'pi' => [ 'endpoints' => [ 'eu-isoe-west-1' => [ 'protocols' => [ 'https', ], ], ], ], 'pipes' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ram' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'rbin' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'rds' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'redshift' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'redshift-serverless' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'resource-groups' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'route53' => [ 'endpoints' => [ 'aws-iso-e-global' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'route53.cloud.adc-e.uk', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-e-global', ], 'route53profiles' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'route53resolver' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 's3' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'savingsplans' => [ 'endpoints' => [ 'aws-iso-e-global' => [ 'credentialScope' => [ 'region' => 'eu-isoe-west-1', ], 'hostname' => 'savingsplans.cloud.adc-e.uk', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-e-global', ], 'scheduler' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'schemas' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'servicecatalog' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'servicequotas' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'sns' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'sqs' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'ssm' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'states' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'sts' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'swf' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'synthetics' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'tagging' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'trustedadvisor' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], 'xray' => [ 'endpoints' => [ 'eu-isoe-west-1' => [], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'csp.hci.ic.gov', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'dnsSuffix' => 'csp.hci.ic.gov', 'partition' => 'aws-iso-f', 'partitionName' => 'AWS ISOF', 'regionRegex' => '^us\\-isof\\-\\w+\\-\\d+$', 'regions' => [ 'us-isof-east-1' => [ 'description' => 'US ISOF EAST', ], 'us-isof-south-1' => [ 'description' => 'US ISOF SOUTH', ], ], 'services' => [ 'access-analyzer' => [ 'endpoints' => [ 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.us-isof-east-1.api.aws.hci.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'access-analyzer.us-isof-south-1.api.aws.hci.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'acm' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'acm-pca' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'api.ecr' => [ 'endpoints' => [ 'us-isof-east-1' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'hostname' => 'api.ecr.us-isof-east-1.csp.hci.ic.gov', ], 'us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'api.ecr.us-isof-south-1.csp.hci.ic.gov', ], ], ], 'api.pricing' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'pricing', ], ], 'endpoints' => [ 'us-isof-south-1' => [], ], ], 'api.sagemaker' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'appconfig' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'appconfigdata' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'application-autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'arc-zonal-shift' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'athena' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'autoscaling' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'backup' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'batch' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'budgets' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'budgets.global.csp.hci.ic.gov', ], 'us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'budgets.global.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'ce' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'ce.us-isof-south-1.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'cloudcontrolapi' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'cloudformation' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'cloudtrail' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'cloudtrail-data' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'codebuild' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'codedeploy' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'codepipeline' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'comprehend' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'compute-optimizer' => [ 'endpoints' => [ 'us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'compute-optimizer.us-isof-south-1.csp.hci.ic.gov', ], ], ], 'config' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'cost-optimization-hub' => [ 'endpoints' => [ 'us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'cost-optimization-hub.us-isof-south-1.csp.hci.ic.gov', ], ], ], 'directconnect' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'dlm' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'dms' => [ 'endpoints' => [ 'dms' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'variants' => [ [ 'hostname' => 'dms.us-isof-east-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'dms-fips' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-isof-east-1.csp.hci.ic.gov', ], 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-isof-east-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'dms.us-isof-east-1.csp.hci.ic.gov', ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'dms.us-isof-south-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-south-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'deprecated' => true, 'hostname' => 'dms.us-isof-south-1.csp.hci.ic.gov', ], ], ], 'ds' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'dynamodb' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'ebs' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'ec2' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'ecs' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'eks' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'elasticache' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'elasticfilesystem' => [ 'endpoints' => [ 'fips-us-isof-east-1' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-isof-east-1.csp.hci.ic.gov', ], 'fips-us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'deprecated' => true, 'hostname' => 'elasticfilesystem-fips.us-isof-south-1.csp.hci.ic.gov', ], 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-isof-east-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'elasticfilesystem-fips.us-isof-south-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'elasticloadbalancing' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'elasticmapreduce' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'es' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'events' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'firehose' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'fsx' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'glue' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'guardduty' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], 'isRegionalized' => true, ], 'iam' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'iam.us-isof-south-1.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'kinesis' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'kms' => [ 'endpoints' => [ 'ProdFips' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-isof-east-1.csp.hci.ic.gov', ], 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-isof-east-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-east-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-isof-east-1.csp.hci.ic.gov', ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'kms-fips.us-isof-south-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-south-1-fips' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'deprecated' => true, 'hostname' => 'kms-fips.us-isof-south-1.csp.hci.ic.gov', ], ], ], 'lakeformation' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'lambda' => [ 'endpoints' => [ 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'lambda.us-isof-east-1.api.aws.hci.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'lambda.us-isof-south-1.api.aws.hci.ic.gov', 'tags' => [ 'dualstack', ], ], ], ], ], ], 'license-manager' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'logs' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'metrics.sagemaker' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'monitoring' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'oam' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'organizations' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'organizations.us-isof-south-1.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'pi' => [ 'endpoints' => [ 'us-isof-east-1' => [ 'protocols' => [ 'https', ], ], 'us-isof-south-1' => [ 'protocols' => [ 'https', ], ], ], ], 'pipes' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'quicksight' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'ram' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'rbin' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'rds' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'redshift' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'redshift-serverless' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'rekognition' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'resource-groups' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'route53' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'route53.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'route53profiles' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'route53resolver' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'runtime.sagemaker' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 's3' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'signatureVersions' => [ 's3v4', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'savingsplans' => [ 'endpoints' => [ 'aws-iso-f-global' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'hostname' => 'savingsplans.csp.hci.ic.gov', ], ], 'isRegionalized' => false, 'partitionEndpoint' => 'aws-iso-f-global', ], 'scheduler' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'schemas' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'secretsmanager' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'servicediscovery' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'servicequotas' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'sns' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'sqs' => [ 'defaults' => [ 'protocols' => [ 'http', 'https', ], 'sslCommonName' => '{region}.queue.{dnsSuffix}', ], 'endpoints' => [ 'fips-us-isof-east-1' => [ 'credentialScope' => [ 'region' => 'us-isof-east-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-isof-east-1.csp.hci.ic.gov', ], 'fips-us-isof-south-1' => [ 'credentialScope' => [ 'region' => 'us-isof-south-1', ], 'deprecated' => true, 'hostname' => 'sqs.us-isof-south-1.csp.hci.ic.gov', ], 'us-isof-east-1' => [ 'variants' => [ [ 'hostname' => 'sqs.us-isof-east-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], 'us-isof-south-1' => [ 'variants' => [ [ 'hostname' => 'sqs.us-isof-south-1.csp.hci.ic.gov', 'tags' => [ 'fips', ], ], ], ], ], ], 'ssm' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'states' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'streams.dynamodb' => [ 'defaults' => [ 'credentialScope' => [ 'service' => 'dynamodb', ], 'protocols' => [ 'http', 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'sts' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'swf' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'synthetics' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'tagging' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'textract' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'transcribe' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'transcribestreaming' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'translate' => [ 'defaults' => [ 'protocols' => [ 'https', ], ], 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], 'trustedadvisor' => [ 'endpoints' => [ 'us-isof-south-1' => [], ], ], 'xray' => [ 'endpoints' => [ 'us-isof-east-1' => [], 'us-isof-south-1' => [], ], ], ], ], [ 'defaults' => [ 'hostname' => '{service}.{region}.{dnsSuffix}', 'protocols' => [ 'https', ], 'signatureVersions' => [ 'v4', ], 'variants' => [ [ 'dnsSuffix' => 'amazonaws.eu', 'hostname' => '{service}-fips.{region}.{dnsSuffix}', 'tags' => [ 'fips', ], ], ], ], 'dnsSuffix' => 'amazonaws.eu', 'partition' => 'aws-eusc', 'partitionName' => 'AWS EUSC', 'regionRegex' => '^eusc\\-(de)\\-\\w+\\-\\d+$', 'regions' => [ 'eusc-de-east-1' => [ 'description' => 'EU (Germany)', ], ], 'services' => [], ], ], 'version' => 3,]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints_prefix_history.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints_prefix_history.json.php new file mode 100644 index 000000000..3e8b7c04e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/endpoints_prefix_history.json.php @@ -0,0 +1,3 @@ + [ 'api.ecr' => [ 'ecr', ], 'api.elastic-inference' => [ 'elastic-inference', ], 'api.sagemaker' => [ 'sagemaker', ], 'ecr' => [ 'api.ecr', ], 'elastic-inference' => [ 'api.elastic-inference', ], 'sagemaker' => [ 'api.sagemaker', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/grandfathered-services.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/grandfathered-services.json.php new file mode 100644 index 000000000..a62e1e71f --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/grandfathered-services.json.php @@ -0,0 +1,3 @@ + [ 'AccessAnalyzer', 'Account', 'ACMPCA', 'ACM', 'PrometheusService', 'Amplify', 'AmplifyBackend', 'AmplifyUIBuilder', 'APIGateway', 'ApiGatewayManagementApi', 'ApiGatewayV2', 'AppConfig', 'AppConfigData', 'Appflow', 'AppIntegrationsService', 'ApplicationAutoScaling', 'ApplicationInsights', 'ApplicationCostProfiler', 'AppMesh', 'AppRunner', 'AppStream', 'AppSync', 'Athena', 'AuditManager', 'AutoScalingPlans', 'AutoScaling', 'BackupGateway', 'Backup', 'Batch', 'BillingConductor', 'Braket', 'Budgets', 'CostExplorer', 'ChimeSDKIdentity', 'ChimeSDKMediaPipelines', 'ChimeSDKMeetings', 'ChimeSDKMessaging', 'Chime', 'Cloud9', 'CloudControlApi', 'CloudDirectory', 'CloudFormation', 'CloudFront', 'CloudHSM', 'CloudHSMV2', 'CloudSearch', 'CloudSearchDomain', 'CloudTrail', 'CodeArtifact', 'CodeBuild', 'CodeCommit', 'CodeDeploy', 'CodeGuruReviewer', 'CodeGuruProfiler', 'CodePipeline', 'CodeStarconnections', 'CodeStarNotifications', 'CodeStar', 'CognitoIdentity', 'CognitoIdentityProvider', 'CognitoSync', 'Comprehend', 'ComprehendMedical', 'ComputeOptimizer', 'ConfigService', 'ConnectContactLens', 'Connect', 'ConnectCampaignService', 'ConnectParticipant', 'CostandUsageReportService', 'CustomerProfiles', 'IoTDataPlane', 'GlueDataBrew', 'DataExchange', 'DataPipeline', 'DataSync', 'DAX', 'Detective', 'DeviceFarm', 'DevOpsGuru', 'DirectConnect', 'ApplicationDiscoveryService', 'DLM', 'DatabaseMigrationService', 'DocDB', 'drs', 'DirectoryService', 'DynamoDB', 'EBS', 'EC2InstanceConnect', 'EC2', 'ECRPublic', 'ECR', 'ECS', 'EKS', 'ElastiCache', 'ElasticBeanstalk', 'EFS', 'ElasticLoadBalancing', 'ElasticLoadBalancingv2', 'EMR', 'ElasticTranscoder', 'SES', 'EMRContainers', 'EMRServerless', 'MarketplaceEntitlementService', 'ElasticsearchService', 'EventBridge', 'CloudWatchEvents', 'CloudWatchEvidently', 'FinSpaceData', 'finspace', 'Firehose', 'FIS', 'FMS', 'ForecastService', 'ForecastQueryService', 'FraudDetector', 'FSx', 'GameLift', 'Glacier', 'GlobalAccelerator', 'Glue', 'ManagedGrafana', 'Greengrass', 'GreengrassV2', 'GroundStation', 'GuardDuty', 'Health', 'HealthLake', 'IAM', 'IdentityStore', 'imagebuilder', 'ImportExport', 'Inspector', 'Inspector2', 'IoTJobsDataPlane', 'IoT', 'IoTAnalytics', 'IoTDeviceAdvisor', 'IoTEventsData', 'IoTEvents', 'IoTFleetHub', 'IoTSecureTunneling', 'IoTSiteWise', 'IoTThingsGraph', 'IoTTwinMaker', 'IoTWireless', 'IVS', 'ivschat', 'Kafka', 'KafkaConnect', 'kendra', 'Keyspaces', 'KinesisVideoArchivedMedia', 'KinesisVideoMedia', 'KinesisVideoSignalingChannels', 'Kinesis', 'KinesisAnalytics', 'KinesisAnalyticsV2', 'KinesisVideo', 'KMS', 'LakeFormation', 'Lambda', 'LexModelBuildingService', 'LicenseManager', 'Lightsail', 'LocationService', 'CloudWatchLogs', 'LookoutEquipment', 'LookoutMetrics', 'LookoutforVision', 'MainframeModernization', 'MachineLearning', 'Macie2', 'ManagedBlockchain', 'MarketplaceCatalog', 'MarketplaceCommerceAnalytics', 'MediaConnect', 'MediaConvert', 'MediaLive', 'MediaPackageVod', 'MediaPackage', 'MediaStoreData', 'MediaStore', 'MediaTailor', 'MemoryDB', 'MarketplaceMetering', 'MigrationHub', 'mgn', 'MigrationHubRefactorSpaces', 'MigrationHubConfig', 'MigrationHubStrategyRecommendations', 'LexModelsV2', 'CloudWatch', 'MQ', 'MTurk', 'MWAA', 'Neptune', 'NetworkFirewall', 'NetworkManager', 'OpenSearchService', 'Organizations', 'Outposts', 'Panorama', 'PersonalizeEvents', 'PersonalizeRuntime', 'Personalize', 'PI', 'PinpointEmail', 'PinpointSMSVoiceV2', 'Pinpoint', 'Polly', 'Pricing', 'Proton', 'QLDBSession', 'QLDB', 'QuickSight', 'RAM', 'RecycleBin', 'RDSDataService', 'RDS', 'RedshiftDataAPIService', 'RedshiftServerless', 'Redshift', 'Rekognition', 'ResilienceHub', 'ResourceGroups', 'ResourceGroupsTaggingAPI', 'RoboMaker', 'Route53RecoveryCluster', 'Route53RecoveryControlConfig', 'Route53RecoveryReadiness', 'Route53', 'Route53Domains', 'Route53Resolver', 'CloudWatchRUM', 'LexRuntimeV2', 'LexRuntimeService', 'SageMakerRuntime', 'S3', 'S3Control', 'S3Outposts', 'AugmentedAIRuntime', 'SagemakerEdgeManager', 'SageMakerFeatureStoreRuntime', 'SageMaker', 'SavingsPlans', 'Schemas', 'SecretsManager', 'SecurityHub', 'ServerlessApplicationRepository', 'ServiceQuotas', 'AppRegistry', 'ServiceCatalog', 'ServiceDiscovery', 'SESV2', 'Shield', 'signer', 'PinpointSMSVoice', 'SMS', 'SnowDeviceManagement', 'Snowball', 'SNS', 'SQS', 'SSMContacts', 'SSMIncidents', 'SSM', 'SSOAdmin', 'SSOOIDC', 'SSO', 'SFN', 'StorageGateway', 'DynamoDBStreams', 'STS', 'Support', 'SWF', 'Synthetics', 'Textract', 'TimestreamQuery', 'TimestreamWrite', 'TranscribeService', 'Transfer', 'Translate', 'VoiceID', 'WAFRegional', 'WAF', 'WAFV2', 'WellArchitected', 'ConnectWisdomService', 'WorkDocs', 'WorkMail', 'WorkMailMessageFlow', 'WorkSpacesWeb', 'WorkSpaces', 'XRay', ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/api-2.json.php new file mode 100644 index 000000000..df33aaf7d --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2014-11-01', 'endpointPrefix' => 'kms', 'jsonVersion' => '1.1', 'protocol' => 'json', 'protocols' => [ 'json', ], 'serviceAbbreviation' => 'KMS', 'serviceFullName' => 'AWS Key Management Service', 'serviceId' => 'KMS', 'signatureVersion' => 'v4', 'targetPrefix' => 'TrentService', 'uid' => 'kms-2014-11-01', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'CancelKeyDeletion' => [ 'name' => 'CancelKeyDeletion', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CancelKeyDeletionRequest', ], 'output' => [ 'shape' => 'CancelKeyDeletionResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'ConnectCustomKeyStore' => [ 'name' => 'ConnectCustomKeyStore', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ConnectCustomKeyStoreRequest', ], 'output' => [ 'shape' => 'ConnectCustomKeyStoreResponse', ], 'errors' => [ [ 'shape' => 'CloudHsmClusterNotActiveException', ], [ 'shape' => 'CustomKeyStoreInvalidStateException', ], [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'CloudHsmClusterInvalidConfigurationException', ], ], ], 'CreateAlias' => [ 'name' => 'CreateAlias', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateAliasRequest', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'AlreadyExistsException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidAliasNameException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'CreateCustomKeyStore' => [ 'name' => 'CreateCustomKeyStore', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateCustomKeyStoreRequest', ], 'output' => [ 'shape' => 'CreateCustomKeyStoreResponse', ], 'errors' => [ [ 'shape' => 'CloudHsmClusterInUseException', ], [ 'shape' => 'CustomKeyStoreNameInUseException', ], [ 'shape' => 'CloudHsmClusterNotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'CloudHsmClusterNotActiveException', ], [ 'shape' => 'IncorrectTrustAnchorException', ], [ 'shape' => 'CloudHsmClusterInvalidConfigurationException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'XksProxyUriInUseException', ], [ 'shape' => 'XksProxyUriEndpointInUseException', ], [ 'shape' => 'XksProxyUriUnreachableException', ], [ 'shape' => 'XksProxyIncorrectAuthenticationCredentialException', ], [ 'shape' => 'XksProxyVpcEndpointServiceInUseException', ], [ 'shape' => 'XksProxyVpcEndpointServiceNotFoundException', ], [ 'shape' => 'XksProxyVpcEndpointServiceInvalidConfigurationException', ], [ 'shape' => 'XksProxyInvalidResponseException', ], [ 'shape' => 'XksProxyInvalidConfigurationException', ], ], ], 'CreateGrant' => [ 'name' => 'CreateGrant', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateGrantRequest', ], 'output' => [ 'shape' => 'CreateGrantResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'CreateKey' => [ 'name' => 'CreateKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateKeyRequest', ], 'output' => [ 'shape' => 'CreateKeyResponse', ], 'errors' => [ [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'TagException', ], [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'CustomKeyStoreInvalidStateException', ], [ 'shape' => 'CloudHsmClusterInvalidConfigurationException', ], [ 'shape' => 'XksKeyInvalidConfigurationException', ], [ 'shape' => 'XksKeyAlreadyInUseException', ], [ 'shape' => 'XksKeyNotFoundException', ], ], ], 'Decrypt' => [ 'name' => 'Decrypt', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DecryptRequest', ], 'output' => [ 'shape' => 'DecryptResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidCiphertextException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'IncorrectKeyException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'DeleteAlias' => [ 'name' => 'DeleteAlias', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteAliasRequest', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'DeleteCustomKeyStore' => [ 'name' => 'DeleteCustomKeyStore', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteCustomKeyStoreRequest', ], 'output' => [ 'shape' => 'DeleteCustomKeyStoreResponse', ], 'errors' => [ [ 'shape' => 'CustomKeyStoreHasCMKsException', ], [ 'shape' => 'CustomKeyStoreInvalidStateException', ], [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'KMSInternalException', ], ], ], 'DeleteImportedKeyMaterial' => [ 'name' => 'DeleteImportedKeyMaterial', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteImportedKeyMaterialRequest', ], 'output' => [ 'shape' => 'DeleteImportedKeyMaterialResponse', ], 'errors' => [ [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'DeriveSharedSecret' => [ 'name' => 'DeriveSharedSecret', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeriveSharedSecretRequest', ], 'output' => [ 'shape' => 'DeriveSharedSecretResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'DescribeCustomKeyStores' => [ 'name' => 'DescribeCustomKeyStores', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DescribeCustomKeyStoresRequest', ], 'output' => [ 'shape' => 'DescribeCustomKeyStoresResponse', ], 'errors' => [ [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'InvalidMarkerException', ], [ 'shape' => 'KMSInternalException', ], ], ], 'DescribeKey' => [ 'name' => 'DescribeKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DescribeKeyRequest', ], 'output' => [ 'shape' => 'DescribeKeyResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], ], ], 'DisableKey' => [ 'name' => 'DisableKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DisableKeyRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'DisableKeyRotation' => [ 'name' => 'DisableKeyRotation', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DisableKeyRotationRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'DisconnectCustomKeyStore' => [ 'name' => 'DisconnectCustomKeyStore', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DisconnectCustomKeyStoreRequest', ], 'output' => [ 'shape' => 'DisconnectCustomKeyStoreResponse', ], 'errors' => [ [ 'shape' => 'CustomKeyStoreInvalidStateException', ], [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'KMSInternalException', ], ], ], 'EnableKey' => [ 'name' => 'EnableKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'EnableKeyRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'EnableKeyRotation' => [ 'name' => 'EnableKeyRotation', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'EnableKeyRotationRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'Encrypt' => [ 'name' => 'Encrypt', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'EncryptRequest', ], 'output' => [ 'shape' => 'EncryptResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateDataKey' => [ 'name' => 'GenerateDataKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateDataKeyRequest', ], 'output' => [ 'shape' => 'GenerateDataKeyResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateDataKeyPair' => [ 'name' => 'GenerateDataKeyPair', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateDataKeyPairRequest', ], 'output' => [ 'shape' => 'GenerateDataKeyPairResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateDataKeyPairWithoutPlaintext' => [ 'name' => 'GenerateDataKeyPairWithoutPlaintext', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateDataKeyPairWithoutPlaintextRequest', ], 'output' => [ 'shape' => 'GenerateDataKeyPairWithoutPlaintextResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateDataKeyWithoutPlaintext' => [ 'name' => 'GenerateDataKeyWithoutPlaintext', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateDataKeyWithoutPlaintextRequest', ], 'output' => [ 'shape' => 'GenerateDataKeyWithoutPlaintextResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateMac' => [ 'name' => 'GenerateMac', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateMacRequest', ], 'output' => [ 'shape' => 'GenerateMacResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'GenerateRandom' => [ 'name' => 'GenerateRandom', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GenerateRandomRequest', ], 'output' => [ 'shape' => 'GenerateRandomResponse', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'CustomKeyStoreInvalidStateException', ], ], ], 'GetKeyPolicy' => [ 'name' => 'GetKeyPolicy', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetKeyPolicyRequest', ], 'output' => [ 'shape' => 'GetKeyPolicyResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'GetKeyRotationStatus' => [ 'name' => 'GetKeyRotationStatus', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetKeyRotationStatusRequest', ], 'output' => [ 'shape' => 'GetKeyRotationStatusResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'GetParametersForImport' => [ 'name' => 'GetParametersForImport', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetParametersForImportRequest', ], 'output' => [ 'shape' => 'GetParametersForImportResponse', ], 'errors' => [ [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'GetPublicKey' => [ 'name' => 'GetPublicKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetPublicKeyRequest', ], 'output' => [ 'shape' => 'GetPublicKeyResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'ImportKeyMaterial' => [ 'name' => 'ImportKeyMaterial', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ImportKeyMaterialRequest', ], 'output' => [ 'shape' => 'ImportKeyMaterialResponse', ], 'errors' => [ [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'InvalidCiphertextException', ], [ 'shape' => 'IncorrectKeyMaterialException', ], [ 'shape' => 'ExpiredImportTokenException', ], [ 'shape' => 'InvalidImportTokenException', ], ], ], 'ListAliases' => [ 'name' => 'ListAliases', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListAliasesRequest', ], 'output' => [ 'shape' => 'ListAliasesResponse', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidMarkerException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'NotFoundException', ], ], ], 'ListGrants' => [ 'name' => 'ListGrants', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListGrantsRequest', ], 'output' => [ 'shape' => 'ListGrantsResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidMarkerException', ], [ 'shape' => 'InvalidGrantIdException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'ListKeyPolicies' => [ 'name' => 'ListKeyPolicies', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListKeyPoliciesRequest', ], 'output' => [ 'shape' => 'ListKeyPoliciesResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'ListKeyRotations' => [ 'name' => 'ListKeyRotations', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListKeyRotationsRequest', ], 'output' => [ 'shape' => 'ListKeyRotationsResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'InvalidMarkerException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'ListKeys' => [ 'name' => 'ListKeys', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListKeysRequest', ], 'output' => [ 'shape' => 'ListKeysResponse', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'InvalidMarkerException', ], ], ], 'ListResourceTags' => [ 'name' => 'ListResourceTags', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListResourceTagsRequest', ], 'output' => [ 'shape' => 'ListResourceTagsResponse', ], 'errors' => [ [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'InvalidMarkerException', ], ], ], 'ListRetirableGrants' => [ 'name' => 'ListRetirableGrants', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListRetirableGrantsRequest', ], 'output' => [ 'shape' => 'ListGrantsResponse', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidMarkerException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], ], ], 'PutKeyPolicy' => [ 'name' => 'PutKeyPolicy', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'PutKeyPolicyRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'ReEncrypt' => [ 'name' => 'ReEncrypt', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ReEncryptRequest', ], 'output' => [ 'shape' => 'ReEncryptResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidCiphertextException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'IncorrectKeyException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'ReplicateKey' => [ 'name' => 'ReplicateKey', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ReplicateKeyRequest', ], 'output' => [ 'shape' => 'ReplicateKeyResponse', ], 'errors' => [ [ 'shape' => 'AlreadyExistsException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'TagException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'RetireGrant' => [ 'name' => 'RetireGrant', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'RetireGrantRequest', ], 'errors' => [ [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'InvalidGrantIdException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'RevokeGrant' => [ 'name' => 'RevokeGrant', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'RevokeGrantRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'InvalidGrantIdException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'RotateKeyOnDemand' => [ 'name' => 'RotateKeyOnDemand', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'RotateKeyOnDemandRequest', ], 'output' => [ 'shape' => 'RotateKeyOnDemandResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'UnsupportedOperationException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'ConflictException', ], ], ], 'ScheduleKeyDeletion' => [ 'name' => 'ScheduleKeyDeletion', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ScheduleKeyDeletionRequest', ], 'output' => [ 'shape' => 'ScheduleKeyDeletionResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'Sign' => [ 'name' => 'Sign', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SignRequest', ], 'output' => [ 'shape' => 'SignResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'TagResource' => [ 'name' => 'TagResource', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'TagResourceRequest', ], 'errors' => [ [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'TagException', ], ], ], 'UntagResource' => [ 'name' => 'UntagResource', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UntagResourceRequest', ], 'errors' => [ [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'TagException', ], ], ], 'UpdateAlias' => [ 'name' => 'UpdateAlias', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UpdateAliasRequest', ], 'errors' => [ [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'LimitExceededException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'UpdateCustomKeyStore' => [ 'name' => 'UpdateCustomKeyStore', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UpdateCustomKeyStoreRequest', ], 'output' => [ 'shape' => 'UpdateCustomKeyStoreResponse', ], 'errors' => [ [ 'shape' => 'CustomKeyStoreNotFoundException', ], [ 'shape' => 'CustomKeyStoreNameInUseException', ], [ 'shape' => 'CloudHsmClusterNotFoundException', ], [ 'shape' => 'CloudHsmClusterNotRelatedException', ], [ 'shape' => 'CustomKeyStoreInvalidStateException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'CloudHsmClusterNotActiveException', ], [ 'shape' => 'CloudHsmClusterInvalidConfigurationException', ], [ 'shape' => 'XksProxyUriInUseException', ], [ 'shape' => 'XksProxyUriEndpointInUseException', ], [ 'shape' => 'XksProxyUriUnreachableException', ], [ 'shape' => 'XksProxyIncorrectAuthenticationCredentialException', ], [ 'shape' => 'XksProxyVpcEndpointServiceInUseException', ], [ 'shape' => 'XksProxyVpcEndpointServiceNotFoundException', ], [ 'shape' => 'XksProxyVpcEndpointServiceInvalidConfigurationException', ], [ 'shape' => 'XksProxyInvalidResponseException', ], [ 'shape' => 'XksProxyInvalidConfigurationException', ], ], ], 'UpdateKeyDescription' => [ 'name' => 'UpdateKeyDescription', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UpdateKeyDescriptionRequest', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], ], ], 'UpdatePrimaryRegion' => [ 'name' => 'UpdatePrimaryRegion', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UpdatePrimaryRegionRequest', ], 'errors' => [ [ 'shape' => 'DisabledException', ], [ 'shape' => 'InvalidArnException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'UnsupportedOperationException', ], ], ], 'Verify' => [ 'name' => 'Verify', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'VerifyRequest', ], 'output' => [ 'shape' => 'VerifyResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'DependencyTimeoutException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'KMSInvalidSignatureException', ], [ 'shape' => 'DryRunOperationException', ], ], ], 'VerifyMac' => [ 'name' => 'VerifyMac', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'VerifyMacRequest', ], 'output' => [ 'shape' => 'VerifyMacResponse', ], 'errors' => [ [ 'shape' => 'NotFoundException', ], [ 'shape' => 'DisabledException', ], [ 'shape' => 'KeyUnavailableException', ], [ 'shape' => 'InvalidKeyUsageException', ], [ 'shape' => 'InvalidGrantTokenException', ], [ 'shape' => 'KMSInternalException', ], [ 'shape' => 'KMSInvalidMacException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'DryRunOperationException', ], ], ], ], 'shapes' => [ 'AWSAccountIdType' => [ 'type' => 'string', ], 'AlgorithmSpec' => [ 'type' => 'string', 'enum' => [ 'RSAES_PKCS1_V1_5', 'RSAES_OAEP_SHA_1', 'RSAES_OAEP_SHA_256', 'RSA_AES_KEY_WRAP_SHA_1', 'RSA_AES_KEY_WRAP_SHA_256', 'SM2PKE', ], ], 'AliasList' => [ 'type' => 'list', 'member' => [ 'shape' => 'AliasListEntry', ], ], 'AliasListEntry' => [ 'type' => 'structure', 'members' => [ 'AliasName' => [ 'shape' => 'AliasNameType', ], 'AliasArn' => [ 'shape' => 'ArnType', ], 'TargetKeyId' => [ 'shape' => 'KeyIdType', ], 'CreationDate' => [ 'shape' => 'DateType', ], 'LastUpdatedDate' => [ 'shape' => 'DateType', ], ], ], 'AliasNameType' => [ 'type' => 'string', 'max' => 256, 'min' => 1, 'pattern' => '^[a-zA-Z0-9:/_-]+$', ], 'AlreadyExistsException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'ArnType' => [ 'type' => 'string', 'max' => 2048, 'min' => 20, ], 'AttestationDocumentType' => [ 'type' => 'blob', 'max' => 262144, 'min' => 1, ], 'BackingKeyIdResponseType' => [ 'type' => 'string', 'max' => 64, 'min' => 0, 'pattern' => '^[a-f0-9]+$', ], 'BackingKeyIdType' => [ 'type' => 'string', 'max' => 64, 'min' => 64, 'pattern' => '^[a-f0-9]+$', ], 'BooleanType' => [ 'type' => 'boolean', ], 'CancelKeyDeletionRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'CancelKeyDeletionResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'CiphertextType' => [ 'type' => 'blob', 'max' => 6144, 'min' => 1, ], 'CloudHsmClusterIdType' => [ 'type' => 'string', 'max' => 24, 'min' => 19, 'pattern' => 'cluster-[2-7a-zA-Z]{11,16}', ], 'CloudHsmClusterInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CloudHsmClusterInvalidConfigurationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CloudHsmClusterNotActiveException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CloudHsmClusterNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CloudHsmClusterNotRelatedException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'ConflictException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'ConnectCustomKeyStoreRequest' => [ 'type' => 'structure', 'required' => [ 'CustomKeyStoreId', ], 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], ], ], 'ConnectCustomKeyStoreResponse' => [ 'type' => 'structure', 'members' => [], ], 'ConnectionErrorCodeType' => [ 'type' => 'string', 'enum' => [ 'INVALID_CREDENTIALS', 'CLUSTER_NOT_FOUND', 'NETWORK_ERRORS', 'INTERNAL_ERROR', 'INSUFFICIENT_CLOUDHSM_HSMS', 'USER_LOCKED_OUT', 'USER_NOT_FOUND', 'USER_LOGGED_IN', 'SUBNET_NOT_FOUND', 'INSUFFICIENT_FREE_ADDRESSES_IN_SUBNET', 'XKS_PROXY_ACCESS_DENIED', 'XKS_PROXY_NOT_REACHABLE', 'XKS_VPC_ENDPOINT_SERVICE_NOT_FOUND', 'XKS_PROXY_INVALID_RESPONSE', 'XKS_PROXY_INVALID_CONFIGURATION', 'XKS_VPC_ENDPOINT_SERVICE_INVALID_CONFIGURATION', 'XKS_PROXY_TIMED_OUT', 'XKS_PROXY_INVALID_TLS_CONFIGURATION', ], ], 'ConnectionStateType' => [ 'type' => 'string', 'enum' => [ 'CONNECTED', 'CONNECTING', 'FAILED', 'DISCONNECTED', 'DISCONNECTING', ], ], 'CreateAliasRequest' => [ 'type' => 'structure', 'required' => [ 'AliasName', 'TargetKeyId', ], 'members' => [ 'AliasName' => [ 'shape' => 'AliasNameType', ], 'TargetKeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'CreateCustomKeyStoreRequest' => [ 'type' => 'structure', 'required' => [ 'CustomKeyStoreName', ], 'members' => [ 'CustomKeyStoreName' => [ 'shape' => 'CustomKeyStoreNameType', ], 'CloudHsmClusterId' => [ 'shape' => 'CloudHsmClusterIdType', ], 'TrustAnchorCertificate' => [ 'shape' => 'TrustAnchorCertificateType', ], 'KeyStorePassword' => [ 'shape' => 'KeyStorePasswordType', ], 'CustomKeyStoreType' => [ 'shape' => 'CustomKeyStoreType', ], 'XksProxyUriEndpoint' => [ 'shape' => 'XksProxyUriEndpointType', ], 'XksProxyUriPath' => [ 'shape' => 'XksProxyUriPathType', ], 'XksProxyVpcEndpointServiceName' => [ 'shape' => 'XksProxyVpcEndpointServiceNameType', ], 'XksProxyAuthenticationCredential' => [ 'shape' => 'XksProxyAuthenticationCredentialType', ], 'XksProxyConnectivity' => [ 'shape' => 'XksProxyConnectivityType', ], ], ], 'CreateCustomKeyStoreResponse' => [ 'type' => 'structure', 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], ], ], 'CreateGrantRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'GranteePrincipal', 'Operations', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GranteePrincipal' => [ 'shape' => 'PrincipalIdType', ], 'RetiringPrincipal' => [ 'shape' => 'PrincipalIdType', ], 'Operations' => [ 'shape' => 'GrantOperationList', ], 'Constraints' => [ 'shape' => 'GrantConstraints', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'Name' => [ 'shape' => 'GrantNameType', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'CreateGrantResponse' => [ 'type' => 'structure', 'members' => [ 'GrantToken' => [ 'shape' => 'GrantTokenType', ], 'GrantId' => [ 'shape' => 'GrantIdType', ], ], ], 'CreateKeyRequest' => [ 'type' => 'structure', 'members' => [ 'Policy' => [ 'shape' => 'PolicyType', ], 'Description' => [ 'shape' => 'DescriptionType', ], 'KeyUsage' => [ 'shape' => 'KeyUsageType', ], 'CustomerMasterKeySpec' => [ 'shape' => 'CustomerMasterKeySpec', 'deprecated' => true, 'deprecatedMessage' => 'This parameter has been deprecated. Instead, use the KeySpec parameter.', ], 'KeySpec' => [ 'shape' => 'KeySpec', ], 'Origin' => [ 'shape' => 'OriginType', ], 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'BypassPolicyLockoutSafetyCheck' => [ 'shape' => 'BooleanType', ], 'Tags' => [ 'shape' => 'TagList', ], 'MultiRegion' => [ 'shape' => 'NullableBooleanType', ], 'XksKeyId' => [ 'shape' => 'XksKeyIdType', ], ], ], 'CreateKeyResponse' => [ 'type' => 'structure', 'members' => [ 'KeyMetadata' => [ 'shape' => 'KeyMetadata', ], ], ], 'CustomKeyStoreHasCMKsException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CustomKeyStoreIdType' => [ 'type' => 'string', 'max' => 64, 'min' => 1, ], 'CustomKeyStoreInvalidStateException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CustomKeyStoreNameInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CustomKeyStoreNameType' => [ 'type' => 'string', 'max' => 256, 'min' => 1, ], 'CustomKeyStoreNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'CustomKeyStoreType' => [ 'type' => 'string', 'enum' => [ 'AWS_CLOUDHSM', 'EXTERNAL_KEY_STORE', ], ], 'CustomKeyStoresList' => [ 'type' => 'list', 'member' => [ 'shape' => 'CustomKeyStoresListEntry', ], ], 'CustomKeyStoresListEntry' => [ 'type' => 'structure', 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'CustomKeyStoreName' => [ 'shape' => 'CustomKeyStoreNameType', ], 'CloudHsmClusterId' => [ 'shape' => 'CloudHsmClusterIdType', ], 'TrustAnchorCertificate' => [ 'shape' => 'TrustAnchorCertificateType', ], 'ConnectionState' => [ 'shape' => 'ConnectionStateType', ], 'ConnectionErrorCode' => [ 'shape' => 'ConnectionErrorCodeType', ], 'CreationDate' => [ 'shape' => 'DateType', ], 'CustomKeyStoreType' => [ 'shape' => 'CustomKeyStoreType', ], 'XksProxyConfiguration' => [ 'shape' => 'XksProxyConfigurationType', ], ], ], 'CustomerMasterKeySpec' => [ 'type' => 'string', 'deprecated' => true, 'deprecatedMessage' => 'This enum has been deprecated. Instead, use the KeySpec enum.', 'enum' => [ 'RSA_2048', 'RSA_3072', 'RSA_4096', 'ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1', 'SYMMETRIC_DEFAULT', 'HMAC_224', 'HMAC_256', 'HMAC_384', 'HMAC_512', 'SM2', ], ], 'DataKeyPairSpec' => [ 'type' => 'string', 'enum' => [ 'RSA_2048', 'RSA_3072', 'RSA_4096', 'ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1', 'SM2', ], ], 'DataKeySpec' => [ 'type' => 'string', 'enum' => [ 'AES_256', 'AES_128', ], ], 'DateType' => [ 'type' => 'timestamp', ], 'DecryptRequest' => [ 'type' => 'structure', 'required' => [ 'CiphertextBlob', ], 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'EncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'Recipient' => [ 'shape' => 'RecipientInfo', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'DecryptResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Plaintext' => [ 'shape' => 'PlaintextType', ], 'EncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'CiphertextForRecipient' => [ 'shape' => 'CiphertextType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'DeleteAliasRequest' => [ 'type' => 'structure', 'required' => [ 'AliasName', ], 'members' => [ 'AliasName' => [ 'shape' => 'AliasNameType', ], ], ], 'DeleteCustomKeyStoreRequest' => [ 'type' => 'structure', 'required' => [ 'CustomKeyStoreId', ], 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], ], ], 'DeleteCustomKeyStoreResponse' => [ 'type' => 'structure', 'members' => [], ], 'DeleteImportedKeyMaterialRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'DeleteImportedKeyMaterialResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdResponseType', ], ], ], 'DependencyTimeoutException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, 'fault' => true, ], 'DeriveSharedSecretRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'KeyAgreementAlgorithm', 'PublicKey', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyAgreementAlgorithm' => [ 'shape' => 'KeyAgreementAlgorithmSpec', ], 'PublicKey' => [ 'shape' => 'PublicKeyType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], 'Recipient' => [ 'shape' => 'RecipientInfo', ], ], ], 'DeriveSharedSecretResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'SharedSecret' => [ 'shape' => 'PlaintextType', ], 'CiphertextForRecipient' => [ 'shape' => 'CiphertextType', ], 'KeyAgreementAlgorithm' => [ 'shape' => 'KeyAgreementAlgorithmSpec', ], 'KeyOrigin' => [ 'shape' => 'OriginType', ], ], ], 'DescribeCustomKeyStoresRequest' => [ 'type' => 'structure', 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'CustomKeyStoreName' => [ 'shape' => 'CustomKeyStoreNameType', ], 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'DescribeCustomKeyStoresResponse' => [ 'type' => 'structure', 'members' => [ 'CustomKeyStores' => [ 'shape' => 'CustomKeyStoresList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'DescribeKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], ], ], 'DescribeKeyResponse' => [ 'type' => 'structure', 'members' => [ 'KeyMetadata' => [ 'shape' => 'KeyMetadata', ], ], ], 'DescriptionType' => [ 'type' => 'string', 'max' => 8192, 'min' => 0, ], 'DisableKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'DisableKeyRotationRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'DisabledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'DisconnectCustomKeyStoreRequest' => [ 'type' => 'structure', 'required' => [ 'CustomKeyStoreId', ], 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], ], ], 'DisconnectCustomKeyStoreResponse' => [ 'type' => 'structure', 'members' => [], ], 'DryRunOperationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'EnableKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'EnableKeyRotationRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'RotationPeriodInDays' => [ 'shape' => 'RotationPeriodInDaysType', ], ], ], 'EncryptRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Plaintext', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Plaintext' => [ 'shape' => 'PlaintextType', ], 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'EncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'EncryptResponse' => [ 'type' => 'structure', 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'EncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], ], ], 'EncryptionAlgorithmSpec' => [ 'type' => 'string', 'enum' => [ 'SYMMETRIC_DEFAULT', 'RSAES_OAEP_SHA_1', 'RSAES_OAEP_SHA_256', 'SM2PKE', ], ], 'EncryptionAlgorithmSpecList' => [ 'type' => 'list', 'member' => [ 'shape' => 'EncryptionAlgorithmSpec', ], ], 'EncryptionContextKey' => [ 'type' => 'string', ], 'EncryptionContextType' => [ 'type' => 'map', 'key' => [ 'shape' => 'EncryptionContextKey', ], 'value' => [ 'shape' => 'EncryptionContextValue', ], ], 'EncryptionContextValue' => [ 'type' => 'string', ], 'ErrorMessageType' => [ 'type' => 'string', ], 'ExpirationModelType' => [ 'type' => 'string', 'enum' => [ 'KEY_MATERIAL_EXPIRES', 'KEY_MATERIAL_DOES_NOT_EXPIRE', ], ], 'ExpiredImportTokenException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'GenerateDataKeyPairRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'KeyPairSpec', ], 'members' => [ 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyPairSpec' => [ 'shape' => 'DataKeyPairSpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'Recipient' => [ 'shape' => 'RecipientInfo', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'GenerateDataKeyPairResponse' => [ 'type' => 'structure', 'members' => [ 'PrivateKeyCiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'PrivateKeyPlaintext' => [ 'shape' => 'PlaintextType', ], 'PublicKey' => [ 'shape' => 'PublicKeyType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyPairSpec' => [ 'shape' => 'DataKeyPairSpec', ], 'CiphertextForRecipient' => [ 'shape' => 'CiphertextType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'GenerateDataKeyPairWithoutPlaintextRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'KeyPairSpec', ], 'members' => [ 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyPairSpec' => [ 'shape' => 'DataKeyPairSpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'GenerateDataKeyPairWithoutPlaintextResponse' => [ 'type' => 'structure', 'members' => [ 'PrivateKeyCiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'PublicKey' => [ 'shape' => 'PublicKeyType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyPairSpec' => [ 'shape' => 'DataKeyPairSpec', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'GenerateDataKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'NumberOfBytes' => [ 'shape' => 'NumberOfBytesType', ], 'KeySpec' => [ 'shape' => 'DataKeySpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'Recipient' => [ 'shape' => 'RecipientInfo', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'GenerateDataKeyResponse' => [ 'type' => 'structure', 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'Plaintext' => [ 'shape' => 'PlaintextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'CiphertextForRecipient' => [ 'shape' => 'CiphertextType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'GenerateDataKeyWithoutPlaintextRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'EncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'KeySpec' => [ 'shape' => 'DataKeySpec', ], 'NumberOfBytes' => [ 'shape' => 'NumberOfBytesType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'GenerateDataKeyWithoutPlaintextResponse' => [ 'type' => 'structure', 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'GenerateMacRequest' => [ 'type' => 'structure', 'required' => [ 'Message', 'KeyId', 'MacAlgorithm', ], 'members' => [ 'Message' => [ 'shape' => 'PlaintextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'MacAlgorithm' => [ 'shape' => 'MacAlgorithmSpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'GenerateMacResponse' => [ 'type' => 'structure', 'members' => [ 'Mac' => [ 'shape' => 'CiphertextType', ], 'MacAlgorithm' => [ 'shape' => 'MacAlgorithmSpec', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'GenerateRandomRequest' => [ 'type' => 'structure', 'members' => [ 'NumberOfBytes' => [ 'shape' => 'NumberOfBytesType', ], 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'Recipient' => [ 'shape' => 'RecipientInfo', ], ], ], 'GenerateRandomResponse' => [ 'type' => 'structure', 'members' => [ 'Plaintext' => [ 'shape' => 'PlaintextType', ], 'CiphertextForRecipient' => [ 'shape' => 'CiphertextType', ], ], ], 'GetKeyPolicyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'PolicyName' => [ 'shape' => 'PolicyNameType', ], ], ], 'GetKeyPolicyResponse' => [ 'type' => 'structure', 'members' => [ 'Policy' => [ 'shape' => 'PolicyType', ], 'PolicyName' => [ 'shape' => 'PolicyNameType', ], ], ], 'GetKeyRotationStatusRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'GetKeyRotationStatusResponse' => [ 'type' => 'structure', 'members' => [ 'KeyRotationEnabled' => [ 'shape' => 'BooleanType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'RotationPeriodInDays' => [ 'shape' => 'RotationPeriodInDaysType', ], 'NextRotationDate' => [ 'shape' => 'DateType', ], 'OnDemandRotationStartDate' => [ 'shape' => 'DateType', ], ], ], 'GetParametersForImportRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'WrappingAlgorithm', 'WrappingKeySpec', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'WrappingAlgorithm' => [ 'shape' => 'AlgorithmSpec', ], 'WrappingKeySpec' => [ 'shape' => 'WrappingKeySpec', ], ], ], 'GetParametersForImportResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'ImportToken' => [ 'shape' => 'CiphertextType', ], 'PublicKey' => [ 'shape' => 'PlaintextType', ], 'ParametersValidTo' => [ 'shape' => 'DateType', ], ], ], 'GetPublicKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], ], ], 'GetPublicKeyResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'PublicKey' => [ 'shape' => 'PublicKeyType', ], 'CustomerMasterKeySpec' => [ 'shape' => 'CustomerMasterKeySpec', 'deprecated' => true, 'deprecatedMessage' => 'This field has been deprecated. Instead, use the KeySpec field.', ], 'KeySpec' => [ 'shape' => 'KeySpec', ], 'KeyUsage' => [ 'shape' => 'KeyUsageType', ], 'EncryptionAlgorithms' => [ 'shape' => 'EncryptionAlgorithmSpecList', ], 'SigningAlgorithms' => [ 'shape' => 'SigningAlgorithmSpecList', ], 'KeyAgreementAlgorithms' => [ 'shape' => 'KeyAgreementAlgorithmSpecList', ], ], ], 'GrantConstraints' => [ 'type' => 'structure', 'members' => [ 'EncryptionContextSubset' => [ 'shape' => 'EncryptionContextType', ], 'EncryptionContextEquals' => [ 'shape' => 'EncryptionContextType', ], ], ], 'GrantIdType' => [ 'type' => 'string', 'max' => 128, 'min' => 1, ], 'GrantList' => [ 'type' => 'list', 'member' => [ 'shape' => 'GrantListEntry', ], ], 'GrantListEntry' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantId' => [ 'shape' => 'GrantIdType', ], 'Name' => [ 'shape' => 'GrantNameType', ], 'CreationDate' => [ 'shape' => 'DateType', ], 'GranteePrincipal' => [ 'shape' => 'PrincipalIdType', ], 'RetiringPrincipal' => [ 'shape' => 'PrincipalIdType', ], 'IssuingAccount' => [ 'shape' => 'PrincipalIdType', ], 'Operations' => [ 'shape' => 'GrantOperationList', ], 'Constraints' => [ 'shape' => 'GrantConstraints', ], ], ], 'GrantNameType' => [ 'type' => 'string', 'max' => 256, 'min' => 1, 'pattern' => '^[a-zA-Z0-9:/_-]+$', ], 'GrantOperation' => [ 'type' => 'string', 'enum' => [ 'Decrypt', 'Encrypt', 'GenerateDataKey', 'GenerateDataKeyWithoutPlaintext', 'ReEncryptFrom', 'ReEncryptTo', 'Sign', 'Verify', 'GetPublicKey', 'CreateGrant', 'RetireGrant', 'DescribeKey', 'GenerateDataKeyPair', 'GenerateDataKeyPairWithoutPlaintext', 'GenerateMac', 'VerifyMac', 'DeriveSharedSecret', ], ], 'GrantOperationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'GrantOperation', ], ], 'GrantTokenList' => [ 'type' => 'list', 'member' => [ 'shape' => 'GrantTokenType', ], 'max' => 10, 'min' => 0, ], 'GrantTokenType' => [ 'type' => 'string', 'max' => 8192, 'min' => 1, ], 'ImportKeyMaterialRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'ImportToken', 'EncryptedKeyMaterial', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'ImportToken' => [ 'shape' => 'CiphertextType', ], 'EncryptedKeyMaterial' => [ 'shape' => 'CiphertextType', ], 'ValidTo' => [ 'shape' => 'DateType', ], 'ExpirationModel' => [ 'shape' => 'ExpirationModelType', ], 'ImportType' => [ 'shape' => 'ImportType', ], 'KeyMaterialDescription' => [ 'shape' => 'KeyMaterialDescriptionType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'ImportKeyMaterialResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'ImportState' => [ 'type' => 'string', 'enum' => [ 'IMPORTED', 'PENDING_IMPORT', ], ], 'ImportType' => [ 'type' => 'string', 'enum' => [ 'NEW_KEY_MATERIAL', 'EXISTING_KEY_MATERIAL', ], ], 'IncludeKeyMaterial' => [ 'type' => 'string', 'enum' => [ 'ALL_KEY_MATERIAL', 'ROTATIONS_ONLY', ], ], 'IncorrectKeyException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'IncorrectKeyMaterialException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'IncorrectTrustAnchorException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidAliasNameException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidArnException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidCiphertextException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidGrantIdException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidGrantTokenException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidImportTokenException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidKeyUsageException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'InvalidMarkerException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'KMSInternalException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, 'fault' => true, ], 'KMSInvalidMacException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'KMSInvalidSignatureException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'KMSInvalidStateException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'KeyAgreementAlgorithmSpec' => [ 'type' => 'string', 'enum' => [ 'ECDH', ], ], 'KeyAgreementAlgorithmSpecList' => [ 'type' => 'list', 'member' => [ 'shape' => 'KeyAgreementAlgorithmSpec', ], ], 'KeyEncryptionMechanism' => [ 'type' => 'string', 'enum' => [ 'RSAES_OAEP_SHA_256', ], ], 'KeyIdType' => [ 'type' => 'string', 'max' => 2048, 'min' => 1, ], 'KeyList' => [ 'type' => 'list', 'member' => [ 'shape' => 'KeyListEntry', ], ], 'KeyListEntry' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyArn' => [ 'shape' => 'ArnType', ], ], ], 'KeyManagerType' => [ 'type' => 'string', 'enum' => [ 'AWS', 'CUSTOMER', ], ], 'KeyMaterialDescriptionType' => [ 'type' => 'string', 'max' => 256, 'min' => 0, 'pattern' => '^[a-zA-Z0-9:/_\\s.-]+$', ], 'KeyMaterialState' => [ 'type' => 'string', 'enum' => [ 'NON_CURRENT', 'CURRENT', 'PENDING_ROTATION', ], ], 'KeyMetadata' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'AWSAccountId' => [ 'shape' => 'AWSAccountIdType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Arn' => [ 'shape' => 'ArnType', ], 'CreationDate' => [ 'shape' => 'DateType', ], 'Enabled' => [ 'shape' => 'BooleanType', ], 'Description' => [ 'shape' => 'DescriptionType', ], 'KeyUsage' => [ 'shape' => 'KeyUsageType', ], 'KeyState' => [ 'shape' => 'KeyState', ], 'DeletionDate' => [ 'shape' => 'DateType', ], 'ValidTo' => [ 'shape' => 'DateType', ], 'Origin' => [ 'shape' => 'OriginType', ], 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'CloudHsmClusterId' => [ 'shape' => 'CloudHsmClusterIdType', ], 'ExpirationModel' => [ 'shape' => 'ExpirationModelType', ], 'KeyManager' => [ 'shape' => 'KeyManagerType', ], 'CustomerMasterKeySpec' => [ 'shape' => 'CustomerMasterKeySpec', 'deprecated' => true, 'deprecatedMessage' => 'This field has been deprecated. Instead, use the KeySpec field.', ], 'KeySpec' => [ 'shape' => 'KeySpec', ], 'EncryptionAlgorithms' => [ 'shape' => 'EncryptionAlgorithmSpecList', ], 'SigningAlgorithms' => [ 'shape' => 'SigningAlgorithmSpecList', ], 'KeyAgreementAlgorithms' => [ 'shape' => 'KeyAgreementAlgorithmSpecList', ], 'MultiRegion' => [ 'shape' => 'NullableBooleanType', ], 'MultiRegionConfiguration' => [ 'shape' => 'MultiRegionConfiguration', ], 'PendingDeletionWindowInDays' => [ 'shape' => 'PendingWindowInDaysType', ], 'MacAlgorithms' => [ 'shape' => 'MacAlgorithmSpecList', ], 'XksKeyConfiguration' => [ 'shape' => 'XksKeyConfigurationType', ], 'CurrentKeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'KeySpec' => [ 'type' => 'string', 'enum' => [ 'RSA_2048', 'RSA_3072', 'RSA_4096', 'ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1', 'SYMMETRIC_DEFAULT', 'HMAC_224', 'HMAC_256', 'HMAC_384', 'HMAC_512', 'SM2', 'ML_DSA_44', 'ML_DSA_65', 'ML_DSA_87', ], ], 'KeyState' => [ 'type' => 'string', 'enum' => [ 'Creating', 'Enabled', 'Disabled', 'PendingDeletion', 'PendingImport', 'PendingReplicaDeletion', 'Unavailable', 'Updating', ], ], 'KeyStorePasswordType' => [ 'type' => 'string', 'max' => 32, 'min' => 7, 'sensitive' => true, ], 'KeyUnavailableException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, 'fault' => true, ], 'KeyUsageType' => [ 'type' => 'string', 'enum' => [ 'SIGN_VERIFY', 'ENCRYPT_DECRYPT', 'GENERATE_VERIFY_MAC', 'KEY_AGREEMENT', ], ], 'LimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'LimitType' => [ 'type' => 'integer', 'max' => 1000, 'min' => 1, ], 'ListAliasesRequest' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'ListAliasesResponse' => [ 'type' => 'structure', 'members' => [ 'Aliases' => [ 'shape' => 'AliasList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListGrantsRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantId' => [ 'shape' => 'GrantIdType', ], 'GranteePrincipal' => [ 'shape' => 'PrincipalIdType', ], ], ], 'ListGrantsResponse' => [ 'type' => 'structure', 'members' => [ 'Grants' => [ 'shape' => 'GrantList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListKeyPoliciesRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'ListKeyPoliciesResponse' => [ 'type' => 'structure', 'members' => [ 'PolicyNames' => [ 'shape' => 'PolicyNameList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListKeyRotationsRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'IncludeKeyMaterial' => [ 'shape' => 'IncludeKeyMaterial', ], 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'ListKeyRotationsResponse' => [ 'type' => 'structure', 'members' => [ 'Rotations' => [ 'shape' => 'RotationsList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListKeysRequest' => [ 'type' => 'structure', 'members' => [ 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'ListKeysResponse' => [ 'type' => 'structure', 'members' => [ 'Keys' => [ 'shape' => 'KeyList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListResourceTagsRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], ], ], 'ListResourceTagsResponse' => [ 'type' => 'structure', 'members' => [ 'Tags' => [ 'shape' => 'TagList', ], 'NextMarker' => [ 'shape' => 'MarkerType', ], 'Truncated' => [ 'shape' => 'BooleanType', ], ], ], 'ListRetirableGrantsRequest' => [ 'type' => 'structure', 'required' => [ 'RetiringPrincipal', ], 'members' => [ 'Limit' => [ 'shape' => 'LimitType', ], 'Marker' => [ 'shape' => 'MarkerType', ], 'RetiringPrincipal' => [ 'shape' => 'PrincipalIdType', ], ], ], 'MacAlgorithmSpec' => [ 'type' => 'string', 'enum' => [ 'HMAC_SHA_224', 'HMAC_SHA_256', 'HMAC_SHA_384', 'HMAC_SHA_512', ], ], 'MacAlgorithmSpecList' => [ 'type' => 'list', 'member' => [ 'shape' => 'MacAlgorithmSpec', ], ], 'MalformedPolicyDocumentException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'MarkerType' => [ 'type' => 'string', 'max' => 1024, 'min' => 1, 'pattern' => '[\\u0020-\\u00FF]*', ], 'MessageType' => [ 'type' => 'string', 'enum' => [ 'RAW', 'DIGEST', 'EXTERNAL_MU', ], ], 'MultiRegionConfiguration' => [ 'type' => 'structure', 'members' => [ 'MultiRegionKeyType' => [ 'shape' => 'MultiRegionKeyType', ], 'PrimaryKey' => [ 'shape' => 'MultiRegionKey', ], 'ReplicaKeys' => [ 'shape' => 'MultiRegionKeyList', ], ], ], 'MultiRegionKey' => [ 'type' => 'structure', 'members' => [ 'Arn' => [ 'shape' => 'ArnType', ], 'Region' => [ 'shape' => 'RegionType', ], ], ], 'MultiRegionKeyList' => [ 'type' => 'list', 'member' => [ 'shape' => 'MultiRegionKey', ], ], 'MultiRegionKeyType' => [ 'type' => 'string', 'enum' => [ 'PRIMARY', 'REPLICA', ], ], 'NotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'NullableBooleanType' => [ 'type' => 'boolean', ], 'NumberOfBytesType' => [ 'type' => 'integer', 'max' => 1024, 'min' => 1, ], 'OriginType' => [ 'type' => 'string', 'enum' => [ 'AWS_KMS', 'EXTERNAL', 'AWS_CLOUDHSM', 'EXTERNAL_KEY_STORE', ], ], 'PendingWindowInDaysType' => [ 'type' => 'integer', 'max' => 365, 'min' => 1, ], 'PlaintextType' => [ 'type' => 'blob', 'max' => 4096, 'min' => 1, 'sensitive' => true, ], 'PolicyNameList' => [ 'type' => 'list', 'member' => [ 'shape' => 'PolicyNameType', ], ], 'PolicyNameType' => [ 'type' => 'string', 'max' => 128, 'min' => 1, 'pattern' => '[\\w]+', ], 'PolicyType' => [ 'type' => 'string', 'max' => 131072, 'min' => 1, 'pattern' => '[\\u0009\\u000A\\u000D\\u0020-\\u00FF]+', ], 'PrincipalIdType' => [ 'type' => 'string', 'max' => 256, 'min' => 1, 'pattern' => '^[\\w+=,.@:/-]+$', ], 'PublicKeyType' => [ 'type' => 'blob', 'max' => 8192, 'min' => 1, ], 'PutKeyPolicyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Policy', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'PolicyName' => [ 'shape' => 'PolicyNameType', ], 'Policy' => [ 'shape' => 'PolicyType', ], 'BypassPolicyLockoutSafetyCheck' => [ 'shape' => 'BooleanType', ], ], ], 'ReEncryptRequest' => [ 'type' => 'structure', 'required' => [ 'CiphertextBlob', 'DestinationKeyId', ], 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'SourceEncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'SourceKeyId' => [ 'shape' => 'KeyIdType', ], 'DestinationKeyId' => [ 'shape' => 'KeyIdType', ], 'DestinationEncryptionContext' => [ 'shape' => 'EncryptionContextType', ], 'SourceEncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'DestinationEncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'ReEncryptResponse' => [ 'type' => 'structure', 'members' => [ 'CiphertextBlob' => [ 'shape' => 'CiphertextType', ], 'SourceKeyId' => [ 'shape' => 'KeyIdType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'SourceEncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'DestinationEncryptionAlgorithm' => [ 'shape' => 'EncryptionAlgorithmSpec', ], 'SourceKeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], 'DestinationKeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], ], ], 'RecipientInfo' => [ 'type' => 'structure', 'members' => [ 'KeyEncryptionAlgorithm' => [ 'shape' => 'KeyEncryptionMechanism', ], 'AttestationDocument' => [ 'shape' => 'AttestationDocumentType', ], ], ], 'RegionType' => [ 'type' => 'string', 'max' => 32, 'min' => 1, 'pattern' => '^([a-z]+-){2,3}\\d+$', ], 'ReplicateKeyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'ReplicaRegion', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'ReplicaRegion' => [ 'shape' => 'RegionType', ], 'Policy' => [ 'shape' => 'PolicyType', ], 'BypassPolicyLockoutSafetyCheck' => [ 'shape' => 'BooleanType', ], 'Description' => [ 'shape' => 'DescriptionType', ], 'Tags' => [ 'shape' => 'TagList', ], ], ], 'ReplicateKeyResponse' => [ 'type' => 'structure', 'members' => [ 'ReplicaKeyMetadata' => [ 'shape' => 'KeyMetadata', ], 'ReplicaPolicy' => [ 'shape' => 'PolicyType', ], 'ReplicaTags' => [ 'shape' => 'TagList', ], ], ], 'RetireGrantRequest' => [ 'type' => 'structure', 'members' => [ 'GrantToken' => [ 'shape' => 'GrantTokenType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantId' => [ 'shape' => 'GrantIdType', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'RevokeGrantRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'GrantId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'GrantId' => [ 'shape' => 'GrantIdType', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'RotateKeyOnDemandRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'RotateKeyOnDemandResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'RotationPeriodInDaysType' => [ 'type' => 'integer', 'max' => 2560, 'min' => 90, ], 'RotationType' => [ 'type' => 'string', 'enum' => [ 'AUTOMATIC', 'ON_DEMAND', ], ], 'RotationsList' => [ 'type' => 'list', 'member' => [ 'shape' => 'RotationsListEntry', ], ], 'RotationsListEntry' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'KeyMaterialId' => [ 'shape' => 'BackingKeyIdType', ], 'KeyMaterialDescription' => [ 'shape' => 'KeyMaterialDescriptionType', ], 'ImportState' => [ 'shape' => 'ImportState', ], 'KeyMaterialState' => [ 'shape' => 'KeyMaterialState', ], 'ExpirationModel' => [ 'shape' => 'ExpirationModelType', ], 'ValidTo' => [ 'shape' => 'DateType', ], 'RotationDate' => [ 'shape' => 'DateType', ], 'RotationType' => [ 'shape' => 'RotationType', ], ], ], 'ScheduleKeyDeletionRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'PendingWindowInDays' => [ 'shape' => 'PendingWindowInDaysType', ], ], ], 'ScheduleKeyDeletionResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'DeletionDate' => [ 'shape' => 'DateType', ], 'KeyState' => [ 'shape' => 'KeyState', ], 'PendingWindowInDays' => [ 'shape' => 'PendingWindowInDaysType', ], ], ], 'SignRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Message', 'SigningAlgorithm', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Message' => [ 'shape' => 'PlaintextType', ], 'MessageType' => [ 'shape' => 'MessageType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'SigningAlgorithm' => [ 'shape' => 'SigningAlgorithmSpec', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'SignResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Signature' => [ 'shape' => 'CiphertextType', ], 'SigningAlgorithm' => [ 'shape' => 'SigningAlgorithmSpec', ], ], ], 'SigningAlgorithmSpec' => [ 'type' => 'string', 'enum' => [ 'RSASSA_PSS_SHA_256', 'RSASSA_PSS_SHA_384', 'RSASSA_PSS_SHA_512', 'RSASSA_PKCS1_V1_5_SHA_256', 'RSASSA_PKCS1_V1_5_SHA_384', 'RSASSA_PKCS1_V1_5_SHA_512', 'ECDSA_SHA_256', 'ECDSA_SHA_384', 'ECDSA_SHA_512', 'SM2DSA', 'ML_DSA_SHAKE_256', ], ], 'SigningAlgorithmSpecList' => [ 'type' => 'list', 'member' => [ 'shape' => 'SigningAlgorithmSpec', ], ], 'Tag' => [ 'type' => 'structure', 'required' => [ 'TagKey', 'TagValue', ], 'members' => [ 'TagKey' => [ 'shape' => 'TagKeyType', ], 'TagValue' => [ 'shape' => 'TagValueType', ], ], ], 'TagException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'TagKeyList' => [ 'type' => 'list', 'member' => [ 'shape' => 'TagKeyType', ], ], 'TagKeyType' => [ 'type' => 'string', 'max' => 128, 'min' => 1, ], 'TagList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Tag', ], ], 'TagResourceRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Tags', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Tags' => [ 'shape' => 'TagList', ], ], ], 'TagValueType' => [ 'type' => 'string', 'max' => 256, 'min' => 0, ], 'TrustAnchorCertificateType' => [ 'type' => 'string', 'max' => 5000, 'min' => 1, ], 'UnsupportedOperationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'UntagResourceRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'TagKeys', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'TagKeys' => [ 'shape' => 'TagKeyList', ], ], ], 'UpdateAliasRequest' => [ 'type' => 'structure', 'required' => [ 'AliasName', 'TargetKeyId', ], 'members' => [ 'AliasName' => [ 'shape' => 'AliasNameType', ], 'TargetKeyId' => [ 'shape' => 'KeyIdType', ], ], ], 'UpdateCustomKeyStoreRequest' => [ 'type' => 'structure', 'required' => [ 'CustomKeyStoreId', ], 'members' => [ 'CustomKeyStoreId' => [ 'shape' => 'CustomKeyStoreIdType', ], 'NewCustomKeyStoreName' => [ 'shape' => 'CustomKeyStoreNameType', ], 'KeyStorePassword' => [ 'shape' => 'KeyStorePasswordType', ], 'CloudHsmClusterId' => [ 'shape' => 'CloudHsmClusterIdType', ], 'XksProxyUriEndpoint' => [ 'shape' => 'XksProxyUriEndpointType', ], 'XksProxyUriPath' => [ 'shape' => 'XksProxyUriPathType', ], 'XksProxyVpcEndpointServiceName' => [ 'shape' => 'XksProxyVpcEndpointServiceNameType', ], 'XksProxyAuthenticationCredential' => [ 'shape' => 'XksProxyAuthenticationCredentialType', ], 'XksProxyConnectivity' => [ 'shape' => 'XksProxyConnectivityType', ], ], ], 'UpdateCustomKeyStoreResponse' => [ 'type' => 'structure', 'members' => [], ], 'UpdateKeyDescriptionRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Description', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Description' => [ 'shape' => 'DescriptionType', ], ], ], 'UpdatePrimaryRegionRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'PrimaryRegion', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'PrimaryRegion' => [ 'shape' => 'RegionType', ], ], ], 'VerifyMacRequest' => [ 'type' => 'structure', 'required' => [ 'Message', 'KeyId', 'MacAlgorithm', 'Mac', ], 'members' => [ 'Message' => [ 'shape' => 'PlaintextType', ], 'KeyId' => [ 'shape' => 'KeyIdType', ], 'MacAlgorithm' => [ 'shape' => 'MacAlgorithmSpec', ], 'Mac' => [ 'shape' => 'CiphertextType', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'VerifyMacResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'MacValid' => [ 'shape' => 'BooleanType', ], 'MacAlgorithm' => [ 'shape' => 'MacAlgorithmSpec', ], ], ], 'VerifyRequest' => [ 'type' => 'structure', 'required' => [ 'KeyId', 'Message', 'Signature', 'SigningAlgorithm', ], 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'Message' => [ 'shape' => 'PlaintextType', ], 'MessageType' => [ 'shape' => 'MessageType', ], 'Signature' => [ 'shape' => 'CiphertextType', ], 'SigningAlgorithm' => [ 'shape' => 'SigningAlgorithmSpec', ], 'GrantTokens' => [ 'shape' => 'GrantTokenList', ], 'DryRun' => [ 'shape' => 'NullableBooleanType', ], ], ], 'VerifyResponse' => [ 'type' => 'structure', 'members' => [ 'KeyId' => [ 'shape' => 'KeyIdType', ], 'SignatureValid' => [ 'shape' => 'BooleanType', ], 'SigningAlgorithm' => [ 'shape' => 'SigningAlgorithmSpec', ], ], ], 'WrappingKeySpec' => [ 'type' => 'string', 'enum' => [ 'RSA_2048', 'RSA_3072', 'RSA_4096', 'SM2', ], ], 'XksKeyAlreadyInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksKeyConfigurationType' => [ 'type' => 'structure', 'members' => [ 'Id' => [ 'shape' => 'XksKeyIdType', ], ], ], 'XksKeyIdType' => [ 'type' => 'string', 'max' => 128, 'min' => 1, 'pattern' => '^[a-zA-Z0-9-_.]+$', ], 'XksKeyInvalidConfigurationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksKeyNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyAuthenticationAccessKeyIdType' => [ 'type' => 'string', 'max' => 30, 'min' => 20, 'pattern' => '^[A-Z2-7]+$', 'sensitive' => true, ], 'XksProxyAuthenticationCredentialType' => [ 'type' => 'structure', 'required' => [ 'AccessKeyId', 'RawSecretAccessKey', ], 'members' => [ 'AccessKeyId' => [ 'shape' => 'XksProxyAuthenticationAccessKeyIdType', ], 'RawSecretAccessKey' => [ 'shape' => 'XksProxyAuthenticationRawSecretAccessKeyType', ], ], ], 'XksProxyAuthenticationRawSecretAccessKeyType' => [ 'type' => 'string', 'max' => 64, 'min' => 43, 'pattern' => '^[a-zA-Z0-9\\/+=]+$', 'sensitive' => true, ], 'XksProxyConfigurationType' => [ 'type' => 'structure', 'members' => [ 'Connectivity' => [ 'shape' => 'XksProxyConnectivityType', ], 'AccessKeyId' => [ 'shape' => 'XksProxyAuthenticationAccessKeyIdType', ], 'UriEndpoint' => [ 'shape' => 'XksProxyUriEndpointType', ], 'UriPath' => [ 'shape' => 'XksProxyUriPathType', ], 'VpcEndpointServiceName' => [ 'shape' => 'XksProxyVpcEndpointServiceNameType', ], ], ], 'XksProxyConnectivityType' => [ 'type' => 'string', 'enum' => [ 'PUBLIC_ENDPOINT', 'VPC_ENDPOINT_SERVICE', ], ], 'XksProxyIncorrectAuthenticationCredentialException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyInvalidConfigurationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyInvalidResponseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyUriEndpointInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyUriEndpointType' => [ 'type' => 'string', 'max' => 128, 'min' => 10, 'pattern' => '^https://[a-zA-Z0-9.-]+$', ], 'XksProxyUriInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyUriPathType' => [ 'type' => 'string', 'max' => 128, 'min' => 10, 'pattern' => '^(/[a-zA-Z0-9\\/_-]+/kms/xks/v\\d{1,2})$|^(/kms/xks/v\\d{1,2})$', ], 'XksProxyUriUnreachableException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyVpcEndpointServiceInUseException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyVpcEndpointServiceInvalidConfigurationException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], 'XksProxyVpcEndpointServiceNameType' => [ 'type' => 'string', 'max' => 64, 'min' => 20, 'pattern' => '^com\\.amazonaws\\.vpce\\.([a-z]+-){2,3}\\d+\\.vpce-svc-[0-9a-z]+$', ], 'XksProxyVpcEndpointServiceNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorMessageType', ], ], 'exception' => true, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..08a3f6ce2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Invalid Configuration: FIPS and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'Invalid Configuration: Dualstack and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [], 'endpoint' => [ 'url' => [ 'ref' => 'Endpoint', ], 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://kms-fips.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS and DualStack are enabled, but this partition does not support one or both', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://kms-fips.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS is enabled but this partition does not support FIPS', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://kms.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'DualStack is enabled but this partition does not support DualStack', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://kms.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Configuration: Missing Region', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/paginators-1.json.php new file mode 100644 index 000000000..8c2a8e2ea --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/paginators-1.json.php @@ -0,0 +1,3 @@ + [ 'DescribeCustomKeyStores' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'CustomKeyStores', ], 'ListAliases' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Aliases', ], 'ListGrants' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Grants', ], 'ListKeyPolicies' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'PolicyNames', ], 'ListKeyRotations' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Rotations', ], 'ListKeys' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Keys', ], 'ListResourceTags' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Tags', ], 'ListRetirableGrants' => [ 'input_token' => 'Marker', 'limit_key' => 'Limit', 'more_results' => 'Truncated', 'output_token' => 'NextMarker', 'result_key' => 'Grants', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/smoke.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/smoke.json.php new file mode 100644 index 000000000..0586afb03 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/kms/2014-11-01/smoke.json.php @@ -0,0 +1,3 @@ + 1, 'defaultRegion' => 'us-west-2', 'testCases' => [ [ 'operationName' => 'ListAliases', 'input' => [], 'errorExpectedFromService' => false, ], [ 'operationName' => 'GetKeyPolicy', 'input' => [ 'KeyId' => '12345678-1234-1234-1234-123456789012', 'PolicyName' => 'fakePolicy', ], 'errorExpectedFromService' => true, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/manifest.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/manifest.json.php new file mode 100644 index 000000000..379bb411b --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/manifest.json.php @@ -0,0 +1,3 @@ + [ 'namespace' => 'AccessAnalyzer', 'versions' => [ 'latest' => '2019-11-01', '2019-11-01' => '2019-11-01', ], 'serviceIdentifier' => 'accessanalyzer', ], 'account' => [ 'namespace' => 'Account', 'versions' => [ 'latest' => '2021-02-01', '2021-02-01' => '2021-02-01', ], 'serviceIdentifier' => 'account', ], 'acm-pca' => [ 'namespace' => 'ACMPCA', 'versions' => [ 'latest' => '2017-08-22', '2017-08-22' => '2017-08-22', ], 'serviceIdentifier' => 'acm_pca', ], 'acm' => [ 'namespace' => 'Acm', 'versions' => [ 'latest' => '2015-12-08', '2015-12-08' => '2015-12-08', ], 'serviceIdentifier' => 'acm', ], 'aiops' => [ 'namespace' => 'AIOps', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'aiops', ], 'amp' => [ 'namespace' => 'PrometheusService', 'versions' => [ 'latest' => '2020-08-01', '2020-08-01' => '2020-08-01', ], 'serviceIdentifier' => 'amp', ], 'amplify' => [ 'namespace' => 'Amplify', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'amplify', ], 'amplifybackend' => [ 'namespace' => 'AmplifyBackend', 'versions' => [ 'latest' => '2020-08-11', '2020-08-11' => '2020-08-11', ], 'serviceIdentifier' => 'amplifybackend', ], 'amplifyuibuilder' => [ 'namespace' => 'AmplifyUIBuilder', 'versions' => [ 'latest' => '2021-08-11', '2021-08-11' => '2021-08-11', ], 'serviceIdentifier' => 'amplifyuibuilder', ], 'apigateway' => [ 'namespace' => 'ApiGateway', 'versions' => [ 'latest' => '2015-07-09', '2015-07-09' => '2015-07-09', '2015-06-01' => '2015-07-09', ], 'serviceIdentifier' => 'api_gateway', ], 'apigatewaymanagementapi' => [ 'namespace' => 'ApiGatewayManagementApi', 'versions' => [ 'latest' => '2018-11-29', '2018-11-29' => '2018-11-29', ], 'serviceIdentifier' => 'apigatewaymanagementapi', ], 'apigatewayv2' => [ 'namespace' => 'ApiGatewayV2', 'versions' => [ 'latest' => '2018-11-29', '2018-11-29' => '2018-11-29', ], 'serviceIdentifier' => 'apigatewayv2', ], 'appconfig' => [ 'namespace' => 'AppConfig', 'versions' => [ 'latest' => '2019-10-09', '2019-10-09' => '2019-10-09', ], 'serviceIdentifier' => 'appconfig', ], 'appconfigdata' => [ 'namespace' => 'AppConfigData', 'versions' => [ 'latest' => '2021-11-11', '2021-11-11' => '2021-11-11', ], 'serviceIdentifier' => 'appconfigdata', ], 'appfabric' => [ 'namespace' => 'AppFabric', 'versions' => [ 'latest' => '2023-05-19', '2023-05-19' => '2023-05-19', ], 'serviceIdentifier' => 'appfabric', ], 'appflow' => [ 'namespace' => 'Appflow', 'versions' => [ 'latest' => '2020-08-23', '2020-08-23' => '2020-08-23', ], 'serviceIdentifier' => 'appflow', ], 'appintegrations' => [ 'namespace' => 'AppIntegrationsService', 'versions' => [ 'latest' => '2020-07-29', '2020-07-29' => '2020-07-29', ], 'serviceIdentifier' => 'appintegrations', ], 'application-autoscaling' => [ 'namespace' => 'ApplicationAutoScaling', 'versions' => [ 'latest' => '2016-02-06', '2016-02-06' => '2016-02-06', ], 'serviceIdentifier' => 'application_auto_scaling', ], 'application-insights' => [ 'namespace' => 'ApplicationInsights', 'versions' => [ 'latest' => '2018-11-25', '2018-11-25' => '2018-11-25', ], 'serviceIdentifier' => 'application_insights', ], 'application-signals' => [ 'namespace' => 'ApplicationSignals', 'versions' => [ 'latest' => '2024-04-15', '2024-04-15' => '2024-04-15', ], 'serviceIdentifier' => 'application_signals', ], 'applicationcostprofiler' => [ 'namespace' => 'ApplicationCostProfiler', 'versions' => [ 'latest' => '2020-09-10', '2020-09-10' => '2020-09-10', ], 'serviceIdentifier' => 'applicationcostprofiler', ], 'appmesh' => [ 'namespace' => 'AppMesh', 'versions' => [ 'latest' => '2019-01-25', '2019-01-25' => '2019-01-25', '2018-10-01' => '2018-10-01', ], 'serviceIdentifier' => 'app_mesh', ], 'apprunner' => [ 'namespace' => 'AppRunner', 'versions' => [ 'latest' => '2020-05-15', '2020-05-15' => '2020-05-15', ], 'serviceIdentifier' => 'apprunner', ], 'appstream' => [ 'namespace' => 'Appstream', 'versions' => [ 'latest' => '2016-12-01', '2016-12-01' => '2016-12-01', ], 'serviceIdentifier' => 'appstream', ], 'appsync' => [ 'namespace' => 'AppSync', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'appsync', ], 'apptest' => [ 'namespace' => 'AppTest', 'versions' => [ 'latest' => '2022-12-06', '2022-12-06' => '2022-12-06', ], 'serviceIdentifier' => 'apptest', ], 'arc-region-switch' => [ 'namespace' => 'ARCRegionSwitch', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'arc_region_switch', ], 'arc-zonal-shift' => [ 'namespace' => 'ARCZonalShift', 'versions' => [ 'latest' => '2022-10-30', '2022-10-30' => '2022-10-30', ], 'serviceIdentifier' => 'arc_zonal_shift', ], 'artifact' => [ 'namespace' => 'Artifact', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'artifact', ], 'athena' => [ 'namespace' => 'Athena', 'versions' => [ 'latest' => '2017-05-18', '2017-05-18' => '2017-05-18', ], 'serviceIdentifier' => 'athena', ], 'auditmanager' => [ 'namespace' => 'AuditManager', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'auditmanager', ], 'autoscaling-plans' => [ 'namespace' => 'AutoScalingPlans', 'versions' => [ 'latest' => '2018-01-06', '2018-01-06' => '2018-01-06', ], 'serviceIdentifier' => 'auto_scaling_plans', ], 'autoscaling' => [ 'namespace' => 'AutoScaling', 'versions' => [ 'latest' => '2011-01-01', '2011-01-01' => '2011-01-01', ], 'serviceIdentifier' => 'auto_scaling', ], 'b2bi' => [ 'namespace' => 'B2bi', 'versions' => [ 'latest' => '2022-06-23', '2022-06-23' => '2022-06-23', ], 'serviceIdentifier' => 'b2bi', ], 'backup-gateway' => [ 'namespace' => 'BackupGateway', 'versions' => [ 'latest' => '2021-01-01', '2021-01-01' => '2021-01-01', ], 'serviceIdentifier' => 'backup_gateway', ], 'backup' => [ 'namespace' => 'Backup', 'versions' => [ 'latest' => '2018-11-15', '2018-11-15' => '2018-11-15', ], 'serviceIdentifier' => 'backup', ], 'backupsearch' => [ 'namespace' => 'BackupSearch', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'backupsearch', ], 'batch' => [ 'namespace' => 'Batch', 'versions' => [ 'latest' => '2016-08-10', '2016-08-10' => '2016-08-10', ], 'serviceIdentifier' => 'batch', ], 'bcm-dashboards' => [ 'namespace' => 'BCMDashboards', 'versions' => [ 'latest' => '2025-08-18', '2025-08-18' => '2025-08-18', ], 'serviceIdentifier' => 'bcm_dashboards', ], 'bcm-data-exports' => [ 'namespace' => 'BCMDataExports', 'versions' => [ 'latest' => '2023-11-26', '2023-11-26' => '2023-11-26', ], 'serviceIdentifier' => 'bcm_data_exports', ], 'bcm-pricing-calculator' => [ 'namespace' => 'BCMPricingCalculator', 'versions' => [ 'latest' => '2024-06-19', '2024-06-19' => '2024-06-19', ], 'serviceIdentifier' => 'bcm_pricing_calculator', ], 'bcm-recommended-actions' => [ 'namespace' => 'BCMRecommendedActions', 'versions' => [ 'latest' => '2024-11-14', '2024-11-14' => '2024-11-14', ], 'serviceIdentifier' => 'bcm_recommended_actions', ], 'bedrock-agent-runtime' => [ 'namespace' => 'BedrockAgentRuntime', 'versions' => [ 'latest' => '2023-07-26', '2023-07-26' => '2023-07-26', ], 'serviceIdentifier' => 'bedrock_agent_runtime', ], 'bedrock-agent' => [ 'namespace' => 'BedrockAgent', 'versions' => [ 'latest' => '2023-06-05', '2023-06-05' => '2023-06-05', ], 'serviceIdentifier' => 'bedrock_agent', ], 'bedrock-agentcore-control' => [ 'namespace' => 'BedrockAgentCoreControl', 'versions' => [ 'latest' => '2023-06-05', '2023-06-05' => '2023-06-05', ], 'serviceIdentifier' => 'bedrock_agentcore_control', ], 'bedrock-agentcore' => [ 'namespace' => 'BedrockAgentCore', 'versions' => [ 'latest' => '2024-02-28', '2024-02-28' => '2024-02-28', ], 'serviceIdentifier' => 'bedrock_agentcore', ], 'bedrock-data-automation-runtime' => [ 'namespace' => 'BedrockDataAutomationRuntime', 'versions' => [ 'latest' => '2024-06-13', '2024-06-13' => '2024-06-13', ], 'serviceIdentifier' => 'bedrock_data_automation_runtime', ], 'bedrock-data-automation' => [ 'namespace' => 'BedrockDataAutomation', 'versions' => [ 'latest' => '2023-07-26', '2023-07-26' => '2023-07-26', ], 'serviceIdentifier' => 'bedrock_data_automation', ], 'bedrock-runtime' => [ 'namespace' => 'BedrockRuntime', 'versions' => [ 'latest' => '2023-09-30', '2023-09-30' => '2023-09-30', ], 'serviceIdentifier' => 'bedrock_runtime', ], 'bedrock' => [ 'namespace' => 'Bedrock', 'versions' => [ 'latest' => '2023-04-20', '2023-04-20' => '2023-04-20', ], 'serviceIdentifier' => 'bedrock', ], 'billing' => [ 'namespace' => 'Billing', 'versions' => [ 'latest' => '2023-09-07', '2023-09-07' => '2023-09-07', ], 'serviceIdentifier' => 'billing', ], 'billingconductor' => [ 'namespace' => 'BillingConductor', 'versions' => [ 'latest' => '2021-07-30', '2021-07-30' => '2021-07-30', ], 'serviceIdentifier' => 'billingconductor', ], 'braket' => [ 'namespace' => 'Braket', 'versions' => [ 'latest' => '2019-09-01', '2019-09-01' => '2019-09-01', ], 'serviceIdentifier' => 'braket', ], 'budgets' => [ 'namespace' => 'Budgets', 'versions' => [ 'latest' => '2016-10-20', '2016-10-20' => '2016-10-20', ], 'serviceIdentifier' => 'budgets', ], 'ce' => [ 'namespace' => 'CostExplorer', 'versions' => [ 'latest' => '2017-10-25', '2017-10-25' => '2017-10-25', ], 'serviceIdentifier' => 'cost_explorer', ], 'chatbot' => [ 'namespace' => 'Chatbot', 'versions' => [ 'latest' => '2017-10-11', '2017-10-11' => '2017-10-11', ], 'serviceIdentifier' => 'chatbot', ], 'chime-sdk-identity' => [ 'namespace' => 'ChimeSDKIdentity', 'versions' => [ 'latest' => '2021-04-20', '2021-04-20' => '2021-04-20', ], 'serviceIdentifier' => 'chime_sdk_identity', ], 'chime-sdk-media-pipelines' => [ 'namespace' => 'ChimeSDKMediaPipelines', 'versions' => [ 'latest' => '2021-07-15', '2021-07-15' => '2021-07-15', ], 'serviceIdentifier' => 'chime_sdk_media_pipelines', ], 'chime-sdk-meetings' => [ 'namespace' => 'ChimeSDKMeetings', 'versions' => [ 'latest' => '2021-07-15', '2021-07-15' => '2021-07-15', ], 'serviceIdentifier' => 'chime_sdk_meetings', ], 'chime-sdk-messaging' => [ 'namespace' => 'ChimeSDKMessaging', 'versions' => [ 'latest' => '2021-05-15', '2021-05-15' => '2021-05-15', ], 'serviceIdentifier' => 'chime_sdk_messaging', ], 'chime-sdk-voice' => [ 'namespace' => 'ChimeSDKVoice', 'versions' => [ 'latest' => '2022-08-03', '2022-08-03' => '2022-08-03', ], 'serviceIdentifier' => 'chime_sdk_voice', ], 'chime' => [ 'namespace' => 'Chime', 'versions' => [ 'latest' => '2018-05-01', '2018-05-01' => '2018-05-01', ], 'serviceIdentifier' => 'chime', ], 'cleanrooms' => [ 'namespace' => 'CleanRooms', 'versions' => [ 'latest' => '2022-02-17', '2022-02-17' => '2022-02-17', ], 'serviceIdentifier' => 'cleanrooms', ], 'cleanroomsml' => [ 'namespace' => 'CleanRoomsML', 'versions' => [ 'latest' => '2023-09-06', '2023-09-06' => '2023-09-06', ], 'serviceIdentifier' => 'cleanroomsml', ], 'cloud9' => [ 'namespace' => 'Cloud9', 'versions' => [ 'latest' => '2017-09-23', '2017-09-23' => '2017-09-23', ], 'serviceIdentifier' => 'cloud9', ], 'cloudcontrol' => [ 'namespace' => 'CloudControlApi', 'versions' => [ 'latest' => '2021-09-30', '2021-09-30' => '2021-09-30', ], 'serviceIdentifier' => 'cloudcontrol', ], 'clouddirectory' => [ 'namespace' => 'CloudDirectory', 'versions' => [ 'latest' => '2017-01-11', '2017-01-11' => '2017-01-11', '2016-05-10' => '2016-05-10', ], 'serviceIdentifier' => 'clouddirectory', ], 'cloudformation' => [ 'namespace' => 'CloudFormation', 'versions' => [ 'latest' => '2010-05-15', '2010-05-15' => '2010-05-15', ], 'serviceIdentifier' => 'cloudformation', ], 'cloudfront-keyvaluestore' => [ 'namespace' => 'CloudFrontKeyValueStore', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'cloudfront_keyvaluestore', ], 'cloudfront' => [ 'namespace' => 'CloudFront', 'versions' => [ 'latest' => '2020-05-31', '2020-05-31' => '2020-05-31', '2019-03-26' => '2019-03-26', '2018-11-05' => '2018-11-05', '2018-06-18' => '2018-06-18', '2017-10-30' => '2017-10-30', '2017-03-25' => '2017-03-25', '2016-11-25' => '2016-11-25', '2016-09-29' => '2016-09-29', '2016-09-07' => '2016-09-07', '2016-08-20' => '2016-08-20', '2016-08-01' => '2016-08-01', '2016-01-28' => '2016-01-28', '2016-01-13' => '2020-05-31', '2015-09-17' => '2020-05-31', '2015-07-27' => '2015-07-27', '2015-04-17' => '2015-07-27', '2014-11-06' => '2015-07-27', ], 'serviceIdentifier' => 'cloudfront', ], 'cloudhsm' => [ 'namespace' => 'CloudHsm', 'versions' => [ 'latest' => '2014-05-30', '2014-05-30' => '2014-05-30', ], 'serviceIdentifier' => 'cloudhsm', ], 'cloudhsmv2' => [ 'namespace' => 'CloudHSMV2', 'versions' => [ 'latest' => '2017-04-28', '2017-04-28' => '2017-04-28', ], 'serviceIdentifier' => 'cloudhsm_v2', ], 'cloudsearch' => [ 'namespace' => 'CloudSearch', 'versions' => [ 'latest' => '2013-01-01', '2013-01-01' => '2013-01-01', ], 'serviceIdentifier' => 'cloudsearch', ], 'cloudsearchdomain' => [ 'namespace' => 'CloudSearchDomain', 'versions' => [ 'latest' => '2013-01-01', '2013-01-01' => '2013-01-01', ], 'serviceIdentifier' => 'cloudsearch_domain', ], 'cloudtrail-data' => [ 'namespace' => 'CloudTrailData', 'versions' => [ 'latest' => '2021-08-11', '2021-08-11' => '2021-08-11', ], 'serviceIdentifier' => 'cloudtrail_data', ], 'cloudtrail' => [ 'namespace' => 'CloudTrail', 'versions' => [ 'latest' => '2013-11-01', '2013-11-01' => '2013-11-01', ], 'serviceIdentifier' => 'cloudtrail', ], 'codeartifact' => [ 'namespace' => 'CodeArtifact', 'versions' => [ 'latest' => '2018-09-22', '2018-09-22' => '2018-09-22', ], 'serviceIdentifier' => 'codeartifact', ], 'codebuild' => [ 'namespace' => 'CodeBuild', 'versions' => [ 'latest' => '2016-10-06', '2016-10-06' => '2016-10-06', ], 'serviceIdentifier' => 'codebuild', ], 'codecatalyst' => [ 'namespace' => 'CodeCatalyst', 'versions' => [ 'latest' => '2022-09-28', '2022-09-28' => '2022-09-28', ], 'serviceIdentifier' => 'codecatalyst', ], 'codecommit' => [ 'namespace' => 'CodeCommit', 'versions' => [ 'latest' => '2015-04-13', '2015-04-13' => '2015-04-13', ], 'serviceIdentifier' => 'codecommit', ], 'codeconnections' => [ 'namespace' => 'CodeConnections', 'versions' => [ 'latest' => '2023-12-01', '2023-12-01' => '2023-12-01', ], 'serviceIdentifier' => 'codeconnections', ], 'codedeploy' => [ 'namespace' => 'CodeDeploy', 'versions' => [ 'latest' => '2014-10-06', '2014-10-06' => '2014-10-06', ], 'serviceIdentifier' => 'codedeploy', ], 'codeguru-reviewer' => [ 'namespace' => 'CodeGuruReviewer', 'versions' => [ 'latest' => '2019-09-19', '2019-09-19' => '2019-09-19', ], 'serviceIdentifier' => 'codeguru_reviewer', ], 'codeguru-security' => [ 'namespace' => 'CodeGuruSecurity', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'codeguru_security', ], 'codeguruprofiler' => [ 'namespace' => 'CodeGuruProfiler', 'versions' => [ 'latest' => '2019-07-18', '2019-07-18' => '2019-07-18', ], 'serviceIdentifier' => 'codeguruprofiler', ], 'codepipeline' => [ 'namespace' => 'CodePipeline', 'versions' => [ 'latest' => '2015-07-09', '2015-07-09' => '2015-07-09', ], 'serviceIdentifier' => 'codepipeline', ], 'codestar-connections' => [ 'namespace' => 'CodeStarconnections', 'versions' => [ 'latest' => '2019-12-01', '2019-12-01' => '2019-12-01', ], 'serviceIdentifier' => 'codestar_connections', ], 'codestar-notifications' => [ 'namespace' => 'CodeStarNotifications', 'versions' => [ 'latest' => '2019-10-15', '2019-10-15' => '2019-10-15', ], 'serviceIdentifier' => 'codestar_notifications', ], 'cognito-identity' => [ 'namespace' => 'CognitoIdentity', 'versions' => [ 'latest' => '2014-06-30', '2014-06-30' => '2014-06-30', ], 'serviceIdentifier' => 'cognito_identity', ], 'cognito-idp' => [ 'namespace' => 'CognitoIdentityProvider', 'versions' => [ 'latest' => '2016-04-18', '2016-04-18' => '2016-04-18', ], 'serviceIdentifier' => 'cognito_identity_provider', ], 'cognito-sync' => [ 'namespace' => 'CognitoSync', 'versions' => [ 'latest' => '2014-06-30', '2014-06-30' => '2014-06-30', ], 'serviceIdentifier' => 'cognito_sync', ], 'comprehend' => [ 'namespace' => 'Comprehend', 'versions' => [ 'latest' => '2017-11-27', '2017-11-27' => '2017-11-27', ], 'serviceIdentifier' => 'comprehend', ], 'comprehendmedical' => [ 'namespace' => 'ComprehendMedical', 'versions' => [ 'latest' => '2018-10-30', '2018-10-30' => '2018-10-30', ], 'serviceIdentifier' => 'comprehendmedical', ], 'compute-optimizer' => [ 'namespace' => 'ComputeOptimizer', 'versions' => [ 'latest' => '2019-11-01', '2019-11-01' => '2019-11-01', ], 'serviceIdentifier' => 'compute_optimizer', ], 'config' => [ 'namespace' => 'ConfigService', 'versions' => [ 'latest' => '2014-11-12', '2014-11-12' => '2014-11-12', ], 'serviceIdentifier' => 'config_service', ], 'connect-contact-lens' => [ 'namespace' => 'ConnectContactLens', 'versions' => [ 'latest' => '2020-08-21', '2020-08-21' => '2020-08-21', ], 'serviceIdentifier' => 'connect_contact_lens', ], 'connect' => [ 'namespace' => 'Connect', 'versions' => [ 'latest' => '2017-08-08', '2017-08-08' => '2017-08-08', ], 'serviceIdentifier' => 'connect', ], 'connectcampaigns' => [ 'namespace' => 'ConnectCampaignService', 'versions' => [ 'latest' => '2021-01-30', '2021-01-30' => '2021-01-30', ], 'serviceIdentifier' => 'connectcampaigns', ], 'connectcampaignsv2' => [ 'namespace' => 'ConnectCampaignsV2', 'versions' => [ 'latest' => '2024-04-23', '2024-04-23' => '2024-04-23', ], 'serviceIdentifier' => 'connectcampaignsv2', ], 'connectcases' => [ 'namespace' => 'ConnectCases', 'versions' => [ 'latest' => '2022-10-03', '2022-10-03' => '2022-10-03', ], 'serviceIdentifier' => 'connectcases', ], 'connectparticipant' => [ 'namespace' => 'ConnectParticipant', 'versions' => [ 'latest' => '2018-09-07', '2018-09-07' => '2018-09-07', ], 'serviceIdentifier' => 'connectparticipant', ], 'controlcatalog' => [ 'namespace' => 'ControlCatalog', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'controlcatalog', ], 'controltower' => [ 'namespace' => 'ControlTower', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'controltower', ], 'cost-optimization-hub' => [ 'namespace' => 'CostOptimizationHub', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'cost_optimization_hub', ], 'cur' => [ 'namespace' => 'CostandUsageReportService', 'versions' => [ 'latest' => '2017-01-06', '2017-01-06' => '2017-01-06', ], 'serviceIdentifier' => 'cost_and_usage_report_service', ], 'customer-profiles' => [ 'namespace' => 'CustomerProfiles', 'versions' => [ 'latest' => '2020-08-15', '2020-08-15' => '2020-08-15', ], 'serviceIdentifier' => 'customer_profiles', ], 'data.iot' => [ 'namespace' => 'IotDataPlane', 'versions' => [ 'latest' => '2015-05-28', '2015-05-28' => '2015-05-28', ], 'serviceIdentifier' => 'iot_data_plane', ], 'databrew' => [ 'namespace' => 'GlueDataBrew', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'databrew', ], 'dataexchange' => [ 'namespace' => 'DataExchange', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'dataexchange', ], 'datapipeline' => [ 'namespace' => 'DataPipeline', 'versions' => [ 'latest' => '2012-10-29', '2012-10-29' => '2012-10-29', ], 'serviceIdentifier' => 'data_pipeline', ], 'datasync' => [ 'namespace' => 'DataSync', 'versions' => [ 'latest' => '2018-11-09', '2018-11-09' => '2018-11-09', ], 'serviceIdentifier' => 'datasync', ], 'datazone' => [ 'namespace' => 'DataZone', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'datazone', ], 'dax' => [ 'namespace' => 'DAX', 'versions' => [ 'latest' => '2017-04-19', '2017-04-19' => '2017-04-19', ], 'serviceIdentifier' => 'dax', ], 'deadline' => [ 'namespace' => 'Deadline', 'versions' => [ 'latest' => '2023-10-12', '2023-10-12' => '2023-10-12', ], 'serviceIdentifier' => 'deadline', ], 'detective' => [ 'namespace' => 'Detective', 'versions' => [ 'latest' => '2018-10-26', '2018-10-26' => '2018-10-26', ], 'serviceIdentifier' => 'detective', ], 'devicefarm' => [ 'namespace' => 'DeviceFarm', 'versions' => [ 'latest' => '2015-06-23', '2015-06-23' => '2015-06-23', ], 'serviceIdentifier' => 'device_farm', ], 'devops-guru' => [ 'namespace' => 'DevOpsGuru', 'versions' => [ 'latest' => '2020-12-01', '2020-12-01' => '2020-12-01', ], 'serviceIdentifier' => 'devops_guru', ], 'directconnect' => [ 'namespace' => 'DirectConnect', 'versions' => [ 'latest' => '2012-10-25', '2012-10-25' => '2012-10-25', ], 'serviceIdentifier' => 'direct_connect', ], 'directory-service-data' => [ 'namespace' => 'DirectoryServiceData', 'versions' => [ 'latest' => '2023-05-31', '2023-05-31' => '2023-05-31', ], 'serviceIdentifier' => 'directory_service_data', ], 'discovery' => [ 'namespace' => 'ApplicationDiscoveryService', 'versions' => [ 'latest' => '2015-11-01', '2015-11-01' => '2015-11-01', ], 'serviceIdentifier' => 'application_discovery_service', ], 'dlm' => [ 'namespace' => 'DLM', 'versions' => [ 'latest' => '2018-01-12', '2018-01-12' => '2018-01-12', ], 'serviceIdentifier' => 'dlm', ], 'dms' => [ 'namespace' => 'DatabaseMigrationService', 'versions' => [ 'latest' => '2016-01-01', '2016-01-01' => '2016-01-01', ], 'serviceIdentifier' => 'database_migration_service', ], 'docdb-elastic' => [ 'namespace' => 'DocDBElastic', 'versions' => [ 'latest' => '2022-11-28', '2022-11-28' => '2022-11-28', ], 'serviceIdentifier' => 'docdb_elastic', ], 'docdb' => [ 'namespace' => 'DocDB', 'versions' => [ 'latest' => '2014-10-31', '2014-10-31' => '2014-10-31', ], 'serviceIdentifier' => 'docdb', ], 'drs' => [ 'namespace' => 'drs', 'versions' => [ 'latest' => '2020-02-26', '2020-02-26' => '2020-02-26', ], 'serviceIdentifier' => 'drs', ], 'ds' => [ 'namespace' => 'DirectoryService', 'versions' => [ 'latest' => '2015-04-16', '2015-04-16' => '2015-04-16', ], 'serviceIdentifier' => 'directory_service', ], 'dsql' => [ 'namespace' => 'DSQL', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'dsql', ], 'dynamodb' => [ 'namespace' => 'DynamoDb', 'versions' => [ 'latest' => '2012-08-10', '2012-08-10' => '2012-08-10', '2011-12-05' => '2011-12-05', ], 'serviceIdentifier' => 'dynamodb', ], 'ebs' => [ 'namespace' => 'EBS', 'versions' => [ 'latest' => '2019-11-02', '2019-11-02' => '2019-11-02', ], 'serviceIdentifier' => 'ebs', ], 'ec2-instance-connect' => [ 'namespace' => 'EC2InstanceConnect', 'versions' => [ 'latest' => '2018-04-02', '2018-04-02' => '2018-04-02', ], 'serviceIdentifier' => 'ec2_instance_connect', ], 'ec2' => [ 'namespace' => 'Ec2', 'versions' => [ 'latest' => '2016-11-15', '2016-11-15' => '2016-11-15', '2016-09-15' => '2016-09-15', '2016-04-01' => '2016-04-01', '2015-10-01' => '2015-10-01', '2015-04-15' => '2016-11-15', ], 'serviceIdentifier' => 'ec2', ], 'ecr-public' => [ 'namespace' => 'ECRPublic', 'versions' => [ 'latest' => '2020-10-30', '2020-10-30' => '2020-10-30', ], 'serviceIdentifier' => 'ecr_public', ], 'ecr' => [ 'namespace' => 'Ecr', 'versions' => [ 'latest' => '2015-09-21', '2015-09-21' => '2015-09-21', ], 'serviceIdentifier' => 'ecr', ], 'ecs' => [ 'namespace' => 'Ecs', 'versions' => [ 'latest' => '2014-11-13', '2014-11-13' => '2014-11-13', ], 'serviceIdentifier' => 'ecs', ], 'eks-auth' => [ 'namespace' => 'EKSAuth', 'versions' => [ 'latest' => '2023-11-26', '2023-11-26' => '2023-11-26', ], 'serviceIdentifier' => 'eks_auth', ], 'eks' => [ 'namespace' => 'EKS', 'versions' => [ 'latest' => '2017-11-01', '2017-11-01' => '2017-11-01', ], 'serviceIdentifier' => 'eks', ], 'elasticache' => [ 'namespace' => 'ElastiCache', 'versions' => [ 'latest' => '2015-02-02', '2015-02-02' => '2015-02-02', ], 'serviceIdentifier' => 'elasticache', ], 'elasticbeanstalk' => [ 'namespace' => 'ElasticBeanstalk', 'versions' => [ 'latest' => '2010-12-01', '2010-12-01' => '2010-12-01', ], 'serviceIdentifier' => 'elastic_beanstalk', ], 'elasticfilesystem' => [ 'namespace' => 'Efs', 'versions' => [ 'latest' => '2015-02-01', '2015-02-01' => '2015-02-01', ], 'serviceIdentifier' => 'efs', ], 'elasticloadbalancing' => [ 'namespace' => 'ElasticLoadBalancing', 'versions' => [ 'latest' => '2012-06-01', '2012-06-01' => '2012-06-01', ], 'serviceIdentifier' => 'elastic_load_balancing', ], 'elasticloadbalancingv2' => [ 'namespace' => 'ElasticLoadBalancingV2', 'versions' => [ 'latest' => '2015-12-01', '2015-12-01' => '2015-12-01', ], 'serviceIdentifier' => 'elastic_load_balancing_v2', ], 'elasticmapreduce' => [ 'namespace' => 'Emr', 'versions' => [ 'latest' => '2009-03-31', '2009-03-31' => '2009-03-31', ], 'serviceIdentifier' => 'emr', ], 'elastictranscoder' => [ 'namespace' => 'ElasticTranscoder', 'versions' => [ 'latest' => '2012-09-25', '2012-09-25' => '2012-09-25', ], 'serviceIdentifier' => 'elastic_transcoder', ], 'email' => [ 'namespace' => 'Ses', 'versions' => [ 'latest' => '2010-12-01', '2010-12-01' => '2010-12-01', ], 'serviceIdentifier' => 'ses', ], 'emr-containers' => [ 'namespace' => 'EMRContainers', 'versions' => [ 'latest' => '2020-10-01', '2020-10-01' => '2020-10-01', ], 'serviceIdentifier' => 'emr_containers', ], 'emr-serverless' => [ 'namespace' => 'EMRServerless', 'versions' => [ 'latest' => '2021-07-13', '2021-07-13' => '2021-07-13', ], 'serviceIdentifier' => 'emr_serverless', ], 'entitlement.marketplace' => [ 'namespace' => 'MarketplaceEntitlementService', 'versions' => [ 'latest' => '2017-01-11', '2017-01-11' => '2017-01-11', ], 'serviceIdentifier' => 'marketplace_entitlement_service', ], 'entityresolution' => [ 'namespace' => 'EntityResolution', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'entityresolution', ], 'es' => [ 'namespace' => 'ElasticsearchService', 'versions' => [ 'latest' => '2015-01-01', '2015-01-01' => '2015-01-01', ], 'serviceIdentifier' => 'elasticsearch_service', ], 'eventbridge' => [ 'namespace' => 'EventBridge', 'versions' => [ 'latest' => '2015-10-07', '2015-10-07' => '2015-10-07', ], 'serviceIdentifier' => 'eventbridge', ], 'events' => [ 'namespace' => 'CloudWatchEvents', 'versions' => [ 'latest' => '2015-10-07', '2015-10-07' => '2015-10-07', '2014-02-03' => '2015-10-07', ], 'serviceIdentifier' => 'cloudwatch_events', ], 'evidently' => [ 'namespace' => 'CloudWatchEvidently', 'versions' => [ 'latest' => '2021-02-01', '2021-02-01' => '2021-02-01', ], 'serviceIdentifier' => 'evidently', ], 'evs' => [ 'namespace' => 'Evs', 'versions' => [ 'latest' => '2023-07-27', '2023-07-27' => '2023-07-27', ], 'serviceIdentifier' => 'evs', ], 'finspace-data' => [ 'namespace' => 'FinSpaceData', 'versions' => [ 'latest' => '2020-07-13', '2020-07-13' => '2020-07-13', ], 'serviceIdentifier' => 'finspace_data', ], 'finspace' => [ 'namespace' => 'finspace', 'versions' => [ 'latest' => '2021-03-12', '2021-03-12' => '2021-03-12', ], 'serviceIdentifier' => 'finspace', ], 'firehose' => [ 'namespace' => 'Firehose', 'versions' => [ 'latest' => '2015-08-04', '2015-08-04' => '2015-08-04', ], 'serviceIdentifier' => 'firehose', ], 'fis' => [ 'namespace' => 'FIS', 'versions' => [ 'latest' => '2020-12-01', '2020-12-01' => '2020-12-01', ], 'serviceIdentifier' => 'fis', ], 'fms' => [ 'namespace' => 'FMS', 'versions' => [ 'latest' => '2018-01-01', '2018-01-01' => '2018-01-01', ], 'serviceIdentifier' => 'fms', ], 'forecast' => [ 'namespace' => 'ForecastService', 'versions' => [ 'latest' => '2018-06-26', '2018-06-26' => '2018-06-26', ], 'serviceIdentifier' => 'forecast', ], 'forecastquery' => [ 'namespace' => 'ForecastQueryService', 'versions' => [ 'latest' => '2018-06-26', '2018-06-26' => '2018-06-26', ], 'serviceIdentifier' => 'forecastquery', ], 'frauddetector' => [ 'namespace' => 'FraudDetector', 'versions' => [ 'latest' => '2019-11-15', '2019-11-15' => '2019-11-15', ], 'serviceIdentifier' => 'frauddetector', ], 'freetier' => [ 'namespace' => 'FreeTier', 'versions' => [ 'latest' => '2023-09-07', '2023-09-07' => '2023-09-07', ], 'serviceIdentifier' => 'freetier', ], 'fsx' => [ 'namespace' => 'FSx', 'versions' => [ 'latest' => '2018-03-01', '2018-03-01' => '2018-03-01', ], 'serviceIdentifier' => 'fsx', ], 'gamelift' => [ 'namespace' => 'GameLift', 'versions' => [ 'latest' => '2015-10-01', '2015-10-01' => '2015-10-01', ], 'serviceIdentifier' => 'gamelift', ], 'gameliftstreams' => [ 'namespace' => 'GameLiftStreams', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'gameliftstreams', ], 'geo-maps' => [ 'namespace' => 'GeoMaps', 'versions' => [ 'latest' => '2020-11-19', '2020-11-19' => '2020-11-19', ], 'serviceIdentifier' => 'geo_maps', ], 'geo-places' => [ 'namespace' => 'GeoPlaces', 'versions' => [ 'latest' => '2020-11-19', '2020-11-19' => '2020-11-19', ], 'serviceIdentifier' => 'geo_places', ], 'geo-routes' => [ 'namespace' => 'GeoRoutes', 'versions' => [ 'latest' => '2020-11-19', '2020-11-19' => '2020-11-19', ], 'serviceIdentifier' => 'geo_routes', ], 'glacier' => [ 'namespace' => 'Glacier', 'versions' => [ 'latest' => '2012-06-01', '2012-06-01' => '2012-06-01', ], 'serviceIdentifier' => 'glacier', ], 'globalaccelerator' => [ 'namespace' => 'GlobalAccelerator', 'versions' => [ 'latest' => '2018-08-08', '2018-08-08' => '2018-08-08', ], 'serviceIdentifier' => 'global_accelerator', ], 'glue' => [ 'namespace' => 'Glue', 'versions' => [ 'latest' => '2017-03-31', '2017-03-31' => '2017-03-31', ], 'serviceIdentifier' => 'glue', ], 'grafana' => [ 'namespace' => 'ManagedGrafana', 'versions' => [ 'latest' => '2020-08-18', '2020-08-18' => '2020-08-18', ], 'serviceIdentifier' => 'grafana', ], 'greengrass' => [ 'namespace' => 'Greengrass', 'versions' => [ 'latest' => '2017-06-07', '2017-06-07' => '2017-06-07', ], 'serviceIdentifier' => 'greengrass', ], 'greengrassv2' => [ 'namespace' => 'GreengrassV2', 'versions' => [ 'latest' => '2020-11-30', '2020-11-30' => '2020-11-30', ], 'serviceIdentifier' => 'greengrassv2', ], 'groundstation' => [ 'namespace' => 'GroundStation', 'versions' => [ 'latest' => '2019-05-23', '2019-05-23' => '2019-05-23', ], 'serviceIdentifier' => 'groundstation', ], 'guardduty' => [ 'namespace' => 'GuardDuty', 'versions' => [ 'latest' => '2017-11-28', '2017-11-28' => '2017-11-28', ], 'serviceIdentifier' => 'guardduty', ], 'health' => [ 'namespace' => 'Health', 'versions' => [ 'latest' => '2016-08-04', '2016-08-04' => '2016-08-04', ], 'serviceIdentifier' => 'health', ], 'healthlake' => [ 'namespace' => 'HealthLake', 'versions' => [ 'latest' => '2017-07-01', '2017-07-01' => '2017-07-01', ], 'serviceIdentifier' => 'healthlake', ], 'iam' => [ 'namespace' => 'Iam', 'versions' => [ 'latest' => '2010-05-08', '2010-05-08' => '2010-05-08', ], 'serviceIdentifier' => 'iam', ], 'identitystore' => [ 'namespace' => 'IdentityStore', 'versions' => [ 'latest' => '2020-06-15', '2020-06-15' => '2020-06-15', ], 'serviceIdentifier' => 'identitystore', ], 'imagebuilder' => [ 'namespace' => 'imagebuilder', 'versions' => [ 'latest' => '2019-12-02', '2019-12-02' => '2019-12-02', ], 'serviceIdentifier' => 'imagebuilder', ], 'importexport' => [ 'namespace' => 'ImportExport', 'versions' => [ 'latest' => '2010-06-01', '2010-06-01' => '2010-06-01', ], 'serviceIdentifier' => 'importexport', ], 'inspector-scan' => [ 'namespace' => 'InspectorScan', 'versions' => [ 'latest' => '2023-08-08', '2023-08-08' => '2023-08-08', ], 'serviceIdentifier' => 'inspector_scan', ], 'inspector' => [ 'namespace' => 'Inspector', 'versions' => [ 'latest' => '2016-02-16', '2016-02-16' => '2016-02-16', '2015-08-18' => '2016-02-16', ], 'serviceIdentifier' => 'inspector', ], 'inspector2' => [ 'namespace' => 'Inspector2', 'versions' => [ 'latest' => '2020-06-08', '2020-06-08' => '2020-06-08', ], 'serviceIdentifier' => 'inspector2', ], 'internetmonitor' => [ 'namespace' => 'InternetMonitor', 'versions' => [ 'latest' => '2021-06-03', '2021-06-03' => '2021-06-03', ], 'serviceIdentifier' => 'internetmonitor', ], 'invoicing' => [ 'namespace' => 'Invoicing', 'versions' => [ 'latest' => '2024-12-01', '2024-12-01' => '2024-12-01', ], 'serviceIdentifier' => 'invoicing', ], 'iot-jobs-data' => [ 'namespace' => 'IoTJobsDataPlane', 'versions' => [ 'latest' => '2017-09-29', '2017-09-29' => '2017-09-29', ], 'serviceIdentifier' => 'iot_jobs_data_plane', ], 'iot-managed-integrations' => [ 'namespace' => 'IoTManagedIntegrations', 'versions' => [ 'latest' => '2025-03-03', '2025-03-03' => '2025-03-03', ], 'serviceIdentifier' => 'iot_managed_integrations', ], 'iot' => [ 'namespace' => 'Iot', 'versions' => [ 'latest' => '2015-05-28', '2015-05-28' => '2015-05-28', ], 'serviceIdentifier' => 'iot', ], 'iotanalytics' => [ 'namespace' => 'IoTAnalytics', 'versions' => [ 'latest' => '2017-11-27', '2017-11-27' => '2017-11-27', ], 'serviceIdentifier' => 'iotanalytics', ], 'iotdeviceadvisor' => [ 'namespace' => 'IoTDeviceAdvisor', 'versions' => [ 'latest' => '2020-09-18', '2020-09-18' => '2020-09-18', ], 'serviceIdentifier' => 'iotdeviceadvisor', ], 'iotevents-data' => [ 'namespace' => 'IoTEventsData', 'versions' => [ 'latest' => '2018-10-23', '2018-10-23' => '2018-10-23', ], 'serviceIdentifier' => 'iot_events_data', ], 'iotevents' => [ 'namespace' => 'IoTEvents', 'versions' => [ 'latest' => '2018-07-27', '2018-07-27' => '2018-07-27', ], 'serviceIdentifier' => 'iot_events', ], 'iotfleethub' => [ 'namespace' => 'IoTFleetHub', 'versions' => [ 'latest' => '2020-11-03', '2020-11-03' => '2020-11-03', ], 'serviceIdentifier' => 'iotfleethub', ], 'iotfleetwise' => [ 'namespace' => 'IoTFleetWise', 'versions' => [ 'latest' => '2021-06-17', '2021-06-17' => '2021-06-17', ], 'serviceIdentifier' => 'iotfleetwise', ], 'iotsecuretunneling' => [ 'namespace' => 'IoTSecureTunneling', 'versions' => [ 'latest' => '2018-10-05', '2018-10-05' => '2018-10-05', ], 'serviceIdentifier' => 'iotsecuretunneling', ], 'iotsitewise' => [ 'namespace' => 'IoTSiteWise', 'versions' => [ 'latest' => '2019-12-02', '2019-12-02' => '2019-12-02', ], 'serviceIdentifier' => 'iotsitewise', ], 'iotthingsgraph' => [ 'namespace' => 'IoTThingsGraph', 'versions' => [ 'latest' => '2018-09-06', '2018-09-06' => '2018-09-06', ], 'serviceIdentifier' => 'iotthingsgraph', ], 'iottwinmaker' => [ 'namespace' => 'IoTTwinMaker', 'versions' => [ 'latest' => '2021-11-29', '2021-11-29' => '2021-11-29', ], 'serviceIdentifier' => 'iottwinmaker', ], 'iotwireless' => [ 'namespace' => 'IoTWireless', 'versions' => [ 'latest' => '2020-11-22', '2020-11-22' => '2020-11-22', ], 'serviceIdentifier' => 'iot_wireless', ], 'ivs-realtime' => [ 'namespace' => 'IVSRealTime', 'versions' => [ 'latest' => '2020-07-14', '2020-07-14' => '2020-07-14', ], 'serviceIdentifier' => 'ivs_realtime', ], 'ivs' => [ 'namespace' => 'IVS', 'versions' => [ 'latest' => '2020-07-14', '2020-07-14' => '2020-07-14', ], 'serviceIdentifier' => 'ivs', ], 'ivschat' => [ 'namespace' => 'ivschat', 'versions' => [ 'latest' => '2020-07-14', '2020-07-14' => '2020-07-14', ], 'serviceIdentifier' => 'ivschat', ], 'kafka' => [ 'namespace' => 'Kafka', 'versions' => [ 'latest' => '2018-11-14', '2018-11-14' => '2018-11-14', ], 'serviceIdentifier' => 'kafka', ], 'kafkaconnect' => [ 'namespace' => 'KafkaConnect', 'versions' => [ 'latest' => '2021-09-14', '2021-09-14' => '2021-09-14', ], 'serviceIdentifier' => 'kafkaconnect', ], 'kendra-ranking' => [ 'namespace' => 'KendraRanking', 'versions' => [ 'latest' => '2022-10-19', '2022-10-19' => '2022-10-19', ], 'serviceIdentifier' => 'kendra_ranking', ], 'kendra' => [ 'namespace' => 'kendra', 'versions' => [ 'latest' => '2019-02-03', '2019-02-03' => '2019-02-03', ], 'serviceIdentifier' => 'kendra', ], 'keyspaces' => [ 'namespace' => 'Keyspaces', 'versions' => [ 'latest' => '2022-02-10', '2022-02-10' => '2022-02-10', ], 'serviceIdentifier' => 'keyspaces', ], 'keyspacesstreams' => [ 'namespace' => 'KeyspacesStreams', 'versions' => [ 'latest' => '2024-09-09', '2024-09-09' => '2024-09-09', ], 'serviceIdentifier' => 'keyspacesstreams', ], 'kinesis-video-archived-media' => [ 'namespace' => 'KinesisVideoArchivedMedia', 'versions' => [ 'latest' => '2017-09-30', '2017-09-30' => '2017-09-30', ], 'serviceIdentifier' => 'kinesis_video_archived_media', ], 'kinesis-video-media' => [ 'namespace' => 'KinesisVideoMedia', 'versions' => [ 'latest' => '2017-09-30', '2017-09-30' => '2017-09-30', ], 'serviceIdentifier' => 'kinesis_video_media', ], 'kinesis-video-signaling' => [ 'namespace' => 'KinesisVideoSignalingChannels', 'versions' => [ 'latest' => '2019-12-04', '2019-12-04' => '2019-12-04', ], 'serviceIdentifier' => 'kinesis_video_signaling', ], 'kinesis-video-webrtc-storage' => [ 'namespace' => 'KinesisVideoWebRTCStorage', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'kinesis_video_webrtc_storage', ], 'kinesis' => [ 'namespace' => 'Kinesis', 'versions' => [ 'latest' => '2013-12-02', '2013-12-02' => '2013-12-02', ], 'serviceIdentifier' => 'kinesis', ], 'kinesisanalytics' => [ 'namespace' => 'KinesisAnalytics', 'versions' => [ 'latest' => '2015-08-14', '2015-08-14' => '2015-08-14', ], 'serviceIdentifier' => 'kinesis_analytics', ], 'kinesisanalyticsv2' => [ 'namespace' => 'KinesisAnalyticsV2', 'versions' => [ 'latest' => '2018-05-23', '2018-05-23' => '2018-05-23', ], 'serviceIdentifier' => 'kinesis_analytics_v2', ], 'kinesisvideo' => [ 'namespace' => 'KinesisVideo', 'versions' => [ 'latest' => '2017-09-30', '2017-09-30' => '2017-09-30', ], 'serviceIdentifier' => 'kinesis_video', ], 'kms' => [ 'namespace' => 'Kms', 'versions' => [ 'latest' => '2014-11-01', '2014-11-01' => '2014-11-01', ], 'serviceIdentifier' => 'kms', ], 'lakeformation' => [ 'namespace' => 'LakeFormation', 'versions' => [ 'latest' => '2017-03-31', '2017-03-31' => '2017-03-31', ], 'serviceIdentifier' => 'lakeformation', ], 'lambda' => [ 'namespace' => 'Lambda', 'versions' => [ 'latest' => '2015-03-31', '2015-03-31' => '2015-03-31', ], 'serviceIdentifier' => 'lambda', ], 'launch-wizard' => [ 'namespace' => 'LaunchWizard', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'launch_wizard', ], 'lex-models' => [ 'namespace' => 'LexModelBuildingService', 'versions' => [ 'latest' => '2017-04-19', '2017-04-19' => '2017-04-19', ], 'serviceIdentifier' => 'lex_model_building_service', ], 'license-manager-linux-subscriptions' => [ 'namespace' => 'LicenseManagerLinuxSubscriptions', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'license_manager_linux_subscriptions', ], 'license-manager-user-subscriptions' => [ 'namespace' => 'LicenseManagerUserSubscriptions', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'license_manager_user_subscriptions', ], 'license-manager' => [ 'namespace' => 'LicenseManager', 'versions' => [ 'latest' => '2018-08-01', '2018-08-01' => '2018-08-01', ], 'serviceIdentifier' => 'license_manager', ], 'lightsail' => [ 'namespace' => 'Lightsail', 'versions' => [ 'latest' => '2016-11-28', '2016-11-28' => '2016-11-28', ], 'serviceIdentifier' => 'lightsail', ], 'location' => [ 'namespace' => 'LocationService', 'versions' => [ 'latest' => '2020-11-19', '2020-11-19' => '2020-11-19', ], 'serviceIdentifier' => 'location', ], 'logs' => [ 'namespace' => 'CloudWatchLogs', 'versions' => [ 'latest' => '2014-03-28', '2014-03-28' => '2014-03-28', ], 'serviceIdentifier' => 'cloudwatch_logs', ], 'lookoutequipment' => [ 'namespace' => 'LookoutEquipment', 'versions' => [ 'latest' => '2020-12-15', '2020-12-15' => '2020-12-15', ], 'serviceIdentifier' => 'lookoutequipment', ], 'lookoutmetrics' => [ 'namespace' => 'LookoutMetrics', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 'lookoutmetrics', ], 'lookoutvision' => [ 'namespace' => 'LookoutforVision', 'versions' => [ 'latest' => '2020-11-20', '2020-11-20' => '2020-11-20', ], 'serviceIdentifier' => 'lookoutvision', ], 'm2' => [ 'namespace' => 'MainframeModernization', 'versions' => [ 'latest' => '2021-04-28', '2021-04-28' => '2021-04-28', ], 'serviceIdentifier' => 'm2', ], 'machinelearning' => [ 'namespace' => 'MachineLearning', 'versions' => [ 'latest' => '2014-12-12', '2014-12-12' => '2014-12-12', ], 'serviceIdentifier' => 'machine_learning', ], 'macie2' => [ 'namespace' => 'Macie2', 'versions' => [ 'latest' => '2020-01-01', '2020-01-01' => '2020-01-01', ], 'serviceIdentifier' => 'macie2', ], 'mailmanager' => [ 'namespace' => 'MailManager', 'versions' => [ 'latest' => '2023-10-17', '2023-10-17' => '2023-10-17', ], 'serviceIdentifier' => 'mailmanager', ], 'managedblockchain-query' => [ 'namespace' => 'ManagedBlockchainQuery', 'versions' => [ 'latest' => '2023-05-04', '2023-05-04' => '2023-05-04', ], 'serviceIdentifier' => 'managedblockchain_query', ], 'managedblockchain' => [ 'namespace' => 'ManagedBlockchain', 'versions' => [ 'latest' => '2018-09-24', '2018-09-24' => '2018-09-24', ], 'serviceIdentifier' => 'managedblockchain', ], 'marketplace-agreement' => [ 'namespace' => 'MarketplaceAgreement', 'versions' => [ 'latest' => '2020-03-01', '2020-03-01' => '2020-03-01', ], 'serviceIdentifier' => 'marketplace_agreement', ], 'marketplace-catalog' => [ 'namespace' => 'MarketplaceCatalog', 'versions' => [ 'latest' => '2018-09-17', '2018-09-17' => '2018-09-17', ], 'serviceIdentifier' => 'marketplace_catalog', ], 'marketplace-deployment' => [ 'namespace' => 'MarketplaceDeployment', 'versions' => [ 'latest' => '2023-01-25', '2023-01-25' => '2023-01-25', ], 'serviceIdentifier' => 'marketplace_deployment', ], 'marketplace-reporting' => [ 'namespace' => 'MarketplaceReporting', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'marketplace_reporting', ], 'marketplacecommerceanalytics' => [ 'namespace' => 'MarketplaceCommerceAnalytics', 'versions' => [ 'latest' => '2015-07-01', '2015-07-01' => '2015-07-01', ], 'serviceIdentifier' => 'marketplace_commerce_analytics', ], 'mediaconnect' => [ 'namespace' => 'MediaConnect', 'versions' => [ 'latest' => '2018-11-14', '2018-11-14' => '2018-11-14', ], 'serviceIdentifier' => 'mediaconnect', ], 'mediaconvert' => [ 'namespace' => 'MediaConvert', 'versions' => [ 'latest' => '2017-08-29', '2017-08-29' => '2017-08-29', ], 'serviceIdentifier' => 'mediaconvert', ], 'medialive' => [ 'namespace' => 'MediaLive', 'versions' => [ 'latest' => '2017-10-14', '2017-10-14' => '2017-10-14', ], 'serviceIdentifier' => 'medialive', ], 'mediapackage-vod' => [ 'namespace' => 'MediaPackageVod', 'versions' => [ 'latest' => '2018-11-07', '2018-11-07' => '2018-11-07', ], 'serviceIdentifier' => 'mediapackage_vod', ], 'mediapackage' => [ 'namespace' => 'MediaPackage', 'versions' => [ 'latest' => '2017-10-12', '2017-10-12' => '2017-10-12', ], 'serviceIdentifier' => 'mediapackage', ], 'mediapackagev2' => [ 'namespace' => 'MediaPackageV2', 'versions' => [ 'latest' => '2022-12-25', '2022-12-25' => '2022-12-25', ], 'serviceIdentifier' => 'mediapackagev2', ], 'mediastore-data' => [ 'namespace' => 'MediaStoreData', 'versions' => [ 'latest' => '2017-09-01', '2017-09-01' => '2017-09-01', ], 'serviceIdentifier' => 'mediastore_data', ], 'mediastore' => [ 'namespace' => 'MediaStore', 'versions' => [ 'latest' => '2017-09-01', '2017-09-01' => '2017-09-01', ], 'serviceIdentifier' => 'mediastore', ], 'mediatailor' => [ 'namespace' => 'MediaTailor', 'versions' => [ 'latest' => '2018-04-23', '2018-04-23' => '2018-04-23', ], 'serviceIdentifier' => 'mediatailor', ], 'medical-imaging' => [ 'namespace' => 'MedicalImaging', 'versions' => [ 'latest' => '2023-07-19', '2023-07-19' => '2023-07-19', ], 'serviceIdentifier' => 'medical_imaging', ], 'memorydb' => [ 'namespace' => 'MemoryDB', 'versions' => [ 'latest' => '2021-01-01', '2021-01-01' => '2021-01-01', ], 'serviceIdentifier' => 'memorydb', ], 'metering.marketplace' => [ 'namespace' => 'MarketplaceMetering', 'versions' => [ 'latest' => '2016-01-14', '2016-01-14' => '2016-01-14', ], 'serviceIdentifier' => 'marketplace_metering', ], 'mgh' => [ 'namespace' => 'MigrationHub', 'versions' => [ 'latest' => '2017-05-31', '2017-05-31' => '2017-05-31', ], 'serviceIdentifier' => 'migration_hub', ], 'mgn' => [ 'namespace' => 'mgn', 'versions' => [ 'latest' => '2020-02-26', '2020-02-26' => '2020-02-26', ], 'serviceIdentifier' => 'mgn', ], 'migration-hub-refactor-spaces' => [ 'namespace' => 'MigrationHubRefactorSpaces', 'versions' => [ 'latest' => '2021-10-26', '2021-10-26' => '2021-10-26', ], 'serviceIdentifier' => 'migration_hub_refactor_spaces', ], 'migrationhub-config' => [ 'namespace' => 'MigrationHubConfig', 'versions' => [ 'latest' => '2019-06-30', '2019-06-30' => '2019-06-30', ], 'serviceIdentifier' => 'migrationhub_config', ], 'migrationhuborchestrator' => [ 'namespace' => 'MigrationHubOrchestrator', 'versions' => [ 'latest' => '2021-08-28', '2021-08-28' => '2021-08-28', ], 'serviceIdentifier' => 'migrationhuborchestrator', ], 'migrationhubstrategy' => [ 'namespace' => 'MigrationHubStrategyRecommendations', 'versions' => [ 'latest' => '2020-02-19', '2020-02-19' => '2020-02-19', ], 'serviceIdentifier' => 'migrationhubstrategy', ], 'models.lex.v2' => [ 'namespace' => 'LexModelsV2', 'versions' => [ 'latest' => '2020-08-07', '2020-08-07' => '2020-08-07', ], 'serviceIdentifier' => 'lex_models_v2', ], 'monitoring' => [ 'namespace' => 'CloudWatch', 'versions' => [ 'latest' => '2010-08-01', '2010-08-01' => '2010-08-01', ], 'serviceIdentifier' => 'cloudwatch', ], 'mpa' => [ 'namespace' => 'MPA', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'mpa', ], 'mq' => [ 'namespace' => 'MQ', 'versions' => [ 'latest' => '2017-11-27', '2017-11-27' => '2017-11-27', ], 'serviceIdentifier' => 'mq', ], 'mturk-requester' => [ 'namespace' => 'MTurk', 'versions' => [ 'latest' => '2017-01-17', '2017-01-17' => '2017-01-17', ], 'serviceIdentifier' => 'mturk', ], 'mwaa' => [ 'namespace' => 'MWAA', 'versions' => [ 'latest' => '2020-07-01', '2020-07-01' => '2020-07-01', ], 'serviceIdentifier' => 'mwaa', ], 'neptune-graph' => [ 'namespace' => 'NeptuneGraph', 'versions' => [ 'latest' => '2023-11-29', '2023-11-29' => '2023-11-29', ], 'serviceIdentifier' => 'neptune_graph', ], 'neptune' => [ 'namespace' => 'Neptune', 'versions' => [ 'latest' => '2014-10-31', '2014-10-31' => '2014-10-31', ], 'serviceIdentifier' => 'neptune', ], 'neptunedata' => [ 'namespace' => 'Neptunedata', 'versions' => [ 'latest' => '2023-08-01', '2023-08-01' => '2023-08-01', ], 'serviceIdentifier' => 'neptunedata', ], 'network-firewall' => [ 'namespace' => 'NetworkFirewall', 'versions' => [ 'latest' => '2020-11-12', '2020-11-12' => '2020-11-12', ], 'serviceIdentifier' => 'network_firewall', ], 'networkflowmonitor' => [ 'namespace' => 'NetworkFlowMonitor', 'versions' => [ 'latest' => '2023-04-19', '2023-04-19' => '2023-04-19', ], 'serviceIdentifier' => 'networkflowmonitor', ], 'networkmanager' => [ 'namespace' => 'NetworkManager', 'versions' => [ 'latest' => '2019-07-05', '2019-07-05' => '2019-07-05', ], 'serviceIdentifier' => 'networkmanager', ], 'networkmonitor' => [ 'namespace' => 'NetworkMonitor', 'versions' => [ 'latest' => '2023-08-01', '2023-08-01' => '2023-08-01', ], 'serviceIdentifier' => 'networkmonitor', ], 'notifications' => [ 'namespace' => 'Notifications', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'notifications', ], 'notificationscontacts' => [ 'namespace' => 'NotificationsContacts', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'notificationscontacts', ], 'oam' => [ 'namespace' => 'OAM', 'versions' => [ 'latest' => '2022-06-10', '2022-06-10' => '2022-06-10', ], 'serviceIdentifier' => 'oam', ], 'observabilityadmin' => [ 'namespace' => 'ObservabilityAdmin', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'observabilityadmin', ], 'odb' => [ 'namespace' => 'Odb', 'versions' => [ 'latest' => '2024-08-20', '2024-08-20' => '2024-08-20', ], 'serviceIdentifier' => 'odb', ], 'omics' => [ 'namespace' => 'Omics', 'versions' => [ 'latest' => '2022-11-28', '2022-11-28' => '2022-11-28', ], 'serviceIdentifier' => 'omics', ], 'opensearch' => [ 'namespace' => 'OpenSearchService', 'versions' => [ 'latest' => '2021-01-01', '2021-01-01' => '2021-01-01', ], 'serviceIdentifier' => 'opensearch', ], 'opensearchserverless' => [ 'namespace' => 'OpenSearchServerless', 'versions' => [ 'latest' => '2021-11-01', '2021-11-01' => '2021-11-01', ], 'serviceIdentifier' => 'opensearchserverless', ], 'organizations' => [ 'namespace' => 'Organizations', 'versions' => [ 'latest' => '2016-11-28', '2016-11-28' => '2016-11-28', ], 'serviceIdentifier' => 'organizations', ], 'osis' => [ 'namespace' => 'OSIS', 'versions' => [ 'latest' => '2022-01-01', '2022-01-01' => '2022-01-01', ], 'serviceIdentifier' => 'osis', ], 'outposts' => [ 'namespace' => 'Outposts', 'versions' => [ 'latest' => '2019-12-03', '2019-12-03' => '2019-12-03', ], 'serviceIdentifier' => 'outposts', ], 'panorama' => [ 'namespace' => 'Panorama', 'versions' => [ 'latest' => '2019-07-24', '2019-07-24' => '2019-07-24', ], 'serviceIdentifier' => 'panorama', ], 'partnercentral-selling' => [ 'namespace' => 'PartnerCentralSelling', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'partnercentral_selling', ], 'payment-cryptography-data' => [ 'namespace' => 'PaymentCryptographyData', 'versions' => [ 'latest' => '2022-02-03', '2022-02-03' => '2022-02-03', ], 'serviceIdentifier' => 'payment_cryptography_data', ], 'payment-cryptography' => [ 'namespace' => 'PaymentCryptography', 'versions' => [ 'latest' => '2021-09-14', '2021-09-14' => '2021-09-14', ], 'serviceIdentifier' => 'payment_cryptography', ], 'pca-connector-ad' => [ 'namespace' => 'PcaConnectorAd', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'pca_connector_ad', ], 'pca-connector-scep' => [ 'namespace' => 'PcaConnectorScep', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'pca_connector_scep', ], 'pcs' => [ 'namespace' => 'PCS', 'versions' => [ 'latest' => '2023-02-10', '2023-02-10' => '2023-02-10', ], 'serviceIdentifier' => 'pcs', ], 'personalize-events' => [ 'namespace' => 'PersonalizeEvents', 'versions' => [ 'latest' => '2018-03-22', '2018-03-22' => '2018-03-22', ], 'serviceIdentifier' => 'personalize_events', ], 'personalize-runtime' => [ 'namespace' => 'PersonalizeRuntime', 'versions' => [ 'latest' => '2018-05-22', '2018-05-22' => '2018-05-22', ], 'serviceIdentifier' => 'personalize_runtime', ], 'personalize' => [ 'namespace' => 'Personalize', 'versions' => [ 'latest' => '2018-05-22', '2018-05-22' => '2018-05-22', ], 'serviceIdentifier' => 'personalize', ], 'pi' => [ 'namespace' => 'PI', 'versions' => [ 'latest' => '2018-02-27', '2018-02-27' => '2018-02-27', ], 'serviceIdentifier' => 'pi', ], 'pinpoint-email' => [ 'namespace' => 'PinpointEmail', 'versions' => [ 'latest' => '2018-07-26', '2018-07-26' => '2018-07-26', ], 'serviceIdentifier' => 'pinpoint_email', ], 'pinpoint-sms-voice-v2' => [ 'namespace' => 'PinpointSMSVoiceV2', 'versions' => [ 'latest' => '2022-03-31', '2022-03-31' => '2022-03-31', ], 'serviceIdentifier' => 'pinpoint_sms_voice_v2', ], 'pinpoint' => [ 'namespace' => 'Pinpoint', 'versions' => [ 'latest' => '2016-12-01', '2016-12-01' => '2016-12-01', ], 'serviceIdentifier' => 'pinpoint', ], 'pipes' => [ 'namespace' => 'Pipes', 'versions' => [ 'latest' => '2015-10-07', '2015-10-07' => '2015-10-07', ], 'serviceIdentifier' => 'pipes', ], 'polly' => [ 'namespace' => 'Polly', 'versions' => [ 'latest' => '2016-06-10', '2016-06-10' => '2016-06-10', ], 'serviceIdentifier' => 'polly', ], 'pricing' => [ 'namespace' => 'Pricing', 'versions' => [ 'latest' => '2017-10-15', '2017-10-15' => '2017-10-15', ], 'serviceIdentifier' => 'pricing', ], 'proton' => [ 'namespace' => 'Proton', 'versions' => [ 'latest' => '2020-07-20', '2020-07-20' => '2020-07-20', ], 'serviceIdentifier' => 'proton', ], 'qapps' => [ 'namespace' => 'QApps', 'versions' => [ 'latest' => '2023-11-27', '2023-11-27' => '2023-11-27', ], 'serviceIdentifier' => 'qapps', ], 'qbusiness' => [ 'namespace' => 'QBusiness', 'versions' => [ 'latest' => '2023-11-27', '2023-11-27' => '2023-11-27', ], 'serviceIdentifier' => 'qbusiness', ], 'qconnect' => [ 'namespace' => 'QConnect', 'versions' => [ 'latest' => '2020-10-19', '2020-10-19' => '2020-10-19', ], 'serviceIdentifier' => 'qconnect', ], 'qldb-session' => [ 'namespace' => 'QLDBSession', 'versions' => [ 'latest' => '2019-07-11', '2019-07-11' => '2019-07-11', ], 'serviceIdentifier' => 'qldb_session', ], 'qldb' => [ 'namespace' => 'QLDB', 'versions' => [ 'latest' => '2019-01-02', '2019-01-02' => '2019-01-02', ], 'serviceIdentifier' => 'qldb', ], 'quicksight' => [ 'namespace' => 'QuickSight', 'versions' => [ 'latest' => '2018-04-01', '2018-04-01' => '2018-04-01', ], 'serviceIdentifier' => 'quicksight', ], 'ram' => [ 'namespace' => 'RAM', 'versions' => [ 'latest' => '2018-01-04', '2018-01-04' => '2018-01-04', ], 'serviceIdentifier' => 'ram', ], 'rbin' => [ 'namespace' => 'RecycleBin', 'versions' => [ 'latest' => '2021-06-15', '2021-06-15' => '2021-06-15', ], 'serviceIdentifier' => 'rbin', ], 'rds-data' => [ 'namespace' => 'RDSDataService', 'versions' => [ 'latest' => '2018-08-01', '2018-08-01' => '2018-08-01', ], 'serviceIdentifier' => 'rds_data', ], 'rds' => [ 'namespace' => 'Rds', 'versions' => [ 'latest' => '2014-10-31', '2014-10-31' => '2014-10-31', '2014-09-01' => '2014-09-01', ], 'serviceIdentifier' => 'rds', ], 'redshift-data' => [ 'namespace' => 'RedshiftDataAPIService', 'versions' => [ 'latest' => '2019-12-20', '2019-12-20' => '2019-12-20', ], 'serviceIdentifier' => 'redshift_data', ], 'redshift-serverless' => [ 'namespace' => 'RedshiftServerless', 'versions' => [ 'latest' => '2021-04-21', '2021-04-21' => '2021-04-21', ], 'serviceIdentifier' => 'redshift_serverless', ], 'redshift' => [ 'namespace' => 'Redshift', 'versions' => [ 'latest' => '2012-12-01', '2012-12-01' => '2012-12-01', ], 'serviceIdentifier' => 'redshift', ], 'rekognition' => [ 'namespace' => 'Rekognition', 'versions' => [ 'latest' => '2016-06-27', '2016-06-27' => '2016-06-27', ], 'serviceIdentifier' => 'rekognition', ], 'repostspace' => [ 'namespace' => 'Repostspace', 'versions' => [ 'latest' => '2022-05-13', '2022-05-13' => '2022-05-13', ], 'serviceIdentifier' => 'repostspace', ], 'resiliencehub' => [ 'namespace' => 'ResilienceHub', 'versions' => [ 'latest' => '2020-04-30', '2020-04-30' => '2020-04-30', ], 'serviceIdentifier' => 'resiliencehub', ], 'resource-explorer-2' => [ 'namespace' => 'ResourceExplorer2', 'versions' => [ 'latest' => '2022-07-28', '2022-07-28' => '2022-07-28', ], 'serviceIdentifier' => 'resource_explorer_2', ], 'resource-groups' => [ 'namespace' => 'ResourceGroups', 'versions' => [ 'latest' => '2017-11-27', '2017-11-27' => '2017-11-27', ], 'serviceIdentifier' => 'resource_groups', ], 'resourcegroupstaggingapi' => [ 'namespace' => 'ResourceGroupsTaggingAPI', 'versions' => [ 'latest' => '2017-01-26', '2017-01-26' => '2017-01-26', ], 'serviceIdentifier' => 'resource_groups_tagging_api', ], 'robomaker' => [ 'namespace' => 'RoboMaker', 'versions' => [ 'latest' => '2018-06-29', '2018-06-29' => '2018-06-29', ], 'serviceIdentifier' => 'robomaker', ], 'rolesanywhere' => [ 'namespace' => 'RolesAnywhere', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'rolesanywhere', ], 'route53-recovery-cluster' => [ 'namespace' => 'Route53RecoveryCluster', 'versions' => [ 'latest' => '2019-12-02', '2019-12-02' => '2019-12-02', ], 'serviceIdentifier' => 'route53_recovery_cluster', ], 'route53-recovery-control-config' => [ 'namespace' => 'Route53RecoveryControlConfig', 'versions' => [ 'latest' => '2020-11-02', '2020-11-02' => '2020-11-02', ], 'serviceIdentifier' => 'route53_recovery_control_config', ], 'route53-recovery-readiness' => [ 'namespace' => 'Route53RecoveryReadiness', 'versions' => [ 'latest' => '2019-12-02', '2019-12-02' => '2019-12-02', ], 'serviceIdentifier' => 'route53_recovery_readiness', ], 'route53' => [ 'namespace' => 'Route53', 'versions' => [ 'latest' => '2013-04-01', '2013-04-01' => '2013-04-01', ], 'serviceIdentifier' => 'route_53', ], 'route53domains' => [ 'namespace' => 'Route53Domains', 'versions' => [ 'latest' => '2014-05-15', '2014-05-15' => '2014-05-15', ], 'serviceIdentifier' => 'route_53_domains', ], 'route53profiles' => [ 'namespace' => 'Route53Profiles', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'route53profiles', ], 'route53resolver' => [ 'namespace' => 'Route53Resolver', 'versions' => [ 'latest' => '2018-04-01', '2018-04-01' => '2018-04-01', ], 'serviceIdentifier' => 'route53resolver', ], 'rum' => [ 'namespace' => 'CloudWatchRUM', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'rum', ], 'runtime.lex.v2' => [ 'namespace' => 'LexRuntimeV2', 'versions' => [ 'latest' => '2020-08-07', '2020-08-07' => '2020-08-07', ], 'serviceIdentifier' => 'lex_runtime_v2', ], 'runtime.lex' => [ 'namespace' => 'LexRuntimeService', 'versions' => [ 'latest' => '2016-11-28', '2016-11-28' => '2016-11-28', ], 'serviceIdentifier' => 'lex_runtime_service', ], 'runtime.sagemaker' => [ 'namespace' => 'SageMakerRuntime', 'versions' => [ 'latest' => '2017-05-13', '2017-05-13' => '2017-05-13', ], 'serviceIdentifier' => 'sagemaker_runtime', ], 's3' => [ 'namespace' => 'S3', 'versions' => [ 'latest' => '2006-03-01', '2006-03-01' => '2006-03-01', ], 'serviceIdentifier' => 's3', ], 's3control' => [ 'namespace' => 'S3Control', 'versions' => [ 'latest' => '2018-08-20', '2018-08-20' => '2018-08-20', ], 'serviceIdentifier' => 's3_control', ], 's3outposts' => [ 'namespace' => 'S3Outposts', 'versions' => [ 'latest' => '2017-07-25', '2017-07-25' => '2017-07-25', ], 'serviceIdentifier' => 's3outposts', ], 's3tables' => [ 'namespace' => 'S3Tables', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 's3tables', ], 's3vectors' => [ 'namespace' => 'S3Vectors', 'versions' => [ 'latest' => '2025-07-15', '2025-07-15' => '2025-07-15', ], 'serviceIdentifier' => 's3vectors', ], 'sagemaker-a2i-runtime' => [ 'namespace' => 'AugmentedAIRuntime', 'versions' => [ 'latest' => '2019-11-07', '2019-11-07' => '2019-11-07', ], 'serviceIdentifier' => 'sagemaker_a2i_runtime', ], 'sagemaker-edge' => [ 'namespace' => 'SagemakerEdgeManager', 'versions' => [ 'latest' => '2020-09-23', '2020-09-23' => '2020-09-23', ], 'serviceIdentifier' => 'sagemaker_edge', ], 'sagemaker-featurestore-runtime' => [ 'namespace' => 'SageMakerFeatureStoreRuntime', 'versions' => [ 'latest' => '2020-07-01', '2020-07-01' => '2020-07-01', ], 'serviceIdentifier' => 'sagemaker_featurestore_runtime', ], 'sagemaker-geospatial' => [ 'namespace' => 'SageMakerGeospatial', 'versions' => [ 'latest' => '2020-05-27', '2020-05-27' => '2020-05-27', ], 'serviceIdentifier' => 'sagemaker_geospatial', ], 'sagemaker-metrics' => [ 'namespace' => 'SageMakerMetrics', 'versions' => [ 'latest' => '2022-09-30', '2022-09-30' => '2022-09-30', ], 'serviceIdentifier' => 'sagemaker_metrics', ], 'sagemaker' => [ 'namespace' => 'SageMaker', 'versions' => [ 'latest' => '2017-07-24', '2017-07-24' => '2017-07-24', ], 'serviceIdentifier' => 'sagemaker', ], 'savingsplans' => [ 'namespace' => 'SavingsPlans', 'versions' => [ 'latest' => '2019-06-28', '2019-06-28' => '2019-06-28', ], 'serviceIdentifier' => 'savingsplans', ], 'scheduler' => [ 'namespace' => 'Scheduler', 'versions' => [ 'latest' => '2021-06-30', '2021-06-30' => '2021-06-30', ], 'serviceIdentifier' => 'scheduler', ], 'schemas' => [ 'namespace' => 'Schemas', 'versions' => [ 'latest' => '2019-12-02', '2019-12-02' => '2019-12-02', ], 'serviceIdentifier' => 'schemas', ], 'secretsmanager' => [ 'namespace' => 'SecretsManager', 'versions' => [ 'latest' => '2017-10-17', '2017-10-17' => '2017-10-17', ], 'serviceIdentifier' => 'secrets_manager', ], 'security-ir' => [ 'namespace' => 'SecurityIR', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'security_ir', ], 'securityhub' => [ 'namespace' => 'SecurityHub', 'versions' => [ 'latest' => '2018-10-26', '2018-10-26' => '2018-10-26', ], 'serviceIdentifier' => 'securityhub', ], 'securitylake' => [ 'namespace' => 'SecurityLake', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'securitylake', ], 'serverlessrepo' => [ 'namespace' => 'ServerlessApplicationRepository', 'versions' => [ 'latest' => '2017-09-08', '2017-09-08' => '2017-09-08', ], 'serviceIdentifier' => 'serverlessapplicationrepository', ], 'service-quotas' => [ 'namespace' => 'ServiceQuotas', 'versions' => [ 'latest' => '2019-06-24', '2019-06-24' => '2019-06-24', ], 'serviceIdentifier' => 'service_quotas', ], 'servicecatalog-appregistry' => [ 'namespace' => 'AppRegistry', 'versions' => [ 'latest' => '2020-06-24', '2020-06-24' => '2020-06-24', ], 'serviceIdentifier' => 'service_catalog_appregistry', ], 'servicecatalog' => [ 'namespace' => 'ServiceCatalog', 'versions' => [ 'latest' => '2015-12-10', '2015-12-10' => '2015-12-10', ], 'serviceIdentifier' => 'service_catalog', ], 'servicediscovery' => [ 'namespace' => 'ServiceDiscovery', 'versions' => [ 'latest' => '2017-03-14', '2017-03-14' => '2017-03-14', ], 'serviceIdentifier' => 'servicediscovery', ], 'sesv2' => [ 'namespace' => 'SesV2', 'versions' => [ 'latest' => '2019-09-27', '2019-09-27' => '2019-09-27', ], 'serviceIdentifier' => 'sesv2', ], 'shield' => [ 'namespace' => 'Shield', 'versions' => [ 'latest' => '2016-06-02', '2016-06-02' => '2016-06-02', ], 'serviceIdentifier' => 'shield', ], 'signer' => [ 'namespace' => 'signer', 'versions' => [ 'latest' => '2017-08-25', '2017-08-25' => '2017-08-25', ], 'serviceIdentifier' => 'signer', ], 'simspaceweaver' => [ 'namespace' => 'SimSpaceWeaver', 'versions' => [ 'latest' => '2022-10-28', '2022-10-28' => '2022-10-28', ], 'serviceIdentifier' => 'simspaceweaver', ], 'sms-voice' => [ 'namespace' => 'PinpointSMSVoice', 'versions' => [ 'latest' => '2018-09-05', '2018-09-05' => '2018-09-05', ], 'serviceIdentifier' => 'pinpoint_sms_voice', ], 'sms' => [ 'namespace' => 'Sms', 'versions' => [ 'latest' => '2016-10-24', '2016-10-24' => '2016-10-24', ], 'serviceIdentifier' => 'sms', ], 'snow-device-management' => [ 'namespace' => 'SnowDeviceManagement', 'versions' => [ 'latest' => '2021-08-04', '2021-08-04' => '2021-08-04', ], 'serviceIdentifier' => 'snow_device_management', ], 'snowball' => [ 'namespace' => 'SnowBall', 'versions' => [ 'latest' => '2016-06-30', '2016-06-30' => '2016-06-30', ], 'serviceIdentifier' => 'snowball', ], 'sns' => [ 'namespace' => 'Sns', 'versions' => [ 'latest' => '2010-03-31', '2010-03-31' => '2010-03-31', ], 'serviceIdentifier' => 'sns', ], 'socialmessaging' => [ 'namespace' => 'SocialMessaging', 'versions' => [ 'latest' => '2024-01-01', '2024-01-01' => '2024-01-01', ], 'serviceIdentifier' => 'socialmessaging', ], 'sqs' => [ 'namespace' => 'Sqs', 'versions' => [ 'latest' => '2012-11-05', '2012-11-05' => '2012-11-05', ], 'serviceIdentifier' => 'sqs', ], 'ssm-contacts' => [ 'namespace' => 'SSMContacts', 'versions' => [ 'latest' => '2021-05-03', '2021-05-03' => '2021-05-03', ], 'serviceIdentifier' => 'ssm_contacts', ], 'ssm-guiconnect' => [ 'namespace' => 'SSMGuiConnect', 'versions' => [ 'latest' => '2021-05-01', '2021-05-01' => '2021-05-01', ], 'serviceIdentifier' => 'ssm_guiconnect', ], 'ssm-incidents' => [ 'namespace' => 'SSMIncidents', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'ssm_incidents', ], 'ssm-quicksetup' => [ 'namespace' => 'SSMQuickSetup', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'ssm_quicksetup', ], 'ssm-sap' => [ 'namespace' => 'SsmSap', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'ssm_sap', ], 'ssm' => [ 'namespace' => 'Ssm', 'versions' => [ 'latest' => '2014-11-06', '2014-11-06' => '2014-11-06', ], 'serviceIdentifier' => 'ssm', ], 'sso-admin' => [ 'namespace' => 'SSOAdmin', 'versions' => [ 'latest' => '2020-07-20', '2020-07-20' => '2020-07-20', ], 'serviceIdentifier' => 'sso_admin', ], 'sso-oidc' => [ 'namespace' => 'SSOOIDC', 'versions' => [ 'latest' => '2019-06-10', '2019-06-10' => '2019-06-10', ], 'serviceIdentifier' => 'sso_oidc', ], 'sso' => [ 'namespace' => 'SSO', 'versions' => [ 'latest' => '2019-06-10', '2019-06-10' => '2019-06-10', ], 'serviceIdentifier' => 'sso', ], 'states' => [ 'namespace' => 'Sfn', 'versions' => [ 'latest' => '2016-11-23', '2016-11-23' => '2016-11-23', ], 'serviceIdentifier' => 'sfn', ], 'storagegateway' => [ 'namespace' => 'StorageGateway', 'versions' => [ 'latest' => '2013-06-30', '2013-06-30' => '2013-06-30', ], 'serviceIdentifier' => 'storage_gateway', ], 'streams.dynamodb' => [ 'namespace' => 'DynamoDbStreams', 'versions' => [ 'latest' => '2012-08-10', '2012-08-10' => '2012-08-10', ], 'serviceIdentifier' => 'dynamodb_streams', ], 'sts' => [ 'namespace' => 'Sts', 'versions' => [ 'latest' => '2011-06-15', '2011-06-15' => '2011-06-15', ], 'serviceIdentifier' => 'sts', ], 'supplychain' => [ 'namespace' => 'SupplyChain', 'versions' => [ 'latest' => '2024-01-01', '2024-01-01' => '2024-01-01', ], 'serviceIdentifier' => 'supplychain', ], 'support-app' => [ 'namespace' => 'SupportApp', 'versions' => [ 'latest' => '2021-08-20', '2021-08-20' => '2021-08-20', ], 'serviceIdentifier' => 'support_app', ], 'support' => [ 'namespace' => 'Support', 'versions' => [ 'latest' => '2013-04-15', '2013-04-15' => '2013-04-15', ], 'serviceIdentifier' => 'support', ], 'swf' => [ 'namespace' => 'Swf', 'versions' => [ 'latest' => '2012-01-25', '2012-01-25' => '2012-01-25', ], 'serviceIdentifier' => 'swf', ], 'synthetics' => [ 'namespace' => 'Synthetics', 'versions' => [ 'latest' => '2017-10-11', '2017-10-11' => '2017-10-11', ], 'serviceIdentifier' => 'synthetics', ], 'taxsettings' => [ 'namespace' => 'TaxSettings', 'versions' => [ 'latest' => '2018-05-10', '2018-05-10' => '2018-05-10', ], 'serviceIdentifier' => 'taxsettings', ], 'textract' => [ 'namespace' => 'Textract', 'versions' => [ 'latest' => '2018-06-27', '2018-06-27' => '2018-06-27', ], 'serviceIdentifier' => 'textract', ], 'timestream-influxdb' => [ 'namespace' => 'TimestreamInfluxDB', 'versions' => [ 'latest' => '2023-01-27', '2023-01-27' => '2023-01-27', ], 'serviceIdentifier' => 'timestream_influxdb', ], 'timestream-query' => [ 'namespace' => 'TimestreamQuery', 'versions' => [ 'latest' => '2018-11-01', '2018-11-01' => '2018-11-01', ], 'serviceIdentifier' => 'timestream_query', ], 'timestream-write' => [ 'namespace' => 'TimestreamWrite', 'versions' => [ 'latest' => '2018-11-01', '2018-11-01' => '2018-11-01', ], 'serviceIdentifier' => 'timestream_write', ], 'tnb' => [ 'namespace' => 'Tnb', 'versions' => [ 'latest' => '2008-10-21', '2008-10-21' => '2008-10-21', ], 'serviceIdentifier' => 'tnb', ], 'transcribe' => [ 'namespace' => 'TranscribeService', 'versions' => [ 'latest' => '2017-10-26', '2017-10-26' => '2017-10-26', ], 'serviceIdentifier' => 'transcribe', ], 'transfer' => [ 'namespace' => 'Transfer', 'versions' => [ 'latest' => '2018-11-05', '2018-11-05' => '2018-11-05', ], 'serviceIdentifier' => 'transfer', ], 'translate' => [ 'namespace' => 'Translate', 'versions' => [ 'latest' => '2017-07-01', '2017-07-01' => '2017-07-01', ], 'serviceIdentifier' => 'translate', ], 'trustedadvisor' => [ 'namespace' => 'TrustedAdvisor', 'versions' => [ 'latest' => '2022-09-15', '2022-09-15' => '2022-09-15', ], 'serviceIdentifier' => 'trustedadvisor', ], 'verifiedpermissions' => [ 'namespace' => 'VerifiedPermissions', 'versions' => [ 'latest' => '2021-12-01', '2021-12-01' => '2021-12-01', ], 'serviceIdentifier' => 'verifiedpermissions', ], 'voice-id' => [ 'namespace' => 'VoiceID', 'versions' => [ 'latest' => '2021-09-27', '2021-09-27' => '2021-09-27', ], 'serviceIdentifier' => 'voice_id', ], 'vpc-lattice' => [ 'namespace' => 'VPCLattice', 'versions' => [ 'latest' => '2022-11-30', '2022-11-30' => '2022-11-30', ], 'serviceIdentifier' => 'vpc_lattice', ], 'waf-regional' => [ 'namespace' => 'WafRegional', 'versions' => [ 'latest' => '2016-11-28', '2016-11-28' => '2016-11-28', ], 'serviceIdentifier' => 'waf_regional', ], 'waf' => [ 'namespace' => 'Waf', 'versions' => [ 'latest' => '2015-08-24', '2015-08-24' => '2015-08-24', ], 'serviceIdentifier' => 'waf', ], 'wafv2' => [ 'namespace' => 'WAFV2', 'versions' => [ 'latest' => '2019-07-29', '2019-07-29' => '2019-07-29', ], 'serviceIdentifier' => 'wafv2', ], 'wellarchitected' => [ 'namespace' => 'WellArchitected', 'versions' => [ 'latest' => '2020-03-31', '2020-03-31' => '2020-03-31', ], 'serviceIdentifier' => 'wellarchitected', ], 'wisdom' => [ 'namespace' => 'ConnectWisdomService', 'versions' => [ 'latest' => '2020-10-19', '2020-10-19' => '2020-10-19', ], 'serviceIdentifier' => 'wisdom', ], 'workdocs' => [ 'namespace' => 'WorkDocs', 'versions' => [ 'latest' => '2016-05-01', '2016-05-01' => '2016-05-01', ], 'serviceIdentifier' => 'workdocs', ], 'workmail' => [ 'namespace' => 'WorkMail', 'versions' => [ 'latest' => '2017-10-01', '2017-10-01' => '2017-10-01', ], 'serviceIdentifier' => 'workmail', ], 'workmailmessageflow' => [ 'namespace' => 'WorkMailMessageFlow', 'versions' => [ 'latest' => '2019-05-01', '2019-05-01' => '2019-05-01', ], 'serviceIdentifier' => 'workmailmessageflow', ], 'workspaces-instances' => [ 'namespace' => 'WorkspacesInstances', 'versions' => [ 'latest' => '2022-07-26', '2022-07-26' => '2022-07-26', ], 'serviceIdentifier' => 'workspaces_instances', ], 'workspaces-thin-client' => [ 'namespace' => 'WorkSpacesThinClient', 'versions' => [ 'latest' => '2023-08-22', '2023-08-22' => '2023-08-22', ], 'serviceIdentifier' => 'workspaces_thin_client', ], 'workspaces-web' => [ 'namespace' => 'WorkSpacesWeb', 'versions' => [ 'latest' => '2020-07-08', '2020-07-08' => '2020-07-08', ], 'serviceIdentifier' => 'workspaces_web', ], 'workspaces' => [ 'namespace' => 'WorkSpaces', 'versions' => [ 'latest' => '2015-04-08', '2015-04-08' => '2015-04-08', ], 'serviceIdentifier' => 'workspaces', ], 'xray' => [ 'namespace' => 'XRay', 'versions' => [ 'latest' => '2016-04-12', '2016-04-12' => '2016-04-12', ], 'serviceIdentifier' => 'xray', ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/partitions.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/partitions.json.php new file mode 100644 index 000000000..82db877d5 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/partitions.json.php @@ -0,0 +1,3 @@ + [ [ 'id' => 'aws', 'outputs' => [ 'dnsSuffix' => 'amazonaws.com', 'dualStackDnsSuffix' => 'api.aws', 'implicitGlobalRegion' => 'us-east-1', 'name' => 'aws', 'supportsDualStack' => true, 'supportsFIPS' => true, ], 'regionRegex' => '^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$', 'regions' => [ 'af-south-1' => [ 'description' => 'Africa (Cape Town)', ], 'ap-east-1' => [ 'description' => 'Asia Pacific (Hong Kong)', ], 'ap-east-2' => [ 'description' => 'Asia Pacific (Taipei)', ], 'ap-northeast-1' => [ 'description' => 'Asia Pacific (Tokyo)', ], 'ap-northeast-2' => [ 'description' => 'Asia Pacific (Seoul)', ], 'ap-northeast-3' => [ 'description' => 'Asia Pacific (Osaka)', ], 'ap-south-1' => [ 'description' => 'Asia Pacific (Mumbai)', ], 'ap-south-2' => [ 'description' => 'Asia Pacific (Hyderabad)', ], 'ap-southeast-1' => [ 'description' => 'Asia Pacific (Singapore)', ], 'ap-southeast-2' => [ 'description' => 'Asia Pacific (Sydney)', ], 'ap-southeast-3' => [ 'description' => 'Asia Pacific (Jakarta)', ], 'ap-southeast-4' => [ 'description' => 'Asia Pacific (Melbourne)', ], 'ap-southeast-5' => [ 'description' => 'Asia Pacific (Malaysia)', ], 'ap-southeast-6' => [ 'description' => 'Asia Pacific (New Zealand)', ], 'ap-southeast-7' => [ 'description' => 'Asia Pacific (Thailand)', ], 'aws-global' => [ 'description' => 'aws global region', ], 'ca-central-1' => [ 'description' => 'Canada (Central)', ], 'ca-west-1' => [ 'description' => 'Canada West (Calgary)', ], 'eu-central-1' => [ 'description' => 'Europe (Frankfurt)', ], 'eu-central-2' => [ 'description' => 'Europe (Zurich)', ], 'eu-north-1' => [ 'description' => 'Europe (Stockholm)', ], 'eu-south-1' => [ 'description' => 'Europe (Milan)', ], 'eu-south-2' => [ 'description' => 'Europe (Spain)', ], 'eu-west-1' => [ 'description' => 'Europe (Ireland)', ], 'eu-west-2' => [ 'description' => 'Europe (London)', ], 'eu-west-3' => [ 'description' => 'Europe (Paris)', ], 'il-central-1' => [ 'description' => 'Israel (Tel Aviv)', ], 'me-central-1' => [ 'description' => 'Middle East (UAE)', ], 'me-south-1' => [ 'description' => 'Middle East (Bahrain)', ], 'mx-central-1' => [ 'description' => 'Mexico (Central)', ], 'sa-east-1' => [ 'description' => 'South America (Sao Paulo)', ], 'us-east-1' => [ 'description' => 'US East (N. Virginia)', ], 'us-east-2' => [ 'description' => 'US East (Ohio)', ], 'us-west-1' => [ 'description' => 'US West (N. California)', ], 'us-west-2' => [ 'description' => 'US West (Oregon)', ], ], ], [ 'id' => 'aws-cn', 'outputs' => [ 'dnsSuffix' => 'amazonaws.com.cn', 'dualStackDnsSuffix' => 'api.amazonwebservices.com.cn', 'implicitGlobalRegion' => 'cn-northwest-1', 'name' => 'aws-cn', 'supportsDualStack' => true, 'supportsFIPS' => true, ], 'regionRegex' => '^cn\\-\\w+\\-\\d+$', 'regions' => [ 'aws-cn-global' => [ 'description' => 'aws-cn global region', ], 'cn-north-1' => [ 'description' => 'China (Beijing)', ], 'cn-northwest-1' => [ 'description' => 'China (Ningxia)', ], ], ], [ 'id' => 'aws-eusc', 'outputs' => [ 'dnsSuffix' => 'amazonaws.eu', 'dualStackDnsSuffix' => 'api.amazonwebservices.eu', 'implicitGlobalRegion' => 'eusc-de-east-1', 'name' => 'aws-eusc', 'supportsDualStack' => true, 'supportsFIPS' => true, ], 'regionRegex' => '^eusc\\-(de)\\-\\w+\\-\\d+$', 'regions' => [ 'eusc-de-east-1' => [ 'description' => 'EU (Germany)', ], ], ], [ 'id' => 'aws-iso', 'outputs' => [ 'dnsSuffix' => 'c2s.ic.gov', 'dualStackDnsSuffix' => 'api.aws.ic.gov', 'implicitGlobalRegion' => 'us-iso-east-1', 'name' => 'aws-iso', 'supportsDualStack' => false, 'supportsFIPS' => true, ], 'regionRegex' => '^us\\-iso\\-\\w+\\-\\d+$', 'regions' => [ 'aws-iso-global' => [ 'description' => 'aws-iso global region', ], 'us-iso-east-1' => [ 'description' => 'US ISO East', ], 'us-iso-west-1' => [ 'description' => 'US ISO WEST', ], ], ], [ 'id' => 'aws-iso-b', 'outputs' => [ 'dnsSuffix' => 'sc2s.sgov.gov', 'dualStackDnsSuffix' => 'api.aws.scloud', 'implicitGlobalRegion' => 'us-isob-east-1', 'name' => 'aws-iso-b', 'supportsDualStack' => false, 'supportsFIPS' => true, ], 'regionRegex' => '^us\\-isob\\-\\w+\\-\\d+$', 'regions' => [ 'aws-iso-b-global' => [ 'description' => 'aws-iso-b global region', ], 'us-isob-east-1' => [ 'description' => 'US ISOB East (Ohio)', ], ], ], [ 'id' => 'aws-iso-e', 'outputs' => [ 'dnsSuffix' => 'cloud.adc-e.uk', 'dualStackDnsSuffix' => 'api.cloud-aws.adc-e.uk', 'implicitGlobalRegion' => 'eu-isoe-west-1', 'name' => 'aws-iso-e', 'supportsDualStack' => false, 'supportsFIPS' => true, ], 'regionRegex' => '^eu\\-isoe\\-\\w+\\-\\d+$', 'regions' => [ 'aws-iso-e-global' => [ 'description' => 'aws-iso-e global region', ], 'eu-isoe-west-1' => [ 'description' => 'EU ISOE West', ], ], ], [ 'id' => 'aws-iso-f', 'outputs' => [ 'dnsSuffix' => 'csp.hci.ic.gov', 'dualStackDnsSuffix' => 'api.aws.hci.ic.gov', 'implicitGlobalRegion' => 'us-isof-south-1', 'name' => 'aws-iso-f', 'supportsDualStack' => false, 'supportsFIPS' => true, ], 'regionRegex' => '^us\\-isof\\-\\w+\\-\\d+$', 'regions' => [ 'aws-iso-f-global' => [ 'description' => 'aws-iso-f global region', ], 'us-isof-east-1' => [ 'description' => 'US ISOF EAST', ], 'us-isof-south-1' => [ 'description' => 'US ISOF SOUTH', ], ], ], [ 'id' => 'aws-us-gov', 'outputs' => [ 'dnsSuffix' => 'amazonaws.com', 'dualStackDnsSuffix' => 'api.aws', 'implicitGlobalRegion' => 'us-gov-west-1', 'name' => 'aws-us-gov', 'supportsDualStack' => true, 'supportsFIPS' => true, ], 'regionRegex' => '^us\\-gov\\-\\w+\\-\\d+$', 'regions' => [ 'aws-us-gov-global' => [ 'description' => 'aws-us-gov global region', ], 'us-gov-east-1' => [ 'description' => 'AWS GovCloud (US-East)', ], 'us-gov-west-1' => [ 'description' => 'AWS GovCloud (US-West)', ], ], ], ], 'version' => '1.1',]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/api-2.json.php new file mode 100644 index 000000000..0f5ddb928 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2006-03-01', 'checksumFormat' => 'md5', 'endpointPrefix' => 's3', 'globalEndpoint' => 's3.amazonaws.com', 'protocol' => 'rest-xml', 'protocols' => [ 'rest-xml', ], 'serviceAbbreviation' => 'Amazon S3', 'serviceFullName' => 'Amazon Simple Storage Service', 'serviceId' => 'S3', 'signatureVersion' => 's3', 'uid' => 's3-2006-03-01', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'AbortMultipartUpload' => [ 'name' => 'AbortMultipartUpload', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}/{Key+}', 'responseCode' => 204, ], 'input' => [ 'shape' => 'AbortMultipartUploadRequest', ], 'output' => [ 'shape' => 'AbortMultipartUploadOutput', ], 'errors' => [ [ 'shape' => 'NoSuchUpload', ], ], ], 'CompleteMultipartUpload' => [ 'name' => 'CompleteMultipartUpload', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'CompleteMultipartUploadRequest', ], 'output' => [ 'shape' => 'CompleteMultipartUploadOutput', ], ], 'CopyObject' => [ 'name' => 'CopyObject', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'CopyObjectRequest', ], 'output' => [ 'shape' => 'CopyObjectOutput', ], 'errors' => [ [ 'shape' => 'ObjectNotInActiveTierError', ], ], 'staticContextParams' => [ 'DisableS3ExpressSessionAuth' => [ 'value' => true, ], ], ], 'CreateBucket' => [ 'name' => 'CreateBucket', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}', ], 'input' => [ 'shape' => 'CreateBucketRequest', ], 'output' => [ 'shape' => 'CreateBucketOutput', ], 'errors' => [ [ 'shape' => 'BucketAlreadyExists', ], [ 'shape' => 'BucketAlreadyOwnedByYou', ], ], 'staticContextParams' => [ 'DisableAccessPoints' => [ 'value' => true, ], 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'CreateBucketMetadataConfiguration' => [ 'name' => 'CreateBucketMetadataConfiguration', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}?metadataConfiguration', ], 'input' => [ 'shape' => 'CreateBucketMetadataConfigurationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'CreateBucketMetadataTableConfiguration' => [ 'name' => 'CreateBucketMetadataTableConfiguration', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}?metadataTable', ], 'input' => [ 'shape' => 'CreateBucketMetadataTableConfigurationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'CreateMultipartUpload' => [ 'name' => 'CreateMultipartUpload', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}/{Key+}?uploads', ], 'input' => [ 'shape' => 'CreateMultipartUploadRequest', ], 'output' => [ 'shape' => 'CreateMultipartUploadOutput', ], ], 'CreateSession' => [ 'name' => 'CreateSession', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?session', ], 'input' => [ 'shape' => 'CreateSessionRequest', ], 'output' => [ 'shape' => 'CreateSessionOutput', ], 'errors' => [ [ 'shape' => 'NoSuchBucket', ], ], 'staticContextParams' => [ 'DisableS3ExpressSessionAuth' => [ 'value' => true, ], ], ], 'DeleteBucket' => [ 'name' => 'DeleteBucket', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketAnalyticsConfiguration' => [ 'name' => 'DeleteBucketAnalyticsConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?analytics', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketAnalyticsConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketCors' => [ 'name' => 'DeleteBucketCors', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?cors', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketCorsRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketEncryption' => [ 'name' => 'DeleteBucketEncryption', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?encryption', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketEncryptionRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketIntelligentTieringConfiguration' => [ 'name' => 'DeleteBucketIntelligentTieringConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?intelligent-tiering', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketIntelligentTieringConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketInventoryConfiguration' => [ 'name' => 'DeleteBucketInventoryConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?inventory', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketInventoryConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketLifecycle' => [ 'name' => 'DeleteBucketLifecycle', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?lifecycle', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketLifecycleRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketMetadataConfiguration' => [ 'name' => 'DeleteBucketMetadataConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?metadataConfiguration', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketMetadataConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketMetadataTableConfiguration' => [ 'name' => 'DeleteBucketMetadataTableConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?metadataTable', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketMetadataTableConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketMetricsConfiguration' => [ 'name' => 'DeleteBucketMetricsConfiguration', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?metrics', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketMetricsConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketOwnershipControls' => [ 'name' => 'DeleteBucketOwnershipControls', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?ownershipControls', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketOwnershipControlsRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketPolicy' => [ 'name' => 'DeleteBucketPolicy', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?policy', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketPolicyRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketReplication' => [ 'name' => 'DeleteBucketReplication', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?replication', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketReplicationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketTagging' => [ 'name' => 'DeleteBucketTagging', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?tagging', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketTaggingRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteBucketWebsite' => [ 'name' => 'DeleteBucketWebsite', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?website', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteBucketWebsiteRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'DeleteObject' => [ 'name' => 'DeleteObject', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}/{Key+}', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteObjectRequest', ], 'output' => [ 'shape' => 'DeleteObjectOutput', ], ], 'DeleteObjectTagging' => [ 'name' => 'DeleteObjectTagging', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}/{Key+}?tagging', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeleteObjectTaggingRequest', ], 'output' => [ 'shape' => 'DeleteObjectTaggingOutput', ], ], 'DeleteObjects' => [ 'name' => 'DeleteObjects', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}?delete', ], 'input' => [ 'shape' => 'DeleteObjectsRequest', ], 'output' => [ 'shape' => 'DeleteObjectsOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'DeletePublicAccessBlock' => [ 'name' => 'DeletePublicAccessBlock', 'http' => [ 'method' => 'DELETE', 'requestUri' => '/{Bucket}?publicAccessBlock', 'responseCode' => 204, ], 'input' => [ 'shape' => 'DeletePublicAccessBlockRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketAccelerateConfiguration' => [ 'name' => 'GetBucketAccelerateConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?accelerate', ], 'input' => [ 'shape' => 'GetBucketAccelerateConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketAccelerateConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketAcl' => [ 'name' => 'GetBucketAcl', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?acl', ], 'input' => [ 'shape' => 'GetBucketAclRequest', ], 'output' => [ 'shape' => 'GetBucketAclOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketAnalyticsConfiguration' => [ 'name' => 'GetBucketAnalyticsConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?analytics', ], 'input' => [ 'shape' => 'GetBucketAnalyticsConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketAnalyticsConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketCors' => [ 'name' => 'GetBucketCors', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?cors', ], 'input' => [ 'shape' => 'GetBucketCorsRequest', ], 'output' => [ 'shape' => 'GetBucketCorsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketEncryption' => [ 'name' => 'GetBucketEncryption', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?encryption', ], 'input' => [ 'shape' => 'GetBucketEncryptionRequest', ], 'output' => [ 'shape' => 'GetBucketEncryptionOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketIntelligentTieringConfiguration' => [ 'name' => 'GetBucketIntelligentTieringConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?intelligent-tiering', ], 'input' => [ 'shape' => 'GetBucketIntelligentTieringConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketIntelligentTieringConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketInventoryConfiguration' => [ 'name' => 'GetBucketInventoryConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?inventory', ], 'input' => [ 'shape' => 'GetBucketInventoryConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketInventoryConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketLifecycle' => [ 'name' => 'GetBucketLifecycle', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?lifecycle', ], 'input' => [ 'shape' => 'GetBucketLifecycleRequest', ], 'output' => [ 'shape' => 'GetBucketLifecycleOutput', ], 'deprecated' => true, 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketLifecycleConfiguration' => [ 'name' => 'GetBucketLifecycleConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?lifecycle', ], 'input' => [ 'shape' => 'GetBucketLifecycleConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketLifecycleConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketLocation' => [ 'name' => 'GetBucketLocation', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?location', ], 'input' => [ 'shape' => 'GetBucketLocationRequest', ], 'output' => [ 'shape' => 'GetBucketLocationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketLogging' => [ 'name' => 'GetBucketLogging', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?logging', ], 'input' => [ 'shape' => 'GetBucketLoggingRequest', ], 'output' => [ 'shape' => 'GetBucketLoggingOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketMetadataConfiguration' => [ 'name' => 'GetBucketMetadataConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?metadataConfiguration', ], 'input' => [ 'shape' => 'GetBucketMetadataConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketMetadataConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketMetadataTableConfiguration' => [ 'name' => 'GetBucketMetadataTableConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?metadataTable', ], 'input' => [ 'shape' => 'GetBucketMetadataTableConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketMetadataTableConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketMetricsConfiguration' => [ 'name' => 'GetBucketMetricsConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?metrics', ], 'input' => [ 'shape' => 'GetBucketMetricsConfigurationRequest', ], 'output' => [ 'shape' => 'GetBucketMetricsConfigurationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketNotification' => [ 'name' => 'GetBucketNotification', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?notification', ], 'input' => [ 'shape' => 'GetBucketNotificationConfigurationRequest', ], 'output' => [ 'shape' => 'NotificationConfigurationDeprecated', ], 'deprecated' => true, 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketNotificationConfiguration' => [ 'name' => 'GetBucketNotificationConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?notification', ], 'input' => [ 'shape' => 'GetBucketNotificationConfigurationRequest', ], 'output' => [ 'shape' => 'NotificationConfiguration', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketOwnershipControls' => [ 'name' => 'GetBucketOwnershipControls', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?ownershipControls', ], 'input' => [ 'shape' => 'GetBucketOwnershipControlsRequest', ], 'output' => [ 'shape' => 'GetBucketOwnershipControlsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketPolicy' => [ 'name' => 'GetBucketPolicy', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?policy', ], 'input' => [ 'shape' => 'GetBucketPolicyRequest', ], 'output' => [ 'shape' => 'GetBucketPolicyOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketPolicyStatus' => [ 'name' => 'GetBucketPolicyStatus', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?policyStatus', ], 'input' => [ 'shape' => 'GetBucketPolicyStatusRequest', ], 'output' => [ 'shape' => 'GetBucketPolicyStatusOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketReplication' => [ 'name' => 'GetBucketReplication', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?replication', ], 'input' => [ 'shape' => 'GetBucketReplicationRequest', ], 'output' => [ 'shape' => 'GetBucketReplicationOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketRequestPayment' => [ 'name' => 'GetBucketRequestPayment', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?requestPayment', ], 'input' => [ 'shape' => 'GetBucketRequestPaymentRequest', ], 'output' => [ 'shape' => 'GetBucketRequestPaymentOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketTagging' => [ 'name' => 'GetBucketTagging', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?tagging', ], 'input' => [ 'shape' => 'GetBucketTaggingRequest', ], 'output' => [ 'shape' => 'GetBucketTaggingOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketVersioning' => [ 'name' => 'GetBucketVersioning', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?versioning', ], 'input' => [ 'shape' => 'GetBucketVersioningRequest', ], 'output' => [ 'shape' => 'GetBucketVersioningOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetBucketWebsite' => [ 'name' => 'GetBucketWebsite', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?website', ], 'input' => [ 'shape' => 'GetBucketWebsiteRequest', ], 'output' => [ 'shape' => 'GetBucketWebsiteOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'GetObject' => [ 'name' => 'GetObject', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'GetObjectRequest', ], 'output' => [ 'shape' => 'GetObjectOutput', ], 'errors' => [ [ 'shape' => 'NoSuchKey', ], [ 'shape' => 'InvalidObjectState', ], ], 'httpChecksum' => [ 'requestValidationModeMember' => 'ChecksumMode', 'responseAlgorithms' => [ 'CRC64NVME', 'CRC32', 'CRC32C', 'SHA256', 'SHA1', ], ], ], 'GetObjectAcl' => [ 'name' => 'GetObjectAcl', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?acl', ], 'input' => [ 'shape' => 'GetObjectAclRequest', ], 'output' => [ 'shape' => 'GetObjectAclOutput', ], 'errors' => [ [ 'shape' => 'NoSuchKey', ], ], ], 'GetObjectAttributes' => [ 'name' => 'GetObjectAttributes', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?attributes', ], 'input' => [ 'shape' => 'GetObjectAttributesRequest', ], 'output' => [ 'shape' => 'GetObjectAttributesOutput', ], 'errors' => [ [ 'shape' => 'NoSuchKey', ], ], ], 'GetObjectLegalHold' => [ 'name' => 'GetObjectLegalHold', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?legal-hold', ], 'input' => [ 'shape' => 'GetObjectLegalHoldRequest', ], 'output' => [ 'shape' => 'GetObjectLegalHoldOutput', ], ], 'GetObjectLockConfiguration' => [ 'name' => 'GetObjectLockConfiguration', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?object-lock', ], 'input' => [ 'shape' => 'GetObjectLockConfigurationRequest', ], 'output' => [ 'shape' => 'GetObjectLockConfigurationOutput', ], ], 'GetObjectRetention' => [ 'name' => 'GetObjectRetention', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?retention', ], 'input' => [ 'shape' => 'GetObjectRetentionRequest', ], 'output' => [ 'shape' => 'GetObjectRetentionOutput', ], ], 'GetObjectTagging' => [ 'name' => 'GetObjectTagging', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?tagging', ], 'input' => [ 'shape' => 'GetObjectTaggingRequest', ], 'output' => [ 'shape' => 'GetObjectTaggingOutput', ], ], 'GetObjectTorrent' => [ 'name' => 'GetObjectTorrent', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}?torrent', ], 'input' => [ 'shape' => 'GetObjectTorrentRequest', ], 'output' => [ 'shape' => 'GetObjectTorrentOutput', ], ], 'GetPublicAccessBlock' => [ 'name' => 'GetPublicAccessBlock', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?publicAccessBlock', ], 'input' => [ 'shape' => 'GetPublicAccessBlockRequest', ], 'output' => [ 'shape' => 'GetPublicAccessBlockOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'HeadBucket' => [ 'name' => 'HeadBucket', 'http' => [ 'method' => 'HEAD', 'requestUri' => '/{Bucket}', ], 'input' => [ 'shape' => 'HeadBucketRequest', ], 'output' => [ 'shape' => 'HeadBucketOutput', ], 'errors' => [ [ 'shape' => 'NoSuchBucket', ], ], ], 'HeadObject' => [ 'name' => 'HeadObject', 'http' => [ 'method' => 'HEAD', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'HeadObjectRequest', ], 'output' => [ 'shape' => 'HeadObjectOutput', ], 'errors' => [ [ 'shape' => 'NoSuchKey', ], ], ], 'ListBucketAnalyticsConfigurations' => [ 'name' => 'ListBucketAnalyticsConfigurations', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?analytics', ], 'input' => [ 'shape' => 'ListBucketAnalyticsConfigurationsRequest', ], 'output' => [ 'shape' => 'ListBucketAnalyticsConfigurationsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'ListBucketIntelligentTieringConfigurations' => [ 'name' => 'ListBucketIntelligentTieringConfigurations', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?intelligent-tiering', ], 'input' => [ 'shape' => 'ListBucketIntelligentTieringConfigurationsRequest', ], 'output' => [ 'shape' => 'ListBucketIntelligentTieringConfigurationsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'ListBucketInventoryConfigurations' => [ 'name' => 'ListBucketInventoryConfigurations', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?inventory', ], 'input' => [ 'shape' => 'ListBucketInventoryConfigurationsRequest', ], 'output' => [ 'shape' => 'ListBucketInventoryConfigurationsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'ListBucketMetricsConfigurations' => [ 'name' => 'ListBucketMetricsConfigurations', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?metrics', ], 'input' => [ 'shape' => 'ListBucketMetricsConfigurationsRequest', ], 'output' => [ 'shape' => 'ListBucketMetricsConfigurationsOutput', ], ], 'ListBuckets' => [ 'name' => 'ListBuckets', 'http' => [ 'method' => 'GET', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListBucketsRequest', ], 'output' => [ 'shape' => 'ListBucketsOutput', ], ], 'ListDirectoryBuckets' => [ 'name' => 'ListDirectoryBuckets', 'http' => [ 'method' => 'GET', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListDirectoryBucketsRequest', ], 'output' => [ 'shape' => 'ListDirectoryBucketsOutput', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'ListMultipartUploads' => [ 'name' => 'ListMultipartUploads', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?uploads', ], 'input' => [ 'shape' => 'ListMultipartUploadsRequest', ], 'output' => [ 'shape' => 'ListMultipartUploadsOutput', ], ], 'ListObjectVersions' => [ 'name' => 'ListObjectVersions', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?versions', ], 'input' => [ 'shape' => 'ListObjectVersionsRequest', ], 'output' => [ 'shape' => 'ListObjectVersionsOutput', ], ], 'ListObjects' => [ 'name' => 'ListObjects', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}', ], 'input' => [ 'shape' => 'ListObjectsRequest', ], 'output' => [ 'shape' => 'ListObjectsOutput', ], 'errors' => [ [ 'shape' => 'NoSuchBucket', ], ], ], 'ListObjectsV2' => [ 'name' => 'ListObjectsV2', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}?list-type=2', ], 'input' => [ 'shape' => 'ListObjectsV2Request', ], 'output' => [ 'shape' => 'ListObjectsV2Output', ], 'errors' => [ [ 'shape' => 'NoSuchBucket', ], ], ], 'ListParts' => [ 'name' => 'ListParts', 'http' => [ 'method' => 'GET', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'ListPartsRequest', ], 'output' => [ 'shape' => 'ListPartsOutput', ], ], 'PutBucketAccelerateConfiguration' => [ 'name' => 'PutBucketAccelerateConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?accelerate', ], 'input' => [ 'shape' => 'PutBucketAccelerateConfigurationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => false, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketAcl' => [ 'name' => 'PutBucketAcl', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?acl', ], 'input' => [ 'shape' => 'PutBucketAclRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketAnalyticsConfiguration' => [ 'name' => 'PutBucketAnalyticsConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?analytics', ], 'input' => [ 'shape' => 'PutBucketAnalyticsConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketCors' => [ 'name' => 'PutBucketCors', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?cors', ], 'input' => [ 'shape' => 'PutBucketCorsRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketEncryption' => [ 'name' => 'PutBucketEncryption', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?encryption', ], 'input' => [ 'shape' => 'PutBucketEncryptionRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketIntelligentTieringConfiguration' => [ 'name' => 'PutBucketIntelligentTieringConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?intelligent-tiering', ], 'input' => [ 'shape' => 'PutBucketIntelligentTieringConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketInventoryConfiguration' => [ 'name' => 'PutBucketInventoryConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?inventory', ], 'input' => [ 'shape' => 'PutBucketInventoryConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketLifecycle' => [ 'name' => 'PutBucketLifecycle', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?lifecycle', ], 'input' => [ 'shape' => 'PutBucketLifecycleRequest', ], 'deprecated' => true, 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketLifecycleConfiguration' => [ 'name' => 'PutBucketLifecycleConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?lifecycle', ], 'input' => [ 'shape' => 'PutBucketLifecycleConfigurationRequest', ], 'output' => [ 'shape' => 'PutBucketLifecycleConfigurationOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketLogging' => [ 'name' => 'PutBucketLogging', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?logging', ], 'input' => [ 'shape' => 'PutBucketLoggingRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketMetricsConfiguration' => [ 'name' => 'PutBucketMetricsConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?metrics', ], 'input' => [ 'shape' => 'PutBucketMetricsConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketNotification' => [ 'name' => 'PutBucketNotification', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?notification', ], 'input' => [ 'shape' => 'PutBucketNotificationRequest', ], 'deprecated' => true, 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketNotificationConfiguration' => [ 'name' => 'PutBucketNotificationConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?notification', ], 'input' => [ 'shape' => 'PutBucketNotificationConfigurationRequest', ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketOwnershipControls' => [ 'name' => 'PutBucketOwnershipControls', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?ownershipControls', ], 'input' => [ 'shape' => 'PutBucketOwnershipControlsRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketPolicy' => [ 'name' => 'PutBucketPolicy', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?policy', ], 'input' => [ 'shape' => 'PutBucketPolicyRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketReplication' => [ 'name' => 'PutBucketReplication', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?replication', ], 'input' => [ 'shape' => 'PutBucketReplicationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketRequestPayment' => [ 'name' => 'PutBucketRequestPayment', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?requestPayment', ], 'input' => [ 'shape' => 'PutBucketRequestPaymentRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketTagging' => [ 'name' => 'PutBucketTagging', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?tagging', ], 'input' => [ 'shape' => 'PutBucketTaggingRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketVersioning' => [ 'name' => 'PutBucketVersioning', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?versioning', ], 'input' => [ 'shape' => 'PutBucketVersioningRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutBucketWebsite' => [ 'name' => 'PutBucketWebsite', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?website', ], 'input' => [ 'shape' => 'PutBucketWebsiteRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'PutObject' => [ 'name' => 'PutObject', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'PutObjectRequest', ], 'output' => [ 'shape' => 'PutObjectOutput', ], 'errors' => [ [ 'shape' => 'InvalidRequest', ], [ 'shape' => 'InvalidWriteOffset', ], [ 'shape' => 'TooManyParts', ], [ 'shape' => 'EncryptionTypeMismatch', ], ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => false, ], ], 'PutObjectAcl' => [ 'name' => 'PutObjectAcl', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}?acl', ], 'input' => [ 'shape' => 'PutObjectAclRequest', ], 'output' => [ 'shape' => 'PutObjectAclOutput', ], 'errors' => [ [ 'shape' => 'NoSuchKey', ], ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'PutObjectLegalHold' => [ 'name' => 'PutObjectLegalHold', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}?legal-hold', ], 'input' => [ 'shape' => 'PutObjectLegalHoldRequest', ], 'output' => [ 'shape' => 'PutObjectLegalHoldOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'PutObjectLockConfiguration' => [ 'name' => 'PutObjectLockConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?object-lock', ], 'input' => [ 'shape' => 'PutObjectLockConfigurationRequest', ], 'output' => [ 'shape' => 'PutObjectLockConfigurationOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'PutObjectRetention' => [ 'name' => 'PutObjectRetention', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}?retention', ], 'input' => [ 'shape' => 'PutObjectRetentionRequest', ], 'output' => [ 'shape' => 'PutObjectRetentionOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'PutObjectTagging' => [ 'name' => 'PutObjectTagging', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}?tagging', ], 'input' => [ 'shape' => 'PutObjectTaggingRequest', ], 'output' => [ 'shape' => 'PutObjectTaggingOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], ], 'PutPublicAccessBlock' => [ 'name' => 'PutPublicAccessBlock', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?publicAccessBlock', ], 'input' => [ 'shape' => 'PutPublicAccessBlockRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'RenameObject' => [ 'name' => 'RenameObject', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}?renameObject', ], 'input' => [ 'shape' => 'RenameObjectRequest', ], 'output' => [ 'shape' => 'RenameObjectOutput', ], 'errors' => [ [ 'shape' => 'IdempotencyParameterMismatch', ], ], ], 'RestoreObject' => [ 'name' => 'RestoreObject', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}/{Key+}?restore', ], 'input' => [ 'shape' => 'RestoreObjectRequest', ], 'output' => [ 'shape' => 'RestoreObjectOutput', ], 'errors' => [ [ 'shape' => 'ObjectAlreadyInActiveTierError', ], ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => false, ], ], 'SelectObjectContent' => [ 'name' => 'SelectObjectContent', 'http' => [ 'method' => 'POST', 'requestUri' => '/{Bucket}/{Key+}?select&select-type=2', ], 'input' => [ 'shape' => 'SelectObjectContentRequest', 'locationName' => 'SelectObjectContentRequest', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'output' => [ 'shape' => 'SelectObjectContentOutput', ], ], 'UpdateBucketMetadataInventoryTableConfiguration' => [ 'name' => 'UpdateBucketMetadataInventoryTableConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?metadataInventoryTable', ], 'input' => [ 'shape' => 'UpdateBucketMetadataInventoryTableConfigurationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'UpdateBucketMetadataJournalTableConfiguration' => [ 'name' => 'UpdateBucketMetadataJournalTableConfiguration', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}?metadataJournalTable', ], 'input' => [ 'shape' => 'UpdateBucketMetadataJournalTableConfigurationRequest', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => true, ], 'staticContextParams' => [ 'UseS3ExpressControlEndpoint' => [ 'value' => true, ], ], ], 'UploadPart' => [ 'name' => 'UploadPart', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'UploadPartRequest', ], 'output' => [ 'shape' => 'UploadPartOutput', ], 'httpChecksum' => [ 'requestAlgorithmMember' => 'ChecksumAlgorithm', 'requestChecksumRequired' => false, ], ], 'UploadPartCopy' => [ 'name' => 'UploadPartCopy', 'http' => [ 'method' => 'PUT', 'requestUri' => '/{Bucket}/{Key+}', ], 'input' => [ 'shape' => 'UploadPartCopyRequest', ], 'output' => [ 'shape' => 'UploadPartCopyOutput', ], 'staticContextParams' => [ 'DisableS3ExpressSessionAuth' => [ 'value' => true, ], ], ], 'WriteGetObjectResponse' => [ 'name' => 'WriteGetObjectResponse', 'http' => [ 'method' => 'POST', 'requestUri' => '/WriteGetObjectResponse', ], 'input' => [ 'shape' => 'WriteGetObjectResponseRequest', ], 'authtype' => 'v4-unsigned-body', 'endpoint' => [ 'hostPrefix' => '{RequestRoute}.', ], 'staticContextParams' => [ 'UseObjectLambdaEndpoint' => [ 'value' => true, ], ], 'unsignedPayload' => true, ], ], 'shapes' => [ 'AbortDate' => [ 'type' => 'timestamp', ], 'AbortIncompleteMultipartUpload' => [ 'type' => 'structure', 'members' => [ 'DaysAfterInitiation' => [ 'shape' => 'DaysAfterInitiation', ], ], ], 'AbortMultipartUploadOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'AbortMultipartUploadRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'UploadId', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', 'location' => 'querystring', 'locationName' => 'uploadId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'IfMatchInitiatedTime' => [ 'shape' => 'IfMatchInitiatedTime', 'location' => 'header', 'locationName' => 'x-amz-if-match-initiated-time', ], ], ], 'AbortRuleId' => [ 'type' => 'string', ], 'AccelerateConfiguration' => [ 'type' => 'structure', 'members' => [ 'Status' => [ 'shape' => 'BucketAccelerateStatus', ], ], ], 'AcceptRanges' => [ 'type' => 'string', ], 'AccessControlPolicy' => [ 'type' => 'structure', 'members' => [ 'Grants' => [ 'shape' => 'Grants', 'locationName' => 'AccessControlList', ], 'Owner' => [ 'shape' => 'Owner', ], ], ], 'AccessControlTranslation' => [ 'type' => 'structure', 'required' => [ 'Owner', ], 'members' => [ 'Owner' => [ 'shape' => 'OwnerOverride', ], ], ], 'AccessKeyIdValue' => [ 'type' => 'string', ], 'AccessPointAlias' => [ 'type' => 'boolean', 'box' => true, ], 'AccessPointArn' => [ 'type' => 'string', ], 'AccountId' => [ 'type' => 'string', ], 'AllowQuotedRecordDelimiter' => [ 'type' => 'boolean', 'box' => true, ], 'AllowedHeader' => [ 'type' => 'string', ], 'AllowedHeaders' => [ 'type' => 'list', 'member' => [ 'shape' => 'AllowedHeader', ], 'flattened' => true, ], 'AllowedMethod' => [ 'type' => 'string', ], 'AllowedMethods' => [ 'type' => 'list', 'member' => [ 'shape' => 'AllowedMethod', ], 'flattened' => true, ], 'AllowedOrigin' => [ 'type' => 'string', ], 'AllowedOrigins' => [ 'type' => 'list', 'member' => [ 'shape' => 'AllowedOrigin', ], 'flattened' => true, ], 'AnalyticsAndOperator' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tags' => [ 'shape' => 'TagSet', 'flattened' => true, 'locationName' => 'Tag', ], ], ], 'AnalyticsConfiguration' => [ 'type' => 'structure', 'required' => [ 'Id', 'StorageClassAnalysis', ], 'members' => [ 'Id' => [ 'shape' => 'AnalyticsId', ], 'Filter' => [ 'shape' => 'AnalyticsFilter', ], 'StorageClassAnalysis' => [ 'shape' => 'StorageClassAnalysis', ], ], ], 'AnalyticsConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'AnalyticsConfiguration', ], 'flattened' => true, ], 'AnalyticsExportDestination' => [ 'type' => 'structure', 'required' => [ 'S3BucketDestination', ], 'members' => [ 'S3BucketDestination' => [ 'shape' => 'AnalyticsS3BucketDestination', ], ], ], 'AnalyticsFilter' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tag' => [ 'shape' => 'Tag', ], 'And' => [ 'shape' => 'AnalyticsAndOperator', ], ], ], 'AnalyticsId' => [ 'type' => 'string', ], 'AnalyticsS3BucketDestination' => [ 'type' => 'structure', 'required' => [ 'Format', 'Bucket', ], 'members' => [ 'Format' => [ 'shape' => 'AnalyticsS3ExportFileFormat', ], 'BucketAccountId' => [ 'shape' => 'AccountId', ], 'Bucket' => [ 'shape' => 'BucketName', ], 'Prefix' => [ 'shape' => 'Prefix', ], ], ], 'AnalyticsS3ExportFileFormat' => [ 'type' => 'string', 'enum' => [ 'CSV', ], ], 'ArchiveStatus' => [ 'type' => 'string', 'enum' => [ 'ARCHIVE_ACCESS', 'DEEP_ARCHIVE_ACCESS', ], ], 'Body' => [ 'type' => 'blob', ], 'Bucket' => [ 'type' => 'structure', 'members' => [ 'Name' => [ 'shape' => 'BucketName', ], 'CreationDate' => [ 'shape' => 'CreationDate', ], 'BucketRegion' => [ 'shape' => 'BucketRegion', ], 'BucketArn' => [ 'shape' => 'S3RegionalOrS3ExpressBucketArnString', ], ], ], 'BucketAccelerateStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Suspended', ], ], 'BucketAlreadyExists' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 409, ], 'exception' => true, ], 'BucketAlreadyOwnedByYou' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 409, ], 'exception' => true, ], 'BucketCannedACL' => [ 'type' => 'string', 'enum' => [ 'private', 'public-read', 'public-read-write', 'authenticated-read', ], ], 'BucketInfo' => [ 'type' => 'structure', 'members' => [ 'DataRedundancy' => [ 'shape' => 'DataRedundancy', ], 'Type' => [ 'shape' => 'BucketType', ], ], ], 'BucketKeyEnabled' => [ 'type' => 'boolean', 'box' => true, ], 'BucketLifecycleConfiguration' => [ 'type' => 'structure', 'required' => [ 'Rules', ], 'members' => [ 'Rules' => [ 'shape' => 'LifecycleRules', 'locationName' => 'Rule', ], ], ], 'BucketLocationConstraint' => [ 'type' => 'string', 'enum' => [ 'af-south-1', 'ap-east-1', 'ap-northeast-1', 'ap-northeast-2', 'ap-northeast-3', 'ap-south-1', 'ap-south-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-southeast-3', 'ap-southeast-4', 'ap-southeast-5', 'ca-central-1', 'cn-north-1', 'cn-northwest-1', 'EU', 'eu-central-1', 'eu-central-2', 'eu-north-1', 'eu-south-1', 'eu-south-2', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'il-central-1', 'me-central-1', 'me-south-1', 'sa-east-1', 'us-east-2', 'us-gov-east-1', 'us-gov-west-1', 'us-west-1', 'us-west-2', ], ], 'BucketLocationName' => [ 'type' => 'string', ], 'BucketLoggingStatus' => [ 'type' => 'structure', 'members' => [ 'LoggingEnabled' => [ 'shape' => 'LoggingEnabled', ], ], ], 'BucketLogsPermission' => [ 'type' => 'string', 'enum' => [ 'FULL_CONTROL', 'READ', 'WRITE', ], ], 'BucketName' => [ 'type' => 'string', ], 'BucketRegion' => [ 'type' => 'string', ], 'BucketType' => [ 'type' => 'string', 'enum' => [ 'Directory', ], ], 'BucketVersioningStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Suspended', ], ], 'Buckets' => [ 'type' => 'list', 'member' => [ 'shape' => 'Bucket', 'locationName' => 'Bucket', ], ], 'BypassGovernanceRetention' => [ 'type' => 'boolean', 'box' => true, ], 'BytesProcessed' => [ 'type' => 'long', 'box' => true, ], 'BytesReturned' => [ 'type' => 'long', 'box' => true, ], 'BytesScanned' => [ 'type' => 'long', 'box' => true, ], 'CORSConfiguration' => [ 'type' => 'structure', 'required' => [ 'CORSRules', ], 'members' => [ 'CORSRules' => [ 'shape' => 'CORSRules', 'locationName' => 'CORSRule', ], ], ], 'CORSRule' => [ 'type' => 'structure', 'required' => [ 'AllowedMethods', 'AllowedOrigins', ], 'members' => [ 'ID' => [ 'shape' => 'ID', ], 'AllowedHeaders' => [ 'shape' => 'AllowedHeaders', 'locationName' => 'AllowedHeader', ], 'AllowedMethods' => [ 'shape' => 'AllowedMethods', 'locationName' => 'AllowedMethod', ], 'AllowedOrigins' => [ 'shape' => 'AllowedOrigins', 'locationName' => 'AllowedOrigin', ], 'ExposeHeaders' => [ 'shape' => 'ExposeHeaders', 'locationName' => 'ExposeHeader', ], 'MaxAgeSeconds' => [ 'shape' => 'MaxAgeSeconds', ], ], ], 'CORSRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'CORSRule', ], 'flattened' => true, ], 'CSVInput' => [ 'type' => 'structure', 'members' => [ 'FileHeaderInfo' => [ 'shape' => 'FileHeaderInfo', ], 'Comments' => [ 'shape' => 'Comments', ], 'QuoteEscapeCharacter' => [ 'shape' => 'QuoteEscapeCharacter', ], 'RecordDelimiter' => [ 'shape' => 'RecordDelimiter', ], 'FieldDelimiter' => [ 'shape' => 'FieldDelimiter', ], 'QuoteCharacter' => [ 'shape' => 'QuoteCharacter', ], 'AllowQuotedRecordDelimiter' => [ 'shape' => 'AllowQuotedRecordDelimiter', ], ], ], 'CSVOutput' => [ 'type' => 'structure', 'members' => [ 'QuoteFields' => [ 'shape' => 'QuoteFields', ], 'QuoteEscapeCharacter' => [ 'shape' => 'QuoteEscapeCharacter', ], 'RecordDelimiter' => [ 'shape' => 'RecordDelimiter', ], 'FieldDelimiter' => [ 'shape' => 'FieldDelimiter', ], 'QuoteCharacter' => [ 'shape' => 'QuoteCharacter', ], ], ], 'CacheControl' => [ 'type' => 'string', ], 'Checksum' => [ 'type' => 'structure', 'members' => [ 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], ], ], 'ChecksumAlgorithm' => [ 'type' => 'string', 'enum' => [ 'CRC32', 'CRC32C', 'SHA1', 'SHA256', 'CRC64NVME', ], ], 'ChecksumAlgorithmList' => [ 'type' => 'list', 'member' => [ 'shape' => 'ChecksumAlgorithm', ], 'flattened' => true, ], 'ChecksumCRC32' => [ 'type' => 'string', ], 'ChecksumCRC32C' => [ 'type' => 'string', ], 'ChecksumCRC64NVME' => [ 'type' => 'string', ], 'ChecksumMode' => [ 'type' => 'string', 'enum' => [ 'ENABLED', ], ], 'ChecksumSHA1' => [ 'type' => 'string', ], 'ChecksumSHA256' => [ 'type' => 'string', ], 'ChecksumType' => [ 'type' => 'string', 'enum' => [ 'COMPOSITE', 'FULL_OBJECT', ], ], 'ClientToken' => [ 'type' => 'string', ], 'CloudFunction' => [ 'type' => 'string', ], 'CloudFunctionConfiguration' => [ 'type' => 'structure', 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'Event' => [ 'shape' => 'Event', 'deprecated' => true, ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'CloudFunction' => [ 'shape' => 'CloudFunction', ], 'InvocationRole' => [ 'shape' => 'CloudFunctionInvocationRole', ], ], ], 'CloudFunctionInvocationRole' => [ 'type' => 'string', ], 'Code' => [ 'type' => 'string', ], 'Comments' => [ 'type' => 'string', ], 'CommonPrefix' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], ], ], 'CommonPrefixList' => [ 'type' => 'list', 'member' => [ 'shape' => 'CommonPrefix', ], 'flattened' => true, ], 'CompleteMultipartUploadOutput' => [ 'type' => 'structure', 'members' => [ 'Location' => [ 'shape' => 'Location', ], 'Bucket' => [ 'shape' => 'BucketName', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-expiration', ], 'ETag' => [ 'shape' => 'ETag', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'CompleteMultipartUploadRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'UploadId', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'MultipartUpload' => [ 'shape' => 'CompletedMultipartUpload', 'locationName' => 'CompleteMultipartUpload', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'UploadId' => [ 'shape' => 'MultipartUploadId', 'location' => 'querystring', 'locationName' => 'uploadId', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], 'MpuObjectSize' => [ 'shape' => 'MpuObjectSize', 'location' => 'header', 'locationName' => 'x-amz-mp-object-size', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'IfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'IfNoneMatch' => [ 'shape' => 'IfNoneMatch', 'location' => 'header', 'locationName' => 'If-None-Match', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], ], 'payload' => 'MultipartUpload', ], 'CompletedMultipartUpload' => [ 'type' => 'structure', 'members' => [ 'Parts' => [ 'shape' => 'CompletedPartList', 'locationName' => 'Part', ], ], ], 'CompletedPart' => [ 'type' => 'structure', 'members' => [ 'ETag' => [ 'shape' => 'ETag', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], 'PartNumber' => [ 'shape' => 'PartNumber', ], ], ], 'CompletedPartList' => [ 'type' => 'list', 'member' => [ 'shape' => 'CompletedPart', ], 'flattened' => true, ], 'CompressionType' => [ 'type' => 'string', 'enum' => [ 'NONE', 'GZIP', 'BZIP2', ], ], 'Condition' => [ 'type' => 'structure', 'members' => [ 'HttpErrorCodeReturnedEquals' => [ 'shape' => 'HttpErrorCodeReturnedEquals', ], 'KeyPrefixEquals' => [ 'shape' => 'KeyPrefixEquals', ], ], ], 'ConfirmRemoveSelfBucketAccess' => [ 'type' => 'boolean', 'box' => true, ], 'ContentDisposition' => [ 'type' => 'string', ], 'ContentEncoding' => [ 'type' => 'string', ], 'ContentLanguage' => [ 'type' => 'string', ], 'ContentLength' => [ 'type' => 'long', ], 'ContentMD5' => [ 'type' => 'string', ], 'ContentRange' => [ 'type' => 'string', ], 'ContentType' => [ 'type' => 'string', ], 'ContinuationEvent' => [ 'type' => 'structure', 'members' => [], 'event' => true, ], 'CopyObjectOutput' => [ 'type' => 'structure', 'members' => [ 'CopyObjectResult' => [ 'shape' => 'CopyObjectResult', ], 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-expiration', ], 'CopySourceVersionId' => [ 'shape' => 'CopySourceVersionId', 'location' => 'header', 'locationName' => 'x-amz-copy-source-version-id', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], 'payload' => 'CopyObjectResult', ], 'CopyObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'CopySource', 'Key', ], 'members' => [ 'ACL' => [ 'shape' => 'ObjectCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'Cache-Control', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-checksum-algorithm', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'Content-Language', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'Content-Type', ], 'CopySource' => [ 'shape' => 'CopySource', 'contextParam' => [ 'name' => 'CopySource', ], 'location' => 'header', 'locationName' => 'x-amz-copy-source', ], 'CopySourceIfMatch' => [ 'shape' => 'CopySourceIfMatch', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-match', ], 'CopySourceIfModifiedSince' => [ 'shape' => 'CopySourceIfModifiedSince', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-modified-since', ], 'CopySourceIfNoneMatch' => [ 'shape' => 'CopySourceIfNoneMatch', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-none-match', ], 'CopySourceIfUnmodifiedSince' => [ 'shape' => 'CopySourceIfUnmodifiedSince', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-unmodified-since', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'Expires', ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'MetadataDirective' => [ 'shape' => 'MetadataDirective', 'location' => 'header', 'locationName' => 'x-amz-metadata-directive', ], 'TaggingDirective' => [ 'shape' => 'TaggingDirective', 'location' => 'header', 'locationName' => 'x-amz-tagging-directive', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-storage-class', ], 'WebsiteRedirectLocation' => [ 'shape' => 'WebsiteRedirectLocation', 'location' => 'header', 'locationName' => 'x-amz-website-redirect-location', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'CopySourceSSECustomerAlgorithm' => [ 'shape' => 'CopySourceSSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-algorithm', ], 'CopySourceSSECustomerKey' => [ 'shape' => 'CopySourceSSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-key', ], 'CopySourceSSECustomerKeyMD5' => [ 'shape' => 'CopySourceSSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'Tagging' => [ 'shape' => 'TaggingHeader', 'location' => 'header', 'locationName' => 'x-amz-tagging', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-object-lock-mode', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-object-lock-retain-until-date', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-object-lock-legal-hold', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ExpectedSourceBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-source-expected-bucket-owner', ], ], ], 'CopyObjectResult' => [ 'type' => 'structure', 'members' => [ 'ETag' => [ 'shape' => 'ETag', ], 'LastModified' => [ 'shape' => 'LastModified', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], ], ], 'CopyPartResult' => [ 'type' => 'structure', 'members' => [ 'ETag' => [ 'shape' => 'ETag', ], 'LastModified' => [ 'shape' => 'LastModified', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], ], ], 'CopySource' => [ 'type' => 'string', 'pattern' => '\\/?.+\\/.+', ], 'CopySourceIfMatch' => [ 'type' => 'string', ], 'CopySourceIfModifiedSince' => [ 'type' => 'timestamp', ], 'CopySourceIfNoneMatch' => [ 'type' => 'string', ], 'CopySourceIfUnmodifiedSince' => [ 'type' => 'timestamp', ], 'CopySourceRange' => [ 'type' => 'string', ], 'CopySourceSSECustomerAlgorithm' => [ 'type' => 'string', ], 'CopySourceSSECustomerKey' => [ 'type' => 'string', 'sensitive' => true, ], 'CopySourceSSECustomerKeyMD5' => [ 'type' => 'string', ], 'CopySourceVersionId' => [ 'type' => 'string', ], 'CreateBucketConfiguration' => [ 'type' => 'structure', 'members' => [ 'LocationConstraint' => [ 'shape' => 'BucketLocationConstraint', ], 'Location' => [ 'shape' => 'LocationInfo', ], 'Bucket' => [ 'shape' => 'BucketInfo', ], 'Tags' => [ 'shape' => 'TagSet', ], ], ], 'CreateBucketMetadataConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'MetadataConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'MetadataConfiguration' => [ 'shape' => 'MetadataConfiguration', 'locationName' => 'MetadataConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'MetadataConfiguration', ], 'CreateBucketMetadataTableConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'MetadataTableConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'MetadataTableConfiguration' => [ 'shape' => 'MetadataTableConfiguration', 'locationName' => 'MetadataTableConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'MetadataTableConfiguration', ], 'CreateBucketOutput' => [ 'type' => 'structure', 'members' => [ 'Location' => [ 'shape' => 'Location', 'location' => 'header', 'locationName' => 'Location', ], 'BucketArn' => [ 'shape' => 'S3RegionalOrS3ExpressBucketArnString', 'location' => 'header', 'locationName' => 'x-amz-bucket-arn', ], ], ], 'CreateBucketRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'ACL' => [ 'shape' => 'BucketCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CreateBucketConfiguration' => [ 'shape' => 'CreateBucketConfiguration', 'locationName' => 'CreateBucketConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWrite' => [ 'shape' => 'GrantWrite', 'location' => 'header', 'locationName' => 'x-amz-grant-write', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'ObjectLockEnabledForBucket' => [ 'shape' => 'ObjectLockEnabledForBucket', 'location' => 'header', 'locationName' => 'x-amz-bucket-object-lock-enabled', ], 'ObjectOwnership' => [ 'shape' => 'ObjectOwnership', 'location' => 'header', 'locationName' => 'x-amz-object-ownership', ], ], 'payload' => 'CreateBucketConfiguration', ], 'CreateMultipartUploadOutput' => [ 'type' => 'structure', 'members' => [ 'AbortDate' => [ 'shape' => 'AbortDate', 'location' => 'header', 'locationName' => 'x-amz-abort-date', ], 'AbortRuleId' => [ 'shape' => 'AbortRuleId', 'location' => 'header', 'locationName' => 'x-amz-abort-rule-id', ], 'Bucket' => [ 'shape' => 'BucketName', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-checksum-algorithm', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], ], ], 'CreateMultipartUploadRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'ACL' => [ 'shape' => 'ObjectCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'Cache-Control', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'Content-Language', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'Content-Type', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'Expires', ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-storage-class', ], 'WebsiteRedirectLocation' => [ 'shape' => 'WebsiteRedirectLocation', 'location' => 'header', 'locationName' => 'x-amz-website-redirect-location', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'Tagging' => [ 'shape' => 'TaggingHeader', 'location' => 'header', 'locationName' => 'x-amz-tagging', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-object-lock-mode', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-object-lock-retain-until-date', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-object-lock-legal-hold', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-checksum-algorithm', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], ], ], 'CreateSessionOutput' => [ 'type' => 'structure', 'required' => [ 'Credentials', ], 'members' => [ 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'Credentials' => [ 'shape' => 'SessionCredentials', 'locationName' => 'Credentials', ], ], ], 'CreateSessionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'SessionMode' => [ 'shape' => 'SessionMode', 'location' => 'header', 'locationName' => 'x-amz-create-session-mode', ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], ], ], 'CreationDate' => [ 'type' => 'timestamp', ], 'DataRedundancy' => [ 'type' => 'string', 'enum' => [ 'SingleAvailabilityZone', 'SingleLocalZone', ], ], 'Date' => [ 'type' => 'timestamp', 'timestampFormat' => 'iso8601', ], 'Days' => [ 'type' => 'integer', 'box' => true, ], 'DaysAfterInitiation' => [ 'type' => 'integer', 'box' => true, ], 'DefaultRetention' => [ 'type' => 'structure', 'members' => [ 'Mode' => [ 'shape' => 'ObjectLockRetentionMode', ], 'Days' => [ 'shape' => 'Days', ], 'Years' => [ 'shape' => 'Years', ], ], ], 'Delete' => [ 'type' => 'structure', 'required' => [ 'Objects', ], 'members' => [ 'Objects' => [ 'shape' => 'ObjectIdentifierList', 'locationName' => 'Object', ], 'Quiet' => [ 'shape' => 'Quiet', ], ], ], 'DeleteBucketAnalyticsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'AnalyticsId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketCorsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketEncryptionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketIntelligentTieringConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'IntelligentTieringId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketInventoryConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'InventoryId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketLifecycleRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketMetadataConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketMetadataTableConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketMetricsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'MetricsId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketOwnershipControlsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketPolicyRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketReplicationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteBucketWebsiteRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteMarker' => [ 'type' => 'boolean', ], 'DeleteMarkerEntry' => [ 'type' => 'structure', 'members' => [ 'Owner' => [ 'shape' => 'Owner', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', ], 'IsLatest' => [ 'shape' => 'IsLatest', ], 'LastModified' => [ 'shape' => 'LastModified', ], ], ], 'DeleteMarkerReplication' => [ 'type' => 'structure', 'members' => [ 'Status' => [ 'shape' => 'DeleteMarkerReplicationStatus', ], ], ], 'DeleteMarkerReplicationStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'DeleteMarkerVersionId' => [ 'type' => 'string', ], 'DeleteMarkers' => [ 'type' => 'list', 'member' => [ 'shape' => 'DeleteMarkerEntry', ], 'flattened' => true, ], 'DeleteObjectOutput' => [ 'type' => 'structure', 'members' => [ 'DeleteMarker' => [ 'shape' => 'DeleteMarker', 'location' => 'header', 'locationName' => 'x-amz-delete-marker', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'DeleteObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'MFA' => [ 'shape' => 'MFA', 'location' => 'header', 'locationName' => 'x-amz-mfa', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'BypassGovernanceRetention' => [ 'shape' => 'BypassGovernanceRetention', 'location' => 'header', 'locationName' => 'x-amz-bypass-governance-retention', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'IfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'IfMatchLastModifiedTime' => [ 'shape' => 'IfMatchLastModifiedTime', 'location' => 'header', 'locationName' => 'x-amz-if-match-last-modified-time', ], 'IfMatchSize' => [ 'shape' => 'IfMatchSize', 'location' => 'header', 'locationName' => 'x-amz-if-match-size', ], ], ], 'DeleteObjectTaggingOutput' => [ 'type' => 'structure', 'members' => [ 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], ], ], 'DeleteObjectTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeleteObjectsOutput' => [ 'type' => 'structure', 'members' => [ 'Deleted' => [ 'shape' => 'DeletedObjects', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'Errors' => [ 'shape' => 'Errors', 'locationName' => 'Error', ], ], ], 'DeleteObjectsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Delete', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Delete' => [ 'shape' => 'Delete', 'locationName' => 'Delete', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'MFA' => [ 'shape' => 'MFA', 'location' => 'header', 'locationName' => 'x-amz-mfa', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'BypassGovernanceRetention' => [ 'shape' => 'BypassGovernanceRetention', 'location' => 'header', 'locationName' => 'x-amz-bypass-governance-retention', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], ], 'payload' => 'Delete', ], 'DeletePublicAccessBlockRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'DeletedObject' => [ 'type' => 'structure', 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', ], 'DeleteMarker' => [ 'shape' => 'DeleteMarker', ], 'DeleteMarkerVersionId' => [ 'shape' => 'DeleteMarkerVersionId', ], ], ], 'DeletedObjects' => [ 'type' => 'list', 'member' => [ 'shape' => 'DeletedObject', ], 'flattened' => true, ], 'Delimiter' => [ 'type' => 'string', ], 'Description' => [ 'type' => 'string', ], 'Destination' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', ], 'Account' => [ 'shape' => 'AccountId', ], 'StorageClass' => [ 'shape' => 'StorageClass', ], 'AccessControlTranslation' => [ 'shape' => 'AccessControlTranslation', ], 'EncryptionConfiguration' => [ 'shape' => 'EncryptionConfiguration', ], 'ReplicationTime' => [ 'shape' => 'ReplicationTime', ], 'Metrics' => [ 'shape' => 'Metrics', ], ], ], 'DestinationResult' => [ 'type' => 'structure', 'members' => [ 'TableBucketType' => [ 'shape' => 'S3TablesBucketType', ], 'TableBucketArn' => [ 'shape' => 'S3TablesBucketArn', ], 'TableNamespace' => [ 'shape' => 'S3TablesNamespace', ], ], ], 'DirectoryBucketToken' => [ 'type' => 'string', 'max' => 1024, 'min' => 0, ], 'DisplayName' => [ 'type' => 'string', ], 'ETag' => [ 'type' => 'string', ], 'EmailAddress' => [ 'type' => 'string', ], 'EnableRequestProgress' => [ 'type' => 'boolean', 'box' => true, ], 'EncodingType' => [ 'type' => 'string', 'enum' => [ 'url', ], ], 'Encryption' => [ 'type' => 'structure', 'required' => [ 'EncryptionType', ], 'members' => [ 'EncryptionType' => [ 'shape' => 'ServerSideEncryption', ], 'KMSKeyId' => [ 'shape' => 'SSEKMSKeyId', ], 'KMSContext' => [ 'shape' => 'KMSContext', ], ], ], 'EncryptionConfiguration' => [ 'type' => 'structure', 'members' => [ 'ReplicaKmsKeyID' => [ 'shape' => 'ReplicaKmsKeyID', ], ], ], 'EncryptionTypeMismatch' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'End' => [ 'type' => 'long', 'box' => true, ], 'EndEvent' => [ 'type' => 'structure', 'members' => [], 'event' => true, ], 'Error' => [ 'type' => 'structure', 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', ], 'Code' => [ 'shape' => 'Code', ], 'Message' => [ 'shape' => 'Message', ], ], ], 'ErrorCode' => [ 'type' => 'string', ], 'ErrorDetails' => [ 'type' => 'structure', 'members' => [ 'ErrorCode' => [ 'shape' => 'ErrorCode', ], 'ErrorMessage' => [ 'shape' => 'ErrorMessage', ], ], ], 'ErrorDocument' => [ 'type' => 'structure', 'required' => [ 'Key', ], 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], ], ], 'ErrorMessage' => [ 'type' => 'string', ], 'Errors' => [ 'type' => 'list', 'member' => [ 'shape' => 'Error', ], 'flattened' => true, ], 'Event' => [ 'type' => 'string', 'enum' => [ 's3:ReducedRedundancyLostObject', 's3:ObjectCreated:*', 's3:ObjectCreated:Put', 's3:ObjectCreated:Post', 's3:ObjectCreated:Copy', 's3:ObjectCreated:CompleteMultipartUpload', 's3:ObjectRemoved:*', 's3:ObjectRemoved:Delete', 's3:ObjectRemoved:DeleteMarkerCreated', 's3:ObjectRestore:*', 's3:ObjectRestore:Post', 's3:ObjectRestore:Completed', 's3:Replication:*', 's3:Replication:OperationFailedReplication', 's3:Replication:OperationNotTracked', 's3:Replication:OperationMissedThreshold', 's3:Replication:OperationReplicatedAfterThreshold', 's3:ObjectRestore:Delete', 's3:LifecycleTransition', 's3:IntelligentTiering', 's3:ObjectAcl:Put', 's3:LifecycleExpiration:*', 's3:LifecycleExpiration:Delete', 's3:LifecycleExpiration:DeleteMarkerCreated', 's3:ObjectTagging:*', 's3:ObjectTagging:Put', 's3:ObjectTagging:Delete', ], ], 'EventBridgeConfiguration' => [ 'type' => 'structure', 'members' => [], ], 'EventList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Event', ], 'flattened' => true, ], 'ExistingObjectReplication' => [ 'type' => 'structure', 'required' => [ 'Status', ], 'members' => [ 'Status' => [ 'shape' => 'ExistingObjectReplicationStatus', ], ], ], 'ExistingObjectReplicationStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'Expiration' => [ 'type' => 'string', ], 'ExpirationState' => [ 'type' => 'string', 'enum' => [ 'ENABLED', 'DISABLED', ], ], 'ExpirationStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'ExpiredObjectDeleteMarker' => [ 'type' => 'boolean', 'box' => true, ], 'Expires' => [ 'type' => 'timestamp', ], 'ExposeHeader' => [ 'type' => 'string', ], 'ExposeHeaders' => [ 'type' => 'list', 'member' => [ 'shape' => 'ExposeHeader', ], 'flattened' => true, ], 'Expression' => [ 'type' => 'string', ], 'ExpressionType' => [ 'type' => 'string', 'enum' => [ 'SQL', ], ], 'FetchOwner' => [ 'type' => 'boolean', 'box' => true, ], 'FieldDelimiter' => [ 'type' => 'string', ], 'FileHeaderInfo' => [ 'type' => 'string', 'enum' => [ 'USE', 'IGNORE', 'NONE', ], ], 'FilterRule' => [ 'type' => 'structure', 'members' => [ 'Name' => [ 'shape' => 'FilterRuleName', ], 'Value' => [ 'shape' => 'FilterRuleValue', ], ], ], 'FilterRuleList' => [ 'type' => 'list', 'member' => [ 'shape' => 'FilterRule', ], 'flattened' => true, ], 'FilterRuleName' => [ 'type' => 'string', 'enum' => [ 'prefix', 'suffix', ], ], 'FilterRuleValue' => [ 'type' => 'string', ], 'GetBucketAccelerateConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'Status' => [ 'shape' => 'BucketAccelerateStatus', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'GetBucketAccelerateConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], ], ], 'GetBucketAclOutput' => [ 'type' => 'structure', 'members' => [ 'Owner' => [ 'shape' => 'Owner', ], 'Grants' => [ 'shape' => 'Grants', 'locationName' => 'AccessControlList', ], ], ], 'GetBucketAclRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketAnalyticsConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'AnalyticsConfiguration' => [ 'shape' => 'AnalyticsConfiguration', ], ], 'payload' => 'AnalyticsConfiguration', ], 'GetBucketAnalyticsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'AnalyticsId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketCorsOutput' => [ 'type' => 'structure', 'members' => [ 'CORSRules' => [ 'shape' => 'CORSRules', 'locationName' => 'CORSRule', ], ], ], 'GetBucketCorsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketEncryptionOutput' => [ 'type' => 'structure', 'members' => [ 'ServerSideEncryptionConfiguration' => [ 'shape' => 'ServerSideEncryptionConfiguration', ], ], 'payload' => 'ServerSideEncryptionConfiguration', ], 'GetBucketEncryptionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketIntelligentTieringConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'IntelligentTieringConfiguration' => [ 'shape' => 'IntelligentTieringConfiguration', ], ], 'payload' => 'IntelligentTieringConfiguration', ], 'GetBucketIntelligentTieringConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'IntelligentTieringId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketInventoryConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'InventoryConfiguration' => [ 'shape' => 'InventoryConfiguration', ], ], 'payload' => 'InventoryConfiguration', ], 'GetBucketInventoryConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'InventoryId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketLifecycleConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'Rules' => [ 'shape' => 'LifecycleRules', 'locationName' => 'Rule', ], 'TransitionDefaultMinimumObjectSize' => [ 'shape' => 'TransitionDefaultMinimumObjectSize', 'location' => 'header', 'locationName' => 'x-amz-transition-default-minimum-object-size', ], ], ], 'GetBucketLifecycleConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketLifecycleOutput' => [ 'type' => 'structure', 'members' => [ 'Rules' => [ 'shape' => 'Rules', 'locationName' => 'Rule', ], ], ], 'GetBucketLifecycleRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketLocationOutput' => [ 'type' => 'structure', 'members' => [ 'LocationConstraint' => [ 'shape' => 'BucketLocationConstraint', ], ], ], 'GetBucketLocationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketLoggingOutput' => [ 'type' => 'structure', 'members' => [ 'LoggingEnabled' => [ 'shape' => 'LoggingEnabled', ], ], ], 'GetBucketLoggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketMetadataConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'GetBucketMetadataConfigurationResult' => [ 'shape' => 'GetBucketMetadataConfigurationResult', ], ], 'payload' => 'GetBucketMetadataConfigurationResult', ], 'GetBucketMetadataConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketMetadataConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'MetadataConfigurationResult', ], 'members' => [ 'MetadataConfigurationResult' => [ 'shape' => 'MetadataConfigurationResult', ], ], ], 'GetBucketMetadataTableConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'GetBucketMetadataTableConfigurationResult' => [ 'shape' => 'GetBucketMetadataTableConfigurationResult', ], ], 'payload' => 'GetBucketMetadataTableConfigurationResult', ], 'GetBucketMetadataTableConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketMetadataTableConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'MetadataTableConfigurationResult', 'Status', ], 'members' => [ 'MetadataTableConfigurationResult' => [ 'shape' => 'MetadataTableConfigurationResult', ], 'Status' => [ 'shape' => 'MetadataTableStatus', ], 'Error' => [ 'shape' => 'ErrorDetails', ], ], ], 'GetBucketMetricsConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'MetricsConfiguration' => [ 'shape' => 'MetricsConfiguration', ], ], 'payload' => 'MetricsConfiguration', ], 'GetBucketMetricsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'MetricsId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketNotificationConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketOwnershipControlsOutput' => [ 'type' => 'structure', 'members' => [ 'OwnershipControls' => [ 'shape' => 'OwnershipControls', ], ], 'payload' => 'OwnershipControls', ], 'GetBucketOwnershipControlsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketPolicyOutput' => [ 'type' => 'structure', 'members' => [ 'Policy' => [ 'shape' => 'Policy', ], ], 'payload' => 'Policy', ], 'GetBucketPolicyRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketPolicyStatusOutput' => [ 'type' => 'structure', 'members' => [ 'PolicyStatus' => [ 'shape' => 'PolicyStatus', ], ], 'payload' => 'PolicyStatus', ], 'GetBucketPolicyStatusRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketReplicationOutput' => [ 'type' => 'structure', 'members' => [ 'ReplicationConfiguration' => [ 'shape' => 'ReplicationConfiguration', ], ], 'payload' => 'ReplicationConfiguration', ], 'GetBucketReplicationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketRequestPaymentOutput' => [ 'type' => 'structure', 'members' => [ 'Payer' => [ 'shape' => 'Payer', ], ], ], 'GetBucketRequestPaymentRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketTaggingOutput' => [ 'type' => 'structure', 'required' => [ 'TagSet', ], 'members' => [ 'TagSet' => [ 'shape' => 'TagSet', ], ], ], 'GetBucketTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketVersioningOutput' => [ 'type' => 'structure', 'members' => [ 'Status' => [ 'shape' => 'BucketVersioningStatus', ], 'MFADelete' => [ 'shape' => 'MFADeleteStatus', 'locationName' => 'MfaDelete', ], ], ], 'GetBucketVersioningRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetBucketWebsiteOutput' => [ 'type' => 'structure', 'members' => [ 'RedirectAllRequestsTo' => [ 'shape' => 'RedirectAllRequestsTo', ], 'IndexDocument' => [ 'shape' => 'IndexDocument', ], 'ErrorDocument' => [ 'shape' => 'ErrorDocument', ], 'RoutingRules' => [ 'shape' => 'RoutingRules', ], ], ], 'GetBucketWebsiteRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetObjectAclOutput' => [ 'type' => 'structure', 'members' => [ 'Owner' => [ 'shape' => 'Owner', ], 'Grants' => [ 'shape' => 'Grants', 'locationName' => 'AccessControlList', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'GetObjectAclRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetObjectAttributesOutput' => [ 'type' => 'structure', 'members' => [ 'DeleteMarker' => [ 'shape' => 'DeleteMarker', 'location' => 'header', 'locationName' => 'x-amz-delete-marker', ], 'LastModified' => [ 'shape' => 'LastModified', 'location' => 'header', 'locationName' => 'Last-Modified', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'ETag' => [ 'shape' => 'ETag', ], 'Checksum' => [ 'shape' => 'Checksum', ], 'ObjectParts' => [ 'shape' => 'GetObjectAttributesParts', ], 'StorageClass' => [ 'shape' => 'StorageClass', ], 'ObjectSize' => [ 'shape' => 'ObjectSize', ], ], ], 'GetObjectAttributesParts' => [ 'type' => 'structure', 'members' => [ 'TotalPartsCount' => [ 'shape' => 'PartsCount', 'locationName' => 'PartsCount', ], 'PartNumberMarker' => [ 'shape' => 'PartNumberMarker', ], 'NextPartNumberMarker' => [ 'shape' => 'NextPartNumberMarker', ], 'MaxParts' => [ 'shape' => 'MaxParts', ], 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'Parts' => [ 'shape' => 'PartsList', 'locationName' => 'Part', ], ], ], 'GetObjectAttributesRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'ObjectAttributes', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'MaxParts' => [ 'shape' => 'MaxParts', 'location' => 'header', 'locationName' => 'x-amz-max-parts', ], 'PartNumberMarker' => [ 'shape' => 'PartNumberMarker', 'location' => 'header', 'locationName' => 'x-amz-part-number-marker', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ObjectAttributes' => [ 'shape' => 'ObjectAttributesList', 'location' => 'header', 'locationName' => 'x-amz-object-attributes', ], ], ], 'GetObjectLegalHoldOutput' => [ 'type' => 'structure', 'members' => [ 'LegalHold' => [ 'shape' => 'ObjectLockLegalHold', 'locationName' => 'LegalHold', ], ], 'payload' => 'LegalHold', ], 'GetObjectLegalHoldRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetObjectLockConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'ObjectLockConfiguration' => [ 'shape' => 'ObjectLockConfiguration', ], ], 'payload' => 'ObjectLockConfiguration', ], 'GetObjectLockConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetObjectOutput' => [ 'type' => 'structure', 'members' => [ 'Body' => [ 'shape' => 'Body', 'streaming' => true, ], 'DeleteMarker' => [ 'shape' => 'DeleteMarker', 'location' => 'header', 'locationName' => 'x-amz-delete-marker', ], 'AcceptRanges' => [ 'shape' => 'AcceptRanges', 'location' => 'header', 'locationName' => 'accept-ranges', ], 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-expiration', ], 'Restore' => [ 'shape' => 'Restore', 'location' => 'header', 'locationName' => 'x-amz-restore', ], 'LastModified' => [ 'shape' => 'LastModified', 'location' => 'header', 'locationName' => 'Last-Modified', ], 'ContentLength' => [ 'shape' => 'ContentLength', 'location' => 'header', 'locationName' => 'Content-Length', ], 'ETag' => [ 'shape' => 'ETag', 'location' => 'header', 'locationName' => 'ETag', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], 'MissingMeta' => [ 'shape' => 'MissingMeta', 'location' => 'header', 'locationName' => 'x-amz-missing-meta', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'Cache-Control', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'Content-Language', ], 'ContentRange' => [ 'shape' => 'ContentRange', 'location' => 'header', 'locationName' => 'Content-Range', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'Content-Type', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'Expires', ], 'WebsiteRedirectLocation' => [ 'shape' => 'WebsiteRedirectLocation', 'location' => 'header', 'locationName' => 'x-amz-website-redirect-location', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-storage-class', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'ReplicationStatus' => [ 'shape' => 'ReplicationStatus', 'location' => 'header', 'locationName' => 'x-amz-replication-status', ], 'PartsCount' => [ 'shape' => 'PartsCount', 'location' => 'header', 'locationName' => 'x-amz-mp-parts-count', ], 'TagCount' => [ 'shape' => 'TagCount', 'location' => 'header', 'locationName' => 'x-amz-tagging-count', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-object-lock-mode', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-object-lock-retain-until-date', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-object-lock-legal-hold', ], ], 'payload' => 'Body', ], 'GetObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'IfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'IfModifiedSince' => [ 'shape' => 'IfModifiedSince', 'location' => 'header', 'locationName' => 'If-Modified-Since', ], 'IfNoneMatch' => [ 'shape' => 'IfNoneMatch', 'location' => 'header', 'locationName' => 'If-None-Match', ], 'IfUnmodifiedSince' => [ 'shape' => 'IfUnmodifiedSince', 'location' => 'header', 'locationName' => 'If-Unmodified-Since', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'Range' => [ 'shape' => 'Range', 'location' => 'header', 'locationName' => 'Range', ], 'ResponseCacheControl' => [ 'shape' => 'ResponseCacheControl', 'location' => 'querystring', 'locationName' => 'response-cache-control', ], 'ResponseContentDisposition' => [ 'shape' => 'ResponseContentDisposition', 'location' => 'querystring', 'locationName' => 'response-content-disposition', ], 'ResponseContentEncoding' => [ 'shape' => 'ResponseContentEncoding', 'location' => 'querystring', 'locationName' => 'response-content-encoding', ], 'ResponseContentLanguage' => [ 'shape' => 'ResponseContentLanguage', 'location' => 'querystring', 'locationName' => 'response-content-language', ], 'ResponseContentType' => [ 'shape' => 'ResponseContentType', 'location' => 'querystring', 'locationName' => 'response-content-type', ], 'ResponseExpires' => [ 'shape' => 'ResponseExpires', 'location' => 'querystring', 'locationName' => 'response-expires', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'PartNumber' => [ 'shape' => 'PartNumber', 'location' => 'querystring', 'locationName' => 'partNumber', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ChecksumMode' => [ 'shape' => 'ChecksumMode', 'location' => 'header', 'locationName' => 'x-amz-checksum-mode', ], ], ], 'GetObjectResponseStatusCode' => [ 'type' => 'integer', 'box' => true, ], 'GetObjectRetentionOutput' => [ 'type' => 'structure', 'members' => [ 'Retention' => [ 'shape' => 'ObjectLockRetention', 'locationName' => 'Retention', ], ], 'payload' => 'Retention', ], 'GetObjectRetentionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetObjectTaggingOutput' => [ 'type' => 'structure', 'required' => [ 'TagSet', ], 'members' => [ 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'TagSet' => [ 'shape' => 'TagSet', ], ], ], 'GetObjectTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], ], ], 'GetObjectTorrentOutput' => [ 'type' => 'structure', 'members' => [ 'Body' => [ 'shape' => 'Body', 'streaming' => true, ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], 'payload' => 'Body', ], 'GetObjectTorrentRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GetPublicAccessBlockOutput' => [ 'type' => 'structure', 'members' => [ 'PublicAccessBlockConfiguration' => [ 'shape' => 'PublicAccessBlockConfiguration', ], ], 'payload' => 'PublicAccessBlockConfiguration', ], 'GetPublicAccessBlockRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'GlacierJobParameters' => [ 'type' => 'structure', 'required' => [ 'Tier', ], 'members' => [ 'Tier' => [ 'shape' => 'Tier', ], ], ], 'Grant' => [ 'type' => 'structure', 'members' => [ 'Grantee' => [ 'shape' => 'Grantee', ], 'Permission' => [ 'shape' => 'Permission', ], ], ], 'GrantFullControl' => [ 'type' => 'string', ], 'GrantRead' => [ 'type' => 'string', ], 'GrantReadACP' => [ 'type' => 'string', ], 'GrantWrite' => [ 'type' => 'string', ], 'GrantWriteACP' => [ 'type' => 'string', ], 'Grantee' => [ 'type' => 'structure', 'required' => [ 'Type', ], 'members' => [ 'DisplayName' => [ 'shape' => 'DisplayName', ], 'EmailAddress' => [ 'shape' => 'EmailAddress', ], 'ID' => [ 'shape' => 'ID', ], 'Type' => [ 'shape' => 'Type', 'locationName' => 'xsi:type', 'xmlAttribute' => true, ], 'URI' => [ 'shape' => 'URI', ], ], 'xmlNamespace' => [ 'prefix' => 'xsi', 'uri' => 'http://www.w3.org/2001/XMLSchema-instance', ], ], 'Grants' => [ 'type' => 'list', 'member' => [ 'shape' => 'Grant', 'locationName' => 'Grant', ], ], 'HeadBucketOutput' => [ 'type' => 'structure', 'members' => [ 'BucketArn' => [ 'shape' => 'S3RegionalOrS3ExpressBucketArnString', 'location' => 'header', 'locationName' => 'x-amz-bucket-arn', ], 'BucketLocationType' => [ 'shape' => 'LocationType', 'location' => 'header', 'locationName' => 'x-amz-bucket-location-type', ], 'BucketLocationName' => [ 'shape' => 'BucketLocationName', 'location' => 'header', 'locationName' => 'x-amz-bucket-location-name', ], 'BucketRegion' => [ 'shape' => 'Region', 'location' => 'header', 'locationName' => 'x-amz-bucket-region', ], 'AccessPointAlias' => [ 'shape' => 'AccessPointAlias', 'location' => 'header', 'locationName' => 'x-amz-access-point-alias', ], ], ], 'HeadBucketRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'HeadObjectOutput' => [ 'type' => 'structure', 'members' => [ 'DeleteMarker' => [ 'shape' => 'DeleteMarker', 'location' => 'header', 'locationName' => 'x-amz-delete-marker', ], 'AcceptRanges' => [ 'shape' => 'AcceptRanges', 'location' => 'header', 'locationName' => 'accept-ranges', ], 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-expiration', ], 'Restore' => [ 'shape' => 'Restore', 'location' => 'header', 'locationName' => 'x-amz-restore', ], 'ArchiveStatus' => [ 'shape' => 'ArchiveStatus', 'location' => 'header', 'locationName' => 'x-amz-archive-status', ], 'LastModified' => [ 'shape' => 'LastModified', 'location' => 'header', 'locationName' => 'Last-Modified', ], 'ContentLength' => [ 'shape' => 'ContentLength', 'location' => 'header', 'locationName' => 'Content-Length', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], 'ETag' => [ 'shape' => 'ETag', 'location' => 'header', 'locationName' => 'ETag', ], 'MissingMeta' => [ 'shape' => 'MissingMeta', 'location' => 'header', 'locationName' => 'x-amz-missing-meta', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'Cache-Control', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'Content-Language', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'Content-Type', ], 'ContentRange' => [ 'shape' => 'ContentRange', 'location' => 'header', 'locationName' => 'Content-Range', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'Expires', ], 'WebsiteRedirectLocation' => [ 'shape' => 'WebsiteRedirectLocation', 'location' => 'header', 'locationName' => 'x-amz-website-redirect-location', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-storage-class', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'ReplicationStatus' => [ 'shape' => 'ReplicationStatus', 'location' => 'header', 'locationName' => 'x-amz-replication-status', ], 'PartsCount' => [ 'shape' => 'PartsCount', 'location' => 'header', 'locationName' => 'x-amz-mp-parts-count', ], 'TagCount' => [ 'shape' => 'TagCount', 'location' => 'header', 'locationName' => 'x-amz-tagging-count', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-object-lock-mode', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-object-lock-retain-until-date', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-object-lock-legal-hold', ], ], ], 'HeadObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'IfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'IfModifiedSince' => [ 'shape' => 'IfModifiedSince', 'location' => 'header', 'locationName' => 'If-Modified-Since', ], 'IfNoneMatch' => [ 'shape' => 'IfNoneMatch', 'location' => 'header', 'locationName' => 'If-None-Match', ], 'IfUnmodifiedSince' => [ 'shape' => 'IfUnmodifiedSince', 'location' => 'header', 'locationName' => 'If-Unmodified-Since', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'Range' => [ 'shape' => 'Range', 'location' => 'header', 'locationName' => 'Range', ], 'ResponseCacheControl' => [ 'shape' => 'ResponseCacheControl', 'location' => 'querystring', 'locationName' => 'response-cache-control', ], 'ResponseContentDisposition' => [ 'shape' => 'ResponseContentDisposition', 'location' => 'querystring', 'locationName' => 'response-content-disposition', ], 'ResponseContentEncoding' => [ 'shape' => 'ResponseContentEncoding', 'location' => 'querystring', 'locationName' => 'response-content-encoding', ], 'ResponseContentLanguage' => [ 'shape' => 'ResponseContentLanguage', 'location' => 'querystring', 'locationName' => 'response-content-language', ], 'ResponseContentType' => [ 'shape' => 'ResponseContentType', 'location' => 'querystring', 'locationName' => 'response-content-type', ], 'ResponseExpires' => [ 'shape' => 'ResponseExpires', 'location' => 'querystring', 'locationName' => 'response-expires', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'PartNumber' => [ 'shape' => 'PartNumber', 'location' => 'querystring', 'locationName' => 'partNumber', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ChecksumMode' => [ 'shape' => 'ChecksumMode', 'location' => 'header', 'locationName' => 'x-amz-checksum-mode', ], ], ], 'HostName' => [ 'type' => 'string', ], 'HttpErrorCodeReturnedEquals' => [ 'type' => 'string', ], 'HttpRedirectCode' => [ 'type' => 'string', ], 'ID' => [ 'type' => 'string', ], 'IdempotencyParameterMismatch' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'IfMatch' => [ 'type' => 'string', ], 'IfMatchInitiatedTime' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'IfMatchLastModifiedTime' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'IfMatchSize' => [ 'type' => 'long', 'box' => true, ], 'IfModifiedSince' => [ 'type' => 'timestamp', ], 'IfNoneMatch' => [ 'type' => 'string', ], 'IfUnmodifiedSince' => [ 'type' => 'timestamp', ], 'IndexDocument' => [ 'type' => 'structure', 'required' => [ 'Suffix', ], 'members' => [ 'Suffix' => [ 'shape' => 'Suffix', ], ], ], 'Initiated' => [ 'type' => 'timestamp', ], 'Initiator' => [ 'type' => 'structure', 'members' => [ 'ID' => [ 'shape' => 'ID', ], 'DisplayName' => [ 'shape' => 'DisplayName', ], ], ], 'InputSerialization' => [ 'type' => 'structure', 'members' => [ 'CSV' => [ 'shape' => 'CSVInput', ], 'CompressionType' => [ 'shape' => 'CompressionType', ], 'JSON' => [ 'shape' => 'JSONInput', ], 'Parquet' => [ 'shape' => 'ParquetInput', ], ], ], 'IntelligentTieringAccessTier' => [ 'type' => 'string', 'enum' => [ 'ARCHIVE_ACCESS', 'DEEP_ARCHIVE_ACCESS', ], ], 'IntelligentTieringAndOperator' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tags' => [ 'shape' => 'TagSet', 'flattened' => true, 'locationName' => 'Tag', ], ], ], 'IntelligentTieringConfiguration' => [ 'type' => 'structure', 'required' => [ 'Id', 'Status', 'Tierings', ], 'members' => [ 'Id' => [ 'shape' => 'IntelligentTieringId', ], 'Filter' => [ 'shape' => 'IntelligentTieringFilter', ], 'Status' => [ 'shape' => 'IntelligentTieringStatus', ], 'Tierings' => [ 'shape' => 'TieringList', 'locationName' => 'Tiering', ], ], ], 'IntelligentTieringConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'IntelligentTieringConfiguration', ], 'flattened' => true, ], 'IntelligentTieringDays' => [ 'type' => 'integer', 'box' => true, ], 'IntelligentTieringFilter' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tag' => [ 'shape' => 'Tag', ], 'And' => [ 'shape' => 'IntelligentTieringAndOperator', ], ], ], 'IntelligentTieringId' => [ 'type' => 'string', ], 'IntelligentTieringStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'InvalidObjectState' => [ 'type' => 'structure', 'members' => [ 'StorageClass' => [ 'shape' => 'StorageClass', ], 'AccessTier' => [ 'shape' => 'IntelligentTieringAccessTier', ], ], 'error' => [ 'httpStatusCode' => 403, ], 'exception' => true, ], 'InvalidRequest' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidWriteOffset' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InventoryConfiguration' => [ 'type' => 'structure', 'required' => [ 'Destination', 'IsEnabled', 'Id', 'IncludedObjectVersions', 'Schedule', ], 'members' => [ 'Destination' => [ 'shape' => 'InventoryDestination', ], 'IsEnabled' => [ 'shape' => 'IsEnabled', ], 'Filter' => [ 'shape' => 'InventoryFilter', ], 'Id' => [ 'shape' => 'InventoryId', ], 'IncludedObjectVersions' => [ 'shape' => 'InventoryIncludedObjectVersions', ], 'OptionalFields' => [ 'shape' => 'InventoryOptionalFields', ], 'Schedule' => [ 'shape' => 'InventorySchedule', ], ], ], 'InventoryConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'InventoryConfiguration', ], 'flattened' => true, ], 'InventoryConfigurationState' => [ 'type' => 'string', 'enum' => [ 'ENABLED', 'DISABLED', ], ], 'InventoryDestination' => [ 'type' => 'structure', 'required' => [ 'S3BucketDestination', ], 'members' => [ 'S3BucketDestination' => [ 'shape' => 'InventoryS3BucketDestination', ], ], ], 'InventoryEncryption' => [ 'type' => 'structure', 'members' => [ 'SSES3' => [ 'shape' => 'SSES3', 'locationName' => 'SSE-S3', ], 'SSEKMS' => [ 'shape' => 'SSEKMS', 'locationName' => 'SSE-KMS', ], ], ], 'InventoryFilter' => [ 'type' => 'structure', 'required' => [ 'Prefix', ], 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], ], ], 'InventoryFormat' => [ 'type' => 'string', 'enum' => [ 'CSV', 'ORC', 'Parquet', ], ], 'InventoryFrequency' => [ 'type' => 'string', 'enum' => [ 'Daily', 'Weekly', ], ], 'InventoryId' => [ 'type' => 'string', ], 'InventoryIncludedObjectVersions' => [ 'type' => 'string', 'enum' => [ 'All', 'Current', ], ], 'InventoryOptionalField' => [ 'type' => 'string', 'enum' => [ 'Size', 'LastModifiedDate', 'StorageClass', 'ETag', 'IsMultipartUploaded', 'ReplicationStatus', 'EncryptionStatus', 'ObjectLockRetainUntilDate', 'ObjectLockMode', 'ObjectLockLegalHoldStatus', 'IntelligentTieringAccessTier', 'BucketKeyStatus', 'ChecksumAlgorithm', 'ObjectAccessControlList', 'ObjectOwner', ], ], 'InventoryOptionalFields' => [ 'type' => 'list', 'member' => [ 'shape' => 'InventoryOptionalField', 'locationName' => 'Field', ], ], 'InventoryS3BucketDestination' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Format', ], 'members' => [ 'AccountId' => [ 'shape' => 'AccountId', ], 'Bucket' => [ 'shape' => 'BucketName', ], 'Format' => [ 'shape' => 'InventoryFormat', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Encryption' => [ 'shape' => 'InventoryEncryption', ], ], ], 'InventorySchedule' => [ 'type' => 'structure', 'required' => [ 'Frequency', ], 'members' => [ 'Frequency' => [ 'shape' => 'InventoryFrequency', ], ], ], 'InventoryTableConfiguration' => [ 'type' => 'structure', 'required' => [ 'ConfigurationState', ], 'members' => [ 'ConfigurationState' => [ 'shape' => 'InventoryConfigurationState', ], 'EncryptionConfiguration' => [ 'shape' => 'MetadataTableEncryptionConfiguration', ], ], ], 'InventoryTableConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'ConfigurationState', ], 'members' => [ 'ConfigurationState' => [ 'shape' => 'InventoryConfigurationState', ], 'TableStatus' => [ 'shape' => 'MetadataTableStatus', ], 'Error' => [ 'shape' => 'ErrorDetails', ], 'TableName' => [ 'shape' => 'S3TablesName', ], 'TableArn' => [ 'shape' => 'S3TablesArn', ], ], ], 'InventoryTableConfigurationUpdates' => [ 'type' => 'structure', 'required' => [ 'ConfigurationState', ], 'members' => [ 'ConfigurationState' => [ 'shape' => 'InventoryConfigurationState', ], 'EncryptionConfiguration' => [ 'shape' => 'MetadataTableEncryptionConfiguration', ], ], ], 'IsEnabled' => [ 'type' => 'boolean', 'box' => true, ], 'IsLatest' => [ 'type' => 'boolean', 'box' => true, ], 'IsPublic' => [ 'type' => 'boolean', 'box' => true, ], 'IsRestoreInProgress' => [ 'type' => 'boolean', 'box' => true, ], 'IsTruncated' => [ 'type' => 'boolean', 'box' => true, ], 'JSONInput' => [ 'type' => 'structure', 'members' => [ 'Type' => [ 'shape' => 'JSONType', ], ], ], 'JSONOutput' => [ 'type' => 'structure', 'members' => [ 'RecordDelimiter' => [ 'shape' => 'RecordDelimiter', ], ], ], 'JSONType' => [ 'type' => 'string', 'enum' => [ 'DOCUMENT', 'LINES', ], ], 'JournalTableConfiguration' => [ 'type' => 'structure', 'required' => [ 'RecordExpiration', ], 'members' => [ 'RecordExpiration' => [ 'shape' => 'RecordExpiration', ], 'EncryptionConfiguration' => [ 'shape' => 'MetadataTableEncryptionConfiguration', ], ], ], 'JournalTableConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'TableStatus', 'TableName', 'RecordExpiration', ], 'members' => [ 'TableStatus' => [ 'shape' => 'MetadataTableStatus', ], 'Error' => [ 'shape' => 'ErrorDetails', ], 'TableName' => [ 'shape' => 'S3TablesName', ], 'TableArn' => [ 'shape' => 'S3TablesArn', ], 'RecordExpiration' => [ 'shape' => 'RecordExpiration', ], ], ], 'JournalTableConfigurationUpdates' => [ 'type' => 'structure', 'required' => [ 'RecordExpiration', ], 'members' => [ 'RecordExpiration' => [ 'shape' => 'RecordExpiration', ], ], ], 'KMSContext' => [ 'type' => 'string', ], 'KeyCount' => [ 'type' => 'integer', ], 'KeyMarker' => [ 'type' => 'string', ], 'KeyPrefixEquals' => [ 'type' => 'string', ], 'KmsKeyArn' => [ 'type' => 'string', ], 'LambdaFunctionArn' => [ 'type' => 'string', ], 'LambdaFunctionConfiguration' => [ 'type' => 'structure', 'required' => [ 'LambdaFunctionArn', 'Events', ], 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'LambdaFunctionArn' => [ 'shape' => 'LambdaFunctionArn', 'locationName' => 'CloudFunction', ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'Filter' => [ 'shape' => 'NotificationConfigurationFilter', ], ], ], 'LambdaFunctionConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'LambdaFunctionConfiguration', ], 'flattened' => true, ], 'LastModified' => [ 'type' => 'timestamp', ], 'LastModifiedTime' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'LifecycleConfiguration' => [ 'type' => 'structure', 'required' => [ 'Rules', ], 'members' => [ 'Rules' => [ 'shape' => 'Rules', 'locationName' => 'Rule', ], ], ], 'LifecycleExpiration' => [ 'type' => 'structure', 'members' => [ 'Date' => [ 'shape' => 'Date', ], 'Days' => [ 'shape' => 'Days', ], 'ExpiredObjectDeleteMarker' => [ 'shape' => 'ExpiredObjectDeleteMarker', ], ], ], 'LifecycleRule' => [ 'type' => 'structure', 'required' => [ 'Status', ], 'members' => [ 'Expiration' => [ 'shape' => 'LifecycleExpiration', ], 'ID' => [ 'shape' => 'ID', ], 'Prefix' => [ 'shape' => 'Prefix', 'deprecated' => true, ], 'Filter' => [ 'shape' => 'LifecycleRuleFilter', ], 'Status' => [ 'shape' => 'ExpirationStatus', ], 'Transitions' => [ 'shape' => 'TransitionList', 'locationName' => 'Transition', ], 'NoncurrentVersionTransitions' => [ 'shape' => 'NoncurrentVersionTransitionList', 'locationName' => 'NoncurrentVersionTransition', ], 'NoncurrentVersionExpiration' => [ 'shape' => 'NoncurrentVersionExpiration', ], 'AbortIncompleteMultipartUpload' => [ 'shape' => 'AbortIncompleteMultipartUpload', ], ], ], 'LifecycleRuleAndOperator' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tags' => [ 'shape' => 'TagSet', 'flattened' => true, 'locationName' => 'Tag', ], 'ObjectSizeGreaterThan' => [ 'shape' => 'ObjectSizeGreaterThanBytes', ], 'ObjectSizeLessThan' => [ 'shape' => 'ObjectSizeLessThanBytes', ], ], ], 'LifecycleRuleFilter' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tag' => [ 'shape' => 'Tag', ], 'ObjectSizeGreaterThan' => [ 'shape' => 'ObjectSizeGreaterThanBytes', ], 'ObjectSizeLessThan' => [ 'shape' => 'ObjectSizeLessThanBytes', ], 'And' => [ 'shape' => 'LifecycleRuleAndOperator', ], ], ], 'LifecycleRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'LifecycleRule', ], 'flattened' => true, ], 'ListBucketAnalyticsConfigurationsOutput' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'ContinuationToken' => [ 'shape' => 'Token', ], 'NextContinuationToken' => [ 'shape' => 'NextToken', ], 'AnalyticsConfigurationList' => [ 'shape' => 'AnalyticsConfigurationList', 'locationName' => 'AnalyticsConfiguration', ], ], ], 'ListBucketAnalyticsConfigurationsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'ListBucketIntelligentTieringConfigurationsOutput' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'ContinuationToken' => [ 'shape' => 'Token', ], 'NextContinuationToken' => [ 'shape' => 'NextToken', ], 'IntelligentTieringConfigurationList' => [ 'shape' => 'IntelligentTieringConfigurationList', 'locationName' => 'IntelligentTieringConfiguration', ], ], ], 'ListBucketIntelligentTieringConfigurationsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'ListBucketInventoryConfigurationsOutput' => [ 'type' => 'structure', 'members' => [ 'ContinuationToken' => [ 'shape' => 'Token', ], 'InventoryConfigurationList' => [ 'shape' => 'InventoryConfigurationList', 'locationName' => 'InventoryConfiguration', ], 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'NextContinuationToken' => [ 'shape' => 'NextToken', ], ], ], 'ListBucketInventoryConfigurationsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'ListBucketMetricsConfigurationsOutput' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'ContinuationToken' => [ 'shape' => 'Token', ], 'NextContinuationToken' => [ 'shape' => 'NextToken', ], 'MetricsConfigurationList' => [ 'shape' => 'MetricsConfigurationList', 'locationName' => 'MetricsConfiguration', ], ], ], 'ListBucketMetricsConfigurationsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'ListBucketsOutput' => [ 'type' => 'structure', 'members' => [ 'Buckets' => [ 'shape' => 'Buckets', ], 'Owner' => [ 'shape' => 'Owner', ], 'ContinuationToken' => [ 'shape' => 'NextToken', ], 'Prefix' => [ 'shape' => 'Prefix', ], ], ], 'ListBucketsRequest' => [ 'type' => 'structure', 'members' => [ 'MaxBuckets' => [ 'shape' => 'MaxBuckets', 'location' => 'querystring', 'locationName' => 'max-buckets', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'Prefix' => [ 'shape' => 'Prefix', 'location' => 'querystring', 'locationName' => 'prefix', ], 'BucketRegion' => [ 'shape' => 'BucketRegion', 'location' => 'querystring', 'locationName' => 'bucket-region', ], ], ], 'ListDirectoryBucketsOutput' => [ 'type' => 'structure', 'members' => [ 'Buckets' => [ 'shape' => 'Buckets', ], 'ContinuationToken' => [ 'shape' => 'DirectoryBucketToken', ], ], ], 'ListDirectoryBucketsRequest' => [ 'type' => 'structure', 'members' => [ 'ContinuationToken' => [ 'shape' => 'DirectoryBucketToken', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'MaxDirectoryBuckets' => [ 'shape' => 'MaxDirectoryBuckets', 'location' => 'querystring', 'locationName' => 'max-directory-buckets', ], ], ], 'ListMultipartUploadsOutput' => [ 'type' => 'structure', 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', ], 'KeyMarker' => [ 'shape' => 'KeyMarker', ], 'UploadIdMarker' => [ 'shape' => 'UploadIdMarker', ], 'NextKeyMarker' => [ 'shape' => 'NextKeyMarker', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Delimiter' => [ 'shape' => 'Delimiter', ], 'NextUploadIdMarker' => [ 'shape' => 'NextUploadIdMarker', ], 'MaxUploads' => [ 'shape' => 'MaxUploads', ], 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'Uploads' => [ 'shape' => 'MultipartUploadList', 'locationName' => 'Upload', ], 'CommonPrefixes' => [ 'shape' => 'CommonPrefixList', ], 'EncodingType' => [ 'shape' => 'EncodingType', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'ListMultipartUploadsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Delimiter' => [ 'shape' => 'Delimiter', 'location' => 'querystring', 'locationName' => 'delimiter', ], 'EncodingType' => [ 'shape' => 'EncodingType', 'location' => 'querystring', 'locationName' => 'encoding-type', ], 'KeyMarker' => [ 'shape' => 'KeyMarker', 'location' => 'querystring', 'locationName' => 'key-marker', ], 'MaxUploads' => [ 'shape' => 'MaxUploads', 'location' => 'querystring', 'locationName' => 'max-uploads', ], 'Prefix' => [ 'shape' => 'Prefix', 'contextParam' => [ 'name' => 'Prefix', ], 'location' => 'querystring', 'locationName' => 'prefix', ], 'UploadIdMarker' => [ 'shape' => 'UploadIdMarker', 'location' => 'querystring', 'locationName' => 'upload-id-marker', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], ], ], 'ListObjectVersionsOutput' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'KeyMarker' => [ 'shape' => 'KeyMarker', ], 'VersionIdMarker' => [ 'shape' => 'VersionIdMarker', ], 'NextKeyMarker' => [ 'shape' => 'NextKeyMarker', ], 'NextVersionIdMarker' => [ 'shape' => 'NextVersionIdMarker', ], 'Versions' => [ 'shape' => 'ObjectVersionList', 'locationName' => 'Version', ], 'DeleteMarkers' => [ 'shape' => 'DeleteMarkers', 'locationName' => 'DeleteMarker', ], 'Name' => [ 'shape' => 'BucketName', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Delimiter' => [ 'shape' => 'Delimiter', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', ], 'CommonPrefixes' => [ 'shape' => 'CommonPrefixList', ], 'EncodingType' => [ 'shape' => 'EncodingType', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'ListObjectVersionsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Delimiter' => [ 'shape' => 'Delimiter', 'location' => 'querystring', 'locationName' => 'delimiter', ], 'EncodingType' => [ 'shape' => 'EncodingType', 'location' => 'querystring', 'locationName' => 'encoding-type', ], 'KeyMarker' => [ 'shape' => 'KeyMarker', 'location' => 'querystring', 'locationName' => 'key-marker', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', 'location' => 'querystring', 'locationName' => 'max-keys', ], 'Prefix' => [ 'shape' => 'Prefix', 'contextParam' => [ 'name' => 'Prefix', ], 'location' => 'querystring', 'locationName' => 'prefix', ], 'VersionIdMarker' => [ 'shape' => 'VersionIdMarker', 'location' => 'querystring', 'locationName' => 'version-id-marker', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'OptionalObjectAttributes' => [ 'shape' => 'OptionalObjectAttributesList', 'location' => 'header', 'locationName' => 'x-amz-optional-object-attributes', ], ], ], 'ListObjectsOutput' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'Marker' => [ 'shape' => 'Marker', ], 'NextMarker' => [ 'shape' => 'NextMarker', ], 'Contents' => [ 'shape' => 'ObjectList', ], 'Name' => [ 'shape' => 'BucketName', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Delimiter' => [ 'shape' => 'Delimiter', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', ], 'CommonPrefixes' => [ 'shape' => 'CommonPrefixList', ], 'EncodingType' => [ 'shape' => 'EncodingType', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'ListObjectsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Delimiter' => [ 'shape' => 'Delimiter', 'location' => 'querystring', 'locationName' => 'delimiter', ], 'EncodingType' => [ 'shape' => 'EncodingType', 'location' => 'querystring', 'locationName' => 'encoding-type', ], 'Marker' => [ 'shape' => 'Marker', 'location' => 'querystring', 'locationName' => 'marker', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', 'location' => 'querystring', 'locationName' => 'max-keys', ], 'Prefix' => [ 'shape' => 'Prefix', 'contextParam' => [ 'name' => 'Prefix', ], 'location' => 'querystring', 'locationName' => 'prefix', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'OptionalObjectAttributes' => [ 'shape' => 'OptionalObjectAttributesList', 'location' => 'header', 'locationName' => 'x-amz-optional-object-attributes', ], ], ], 'ListObjectsV2Output' => [ 'type' => 'structure', 'members' => [ 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'Contents' => [ 'shape' => 'ObjectList', ], 'Name' => [ 'shape' => 'BucketName', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Delimiter' => [ 'shape' => 'Delimiter', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', ], 'CommonPrefixes' => [ 'shape' => 'CommonPrefixList', ], 'EncodingType' => [ 'shape' => 'EncodingType', ], 'KeyCount' => [ 'shape' => 'KeyCount', ], 'ContinuationToken' => [ 'shape' => 'Token', ], 'NextContinuationToken' => [ 'shape' => 'NextToken', ], 'StartAfter' => [ 'shape' => 'StartAfter', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'ListObjectsV2Request' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Delimiter' => [ 'shape' => 'Delimiter', 'location' => 'querystring', 'locationName' => 'delimiter', ], 'EncodingType' => [ 'shape' => 'EncodingType', 'location' => 'querystring', 'locationName' => 'encoding-type', ], 'MaxKeys' => [ 'shape' => 'MaxKeys', 'location' => 'querystring', 'locationName' => 'max-keys', ], 'Prefix' => [ 'shape' => 'Prefix', 'contextParam' => [ 'name' => 'Prefix', ], 'location' => 'querystring', 'locationName' => 'prefix', ], 'ContinuationToken' => [ 'shape' => 'Token', 'location' => 'querystring', 'locationName' => 'continuation-token', ], 'FetchOwner' => [ 'shape' => 'FetchOwner', 'location' => 'querystring', 'locationName' => 'fetch-owner', ], 'StartAfter' => [ 'shape' => 'StartAfter', 'location' => 'querystring', 'locationName' => 'start-after', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'OptionalObjectAttributes' => [ 'shape' => 'OptionalObjectAttributesList', 'location' => 'header', 'locationName' => 'x-amz-optional-object-attributes', ], ], ], 'ListPartsOutput' => [ 'type' => 'structure', 'members' => [ 'AbortDate' => [ 'shape' => 'AbortDate', 'location' => 'header', 'locationName' => 'x-amz-abort-date', ], 'AbortRuleId' => [ 'shape' => 'AbortRuleId', 'location' => 'header', 'locationName' => 'x-amz-abort-rule-id', ], 'Bucket' => [ 'shape' => 'BucketName', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', ], 'PartNumberMarker' => [ 'shape' => 'PartNumberMarker', ], 'NextPartNumberMarker' => [ 'shape' => 'NextPartNumberMarker', ], 'MaxParts' => [ 'shape' => 'MaxParts', ], 'IsTruncated' => [ 'shape' => 'IsTruncated', ], 'Parts' => [ 'shape' => 'Parts', 'locationName' => 'Part', ], 'Initiator' => [ 'shape' => 'Initiator', ], 'Owner' => [ 'shape' => 'Owner', ], 'StorageClass' => [ 'shape' => 'StorageClass', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], ], ], 'ListPartsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'UploadId', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'MaxParts' => [ 'shape' => 'MaxParts', 'location' => 'querystring', 'locationName' => 'max-parts', ], 'PartNumberMarker' => [ 'shape' => 'PartNumberMarker', 'location' => 'querystring', 'locationName' => 'part-number-marker', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', 'location' => 'querystring', 'locationName' => 'uploadId', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], ], ], 'Location' => [ 'type' => 'string', ], 'LocationInfo' => [ 'type' => 'structure', 'members' => [ 'Type' => [ 'shape' => 'LocationType', ], 'Name' => [ 'shape' => 'LocationNameAsString', ], ], ], 'LocationNameAsString' => [ 'type' => 'string', ], 'LocationPrefix' => [ 'type' => 'string', ], 'LocationType' => [ 'type' => 'string', 'enum' => [ 'AvailabilityZone', 'LocalZone', ], ], 'LoggingEnabled' => [ 'type' => 'structure', 'required' => [ 'TargetBucket', 'TargetPrefix', ], 'members' => [ 'TargetBucket' => [ 'shape' => 'TargetBucket', ], 'TargetGrants' => [ 'shape' => 'TargetGrants', ], 'TargetPrefix' => [ 'shape' => 'TargetPrefix', ], 'TargetObjectKeyFormat' => [ 'shape' => 'TargetObjectKeyFormat', ], ], ], 'MFA' => [ 'type' => 'string', ], 'MFADelete' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'MFADeleteStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'Marker' => [ 'type' => 'string', ], 'MaxAgeSeconds' => [ 'type' => 'integer', 'box' => true, ], 'MaxBuckets' => [ 'type' => 'integer', 'box' => true, 'max' => 10000, 'min' => 1, ], 'MaxDirectoryBuckets' => [ 'type' => 'integer', 'box' => true, 'max' => 1000, 'min' => 0, ], 'MaxKeys' => [ 'type' => 'integer', ], 'MaxParts' => [ 'type' => 'integer', ], 'MaxUploads' => [ 'type' => 'integer', ], 'Message' => [ 'type' => 'string', ], 'Metadata' => [ 'type' => 'map', 'key' => [ 'shape' => 'MetadataKey', ], 'value' => [ 'shape' => 'MetadataValue', ], ], 'MetadataConfiguration' => [ 'type' => 'structure', 'required' => [ 'JournalTableConfiguration', ], 'members' => [ 'JournalTableConfiguration' => [ 'shape' => 'JournalTableConfiguration', ], 'InventoryTableConfiguration' => [ 'shape' => 'InventoryTableConfiguration', ], ], ], 'MetadataConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'DestinationResult', ], 'members' => [ 'DestinationResult' => [ 'shape' => 'DestinationResult', ], 'JournalTableConfigurationResult' => [ 'shape' => 'JournalTableConfigurationResult', ], 'InventoryTableConfigurationResult' => [ 'shape' => 'InventoryTableConfigurationResult', ], ], ], 'MetadataDirective' => [ 'type' => 'string', 'enum' => [ 'COPY', 'REPLACE', ], ], 'MetadataEntry' => [ 'type' => 'structure', 'members' => [ 'Name' => [ 'shape' => 'MetadataKey', ], 'Value' => [ 'shape' => 'MetadataValue', ], ], ], 'MetadataKey' => [ 'type' => 'string', ], 'MetadataTableConfiguration' => [ 'type' => 'structure', 'required' => [ 'S3TablesDestination', ], 'members' => [ 'S3TablesDestination' => [ 'shape' => 'S3TablesDestination', ], ], ], 'MetadataTableConfigurationResult' => [ 'type' => 'structure', 'required' => [ 'S3TablesDestinationResult', ], 'members' => [ 'S3TablesDestinationResult' => [ 'shape' => 'S3TablesDestinationResult', ], ], ], 'MetadataTableEncryptionConfiguration' => [ 'type' => 'structure', 'required' => [ 'SseAlgorithm', ], 'members' => [ 'SseAlgorithm' => [ 'shape' => 'TableSseAlgorithm', ], 'KmsKeyArn' => [ 'shape' => 'KmsKeyArn', ], ], ], 'MetadataTableStatus' => [ 'type' => 'string', ], 'MetadataValue' => [ 'type' => 'string', ], 'Metrics' => [ 'type' => 'structure', 'required' => [ 'Status', ], 'members' => [ 'Status' => [ 'shape' => 'MetricsStatus', ], 'EventThreshold' => [ 'shape' => 'ReplicationTimeValue', ], ], ], 'MetricsAndOperator' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tags' => [ 'shape' => 'TagSet', 'flattened' => true, 'locationName' => 'Tag', ], 'AccessPointArn' => [ 'shape' => 'AccessPointArn', ], ], ], 'MetricsConfiguration' => [ 'type' => 'structure', 'required' => [ 'Id', ], 'members' => [ 'Id' => [ 'shape' => 'MetricsId', ], 'Filter' => [ 'shape' => 'MetricsFilter', ], ], ], 'MetricsConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'MetricsConfiguration', ], 'flattened' => true, ], 'MetricsFilter' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tag' => [ 'shape' => 'Tag', ], 'AccessPointArn' => [ 'shape' => 'AccessPointArn', ], 'And' => [ 'shape' => 'MetricsAndOperator', ], ], ], 'MetricsId' => [ 'type' => 'string', ], 'MetricsStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'Minutes' => [ 'type' => 'integer', 'box' => true, ], 'MissingMeta' => [ 'type' => 'integer', ], 'MpuObjectSize' => [ 'type' => 'long', ], 'MultipartUpload' => [ 'type' => 'structure', 'members' => [ 'UploadId' => [ 'shape' => 'MultipartUploadId', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'Initiated' => [ 'shape' => 'Initiated', ], 'StorageClass' => [ 'shape' => 'StorageClass', ], 'Owner' => [ 'shape' => 'Owner', ], 'Initiator' => [ 'shape' => 'Initiator', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], ], ], 'MultipartUploadId' => [ 'type' => 'string', ], 'MultipartUploadList' => [ 'type' => 'list', 'member' => [ 'shape' => 'MultipartUpload', ], 'flattened' => true, ], 'NextKeyMarker' => [ 'type' => 'string', ], 'NextMarker' => [ 'type' => 'string', ], 'NextPartNumberMarker' => [ 'type' => 'integer', 'box' => true, ], 'NextToken' => [ 'type' => 'string', ], 'NextUploadIdMarker' => [ 'type' => 'string', ], 'NextVersionIdMarker' => [ 'type' => 'string', ], 'NoSuchBucket' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 404, ], 'exception' => true, ], 'NoSuchKey' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 404, ], 'exception' => true, ], 'NoSuchUpload' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 404, ], 'exception' => true, ], 'NoncurrentVersionExpiration' => [ 'type' => 'structure', 'members' => [ 'NoncurrentDays' => [ 'shape' => 'Days', ], 'NewerNoncurrentVersions' => [ 'shape' => 'VersionCount', ], ], ], 'NoncurrentVersionTransition' => [ 'type' => 'structure', 'members' => [ 'NoncurrentDays' => [ 'shape' => 'Days', ], 'StorageClass' => [ 'shape' => 'TransitionStorageClass', ], 'NewerNoncurrentVersions' => [ 'shape' => 'VersionCount', ], ], ], 'NoncurrentVersionTransitionList' => [ 'type' => 'list', 'member' => [ 'shape' => 'NoncurrentVersionTransition', ], 'flattened' => true, ], 'NotificationConfiguration' => [ 'type' => 'structure', 'members' => [ 'TopicConfigurations' => [ 'shape' => 'TopicConfigurationList', 'locationName' => 'TopicConfiguration', ], 'QueueConfigurations' => [ 'shape' => 'QueueConfigurationList', 'locationName' => 'QueueConfiguration', ], 'LambdaFunctionConfigurations' => [ 'shape' => 'LambdaFunctionConfigurationList', 'locationName' => 'CloudFunctionConfiguration', ], 'EventBridgeConfiguration' => [ 'shape' => 'EventBridgeConfiguration', ], ], ], 'NotificationConfigurationDeprecated' => [ 'type' => 'structure', 'members' => [ 'TopicConfiguration' => [ 'shape' => 'TopicConfigurationDeprecated', ], 'QueueConfiguration' => [ 'shape' => 'QueueConfigurationDeprecated', ], 'CloudFunctionConfiguration' => [ 'shape' => 'CloudFunctionConfiguration', ], ], ], 'NotificationConfigurationFilter' => [ 'type' => 'structure', 'members' => [ 'Key' => [ 'shape' => 'S3KeyFilter', 'locationName' => 'S3Key', ], ], ], 'NotificationId' => [ 'type' => 'string', ], 'Object' => [ 'type' => 'structure', 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], 'LastModified' => [ 'shape' => 'LastModified', ], 'ETag' => [ 'shape' => 'ETag', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithmList', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], 'Size' => [ 'shape' => 'Size', ], 'StorageClass' => [ 'shape' => 'ObjectStorageClass', ], 'Owner' => [ 'shape' => 'Owner', ], 'RestoreStatus' => [ 'shape' => 'RestoreStatus', ], ], ], 'ObjectAlreadyInActiveTierError' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 403, ], 'exception' => true, ], 'ObjectAttributes' => [ 'type' => 'string', 'enum' => [ 'ETag', 'Checksum', 'ObjectParts', 'StorageClass', 'ObjectSize', ], ], 'ObjectAttributesList' => [ 'type' => 'list', 'member' => [ 'shape' => 'ObjectAttributes', ], ], 'ObjectCannedACL' => [ 'type' => 'string', 'enum' => [ 'private', 'public-read', 'public-read-write', 'authenticated-read', 'aws-exec-read', 'bucket-owner-read', 'bucket-owner-full-control', ], ], 'ObjectIdentifier' => [ 'type' => 'structure', 'required' => [ 'Key', ], 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', ], 'ETag' => [ 'shape' => 'ETag', ], 'LastModifiedTime' => [ 'shape' => 'LastModifiedTime', ], 'Size' => [ 'shape' => 'Size', ], ], ], 'ObjectIdentifierList' => [ 'type' => 'list', 'member' => [ 'shape' => 'ObjectIdentifier', ], 'flattened' => true, ], 'ObjectKey' => [ 'type' => 'string', 'min' => 1, ], 'ObjectList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Object', ], 'flattened' => true, ], 'ObjectLockConfiguration' => [ 'type' => 'structure', 'members' => [ 'ObjectLockEnabled' => [ 'shape' => 'ObjectLockEnabled', ], 'Rule' => [ 'shape' => 'ObjectLockRule', ], ], ], 'ObjectLockEnabled' => [ 'type' => 'string', 'enum' => [ 'Enabled', ], ], 'ObjectLockEnabledForBucket' => [ 'type' => 'boolean', 'box' => true, ], 'ObjectLockLegalHold' => [ 'type' => 'structure', 'members' => [ 'Status' => [ 'shape' => 'ObjectLockLegalHoldStatus', ], ], ], 'ObjectLockLegalHoldStatus' => [ 'type' => 'string', 'enum' => [ 'ON', 'OFF', ], ], 'ObjectLockMode' => [ 'type' => 'string', 'enum' => [ 'GOVERNANCE', 'COMPLIANCE', ], ], 'ObjectLockRetainUntilDate' => [ 'type' => 'timestamp', 'timestampFormat' => 'iso8601', ], 'ObjectLockRetention' => [ 'type' => 'structure', 'members' => [ 'Mode' => [ 'shape' => 'ObjectLockRetentionMode', ], 'RetainUntilDate' => [ 'shape' => 'Date', ], ], ], 'ObjectLockRetentionMode' => [ 'type' => 'string', 'enum' => [ 'GOVERNANCE', 'COMPLIANCE', ], ], 'ObjectLockRule' => [ 'type' => 'structure', 'members' => [ 'DefaultRetention' => [ 'shape' => 'DefaultRetention', ], ], ], 'ObjectLockToken' => [ 'type' => 'string', ], 'ObjectNotInActiveTierError' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 403, ], 'exception' => true, ], 'ObjectOwnership' => [ 'type' => 'string', 'enum' => [ 'BucketOwnerPreferred', 'ObjectWriter', 'BucketOwnerEnforced', ], ], 'ObjectPart' => [ 'type' => 'structure', 'members' => [ 'PartNumber' => [ 'shape' => 'PartNumber', ], 'Size' => [ 'shape' => 'Size', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], ], ], 'ObjectSize' => [ 'type' => 'long', 'box' => true, ], 'ObjectSizeGreaterThanBytes' => [ 'type' => 'long', 'box' => true, ], 'ObjectSizeLessThanBytes' => [ 'type' => 'long', 'box' => true, ], 'ObjectStorageClass' => [ 'type' => 'string', 'enum' => [ 'STANDARD', 'REDUCED_REDUNDANCY', 'GLACIER', 'STANDARD_IA', 'ONEZONE_IA', 'INTELLIGENT_TIERING', 'DEEP_ARCHIVE', 'OUTPOSTS', 'GLACIER_IR', 'SNOW', 'EXPRESS_ONEZONE', 'FSX_OPENZFS', ], ], 'ObjectVersion' => [ 'type' => 'structure', 'members' => [ 'ETag' => [ 'shape' => 'ETag', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithmList', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', ], 'Size' => [ 'shape' => 'Size', ], 'StorageClass' => [ 'shape' => 'ObjectVersionStorageClass', ], 'Key' => [ 'shape' => 'ObjectKey', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', ], 'IsLatest' => [ 'shape' => 'IsLatest', ], 'LastModified' => [ 'shape' => 'LastModified', ], 'Owner' => [ 'shape' => 'Owner', ], 'RestoreStatus' => [ 'shape' => 'RestoreStatus', ], ], ], 'ObjectVersionId' => [ 'type' => 'string', ], 'ObjectVersionList' => [ 'type' => 'list', 'member' => [ 'shape' => 'ObjectVersion', ], 'flattened' => true, ], 'ObjectVersionStorageClass' => [ 'type' => 'string', 'enum' => [ 'STANDARD', ], ], 'OptionalObjectAttributes' => [ 'type' => 'string', 'enum' => [ 'RestoreStatus', ], ], 'OptionalObjectAttributesList' => [ 'type' => 'list', 'member' => [ 'shape' => 'OptionalObjectAttributes', ], ], 'OutputLocation' => [ 'type' => 'structure', 'members' => [ 'S3' => [ 'shape' => 'S3Location', ], ], ], 'OutputSerialization' => [ 'type' => 'structure', 'members' => [ 'CSV' => [ 'shape' => 'CSVOutput', ], 'JSON' => [ 'shape' => 'JSONOutput', ], ], ], 'Owner' => [ 'type' => 'structure', 'members' => [ 'DisplayName' => [ 'shape' => 'DisplayName', ], 'ID' => [ 'shape' => 'ID', ], ], ], 'OwnerOverride' => [ 'type' => 'string', 'enum' => [ 'Destination', ], ], 'OwnershipControls' => [ 'type' => 'structure', 'required' => [ 'Rules', ], 'members' => [ 'Rules' => [ 'shape' => 'OwnershipControlsRules', 'locationName' => 'Rule', ], ], ], 'OwnershipControlsRule' => [ 'type' => 'structure', 'required' => [ 'ObjectOwnership', ], 'members' => [ 'ObjectOwnership' => [ 'shape' => 'ObjectOwnership', ], ], ], 'OwnershipControlsRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'OwnershipControlsRule', ], 'flattened' => true, ], 'ParquetInput' => [ 'type' => 'structure', 'members' => [], ], 'Part' => [ 'type' => 'structure', 'members' => [ 'PartNumber' => [ 'shape' => 'PartNumber', ], 'LastModified' => [ 'shape' => 'LastModified', ], 'ETag' => [ 'shape' => 'ETag', ], 'Size' => [ 'shape' => 'Size', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', ], ], ], 'PartNumber' => [ 'type' => 'integer', ], 'PartNumberMarker' => [ 'type' => 'integer', ], 'PartitionDateSource' => [ 'type' => 'string', 'enum' => [ 'EventTime', 'DeliveryTime', ], ], 'PartitionedPrefix' => [ 'type' => 'structure', 'members' => [ 'PartitionDateSource' => [ 'shape' => 'PartitionDateSource', ], ], 'locationName' => 'PartitionedPrefix', ], 'Parts' => [ 'type' => 'list', 'member' => [ 'shape' => 'Part', ], 'flattened' => true, ], 'PartsCount' => [ 'type' => 'integer', 'box' => true, ], 'PartsList' => [ 'type' => 'list', 'member' => [ 'shape' => 'ObjectPart', ], 'flattened' => true, ], 'Payer' => [ 'type' => 'string', 'enum' => [ 'Requester', 'BucketOwner', ], ], 'Permission' => [ 'type' => 'string', 'enum' => [ 'FULL_CONTROL', 'WRITE', 'WRITE_ACP', 'READ', 'READ_ACP', ], ], 'Policy' => [ 'type' => 'string', ], 'PolicyStatus' => [ 'type' => 'structure', 'members' => [ 'IsPublic' => [ 'shape' => 'IsPublic', 'locationName' => 'IsPublic', ], ], ], 'Prefix' => [ 'type' => 'string', ], 'Priority' => [ 'type' => 'integer', 'box' => true, ], 'Progress' => [ 'type' => 'structure', 'members' => [ 'BytesScanned' => [ 'shape' => 'BytesScanned', ], 'BytesProcessed' => [ 'shape' => 'BytesProcessed', ], 'BytesReturned' => [ 'shape' => 'BytesReturned', ], ], ], 'ProgressEvent' => [ 'type' => 'structure', 'members' => [ 'Details' => [ 'shape' => 'Progress', 'eventpayload' => true, ], ], 'event' => true, ], 'Protocol' => [ 'type' => 'string', 'enum' => [ 'http', 'https', ], ], 'PublicAccessBlockConfiguration' => [ 'type' => 'structure', 'members' => [ 'BlockPublicAcls' => [ 'shape' => 'Setting', 'locationName' => 'BlockPublicAcls', ], 'IgnorePublicAcls' => [ 'shape' => 'Setting', 'locationName' => 'IgnorePublicAcls', ], 'BlockPublicPolicy' => [ 'shape' => 'Setting', 'locationName' => 'BlockPublicPolicy', ], 'RestrictPublicBuckets' => [ 'shape' => 'Setting', 'locationName' => 'RestrictPublicBuckets', ], ], ], 'PutBucketAccelerateConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'AccelerateConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'AccelerateConfiguration' => [ 'shape' => 'AccelerateConfiguration', 'locationName' => 'AccelerateConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], ], 'payload' => 'AccelerateConfiguration', ], 'PutBucketAclRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'ACL' => [ 'shape' => 'BucketCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'AccessControlPolicy' => [ 'shape' => 'AccessControlPolicy', 'locationName' => 'AccessControlPolicy', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWrite' => [ 'shape' => 'GrantWrite', 'location' => 'header', 'locationName' => 'x-amz-grant-write', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'AccessControlPolicy', ], 'PutBucketAnalyticsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', 'AnalyticsConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'AnalyticsId', 'location' => 'querystring', 'locationName' => 'id', ], 'AnalyticsConfiguration' => [ 'shape' => 'AnalyticsConfiguration', 'locationName' => 'AnalyticsConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'AnalyticsConfiguration', ], 'PutBucketCorsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'CORSConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CORSConfiguration' => [ 'shape' => 'CORSConfiguration', 'locationName' => 'CORSConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'CORSConfiguration', ], 'PutBucketEncryptionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'ServerSideEncryptionConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ServerSideEncryptionConfiguration' => [ 'shape' => 'ServerSideEncryptionConfiguration', 'locationName' => 'ServerSideEncryptionConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'ServerSideEncryptionConfiguration', ], 'PutBucketIntelligentTieringConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', 'IntelligentTieringConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'IntelligentTieringId', 'location' => 'querystring', 'locationName' => 'id', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'IntelligentTieringConfiguration' => [ 'shape' => 'IntelligentTieringConfiguration', 'locationName' => 'IntelligentTieringConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], ], 'payload' => 'IntelligentTieringConfiguration', ], 'PutBucketInventoryConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', 'InventoryConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'InventoryId', 'location' => 'querystring', 'locationName' => 'id', ], 'InventoryConfiguration' => [ 'shape' => 'InventoryConfiguration', 'locationName' => 'InventoryConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'InventoryConfiguration', ], 'PutBucketLifecycleConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'TransitionDefaultMinimumObjectSize' => [ 'shape' => 'TransitionDefaultMinimumObjectSize', 'location' => 'header', 'locationName' => 'x-amz-transition-default-minimum-object-size', ], ], ], 'PutBucketLifecycleConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'LifecycleConfiguration' => [ 'shape' => 'BucketLifecycleConfiguration', 'locationName' => 'LifecycleConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'TransitionDefaultMinimumObjectSize' => [ 'shape' => 'TransitionDefaultMinimumObjectSize', 'location' => 'header', 'locationName' => 'x-amz-transition-default-minimum-object-size', ], ], 'payload' => 'LifecycleConfiguration', ], 'PutBucketLifecycleRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'LifecycleConfiguration' => [ 'shape' => 'LifecycleConfiguration', 'locationName' => 'LifecycleConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'LifecycleConfiguration', ], 'PutBucketLoggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'BucketLoggingStatus', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'BucketLoggingStatus' => [ 'shape' => 'BucketLoggingStatus', 'locationName' => 'BucketLoggingStatus', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'BucketLoggingStatus', ], 'PutBucketMetricsConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Id', 'MetricsConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Id' => [ 'shape' => 'MetricsId', 'location' => 'querystring', 'locationName' => 'id', ], 'MetricsConfiguration' => [ 'shape' => 'MetricsConfiguration', 'locationName' => 'MetricsConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'MetricsConfiguration', ], 'PutBucketNotificationConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'NotificationConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'NotificationConfiguration' => [ 'shape' => 'NotificationConfiguration', 'locationName' => 'NotificationConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'SkipDestinationValidation' => [ 'shape' => 'SkipValidation', 'location' => 'header', 'locationName' => 'x-amz-skip-destination-validation', ], ], 'payload' => 'NotificationConfiguration', ], 'PutBucketNotificationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'NotificationConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'NotificationConfiguration' => [ 'shape' => 'NotificationConfigurationDeprecated', 'locationName' => 'NotificationConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'NotificationConfiguration', ], 'PutBucketOwnershipControlsRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'OwnershipControls', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'OwnershipControls' => [ 'shape' => 'OwnershipControls', 'locationName' => 'OwnershipControls', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], ], 'payload' => 'OwnershipControls', ], 'PutBucketPolicyRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Policy', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ConfirmRemoveSelfBucketAccess' => [ 'shape' => 'ConfirmRemoveSelfBucketAccess', 'location' => 'header', 'locationName' => 'x-amz-confirm-remove-self-bucket-access', ], 'Policy' => [ 'shape' => 'Policy', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'Policy', ], 'PutBucketReplicationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'ReplicationConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ReplicationConfiguration' => [ 'shape' => 'ReplicationConfiguration', 'locationName' => 'ReplicationConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'Token' => [ 'shape' => 'ObjectLockToken', 'location' => 'header', 'locationName' => 'x-amz-bucket-object-lock-token', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'ReplicationConfiguration', ], 'PutBucketRequestPaymentRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'RequestPaymentConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'RequestPaymentConfiguration' => [ 'shape' => 'RequestPaymentConfiguration', 'locationName' => 'RequestPaymentConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'RequestPaymentConfiguration', ], 'PutBucketTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Tagging', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'Tagging' => [ 'shape' => 'Tagging', 'locationName' => 'Tagging', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'Tagging', ], 'PutBucketVersioningRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'VersioningConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'MFA' => [ 'shape' => 'MFA', 'location' => 'header', 'locationName' => 'x-amz-mfa', ], 'VersioningConfiguration' => [ 'shape' => 'VersioningConfiguration', 'locationName' => 'VersioningConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'VersioningConfiguration', ], 'PutBucketWebsiteRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'WebsiteConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'WebsiteConfiguration' => [ 'shape' => 'WebsiteConfiguration', 'locationName' => 'WebsiteConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'WebsiteConfiguration', ], 'PutObjectAclOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'PutObjectAclRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'ACL' => [ 'shape' => 'ObjectCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'AccessControlPolicy' => [ 'shape' => 'AccessControlPolicy', 'locationName' => 'AccessControlPolicy', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWrite' => [ 'shape' => 'GrantWrite', 'location' => 'header', 'locationName' => 'x-amz-grant-write', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'AccessControlPolicy', ], 'PutObjectLegalHoldOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'PutObjectLegalHoldRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'LegalHold' => [ 'shape' => 'ObjectLockLegalHold', 'locationName' => 'LegalHold', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'LegalHold', ], 'PutObjectLockConfigurationOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'PutObjectLockConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ObjectLockConfiguration' => [ 'shape' => 'ObjectLockConfiguration', 'locationName' => 'ObjectLockConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'Token' => [ 'shape' => 'ObjectLockToken', 'location' => 'header', 'locationName' => 'x-amz-bucket-object-lock-token', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'ObjectLockConfiguration', ], 'PutObjectOutput' => [ 'type' => 'structure', 'members' => [ 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-expiration', ], 'ETag' => [ 'shape' => 'ETag', 'location' => 'header', 'locationName' => 'ETag', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'ChecksumType' => [ 'shape' => 'ChecksumType', 'location' => 'header', 'locationName' => 'x-amz-checksum-type', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'Size' => [ 'shape' => 'Size', 'location' => 'header', 'locationName' => 'x-amz-object-size', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'PutObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'ACL' => [ 'shape' => 'ObjectCannedACL', 'location' => 'header', 'locationName' => 'x-amz-acl', ], 'Body' => [ 'shape' => 'Body', 'streaming' => true, ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'Cache-Control', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'Content-Language', ], 'ContentLength' => [ 'shape' => 'ContentLength', 'location' => 'header', 'locationName' => 'Content-Length', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'Content-Type', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'Expires', ], 'IfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'IfNoneMatch' => [ 'shape' => 'IfNoneMatch', 'location' => 'header', 'locationName' => 'If-None-Match', ], 'GrantFullControl' => [ 'shape' => 'GrantFullControl', 'location' => 'header', 'locationName' => 'x-amz-grant-full-control', ], 'GrantRead' => [ 'shape' => 'GrantRead', 'location' => 'header', 'locationName' => 'x-amz-grant-read', ], 'GrantReadACP' => [ 'shape' => 'GrantReadACP', 'location' => 'header', 'locationName' => 'x-amz-grant-read-acp', ], 'GrantWriteACP' => [ 'shape' => 'GrantWriteACP', 'location' => 'header', 'locationName' => 'x-amz-grant-write-acp', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'WriteOffsetBytes' => [ 'shape' => 'WriteOffsetBytes', 'location' => 'header', 'locationName' => 'x-amz-write-offset-bytes', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-storage-class', ], 'WebsiteRedirectLocation' => [ 'shape' => 'WebsiteRedirectLocation', 'location' => 'header', 'locationName' => 'x-amz-website-redirect-location', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'SSEKMSEncryptionContext' => [ 'shape' => 'SSEKMSEncryptionContext', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-context', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'Tagging' => [ 'shape' => 'TaggingHeader', 'location' => 'header', 'locationName' => 'x-amz-tagging', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-object-lock-mode', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-object-lock-retain-until-date', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-object-lock-legal-hold', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'Body', ], 'PutObjectRetentionOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'PutObjectRetentionRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'Retention' => [ 'shape' => 'ObjectLockRetention', 'locationName' => 'Retention', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'BypassGovernanceRetention' => [ 'shape' => 'BypassGovernanceRetention', 'location' => 'header', 'locationName' => 'x-amz-bypass-governance-retention', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'Retention', ], 'PutObjectTaggingOutput' => [ 'type' => 'structure', 'members' => [ 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-version-id', ], ], ], 'PutObjectTaggingRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'Tagging', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'Tagging' => [ 'shape' => 'Tagging', 'locationName' => 'Tagging', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], ], 'payload' => 'Tagging', ], 'PutPublicAccessBlockRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'PublicAccessBlockConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'PublicAccessBlockConfiguration' => [ 'shape' => 'PublicAccessBlockConfiguration', 'locationName' => 'PublicAccessBlockConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'PublicAccessBlockConfiguration', ], 'QueueArn' => [ 'type' => 'string', ], 'QueueConfiguration' => [ 'type' => 'structure', 'required' => [ 'QueueArn', 'Events', ], 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'QueueArn' => [ 'shape' => 'QueueArn', 'locationName' => 'Queue', ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'Filter' => [ 'shape' => 'NotificationConfigurationFilter', ], ], ], 'QueueConfigurationDeprecated' => [ 'type' => 'structure', 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'Event' => [ 'shape' => 'Event', 'deprecated' => true, ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'Queue' => [ 'shape' => 'QueueArn', ], ], ], 'QueueConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'QueueConfiguration', ], 'flattened' => true, ], 'Quiet' => [ 'type' => 'boolean', 'box' => true, ], 'QuoteCharacter' => [ 'type' => 'string', ], 'QuoteEscapeCharacter' => [ 'type' => 'string', ], 'QuoteFields' => [ 'type' => 'string', 'enum' => [ 'ALWAYS', 'ASNEEDED', ], ], 'Range' => [ 'type' => 'string', ], 'RecordDelimiter' => [ 'type' => 'string', ], 'RecordExpiration' => [ 'type' => 'structure', 'required' => [ 'Expiration', ], 'members' => [ 'Expiration' => [ 'shape' => 'ExpirationState', ], 'Days' => [ 'shape' => 'RecordExpirationDays', 'box' => true, ], ], ], 'RecordExpirationDays' => [ 'type' => 'integer', ], 'RecordsEvent' => [ 'type' => 'structure', 'members' => [ 'Payload' => [ 'shape' => 'Body', 'eventpayload' => true, ], ], 'event' => true, ], 'Redirect' => [ 'type' => 'structure', 'members' => [ 'HostName' => [ 'shape' => 'HostName', ], 'HttpRedirectCode' => [ 'shape' => 'HttpRedirectCode', ], 'Protocol' => [ 'shape' => 'Protocol', ], 'ReplaceKeyPrefixWith' => [ 'shape' => 'ReplaceKeyPrefixWith', ], 'ReplaceKeyWith' => [ 'shape' => 'ReplaceKeyWith', ], ], ], 'RedirectAllRequestsTo' => [ 'type' => 'structure', 'required' => [ 'HostName', ], 'members' => [ 'HostName' => [ 'shape' => 'HostName', ], 'Protocol' => [ 'shape' => 'Protocol', ], ], ], 'Region' => [ 'type' => 'string', 'max' => 20, 'min' => 0, ], 'RenameObjectOutput' => [ 'type' => 'structure', 'members' => [], ], 'RenameObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'RenameSource', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'RenameSource' => [ 'shape' => 'RenameSource', 'location' => 'header', 'locationName' => 'x-amz-rename-source', ], 'DestinationIfMatch' => [ 'shape' => 'IfMatch', 'location' => 'header', 'locationName' => 'If-Match', ], 'DestinationIfNoneMatch' => [ 'shape' => 'IfNoneMatch', 'location' => 'header', 'locationName' => 'If-None-Match', ], 'DestinationIfModifiedSince' => [ 'shape' => 'IfModifiedSince', 'location' => 'header', 'locationName' => 'If-Modified-Since', ], 'DestinationIfUnmodifiedSince' => [ 'shape' => 'IfUnmodifiedSince', 'location' => 'header', 'locationName' => 'If-Unmodified-Since', ], 'SourceIfMatch' => [ 'shape' => 'RenameSourceIfMatch', 'location' => 'header', 'locationName' => 'x-amz-rename-source-if-match', ], 'SourceIfNoneMatch' => [ 'shape' => 'RenameSourceIfNoneMatch', 'location' => 'header', 'locationName' => 'x-amz-rename-source-if-none-match', ], 'SourceIfModifiedSince' => [ 'shape' => 'RenameSourceIfModifiedSince', 'location' => 'header', 'locationName' => 'x-amz-rename-source-if-modified-since', ], 'SourceIfUnmodifiedSince' => [ 'shape' => 'RenameSourceIfUnmodifiedSince', 'location' => 'header', 'locationName' => 'x-amz-rename-source-if-unmodified-since', ], 'ClientToken' => [ 'shape' => 'ClientToken', 'idempotencyToken' => true, 'location' => 'header', 'locationName' => 'x-amz-client-token', ], ], ], 'RenameSource' => [ 'type' => 'string', 'pattern' => '\\/?.+\\/.+', ], 'RenameSourceIfMatch' => [ 'type' => 'string', ], 'RenameSourceIfModifiedSince' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'RenameSourceIfNoneMatch' => [ 'type' => 'string', ], 'RenameSourceIfUnmodifiedSince' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'ReplaceKeyPrefixWith' => [ 'type' => 'string', ], 'ReplaceKeyWith' => [ 'type' => 'string', ], 'ReplicaKmsKeyID' => [ 'type' => 'string', ], 'ReplicaModifications' => [ 'type' => 'structure', 'required' => [ 'Status', ], 'members' => [ 'Status' => [ 'shape' => 'ReplicaModificationsStatus', ], ], ], 'ReplicaModificationsStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'ReplicationConfiguration' => [ 'type' => 'structure', 'required' => [ 'Role', 'Rules', ], 'members' => [ 'Role' => [ 'shape' => 'Role', ], 'Rules' => [ 'shape' => 'ReplicationRules', 'locationName' => 'Rule', ], ], ], 'ReplicationRule' => [ 'type' => 'structure', 'required' => [ 'Status', 'Destination', ], 'members' => [ 'ID' => [ 'shape' => 'ID', ], 'Priority' => [ 'shape' => 'Priority', ], 'Prefix' => [ 'shape' => 'Prefix', 'deprecated' => true, ], 'Filter' => [ 'shape' => 'ReplicationRuleFilter', ], 'Status' => [ 'shape' => 'ReplicationRuleStatus', ], 'SourceSelectionCriteria' => [ 'shape' => 'SourceSelectionCriteria', ], 'ExistingObjectReplication' => [ 'shape' => 'ExistingObjectReplication', ], 'Destination' => [ 'shape' => 'Destination', ], 'DeleteMarkerReplication' => [ 'shape' => 'DeleteMarkerReplication', ], ], ], 'ReplicationRuleAndOperator' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tags' => [ 'shape' => 'TagSet', 'flattened' => true, 'locationName' => 'Tag', ], ], ], 'ReplicationRuleFilter' => [ 'type' => 'structure', 'members' => [ 'Prefix' => [ 'shape' => 'Prefix', ], 'Tag' => [ 'shape' => 'Tag', ], 'And' => [ 'shape' => 'ReplicationRuleAndOperator', ], ], ], 'ReplicationRuleStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'ReplicationRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'ReplicationRule', ], 'flattened' => true, ], 'ReplicationStatus' => [ 'type' => 'string', 'enum' => [ 'COMPLETE', 'PENDING', 'FAILED', 'REPLICA', 'COMPLETED', ], ], 'ReplicationTime' => [ 'type' => 'structure', 'required' => [ 'Status', 'Time', ], 'members' => [ 'Status' => [ 'shape' => 'ReplicationTimeStatus', ], 'Time' => [ 'shape' => 'ReplicationTimeValue', ], ], ], 'ReplicationTimeStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'ReplicationTimeValue' => [ 'type' => 'structure', 'members' => [ 'Minutes' => [ 'shape' => 'Minutes', ], ], ], 'RequestCharged' => [ 'type' => 'string', 'enum' => [ 'requester', ], ], 'RequestPayer' => [ 'type' => 'string', 'enum' => [ 'requester', ], ], 'RequestPaymentConfiguration' => [ 'type' => 'structure', 'required' => [ 'Payer', ], 'members' => [ 'Payer' => [ 'shape' => 'Payer', ], ], ], 'RequestProgress' => [ 'type' => 'structure', 'members' => [ 'Enabled' => [ 'shape' => 'EnableRequestProgress', ], ], ], 'RequestRoute' => [ 'type' => 'string', ], 'RequestToken' => [ 'type' => 'string', ], 'ResponseCacheControl' => [ 'type' => 'string', ], 'ResponseContentDisposition' => [ 'type' => 'string', ], 'ResponseContentEncoding' => [ 'type' => 'string', ], 'ResponseContentLanguage' => [ 'type' => 'string', ], 'ResponseContentType' => [ 'type' => 'string', ], 'ResponseExpires' => [ 'type' => 'timestamp', 'timestampFormat' => 'rfc822', ], 'Restore' => [ 'type' => 'string', ], 'RestoreExpiryDate' => [ 'type' => 'timestamp', ], 'RestoreObjectOutput' => [ 'type' => 'structure', 'members' => [ 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], 'RestoreOutputPath' => [ 'shape' => 'RestoreOutputPath', 'location' => 'header', 'locationName' => 'x-amz-restore-output-path', ], ], ], 'RestoreObjectRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'querystring', 'locationName' => 'versionId', ], 'RestoreRequest' => [ 'shape' => 'RestoreRequest', 'locationName' => 'RestoreRequest', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'RestoreRequest', ], 'RestoreOutputPath' => [ 'type' => 'string', ], 'RestoreRequest' => [ 'type' => 'structure', 'members' => [ 'Days' => [ 'shape' => 'Days', ], 'GlacierJobParameters' => [ 'shape' => 'GlacierJobParameters', ], 'Type' => [ 'shape' => 'RestoreRequestType', ], 'Tier' => [ 'shape' => 'Tier', ], 'Description' => [ 'shape' => 'Description', ], 'SelectParameters' => [ 'shape' => 'SelectParameters', ], 'OutputLocation' => [ 'shape' => 'OutputLocation', ], ], ], 'RestoreRequestType' => [ 'type' => 'string', 'enum' => [ 'SELECT', ], ], 'RestoreStatus' => [ 'type' => 'structure', 'members' => [ 'IsRestoreInProgress' => [ 'shape' => 'IsRestoreInProgress', ], 'RestoreExpiryDate' => [ 'shape' => 'RestoreExpiryDate', ], ], ], 'Role' => [ 'type' => 'string', ], 'RoutingRule' => [ 'type' => 'structure', 'required' => [ 'Redirect', ], 'members' => [ 'Condition' => [ 'shape' => 'Condition', ], 'Redirect' => [ 'shape' => 'Redirect', ], ], ], 'RoutingRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'RoutingRule', 'locationName' => 'RoutingRule', ], ], 'Rule' => [ 'type' => 'structure', 'required' => [ 'Prefix', 'Status', ], 'members' => [ 'Expiration' => [ 'shape' => 'LifecycleExpiration', ], 'ID' => [ 'shape' => 'ID', ], 'Prefix' => [ 'shape' => 'Prefix', ], 'Status' => [ 'shape' => 'ExpirationStatus', ], 'Transition' => [ 'shape' => 'Transition', ], 'NoncurrentVersionTransition' => [ 'shape' => 'NoncurrentVersionTransition', ], 'NoncurrentVersionExpiration' => [ 'shape' => 'NoncurrentVersionExpiration', ], 'AbortIncompleteMultipartUpload' => [ 'shape' => 'AbortIncompleteMultipartUpload', ], ], ], 'Rules' => [ 'type' => 'list', 'member' => [ 'shape' => 'Rule', ], 'flattened' => true, ], 'S3KeyFilter' => [ 'type' => 'structure', 'members' => [ 'FilterRules' => [ 'shape' => 'FilterRuleList', 'locationName' => 'FilterRule', ], ], ], 'S3Location' => [ 'type' => 'structure', 'required' => [ 'BucketName', 'Prefix', ], 'members' => [ 'BucketName' => [ 'shape' => 'BucketName', ], 'Prefix' => [ 'shape' => 'LocationPrefix', ], 'Encryption' => [ 'shape' => 'Encryption', ], 'CannedACL' => [ 'shape' => 'ObjectCannedACL', ], 'AccessControlList' => [ 'shape' => 'Grants', ], 'Tagging' => [ 'shape' => 'Tagging', ], 'UserMetadata' => [ 'shape' => 'UserMetadata', ], 'StorageClass' => [ 'shape' => 'StorageClass', ], ], ], 'S3RegionalOrS3ExpressBucketArnString' => [ 'type' => 'string', 'max' => 128, 'min' => 1, 'pattern' => 'arn:[^:]+:(s3|s3express):.*', ], 'S3TablesArn' => [ 'type' => 'string', ], 'S3TablesBucketArn' => [ 'type' => 'string', ], 'S3TablesBucketType' => [ 'type' => 'string', 'enum' => [ 'aws', 'customer', ], ], 'S3TablesDestination' => [ 'type' => 'structure', 'required' => [ 'TableBucketArn', 'TableName', ], 'members' => [ 'TableBucketArn' => [ 'shape' => 'S3TablesBucketArn', ], 'TableName' => [ 'shape' => 'S3TablesName', ], ], ], 'S3TablesDestinationResult' => [ 'type' => 'structure', 'required' => [ 'TableBucketArn', 'TableName', 'TableArn', 'TableNamespace', ], 'members' => [ 'TableBucketArn' => [ 'shape' => 'S3TablesBucketArn', ], 'TableName' => [ 'shape' => 'S3TablesName', ], 'TableArn' => [ 'shape' => 'S3TablesArn', ], 'TableNamespace' => [ 'shape' => 'S3TablesNamespace', ], ], ], 'S3TablesName' => [ 'type' => 'string', ], 'S3TablesNamespace' => [ 'type' => 'string', ], 'SSECustomerAlgorithm' => [ 'type' => 'string', ], 'SSECustomerKey' => [ 'type' => 'string', 'sensitive' => true, ], 'SSECustomerKeyMD5' => [ 'type' => 'string', ], 'SSEKMS' => [ 'type' => 'structure', 'required' => [ 'KeyId', ], 'members' => [ 'KeyId' => [ 'shape' => 'SSEKMSKeyId', ], ], 'locationName' => 'SSE-KMS', ], 'SSEKMSEncryptionContext' => [ 'type' => 'string', 'sensitive' => true, ], 'SSEKMSKeyId' => [ 'type' => 'string', 'sensitive' => true, ], 'SSES3' => [ 'type' => 'structure', 'members' => [], 'locationName' => 'SSE-S3', ], 'ScanRange' => [ 'type' => 'structure', 'members' => [ 'Start' => [ 'shape' => 'Start', ], 'End' => [ 'shape' => 'End', ], ], ], 'SelectObjectContentEventStream' => [ 'type' => 'structure', 'members' => [ 'Records' => [ 'shape' => 'RecordsEvent', ], 'Stats' => [ 'shape' => 'StatsEvent', ], 'Progress' => [ 'shape' => 'ProgressEvent', ], 'Cont' => [ 'shape' => 'ContinuationEvent', ], 'End' => [ 'shape' => 'EndEvent', ], ], 'eventstream' => true, ], 'SelectObjectContentOutput' => [ 'type' => 'structure', 'members' => [ 'Payload' => [ 'shape' => 'SelectObjectContentEventStream', ], ], 'payload' => 'Payload', ], 'SelectObjectContentRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'Expression', 'ExpressionType', 'InputSerialization', 'OutputSerialization', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'Expression' => [ 'shape' => 'Expression', ], 'ExpressionType' => [ 'shape' => 'ExpressionType', ], 'RequestProgress' => [ 'shape' => 'RequestProgress', ], 'InputSerialization' => [ 'shape' => 'InputSerialization', ], 'OutputSerialization' => [ 'shape' => 'OutputSerialization', ], 'ScanRange' => [ 'shape' => 'ScanRange', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], ], 'SelectParameters' => [ 'type' => 'structure', 'required' => [ 'InputSerialization', 'ExpressionType', 'Expression', 'OutputSerialization', ], 'members' => [ 'InputSerialization' => [ 'shape' => 'InputSerialization', ], 'ExpressionType' => [ 'shape' => 'ExpressionType', ], 'Expression' => [ 'shape' => 'Expression', ], 'OutputSerialization' => [ 'shape' => 'OutputSerialization', ], ], ], 'ServerSideEncryption' => [ 'type' => 'string', 'enum' => [ 'AES256', 'aws:fsx', 'aws:kms', 'aws:kms:dsse', ], ], 'ServerSideEncryptionByDefault' => [ 'type' => 'structure', 'required' => [ 'SSEAlgorithm', ], 'members' => [ 'SSEAlgorithm' => [ 'shape' => 'ServerSideEncryption', ], 'KMSMasterKeyID' => [ 'shape' => 'SSEKMSKeyId', ], ], ], 'ServerSideEncryptionConfiguration' => [ 'type' => 'structure', 'required' => [ 'Rules', ], 'members' => [ 'Rules' => [ 'shape' => 'ServerSideEncryptionRules', 'locationName' => 'Rule', ], ], ], 'ServerSideEncryptionRule' => [ 'type' => 'structure', 'members' => [ 'ApplyServerSideEncryptionByDefault' => [ 'shape' => 'ServerSideEncryptionByDefault', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', ], ], ], 'ServerSideEncryptionRules' => [ 'type' => 'list', 'member' => [ 'shape' => 'ServerSideEncryptionRule', ], 'flattened' => true, ], 'SessionCredentialValue' => [ 'type' => 'string', 'sensitive' => true, ], 'SessionCredentials' => [ 'type' => 'structure', 'required' => [ 'AccessKeyId', 'SecretAccessKey', 'SessionToken', 'Expiration', ], 'members' => [ 'AccessKeyId' => [ 'shape' => 'AccessKeyIdValue', 'locationName' => 'AccessKeyId', ], 'SecretAccessKey' => [ 'shape' => 'SessionCredentialValue', 'locationName' => 'SecretAccessKey', ], 'SessionToken' => [ 'shape' => 'SessionCredentialValue', 'locationName' => 'SessionToken', ], 'Expiration' => [ 'shape' => 'SessionExpiration', 'locationName' => 'Expiration', ], ], ], 'SessionExpiration' => [ 'type' => 'timestamp', ], 'SessionMode' => [ 'type' => 'string', 'enum' => [ 'ReadOnly', 'ReadWrite', ], ], 'Setting' => [ 'type' => 'boolean', 'box' => true, ], 'SimplePrefix' => [ 'type' => 'structure', 'members' => [], 'locationName' => 'SimplePrefix', ], 'Size' => [ 'type' => 'long', 'box' => true, ], 'SkipValidation' => [ 'type' => 'boolean', 'box' => true, ], 'SourceSelectionCriteria' => [ 'type' => 'structure', 'members' => [ 'SseKmsEncryptedObjects' => [ 'shape' => 'SseKmsEncryptedObjects', ], 'ReplicaModifications' => [ 'shape' => 'ReplicaModifications', ], ], ], 'SseKmsEncryptedObjects' => [ 'type' => 'structure', 'required' => [ 'Status', ], 'members' => [ 'Status' => [ 'shape' => 'SseKmsEncryptedObjectsStatus', ], ], ], 'SseKmsEncryptedObjectsStatus' => [ 'type' => 'string', 'enum' => [ 'Enabled', 'Disabled', ], ], 'Start' => [ 'type' => 'long', 'box' => true, ], 'StartAfter' => [ 'type' => 'string', ], 'Stats' => [ 'type' => 'structure', 'members' => [ 'BytesScanned' => [ 'shape' => 'BytesScanned', ], 'BytesProcessed' => [ 'shape' => 'BytesProcessed', ], 'BytesReturned' => [ 'shape' => 'BytesReturned', ], ], ], 'StatsEvent' => [ 'type' => 'structure', 'members' => [ 'Details' => [ 'shape' => 'Stats', 'eventpayload' => true, ], ], 'event' => true, ], 'StorageClass' => [ 'type' => 'string', 'enum' => [ 'STANDARD', 'REDUCED_REDUNDANCY', 'STANDARD_IA', 'ONEZONE_IA', 'INTELLIGENT_TIERING', 'GLACIER', 'DEEP_ARCHIVE', 'OUTPOSTS', 'GLACIER_IR', 'SNOW', 'EXPRESS_ONEZONE', 'FSX_OPENZFS', ], ], 'StorageClassAnalysis' => [ 'type' => 'structure', 'members' => [ 'DataExport' => [ 'shape' => 'StorageClassAnalysisDataExport', ], ], ], 'StorageClassAnalysisDataExport' => [ 'type' => 'structure', 'required' => [ 'OutputSchemaVersion', 'Destination', ], 'members' => [ 'OutputSchemaVersion' => [ 'shape' => 'StorageClassAnalysisSchemaVersion', ], 'Destination' => [ 'shape' => 'AnalyticsExportDestination', ], ], ], 'StorageClassAnalysisSchemaVersion' => [ 'type' => 'string', 'enum' => [ 'V_1', ], ], 'Suffix' => [ 'type' => 'string', ], 'TableSseAlgorithm' => [ 'type' => 'string', 'enum' => [ 'aws:kms', 'AES256', ], ], 'Tag' => [ 'type' => 'structure', 'required' => [ 'Key', 'Value', ], 'members' => [ 'Key' => [ 'shape' => 'ObjectKey', ], 'Value' => [ 'shape' => 'Value', ], ], ], 'TagCount' => [ 'type' => 'integer', 'box' => true, ], 'TagSet' => [ 'type' => 'list', 'member' => [ 'shape' => 'Tag', 'locationName' => 'Tag', ], ], 'Tagging' => [ 'type' => 'structure', 'required' => [ 'TagSet', ], 'members' => [ 'TagSet' => [ 'shape' => 'TagSet', ], ], ], 'TaggingDirective' => [ 'type' => 'string', 'enum' => [ 'COPY', 'REPLACE', ], ], 'TaggingHeader' => [ 'type' => 'string', ], 'TargetBucket' => [ 'type' => 'string', ], 'TargetGrant' => [ 'type' => 'structure', 'members' => [ 'Grantee' => [ 'shape' => 'Grantee', ], 'Permission' => [ 'shape' => 'BucketLogsPermission', ], ], ], 'TargetGrants' => [ 'type' => 'list', 'member' => [ 'shape' => 'TargetGrant', 'locationName' => 'Grant', ], ], 'TargetObjectKeyFormat' => [ 'type' => 'structure', 'members' => [ 'SimplePrefix' => [ 'shape' => 'SimplePrefix', 'locationName' => 'SimplePrefix', ], 'PartitionedPrefix' => [ 'shape' => 'PartitionedPrefix', 'locationName' => 'PartitionedPrefix', ], ], ], 'TargetPrefix' => [ 'type' => 'string', ], 'Tier' => [ 'type' => 'string', 'enum' => [ 'Standard', 'Bulk', 'Expedited', ], ], 'Tiering' => [ 'type' => 'structure', 'required' => [ 'Days', 'AccessTier', ], 'members' => [ 'Days' => [ 'shape' => 'IntelligentTieringDays', ], 'AccessTier' => [ 'shape' => 'IntelligentTieringAccessTier', ], ], ], 'TieringList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Tiering', ], 'flattened' => true, ], 'Token' => [ 'type' => 'string', ], 'TooManyParts' => [ 'type' => 'structure', 'members' => [], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'TopicArn' => [ 'type' => 'string', ], 'TopicConfiguration' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'Events', ], 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'TopicArn' => [ 'shape' => 'TopicArn', 'locationName' => 'Topic', ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'Filter' => [ 'shape' => 'NotificationConfigurationFilter', ], ], ], 'TopicConfigurationDeprecated' => [ 'type' => 'structure', 'members' => [ 'Id' => [ 'shape' => 'NotificationId', ], 'Events' => [ 'shape' => 'EventList', 'locationName' => 'Event', ], 'Event' => [ 'shape' => 'Event', 'deprecated' => true, ], 'Topic' => [ 'shape' => 'TopicArn', ], ], ], 'TopicConfigurationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'TopicConfiguration', ], 'flattened' => true, ], 'Transition' => [ 'type' => 'structure', 'members' => [ 'Date' => [ 'shape' => 'Date', ], 'Days' => [ 'shape' => 'Days', ], 'StorageClass' => [ 'shape' => 'TransitionStorageClass', ], ], ], 'TransitionDefaultMinimumObjectSize' => [ 'type' => 'string', 'enum' => [ 'varies_by_storage_class', 'all_storage_classes_128K', ], ], 'TransitionList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Transition', ], 'flattened' => true, ], 'TransitionStorageClass' => [ 'type' => 'string', 'enum' => [ 'GLACIER', 'STANDARD_IA', 'ONEZONE_IA', 'INTELLIGENT_TIERING', 'DEEP_ARCHIVE', 'GLACIER_IR', ], ], 'Type' => [ 'type' => 'string', 'enum' => [ 'CanonicalUser', 'AmazonCustomerByEmail', 'Group', ], ], 'URI' => [ 'type' => 'string', ], 'UpdateBucketMetadataInventoryTableConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'InventoryTableConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'InventoryTableConfiguration' => [ 'shape' => 'InventoryTableConfigurationUpdates', 'locationName' => 'InventoryTableConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'InventoryTableConfiguration', ], 'UpdateBucketMetadataJournalTableConfigurationRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'JournalTableConfiguration', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'JournalTableConfiguration' => [ 'shape' => 'JournalTableConfigurationUpdates', 'locationName' => 'JournalTableConfiguration', 'xmlNamespace' => [ 'uri' => 'http://s3.amazonaws.com/doc/2006-03-01/', ], ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'JournalTableConfiguration', ], 'UploadIdMarker' => [ 'type' => 'string', ], 'UploadPartCopyOutput' => [ 'type' => 'structure', 'members' => [ 'CopySourceVersionId' => [ 'shape' => 'CopySourceVersionId', 'location' => 'header', 'locationName' => 'x-amz-copy-source-version-id', ], 'CopyPartResult' => [ 'shape' => 'CopyPartResult', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], 'payload' => 'CopyPartResult', ], 'UploadPartCopyRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'CopySource', 'Key', 'PartNumber', 'UploadId', ], 'members' => [ 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'CopySource' => [ 'shape' => 'CopySource', 'location' => 'header', 'locationName' => 'x-amz-copy-source', ], 'CopySourceIfMatch' => [ 'shape' => 'CopySourceIfMatch', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-match', ], 'CopySourceIfModifiedSince' => [ 'shape' => 'CopySourceIfModifiedSince', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-modified-since', ], 'CopySourceIfNoneMatch' => [ 'shape' => 'CopySourceIfNoneMatch', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-none-match', ], 'CopySourceIfUnmodifiedSince' => [ 'shape' => 'CopySourceIfUnmodifiedSince', 'location' => 'header', 'locationName' => 'x-amz-copy-source-if-unmodified-since', ], 'CopySourceRange' => [ 'shape' => 'CopySourceRange', 'location' => 'header', 'locationName' => 'x-amz-copy-source-range', ], 'Key' => [ 'shape' => 'ObjectKey', 'location' => 'uri', 'locationName' => 'Key', ], 'PartNumber' => [ 'shape' => 'PartNumber', 'location' => 'querystring', 'locationName' => 'partNumber', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', 'location' => 'querystring', 'locationName' => 'uploadId', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'CopySourceSSECustomerAlgorithm' => [ 'shape' => 'CopySourceSSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-algorithm', ], 'CopySourceSSECustomerKey' => [ 'shape' => 'CopySourceSSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-key', ], 'CopySourceSSECustomerKeyMD5' => [ 'shape' => 'CopySourceSSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-copy-source-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], 'ExpectedSourceBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-source-expected-bucket-owner', ], ], ], 'UploadPartOutput' => [ 'type' => 'structure', 'members' => [ 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption', ], 'ETag' => [ 'shape' => 'ETag', 'location' => 'header', 'locationName' => 'ETag', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-aws-kms-key-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-bucket-key-enabled', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-request-charged', ], ], ], 'UploadPartRequest' => [ 'type' => 'structure', 'required' => [ 'Bucket', 'Key', 'PartNumber', 'UploadId', ], 'members' => [ 'Body' => [ 'shape' => 'Body', 'streaming' => true, ], 'Bucket' => [ 'shape' => 'BucketName', 'contextParam' => [ 'name' => 'Bucket', ], 'location' => 'uri', 'locationName' => 'Bucket', ], 'ContentLength' => [ 'shape' => 'ContentLength', 'location' => 'header', 'locationName' => 'Content-Length', ], 'ContentMD5' => [ 'shape' => 'ContentMD5', 'location' => 'header', 'locationName' => 'Content-MD5', ], 'ChecksumAlgorithm' => [ 'shape' => 'ChecksumAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-sdk-checksum-algorithm', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-checksum-sha256', ], 'Key' => [ 'shape' => 'ObjectKey', 'contextParam' => [ 'name' => 'Key', ], 'location' => 'uri', 'locationName' => 'Key', ], 'PartNumber' => [ 'shape' => 'PartNumber', 'location' => 'querystring', 'locationName' => 'partNumber', ], 'UploadId' => [ 'shape' => 'MultipartUploadId', 'location' => 'querystring', 'locationName' => 'uploadId', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-algorithm', ], 'SSECustomerKey' => [ 'shape' => 'SSECustomerKey', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-server-side-encryption-customer-key-MD5', ], 'RequestPayer' => [ 'shape' => 'RequestPayer', 'location' => 'header', 'locationName' => 'x-amz-request-payer', ], 'ExpectedBucketOwner' => [ 'shape' => 'AccountId', 'location' => 'header', 'locationName' => 'x-amz-expected-bucket-owner', ], ], 'payload' => 'Body', ], 'UserMetadata' => [ 'type' => 'list', 'member' => [ 'shape' => 'MetadataEntry', 'locationName' => 'MetadataEntry', ], ], 'Value' => [ 'type' => 'string', ], 'VersionCount' => [ 'type' => 'integer', 'box' => true, ], 'VersionIdMarker' => [ 'type' => 'string', ], 'VersioningConfiguration' => [ 'type' => 'structure', 'members' => [ 'MFADelete' => [ 'shape' => 'MFADelete', 'locationName' => 'MfaDelete', ], 'Status' => [ 'shape' => 'BucketVersioningStatus', ], ], ], 'WebsiteConfiguration' => [ 'type' => 'structure', 'members' => [ 'ErrorDocument' => [ 'shape' => 'ErrorDocument', ], 'IndexDocument' => [ 'shape' => 'IndexDocument', ], 'RedirectAllRequestsTo' => [ 'shape' => 'RedirectAllRequestsTo', ], 'RoutingRules' => [ 'shape' => 'RoutingRules', ], ], ], 'WebsiteRedirectLocation' => [ 'type' => 'string', ], 'WriteGetObjectResponseRequest' => [ 'type' => 'structure', 'required' => [ 'RequestRoute', 'RequestToken', ], 'members' => [ 'RequestRoute' => [ 'shape' => 'RequestRoute', 'hostLabel' => true, 'location' => 'header', 'locationName' => 'x-amz-request-route', ], 'RequestToken' => [ 'shape' => 'RequestToken', 'location' => 'header', 'locationName' => 'x-amz-request-token', ], 'Body' => [ 'shape' => 'Body', 'streaming' => true, ], 'StatusCode' => [ 'shape' => 'GetObjectResponseStatusCode', 'location' => 'header', 'locationName' => 'x-amz-fwd-status', ], 'ErrorCode' => [ 'shape' => 'ErrorCode', 'location' => 'header', 'locationName' => 'x-amz-fwd-error-code', ], 'ErrorMessage' => [ 'shape' => 'ErrorMessage', 'location' => 'header', 'locationName' => 'x-amz-fwd-error-message', ], 'AcceptRanges' => [ 'shape' => 'AcceptRanges', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-accept-ranges', ], 'CacheControl' => [ 'shape' => 'CacheControl', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Cache-Control', ], 'ContentDisposition' => [ 'shape' => 'ContentDisposition', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Content-Disposition', ], 'ContentEncoding' => [ 'shape' => 'ContentEncoding', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Content-Encoding', ], 'ContentLanguage' => [ 'shape' => 'ContentLanguage', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Content-Language', ], 'ContentLength' => [ 'shape' => 'ContentLength', 'location' => 'header', 'locationName' => 'Content-Length', ], 'ContentRange' => [ 'shape' => 'ContentRange', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Content-Range', ], 'ContentType' => [ 'shape' => 'ContentType', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Content-Type', ], 'ChecksumCRC32' => [ 'shape' => 'ChecksumCRC32', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-checksum-crc32', ], 'ChecksumCRC32C' => [ 'shape' => 'ChecksumCRC32C', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-checksum-crc32c', ], 'ChecksumCRC64NVME' => [ 'shape' => 'ChecksumCRC64NVME', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-checksum-crc64nvme', ], 'ChecksumSHA1' => [ 'shape' => 'ChecksumSHA1', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-checksum-sha1', ], 'ChecksumSHA256' => [ 'shape' => 'ChecksumSHA256', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-checksum-sha256', ], 'DeleteMarker' => [ 'shape' => 'DeleteMarker', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-delete-marker', ], 'ETag' => [ 'shape' => 'ETag', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-ETag', ], 'Expires' => [ 'shape' => 'Expires', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Expires', ], 'Expiration' => [ 'shape' => 'Expiration', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-expiration', ], 'LastModified' => [ 'shape' => 'LastModified', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-Last-Modified', ], 'MissingMeta' => [ 'shape' => 'MissingMeta', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-missing-meta', ], 'Metadata' => [ 'shape' => 'Metadata', 'location' => 'headers', 'locationName' => 'x-amz-meta-', ], 'ObjectLockMode' => [ 'shape' => 'ObjectLockMode', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-object-lock-mode', ], 'ObjectLockLegalHoldStatus' => [ 'shape' => 'ObjectLockLegalHoldStatus', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-object-lock-legal-hold', ], 'ObjectLockRetainUntilDate' => [ 'shape' => 'ObjectLockRetainUntilDate', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-object-lock-retain-until-date', ], 'PartsCount' => [ 'shape' => 'PartsCount', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-mp-parts-count', ], 'ReplicationStatus' => [ 'shape' => 'ReplicationStatus', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-replication-status', ], 'RequestCharged' => [ 'shape' => 'RequestCharged', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-request-charged', ], 'Restore' => [ 'shape' => 'Restore', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-restore', ], 'ServerSideEncryption' => [ 'shape' => 'ServerSideEncryption', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-server-side-encryption', ], 'SSECustomerAlgorithm' => [ 'shape' => 'SSECustomerAlgorithm', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-server-side-encryption-customer-algorithm', ], 'SSEKMSKeyId' => [ 'shape' => 'SSEKMSKeyId', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-server-side-encryption-aws-kms-key-id', ], 'SSECustomerKeyMD5' => [ 'shape' => 'SSECustomerKeyMD5', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-server-side-encryption-customer-key-MD5', ], 'StorageClass' => [ 'shape' => 'StorageClass', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-storage-class', ], 'TagCount' => [ 'shape' => 'TagCount', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-tagging-count', ], 'VersionId' => [ 'shape' => 'ObjectVersionId', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-version-id', ], 'BucketKeyEnabled' => [ 'shape' => 'BucketKeyEnabled', 'location' => 'header', 'locationName' => 'x-amz-fwd-header-x-amz-server-side-encryption-bucket-key-enabled', ], ], 'payload' => 'Body', ], 'WriteOffsetBytes' => [ 'type' => 'long', 'box' => true, ], 'Years' => [ 'type' => 'integer', 'box' => true, ], ], 'clientContextParams' => [ 'Accelerate' => [ 'documentation' => 'Enables this client to use S3 Transfer Acceleration endpoints.', 'type' => 'boolean', ], 'DisableMultiRegionAccessPoints' => [ 'documentation' => 'Disables this client\'s usage of Multi-Region Access Points.', 'type' => 'boolean', ], 'DisableS3ExpressSessionAuth' => [ 'documentation' => 'Disables this client\'s usage of Session Auth for S3Express buckets and reverts to using conventional SigV4 for those.', 'type' => 'boolean', ], 'ForcePathStyle' => [ 'documentation' => 'Forces this client to use path-style addressing for buckets.', 'type' => 'boolean', ], 'UseArnRegion' => [ 'documentation' => 'Enables this client to use an ARN\'s region when constructing an endpoint instead of the client\'s configured region.', 'type' => 'boolean', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..d9d6b0ec7 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Bucket' => [ 'required' => false, 'documentation' => 'The S3 bucket used to send the request. This is an optional parameter that will be set automatically for operations that are scoped to an S3 bucket.', 'type' => 'String', ], 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], 'ForcePathStyle' => [ 'builtIn' => 'AWS::S3::ForcePathStyle', 'required' => true, 'default' => false, 'documentation' => 'When true, force a path-style endpoint to be used where the bucket name is part of the path.', 'type' => 'Boolean', ], 'Accelerate' => [ 'builtIn' => 'AWS::S3::Accelerate', 'required' => true, 'default' => false, 'documentation' => 'When true, use S3 Accelerate. NOTE: Not all regions support S3 accelerate.', 'type' => 'Boolean', ], 'UseGlobalEndpoint' => [ 'builtIn' => 'AWS::S3::UseGlobalEndpoint', 'required' => true, 'default' => false, 'documentation' => 'Whether the global endpoint should be used, rather then the regional endpoint for us-east-1.', 'type' => 'Boolean', ], 'UseObjectLambdaEndpoint' => [ 'required' => false, 'documentation' => 'Internal parameter to use object lambda endpoint for an operation (eg: WriteGetObjectResponse)', 'type' => 'Boolean', ], 'Key' => [ 'required' => false, 'documentation' => 'The S3 Key used to send the request. This is an optional parameter that will be set automatically for operations that are scoped to an S3 Key.', 'type' => 'String', ], 'Prefix' => [ 'required' => false, 'documentation' => 'The S3 Prefix used to send the request. This is an optional parameter that will be set automatically for operations that are scoped to an S3 Prefix.', 'type' => 'String', ], 'CopySource' => [ 'required' => false, 'documentation' => 'The Copy Source used for Copy Object request. This is an optional parameter that will be set automatically for operations that are scoped to Copy Source.', 'type' => 'String', ], 'DisableAccessPoints' => [ 'required' => false, 'documentation' => 'Internal parameter to disable Access Point Buckets', 'type' => 'Boolean', ], 'DisableMultiRegionAccessPoints' => [ 'builtIn' => 'AWS::S3::DisableMultiRegionAccessPoints', 'required' => true, 'default' => false, 'documentation' => 'Whether multi-region access points (MRAP) should be disabled.', 'type' => 'Boolean', ], 'UseArnRegion' => [ 'builtIn' => 'AWS::S3::UseArnRegion', 'required' => false, 'documentation' => 'When an Access Point ARN is provided and this flag is enabled, the SDK MUST use the ARN\'s region when constructing the endpoint instead of the client\'s configured region.', 'type' => 'Boolean', ], 'UseS3ExpressControlEndpoint' => [ 'required' => false, 'documentation' => 'Internal parameter to indicate whether S3Express operation should use control plane, (ex. CreateBucket)', 'type' => 'Boolean', ], 'DisableS3ExpressSessionAuth' => [ 'required' => false, 'documentation' => 'Parameter to indicate whether S3Express session auth should be disabled', 'type' => 'Boolean', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Accelerate cannot be used with FIPS', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'error' => 'Cannot set dual-stack in combination with a custom endpoint.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'A custom endpoint cannot be combined with FIPS', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'A custom endpoint cannot be combined with S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'partitionResult', ], 'name', ], ], 'aws-cn', ], ], ], 'error' => 'Partition does not support FIPS', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 0, 6, true, ], 'assign' => 'bucketSuffix', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'bucketSuffix', ], '--x-s3', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3Express does not support Dual-stack.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3Express does not support S3 Accelerate.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseS3ExpressControlEndpoint', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseS3ExpressControlEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://s3express-control-fips.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3express-control.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 14, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 14, 16, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 15, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 15, 17, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 19, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 19, 21, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 20, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 20, 22, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 26, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 26, 28, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Unrecognized S3Express bucket name format.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 14, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 14, 16, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 15, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 15, 17, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 19, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 19, 21, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 20, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 20, 22, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 6, 26, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 26, 28, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Unrecognized S3Express bucket name format.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 0, 7, true, ], 'assign' => 'accessPointSuffix', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'accessPointSuffix', ], '--xa-s3', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3Express does not support Dual-stack.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3Express does not support S3 Accelerate.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableS3ExpressSessionAuth', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 15, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 15, 17, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 16, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 16, 18, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 20, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 20, 22, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 21, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 21, 23, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 27, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 27, 29, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Unrecognized S3Express bucket name format.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 15, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 15, 17, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 16, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 16, 18, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 20, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 20, 22, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 21, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 21, 23, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 7, 27, true, ], 'assign' => 's3expressAvailabilityZoneId', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 27, 29, true, ], 'assign' => 's3expressAvailabilityZoneDelim', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 's3expressAvailabilityZoneDelim', ], '--', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4-s3express', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Unrecognized S3Express bucket name format.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'S3Express bucket name is not a valid virtual hostable name.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseS3ExpressControlEndpoint', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseS3ExpressControlEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://s3express-control-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3express-control.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'backend' => 'S3Express', 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3express', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 49, 50, true, ], 'assign' => 'hardwareType', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 8, 12, true, ], 'assign' => 'regionPrefix', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 0, 7, true, ], 'assign' => 'bucketAliasSuffix', ], [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 32, 49, true, ], 'assign' => 'outpostId', ], [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'regionPartition', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'bucketAliasSuffix', ], '--op-s3', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'outpostId', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'hardwareType', ], 'e', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'regionPrefix', ], 'beta', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], ], 'error' => 'Expected a endpoint to be specified but no endpoint was found', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.ec2.{url#authority}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.ec2.s3-outposts.{Region}.{regionPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'hardwareType', ], 'o', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'regionPrefix', ], 'beta', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], ], 'error' => 'Expected a endpoint to be specified but no endpoint was found', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.op-{outpostId}.{url#authority}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.op-{outpostId}.s3-outposts.{Region}.{regionPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Unrecognized hardware type: "Expected hardware type o or e but got {hardwareType}"', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], ], ], ], 'error' => 'Custom endpoint `{Endpoint}` was not a valid URI', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'ForcePathStyle', ], false, ], ], [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'Region', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'partitionResult', ], 'name', ], ], 'aws-cn', ], ], ], 'error' => 'S3 Accelerate cannot be used in this region', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.dualstack.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.dualstack.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], false, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'isIp', ], ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region: region was not a valid DNS name.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'url', ], 'scheme', ], ], 'http', ], ], [ 'fn' => 'aws.isVirtualHostableS3Bucket', 'argv' => [ [ 'ref' => 'Bucket', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'ForcePathStyle', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'Region', ], false, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{Bucket}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region: region was not a valid DNS name.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'ForcePathStyle', ], false, ], ], [ 'fn' => 'aws.parseArn', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'bucketArn', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[0]', ], 'assign' => 'arnType', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'arnType', ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'service', ], ], 's3-object-lambda', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'arnType', ], 'accesspoint', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[1]', ], 'assign' => 'accessPointName', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'accessPointName', ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3 Object Lambda does not support Dual-stack', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3 Object Lambda does not support S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableAccessPoints', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableAccessPoints', ], true, ], ], ], 'error' => 'Access points are not supported for this operation', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[2]', ], ], ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseArnRegion', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseArnRegion', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '{Region}', ], ], ], ], ], 'error' => 'Invalid configuration: region from ARN `{bucketArn#region}` does not match client region `{Region}` and UseArnRegion is `false`', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], ], 'assign' => 'bucketPartition', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketPartition', ], 'name', ], ], [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'partitionResult', ], 'name', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'accountId', ], ], '', ], ], ], 'error' => 'Invalid ARN: Missing account id', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'accountId', ], ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'accessPointName', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => '{url#scheme}://{accessPointName}-{bucketArn#accountId}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-object-lambda-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-object-lambda.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The ARN may only contain a single resource component after `accesspoint`.', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: bucket ARN is missing a region', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `{arnType}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'arnType', ], 'accesspoint', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[1]', ], 'assign' => 'accessPointName', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'accessPointName', ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'arnType', ], 'accesspoint', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'DisableAccessPoints', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableAccessPoints', ], true, ], ], ], 'error' => 'Access points are not supported for this operation', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[2]', ], ], ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseArnRegion', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseArnRegion', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '{Region}', ], ], ], ], ], 'error' => 'Invalid configuration: region from ARN `{bucketArn#region}` does not match client region `{Region}` and UseArnRegion is `false`', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], ], 'assign' => 'bucketPartition', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketPartition', ], 'name', ], ], '{partitionResult#name}', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'service', ], ], 's3', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'accountId', ], ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'accessPointName', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'Access Points do not support S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-accesspoint-fips.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-accesspoint-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-accesspoint.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => '{url#scheme}://{accessPointName}-{bucketArn#accountId}.{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.s3-accesspoint.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The ARN was not for the S3 service, found: {bucketArn#service}', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The ARN may only contain a single resource component after `accesspoint`.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'accessPointName', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3 MRAP does not support dual-stack', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'S3 MRAP does not support FIPS', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3 MRAP does not support S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'DisableMultiRegionAccessPoints', ], true, ], ], ], 'error' => 'Invalid configuration: Multi-Region Access Point ARNs are disabled.', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'mrapPartition', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'mrapPartition', ], 'name', ], ], [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'partition', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{accessPointName}.accesspoint.s3-global.{mrapPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3', 'signingRegionSet' => [ '*', ], ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Client was configured for partition `{mrapPartition#name}` but bucket referred to partition `{bucketArn#partition}`', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Access Point Name', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'service', ], ], 's3-outposts', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3 Outposts does not support Dual-stack', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'S3 Outposts does not support FIPS', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3 Outposts does not support S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[4]', ], ], ], ], ], 'error' => 'Invalid Arn: Outpost Access Point ARN contains sub resources', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[1]', ], 'assign' => 'outpostId', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'outpostId', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseArnRegion', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseArnRegion', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], '{Region}', ], ], ], ], ], 'error' => 'Invalid configuration: region from ARN `{bucketArn#region}` does not match client region `{Region}` and UseArnRegion is `false`', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], ], 'assign' => 'bucketPartition', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketPartition', ], 'name', ], ], [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'partitionResult', ], 'name', ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'region', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'accountId', ], ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[2]', ], 'assign' => 'outpostType', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'bucketArn', ], 'resourceId[3]', ], 'assign' => 'accessPointName', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'outpostType', ], 'accesspoint', ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.{outpostId}.{url#authority}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://{accessPointName}-{bucketArn#accountId}.{outpostId}.s3-outposts.{bucketArn#region}.{bucketPartition#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4a', 'signingName' => 's3-outposts', 'signingRegionSet' => [ '*', ], ], [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-outposts', 'signingRegion' => '{bucketArn#region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Expected an outpost type `accesspoint`, found {outpostType}', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: expected an access point name', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: Expected a 4-component resource', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `{outpostId}`', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: The Outpost Id was not set', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: Unrecognized format: {Bucket} (type: {arnType})', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid ARN: No ARN type specified', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'substring', 'argv' => [ [ 'ref' => 'Bucket', ], 0, 4, false, ], 'assign' => 'arnPrefix', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'arnPrefix', ], 'arn:', ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'fn' => 'aws.parseArn', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], ], ], ], ], ], 'error' => 'Invalid ARN: `{Bucket}` was not a valid ARN', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'ForcePathStyle', ], true, ], ], [ 'fn' => 'aws.parseArn', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], ], 'error' => 'Path-style addressing cannot be used with ARN buckets', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'uriEncode', 'argv' => [ [ 'ref' => 'Bucket', ], ], 'assign' => 'uri_encoded_bucket', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3-fips.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://s3.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Path-style addressing cannot be used with S3 Accelerate', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'UseObjectLambdaEndpoint', ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseObjectLambdaEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'Region', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'S3 Object Lambda does not support Dual-stack', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'Accelerate', ], true, ], ], ], 'error' => 'S3 Object Lambda does not support S3 Accelerate', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'endpoint' => [ 'url' => 'https://s3-object-lambda-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3-object-lambda.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3-object-lambda', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region: region was not a valid DNS name.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Bucket', ], ], ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'partitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isValidHostLabel', 'argv' => [ [ 'ref' => 'Region', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3-fips.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], [ 'fn' => 'parseURL', 'argv' => [ [ 'ref' => 'Endpoint', ], ], 'assign' => 'url', ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => '{url#scheme}://{url#authority}{url#path}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://s3.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://s3.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://s3.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], false, ], ], ], 'endpoint' => [ 'url' => 'https://s3.{Region}.{partitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'disableDoubleEncoding' => true, 'name' => 'sigv4', 'signingName' => 's3', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid region: region was not a valid DNS name.', 'type' => 'error', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'A region must be set when sending requests to S3.', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/paginators-1.json.php new file mode 100644 index 000000000..c255cce45 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/paginators-1.json.php @@ -0,0 +1,3 @@ + [ 'ListBuckets' => [ 'input_token' => 'ContinuationToken', 'limit_key' => 'MaxBuckets', 'output_token' => 'ContinuationToken', 'result_key' => 'Buckets', ], 'ListDirectoryBuckets' => [ 'input_token' => 'ContinuationToken', 'limit_key' => 'MaxDirectoryBuckets', 'output_token' => 'ContinuationToken', 'result_key' => 'Buckets', ], 'ListMultipartUploads' => [ 'input_token' => [ 'KeyMarker', 'UploadIdMarker', ], 'limit_key' => 'MaxUploads', 'more_results' => 'IsTruncated', 'output_token' => [ 'NextKeyMarker', 'NextUploadIdMarker', ], 'result_key' => [ 'Uploads', 'CommonPrefixes', ], ], 'ListObjectVersions' => [ 'input_token' => [ 'KeyMarker', 'VersionIdMarker', ], 'limit_key' => 'MaxKeys', 'more_results' => 'IsTruncated', 'output_token' => [ 'NextKeyMarker', 'NextVersionIdMarker', ], 'result_key' => [ 'Versions', 'DeleteMarkers', 'CommonPrefixes', ], ], 'ListObjects' => [ 'input_token' => 'Marker', 'limit_key' => 'MaxKeys', 'more_results' => 'IsTruncated', 'output_token' => 'NextMarker || Contents[-1].Key', 'result_key' => [ 'Contents', 'CommonPrefixes', ], ], 'ListObjectsV2' => [ 'input_token' => 'ContinuationToken', 'limit_key' => 'MaxKeys', 'output_token' => 'NextContinuationToken', 'result_key' => [ 'Contents', 'CommonPrefixes', ], ], 'ListParts' => [ 'input_token' => 'PartNumberMarker', 'limit_key' => 'MaxParts', 'more_results' => 'IsTruncated', 'output_token' => 'NextPartNumberMarker', 'result_key' => 'Parts', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/smoke.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/smoke.json.php new file mode 100644 index 000000000..1d393b0a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/smoke.json.php @@ -0,0 +1,3 @@ + 1, 'defaultRegion' => 'us-west-2', 'testCases' => [ [ 'operationName' => 'ListBuckets', 'input' => [], 'errorExpectedFromService' => false, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-1.json.php new file mode 100644 index 000000000..70e0bdb8a --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-1.json.php @@ -0,0 +1,3 @@ + [ '__default__' => [ 'interval' => 5, 'max_attempts' => 20, ], 'BucketExists' => [ 'operation' => 'HeadBucket', 'ignore_errors' => [ 'NoSuchBucket', ], 'success_type' => 'output', ], 'BucketNotExists' => [ 'operation' => 'HeadBucket', 'success_type' => 'error', 'success_value' => 'NoSuchBucket', ], 'ObjectExists' => [ 'operation' => 'HeadObject', 'ignore_errors' => [ 'NoSuchKey', ], 'success_type' => 'output', ], 'ObjectNotExists' => [ 'operation' => 'HeadObject', 'success_type' => 'error', 'success_value' => 'NoSuchKey', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-2.json.php new file mode 100644 index 000000000..605816854 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/s3/2006-03-01/waiters-2.json.php @@ -0,0 +1,3 @@ + 2, 'waiters' => [ 'BucketExists' => [ 'delay' => 5, 'operation' => 'HeadBucket', 'maxAttempts' => 20, 'acceptors' => [ [ 'expected' => 200, 'matcher' => 'status', 'state' => 'success', ], [ 'expected' => 301, 'matcher' => 'status', 'state' => 'success', ], [ 'expected' => 403, 'matcher' => 'status', 'state' => 'success', ], [ 'expected' => 404, 'matcher' => 'status', 'state' => 'retry', ], ], ], 'BucketNotExists' => [ 'delay' => 5, 'operation' => 'HeadBucket', 'maxAttempts' => 20, 'acceptors' => [ [ 'expected' => 404, 'matcher' => 'status', 'state' => 'success', ], ], ], 'ObjectExists' => [ 'delay' => 5, 'operation' => 'HeadObject', 'maxAttempts' => 20, 'acceptors' => [ [ 'expected' => 200, 'matcher' => 'status', 'state' => 'success', ], [ 'expected' => 404, 'matcher' => 'status', 'state' => 'retry', ], ], ], 'ObjectNotExists' => [ 'delay' => 5, 'operation' => 'HeadObject', 'maxAttempts' => 20, 'acceptors' => [ [ 'expected' => 404, 'matcher' => 'status', 'state' => 'success', ], ], ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sdk-default-configuration.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sdk-default-configuration.json.php new file mode 100644 index 000000000..2d28bf8f2 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sdk-default-configuration.json.php @@ -0,0 +1,3 @@ + 1, 'base' => [ 'retryMode' => 'standard', 'stsRegionalEndpoints' => 'regional', 's3UsEast1RegionalEndpoints' => 'regional', 'connectTimeoutInMillis' => 1100, 'tlsNegotiationTimeoutInMillis' => 1100, ], 'modes' => [ 'standard' => [ 'connectTimeoutInMillis' => [ 'override' => 3100, ], 'tlsNegotiationTimeoutInMillis' => [ 'override' => 3100, ], ], 'in-region' => [], 'cross-region' => [ 'connectTimeoutInMillis' => [ 'override' => 3100, ], 'tlsNegotiationTimeoutInMillis' => [ 'override' => 3100, ], ], 'mobile' => [ 'connectTimeoutInMillis' => [ 'override' => 30000, ], 'tlsNegotiationTimeoutInMillis' => [ 'override' => 30000, ], ], ], 'documentation' => [ 'modes' => [ 'standard' => '

    The STANDARD mode provides the latest recommended default values that should be safe to run in most scenarios

    Note that the default values vended from this mode might change as best practices may evolve. As a result, it is encouraged to perform tests when upgrading the SDK

    ', 'in-region' => '

    The IN_REGION mode builds on the standard mode and includes optimization tailored for applications which call AWS services from within the same AWS region

    Note that the default values vended from this mode might change as best practices may evolve. As a result, it is encouraged to perform tests when upgrading the SDK

    ', 'cross-region' => '

    The CROSS_REGION mode builds on the standard mode and includes optimization tailored for applications which call AWS services in a different region

    Note that the default values vended from this mode might change as best practices may evolve. As a result, it is encouraged to perform tests when upgrading the SDK

    ', 'mobile' => '

    The MOBILE mode builds on the standard mode and includes optimization tailored for mobile applications

    Note that the default values vended from this mode might change as best practices may evolve. As a result, it is encouraged to perform tests when upgrading the SDK

    ', 'auto' => '

    The AUTO mode is an experimental mode that builds on the standard mode. The SDK will attempt to discover the execution environment to determine the appropriate settings automatically.

    Note that the auto detection is heuristics-based and does not guarantee 100% accuracy. STANDARD mode will be used if the execution environment cannot be determined. The auto detection might query EC2 Instance Metadata service, which might introduce latency. Therefore we recommend choosing an explicit defaults_mode instead if startup latency is critical to your application

    ', 'legacy' => '

    The LEGACY mode provides default settings that vary per SDK and were used prior to establishment of defaults_mode

    ', ], 'configuration' => [ 'retryMode' => '

    A retry mode specifies how the SDK attempts retries. See Retry Mode

    ', 'stsRegionalEndpoints' => '

    Specifies how the SDK determines the AWS service endpoint that it uses to talk to the AWS Security Token Service (AWS STS). See Setting STS Regional endpoints

    ', 's3UsEast1RegionalEndpoints' => '

    Specifies how the SDK determines the AWS service endpoint that it uses to talk to the Amazon S3 for the us-east-1 region

    ', 'connectTimeoutInMillis' => '

    The amount of time after making an initial connection attempt on a socket, where if the client does not receive a completion of the connect handshake, the client gives up and fails the operation

    ', 'tlsNegotiationTimeoutInMillis' => '

    The maximum amount of time that a TLS handshake is allowed to take from the time the CLIENT HELLO message is sent to ethe time the client and server have fully negotiated ciphers and exchanged keys

    ', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/api-2.json.php new file mode 100644 index 000000000..d1fdb5828 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2010-03-31', 'endpointPrefix' => 'sns', 'protocol' => 'query', 'protocols' => [ 'query', ], 'serviceAbbreviation' => 'Amazon SNS', 'serviceFullName' => 'Amazon Simple Notification Service', 'serviceId' => 'SNS', 'signatureVersion' => 'v4', 'uid' => 'sns-2010-03-31', 'xmlNamespace' => 'http://sns.amazonaws.com/doc/2010-03-31/', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'AddPermission' => [ 'name' => 'AddPermission', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'AddPermissionInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'CheckIfPhoneNumberIsOptedOut' => [ 'name' => 'CheckIfPhoneNumberIsOptedOut', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CheckIfPhoneNumberIsOptedOutInput', ], 'output' => [ 'shape' => 'CheckIfPhoneNumberIsOptedOutResponse', 'resultWrapper' => 'CheckIfPhoneNumberIsOptedOutResult', ], 'errors' => [ [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidParameterException', ], ], ], 'ConfirmSubscription' => [ 'name' => 'ConfirmSubscription', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ConfirmSubscriptionInput', ], 'output' => [ 'shape' => 'ConfirmSubscriptionResponse', 'resultWrapper' => 'ConfirmSubscriptionResult', ], 'errors' => [ [ 'shape' => 'SubscriptionLimitExceededException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'FilterPolicyLimitExceededException', ], [ 'shape' => 'ReplayLimitExceededException', ], ], ], 'CreatePlatformApplication' => [ 'name' => 'CreatePlatformApplication', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreatePlatformApplicationInput', ], 'output' => [ 'shape' => 'CreatePlatformApplicationResponse', 'resultWrapper' => 'CreatePlatformApplicationResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'CreatePlatformEndpoint' => [ 'name' => 'CreatePlatformEndpoint', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreatePlatformEndpointInput', ], 'output' => [ 'shape' => 'CreateEndpointResponse', 'resultWrapper' => 'CreatePlatformEndpointResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'CreateSMSSandboxPhoneNumber' => [ 'name' => 'CreateSMSSandboxPhoneNumber', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateSMSSandboxPhoneNumberInput', ], 'output' => [ 'shape' => 'CreateSMSSandboxPhoneNumberResult', 'resultWrapper' => 'CreateSMSSandboxPhoneNumberResult', ], 'errors' => [ [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'OptedOutException', ], [ 'shape' => 'UserErrorException', ], [ 'shape' => 'ThrottledException', ], ], ], 'CreateTopic' => [ 'name' => 'CreateTopic', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'CreateTopicInput', ], 'output' => [ 'shape' => 'CreateTopicResponse', 'resultWrapper' => 'CreateTopicResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'TopicLimitExceededException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], [ 'shape' => 'TagLimitExceededException', ], [ 'shape' => 'StaleTagException', ], [ 'shape' => 'TagPolicyException', ], [ 'shape' => 'ConcurrentAccessException', ], ], ], 'DeleteEndpoint' => [ 'name' => 'DeleteEndpoint', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteEndpointInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'DeletePlatformApplication' => [ 'name' => 'DeletePlatformApplication', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeletePlatformApplicationInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'DeleteSMSSandboxPhoneNumber' => [ 'name' => 'DeleteSMSSandboxPhoneNumber', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteSMSSandboxPhoneNumberInput', ], 'output' => [ 'shape' => 'DeleteSMSSandboxPhoneNumberResult', 'resultWrapper' => 'DeleteSMSSandboxPhoneNumberResult', ], 'errors' => [ [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'UserErrorException', ], [ 'shape' => 'ThrottledException', ], ], ], 'DeleteTopic' => [ 'name' => 'DeleteTopic', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DeleteTopicInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InvalidStateException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'StaleTagException', ], [ 'shape' => 'TagPolicyException', ], [ 'shape' => 'ConcurrentAccessException', ], ], ], 'GetDataProtectionPolicy' => [ 'name' => 'GetDataProtectionPolicy', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetDataProtectionPolicyInput', ], 'output' => [ 'shape' => 'GetDataProtectionPolicyResponse', 'resultWrapper' => 'GetDataProtectionPolicyResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'GetEndpointAttributes' => [ 'name' => 'GetEndpointAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetEndpointAttributesInput', ], 'output' => [ 'shape' => 'GetEndpointAttributesResponse', 'resultWrapper' => 'GetEndpointAttributesResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'GetPlatformApplicationAttributes' => [ 'name' => 'GetPlatformApplicationAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetPlatformApplicationAttributesInput', ], 'output' => [ 'shape' => 'GetPlatformApplicationAttributesResponse', 'resultWrapper' => 'GetPlatformApplicationAttributesResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'GetSMSAttributes' => [ 'name' => 'GetSMSAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetSMSAttributesInput', ], 'output' => [ 'shape' => 'GetSMSAttributesResponse', 'resultWrapper' => 'GetSMSAttributesResult', ], 'errors' => [ [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidParameterException', ], ], ], 'GetSMSSandboxAccountStatus' => [ 'name' => 'GetSMSSandboxAccountStatus', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetSMSSandboxAccountStatusInput', ], 'output' => [ 'shape' => 'GetSMSSandboxAccountStatusResult', 'resultWrapper' => 'GetSMSSandboxAccountStatusResult', ], 'errors' => [ [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'ThrottledException', ], ], ], 'GetSubscriptionAttributes' => [ 'name' => 'GetSubscriptionAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetSubscriptionAttributesInput', ], 'output' => [ 'shape' => 'GetSubscriptionAttributesResponse', 'resultWrapper' => 'GetSubscriptionAttributesResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'GetTopicAttributes' => [ 'name' => 'GetTopicAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetTopicAttributesInput', ], 'output' => [ 'shape' => 'GetTopicAttributesResponse', 'resultWrapper' => 'GetTopicAttributesResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'ListEndpointsByPlatformApplication' => [ 'name' => 'ListEndpointsByPlatformApplication', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListEndpointsByPlatformApplicationInput', ], 'output' => [ 'shape' => 'ListEndpointsByPlatformApplicationResponse', 'resultWrapper' => 'ListEndpointsByPlatformApplicationResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'ListOriginationNumbers' => [ 'name' => 'ListOriginationNumbers', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListOriginationNumbersRequest', ], 'output' => [ 'shape' => 'ListOriginationNumbersResult', 'resultWrapper' => 'ListOriginationNumbersResult', ], 'errors' => [ [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'ValidationException', ], ], ], 'ListPhoneNumbersOptedOut' => [ 'name' => 'ListPhoneNumbersOptedOut', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListPhoneNumbersOptedOutInput', ], 'output' => [ 'shape' => 'ListPhoneNumbersOptedOutResponse', 'resultWrapper' => 'ListPhoneNumbersOptedOutResult', ], 'errors' => [ [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidParameterException', ], ], ], 'ListPlatformApplications' => [ 'name' => 'ListPlatformApplications', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListPlatformApplicationsInput', ], 'output' => [ 'shape' => 'ListPlatformApplicationsResponse', 'resultWrapper' => 'ListPlatformApplicationsResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'ListSMSSandboxPhoneNumbers' => [ 'name' => 'ListSMSSandboxPhoneNumbers', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListSMSSandboxPhoneNumbersInput', ], 'output' => [ 'shape' => 'ListSMSSandboxPhoneNumbersResult', 'resultWrapper' => 'ListSMSSandboxPhoneNumbersResult', ], 'errors' => [ [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'ThrottledException', ], ], ], 'ListSubscriptions' => [ 'name' => 'ListSubscriptions', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListSubscriptionsInput', ], 'output' => [ 'shape' => 'ListSubscriptionsResponse', 'resultWrapper' => 'ListSubscriptionsResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'ListSubscriptionsByTopic' => [ 'name' => 'ListSubscriptionsByTopic', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListSubscriptionsByTopicInput', ], 'output' => [ 'shape' => 'ListSubscriptionsByTopicResponse', 'resultWrapper' => 'ListSubscriptionsByTopicResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'ListTagsForResource' => [ 'name' => 'ListTagsForResource', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListTagsForResourceRequest', ], 'output' => [ 'shape' => 'ListTagsForResourceResponse', 'resultWrapper' => 'ListTagsForResourceResult', ], 'errors' => [ [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'TagPolicyException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'ConcurrentAccessException', ], ], ], 'ListTopics' => [ 'name' => 'ListTopics', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'ListTopicsInput', ], 'output' => [ 'shape' => 'ListTopicsResponse', 'resultWrapper' => 'ListTopicsResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'OptInPhoneNumber' => [ 'name' => 'OptInPhoneNumber', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'OptInPhoneNumberInput', ], 'output' => [ 'shape' => 'OptInPhoneNumberResponse', 'resultWrapper' => 'OptInPhoneNumberResult', ], 'errors' => [ [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidParameterException', ], ], ], 'Publish' => [ 'name' => 'Publish', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'PublishInput', ], 'output' => [ 'shape' => 'PublishResponse', 'resultWrapper' => 'PublishResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InvalidParameterValueException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'EndpointDisabledException', ], [ 'shape' => 'PlatformApplicationDisabledException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'KMSDisabledException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'KMSNotFoundException', ], [ 'shape' => 'KMSOptInRequired', ], [ 'shape' => 'KMSThrottlingException', ], [ 'shape' => 'KMSAccessDeniedException', ], [ 'shape' => 'InvalidSecurityException', ], [ 'shape' => 'ValidationException', ], ], ], 'PublishBatch' => [ 'name' => 'PublishBatch', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'PublishBatchInput', ], 'output' => [ 'shape' => 'PublishBatchResponse', 'resultWrapper' => 'PublishBatchResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InvalidParameterValueException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'EndpointDisabledException', ], [ 'shape' => 'PlatformApplicationDisabledException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'BatchEntryIdsNotDistinctException', ], [ 'shape' => 'BatchRequestTooLongException', ], [ 'shape' => 'EmptyBatchRequestException', ], [ 'shape' => 'InvalidBatchEntryIdException', ], [ 'shape' => 'TooManyEntriesInBatchRequestException', ], [ 'shape' => 'KMSDisabledException', ], [ 'shape' => 'KMSInvalidStateException', ], [ 'shape' => 'KMSNotFoundException', ], [ 'shape' => 'KMSOptInRequired', ], [ 'shape' => 'KMSThrottlingException', ], [ 'shape' => 'KMSAccessDeniedException', ], [ 'shape' => 'InvalidSecurityException', ], [ 'shape' => 'ValidationException', ], ], ], 'PutDataProtectionPolicy' => [ 'name' => 'PutDataProtectionPolicy', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'PutDataProtectionPolicyInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'RemovePermission' => [ 'name' => 'RemovePermission', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'RemovePermissionInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'SetEndpointAttributes' => [ 'name' => 'SetEndpointAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SetEndpointAttributesInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'SetPlatformApplicationAttributes' => [ 'name' => 'SetPlatformApplicationAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SetPlatformApplicationAttributesInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], ], ], 'SetSMSAttributes' => [ 'name' => 'SetSMSAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SetSMSAttributesInput', ], 'output' => [ 'shape' => 'SetSMSAttributesResponse', 'resultWrapper' => 'SetSMSAttributesResult', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'ThrottledException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'SetSubscriptionAttributes' => [ 'name' => 'SetSubscriptionAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SetSubscriptionAttributesInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'FilterPolicyLimitExceededException', ], [ 'shape' => 'ReplayLimitExceededException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], ], ], 'SetTopicAttributes' => [ 'name' => 'SetTopicAttributes', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SetTopicAttributesInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'Subscribe' => [ 'name' => 'Subscribe', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'SubscribeInput', ], 'output' => [ 'shape' => 'SubscribeResponse', 'resultWrapper' => 'SubscribeResult', ], 'errors' => [ [ 'shape' => 'SubscriptionLimitExceededException', ], [ 'shape' => 'FilterPolicyLimitExceededException', ], [ 'shape' => 'ReplayLimitExceededException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'TagResource' => [ 'name' => 'TagResource', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'TagResourceRequest', ], 'output' => [ 'shape' => 'TagResourceResponse', 'resultWrapper' => 'TagResourceResult', ], 'errors' => [ [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'TagLimitExceededException', ], [ 'shape' => 'StaleTagException', ], [ 'shape' => 'TagPolicyException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'ConcurrentAccessException', ], ], ], 'Unsubscribe' => [ 'name' => 'Unsubscribe', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UnsubscribeInput', ], 'errors' => [ [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'NotFoundException', ], [ 'shape' => 'InvalidSecurityException', ], ], ], 'UntagResource' => [ 'name' => 'UntagResource', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'UntagResourceRequest', ], 'output' => [ 'shape' => 'UntagResourceResponse', 'resultWrapper' => 'UntagResourceResult', ], 'errors' => [ [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'TagLimitExceededException', ], [ 'shape' => 'StaleTagException', ], [ 'shape' => 'TagPolicyException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'ConcurrentAccessException', ], ], ], 'VerifySMSSandboxPhoneNumber' => [ 'name' => 'VerifySMSSandboxPhoneNumber', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'VerifySMSSandboxPhoneNumberInput', ], 'output' => [ 'shape' => 'VerifySMSSandboxPhoneNumberResult', 'resultWrapper' => 'VerifySMSSandboxPhoneNumberResult', ], 'errors' => [ [ 'shape' => 'AuthorizationErrorException', ], [ 'shape' => 'InternalErrorException', ], [ 'shape' => 'InvalidParameterException', ], [ 'shape' => 'ResourceNotFoundException', ], [ 'shape' => 'VerificationException', ], [ 'shape' => 'ThrottledException', ], ], ], ], 'shapes' => [ 'ActionsList' => [ 'type' => 'list', 'member' => [ 'shape' => 'action', ], ], 'AddPermissionInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'Label', 'AWSAccountId', 'ActionName', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'Label' => [ 'shape' => 'label', ], 'AWSAccountId' => [ 'shape' => 'DelegatesList', ], 'ActionName' => [ 'shape' => 'ActionsList', ], ], ], 'AmazonResourceName' => [ 'type' => 'string', 'max' => 1011, 'min' => 1, ], 'AuthorizationErrorException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'AuthorizationError', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'BatchEntryIdsNotDistinctException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'BatchEntryIdsNotDistinct', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'BatchRequestTooLongException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'BatchRequestTooLong', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'BatchResultErrorEntry' => [ 'type' => 'structure', 'required' => [ 'Id', 'Code', 'SenderFault', ], 'members' => [ 'Id' => [ 'shape' => 'String', ], 'Code' => [ 'shape' => 'String', ], 'Message' => [ 'shape' => 'String', ], 'SenderFault' => [ 'shape' => 'boolean', ], ], ], 'BatchResultErrorEntryList' => [ 'type' => 'list', 'member' => [ 'shape' => 'BatchResultErrorEntry', ], ], 'Binary' => [ 'type' => 'blob', ], 'CheckIfPhoneNumberIsOptedOutInput' => [ 'type' => 'structure', 'required' => [ 'phoneNumber', ], 'members' => [ 'phoneNumber' => [ 'shape' => 'PhoneNumber', ], ], ], 'CheckIfPhoneNumberIsOptedOutResponse' => [ 'type' => 'structure', 'members' => [ 'isOptedOut' => [ 'shape' => 'boolean', ], ], ], 'ConcurrentAccessException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'ConcurrentAccess', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'ConfirmSubscriptionInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'Token', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'Token' => [ 'shape' => 'token', ], 'AuthenticateOnUnsubscribe' => [ 'shape' => 'authenticateOnUnsubscribe', ], ], ], 'ConfirmSubscriptionResponse' => [ 'type' => 'structure', 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], ], ], 'CreateEndpointResponse' => [ 'type' => 'structure', 'members' => [ 'EndpointArn' => [ 'shape' => 'String', ], ], ], 'CreatePlatformApplicationInput' => [ 'type' => 'structure', 'required' => [ 'Name', 'Platform', 'Attributes', ], 'members' => [ 'Name' => [ 'shape' => 'String', ], 'Platform' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'CreatePlatformApplicationResponse' => [ 'type' => 'structure', 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], ], ], 'CreatePlatformEndpointInput' => [ 'type' => 'structure', 'required' => [ 'PlatformApplicationArn', 'Token', ], 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], 'Token' => [ 'shape' => 'String', ], 'CustomUserData' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'CreateSMSSandboxPhoneNumberInput' => [ 'type' => 'structure', 'required' => [ 'PhoneNumber', ], 'members' => [ 'PhoneNumber' => [ 'shape' => 'PhoneNumberString', ], 'LanguageCode' => [ 'shape' => 'LanguageCodeString', ], ], ], 'CreateSMSSandboxPhoneNumberResult' => [ 'type' => 'structure', 'members' => [], ], 'CreateTopicInput' => [ 'type' => 'structure', 'required' => [ 'Name', ], 'members' => [ 'Name' => [ 'shape' => 'topicName', ], 'Attributes' => [ 'shape' => 'TopicAttributesMap', ], 'Tags' => [ 'shape' => 'TagList', ], 'DataProtectionPolicy' => [ 'shape' => 'attributeValue', ], ], ], 'CreateTopicResponse' => [ 'type' => 'structure', 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], ], ], 'DelegatesList' => [ 'type' => 'list', 'member' => [ 'shape' => 'delegate', ], ], 'DeleteEndpointInput' => [ 'type' => 'structure', 'required' => [ 'EndpointArn', ], 'members' => [ 'EndpointArn' => [ 'shape' => 'String', ], ], ], 'DeletePlatformApplicationInput' => [ 'type' => 'structure', 'required' => [ 'PlatformApplicationArn', ], 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], ], ], 'DeleteSMSSandboxPhoneNumberInput' => [ 'type' => 'structure', 'required' => [ 'PhoneNumber', ], 'members' => [ 'PhoneNumber' => [ 'shape' => 'PhoneNumberString', ], ], ], 'DeleteSMSSandboxPhoneNumberResult' => [ 'type' => 'structure', 'members' => [], ], 'DeleteTopicInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], ], ], 'EmptyBatchRequestException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'EmptyBatchRequest', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'Endpoint' => [ 'type' => 'structure', 'members' => [ 'EndpointArn' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'EndpointDisabledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'EndpointDisabled', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'FilterPolicyLimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'FilterPolicyLimitExceeded', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'GetDataProtectionPolicyInput' => [ 'type' => 'structure', 'required' => [ 'ResourceArn', ], 'members' => [ 'ResourceArn' => [ 'shape' => 'topicARN', ], ], ], 'GetDataProtectionPolicyResponse' => [ 'type' => 'structure', 'members' => [ 'DataProtectionPolicy' => [ 'shape' => 'attributeValue', ], ], ], 'GetEndpointAttributesInput' => [ 'type' => 'structure', 'required' => [ 'EndpointArn', ], 'members' => [ 'EndpointArn' => [ 'shape' => 'String', ], ], ], 'GetEndpointAttributesResponse' => [ 'type' => 'structure', 'members' => [ 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'GetPlatformApplicationAttributesInput' => [ 'type' => 'structure', 'required' => [ 'PlatformApplicationArn', ], 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], ], ], 'GetPlatformApplicationAttributesResponse' => [ 'type' => 'structure', 'members' => [ 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'GetSMSAttributesInput' => [ 'type' => 'structure', 'members' => [ 'attributes' => [ 'shape' => 'ListString', ], ], ], 'GetSMSAttributesResponse' => [ 'type' => 'structure', 'members' => [ 'attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'GetSMSSandboxAccountStatusInput' => [ 'type' => 'structure', 'members' => [], ], 'GetSMSSandboxAccountStatusResult' => [ 'type' => 'structure', 'required' => [ 'IsInSandbox', ], 'members' => [ 'IsInSandbox' => [ 'shape' => 'boolean', ], ], ], 'GetSubscriptionAttributesInput' => [ 'type' => 'structure', 'required' => [ 'SubscriptionArn', ], 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], ], ], 'GetSubscriptionAttributesResponse' => [ 'type' => 'structure', 'members' => [ 'Attributes' => [ 'shape' => 'SubscriptionAttributesMap', ], ], ], 'GetTopicAttributesInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], ], ], 'GetTopicAttributesResponse' => [ 'type' => 'structure', 'members' => [ 'Attributes' => [ 'shape' => 'TopicAttributesMap', ], ], ], 'InternalErrorException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'InternalError', 'httpStatusCode' => 500, ], 'exception' => true, 'fault' => true, ], 'InvalidBatchEntryIdException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'InvalidBatchEntryId', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'InvalidParameterException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'InvalidParameter', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'InvalidParameterValueException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'ParameterValueInvalid', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'InvalidSecurityException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'InvalidSecurity', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'InvalidStateException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'InvalidState', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'Iso2CountryCode' => [ 'type' => 'string', 'max' => 2, 'pattern' => '^[A-Za-z]{2}$', ], 'KMSAccessDeniedException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSAccessDenied', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'KMSDisabledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSDisabled', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'KMSInvalidStateException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSInvalidState', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'KMSNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSNotFound', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'KMSOptInRequired' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSOptInRequired', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'KMSThrottlingException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'KMSThrottling', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'LanguageCodeString' => [ 'type' => 'string', 'enum' => [ 'en-US', 'en-GB', 'es-419', 'es-ES', 'de-DE', 'fr-CA', 'fr-FR', 'it-IT', 'ja-JP', 'pt-BR', 'kr-KR', 'zh-CN', 'zh-TW', ], ], 'ListEndpointsByPlatformApplicationInput' => [ 'type' => 'structure', 'required' => [ 'PlatformApplicationArn', ], 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], 'NextToken' => [ 'shape' => 'String', ], ], ], 'ListEndpointsByPlatformApplicationResponse' => [ 'type' => 'structure', 'members' => [ 'Endpoints' => [ 'shape' => 'ListOfEndpoints', ], 'NextToken' => [ 'shape' => 'String', ], ], ], 'ListOfEndpoints' => [ 'type' => 'list', 'member' => [ 'shape' => 'Endpoint', ], ], 'ListOfPlatformApplications' => [ 'type' => 'list', 'member' => [ 'shape' => 'PlatformApplication', ], ], 'ListOriginationNumbersRequest' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'nextToken', ], 'MaxResults' => [ 'shape' => 'MaxItemsListOriginationNumbers', ], ], ], 'ListOriginationNumbersResult' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'nextToken', ], 'PhoneNumbers' => [ 'shape' => 'PhoneNumberInformationList', ], ], ], 'ListPhoneNumbersOptedOutInput' => [ 'type' => 'structure', 'members' => [ 'nextToken' => [ 'shape' => 'string', ], ], ], 'ListPhoneNumbersOptedOutResponse' => [ 'type' => 'structure', 'members' => [ 'phoneNumbers' => [ 'shape' => 'PhoneNumberList', ], 'nextToken' => [ 'shape' => 'string', ], ], ], 'ListPlatformApplicationsInput' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'String', ], ], ], 'ListPlatformApplicationsResponse' => [ 'type' => 'structure', 'members' => [ 'PlatformApplications' => [ 'shape' => 'ListOfPlatformApplications', ], 'NextToken' => [ 'shape' => 'String', ], ], ], 'ListSMSSandboxPhoneNumbersInput' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'nextToken', ], 'MaxResults' => [ 'shape' => 'MaxItems', ], ], ], 'ListSMSSandboxPhoneNumbersResult' => [ 'type' => 'structure', 'required' => [ 'PhoneNumbers', ], 'members' => [ 'PhoneNumbers' => [ 'shape' => 'SMSSandboxPhoneNumberList', ], 'NextToken' => [ 'shape' => 'string', ], ], ], 'ListString' => [ 'type' => 'list', 'member' => [ 'shape' => 'String', ], ], 'ListSubscriptionsByTopicInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'ListSubscriptionsByTopicResponse' => [ 'type' => 'structure', 'members' => [ 'Subscriptions' => [ 'shape' => 'SubscriptionsList', ], 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'ListSubscriptionsInput' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'ListSubscriptionsResponse' => [ 'type' => 'structure', 'members' => [ 'Subscriptions' => [ 'shape' => 'SubscriptionsList', ], 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'ListTagsForResourceRequest' => [ 'type' => 'structure', 'required' => [ 'ResourceArn', ], 'members' => [ 'ResourceArn' => [ 'shape' => 'AmazonResourceName', ], ], ], 'ListTagsForResourceResponse' => [ 'type' => 'structure', 'members' => [ 'Tags' => [ 'shape' => 'TagList', ], ], ], 'ListTopicsInput' => [ 'type' => 'structure', 'members' => [ 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'ListTopicsResponse' => [ 'type' => 'structure', 'members' => [ 'Topics' => [ 'shape' => 'TopicsList', ], 'NextToken' => [ 'shape' => 'nextToken', ], ], ], 'MapStringToString' => [ 'type' => 'map', 'key' => [ 'shape' => 'String', ], 'value' => [ 'shape' => 'String', ], ], 'MaxItems' => [ 'type' => 'integer', 'max' => 100, 'min' => 1, ], 'MaxItemsListOriginationNumbers' => [ 'type' => 'integer', 'max' => 30, 'min' => 1, ], 'MessageAttributeMap' => [ 'type' => 'map', 'key' => [ 'shape' => 'String', 'locationName' => 'Name', ], 'value' => [ 'shape' => 'MessageAttributeValue', 'locationName' => 'Value', ], ], 'MessageAttributeValue' => [ 'type' => 'structure', 'required' => [ 'DataType', ], 'members' => [ 'DataType' => [ 'shape' => 'String', ], 'StringValue' => [ 'shape' => 'String', ], 'BinaryValue' => [ 'shape' => 'Binary', ], ], ], 'NotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'NotFound', 'httpStatusCode' => 404, 'senderFault' => true, ], 'exception' => true, ], 'NumberCapability' => [ 'type' => 'string', 'enum' => [ 'SMS', 'MMS', 'VOICE', ], ], 'NumberCapabilityList' => [ 'type' => 'list', 'member' => [ 'shape' => 'NumberCapability', ], ], 'OTPCode' => [ 'type' => 'string', 'max' => 8, 'min' => 5, 'pattern' => '^[0-9]+$', ], 'OptInPhoneNumberInput' => [ 'type' => 'structure', 'required' => [ 'phoneNumber', ], 'members' => [ 'phoneNumber' => [ 'shape' => 'PhoneNumber', ], ], ], 'OptInPhoneNumberResponse' => [ 'type' => 'structure', 'members' => [], ], 'OptedOutException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'OptedOut', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'PhoneNumber' => [ 'type' => 'string', 'sensitive' => true, ], 'PhoneNumberInformation' => [ 'type' => 'structure', 'members' => [ 'CreatedAt' => [ 'shape' => 'Timestamp', ], 'PhoneNumber' => [ 'shape' => 'PhoneNumber', ], 'Status' => [ 'shape' => 'String', ], 'Iso2CountryCode' => [ 'shape' => 'Iso2CountryCode', ], 'RouteType' => [ 'shape' => 'RouteType', ], 'NumberCapabilities' => [ 'shape' => 'NumberCapabilityList', ], ], ], 'PhoneNumberInformationList' => [ 'type' => 'list', 'member' => [ 'shape' => 'PhoneNumberInformation', ], ], 'PhoneNumberList' => [ 'type' => 'list', 'member' => [ 'shape' => 'PhoneNumber', ], ], 'PhoneNumberString' => [ 'type' => 'string', 'max' => 20, 'pattern' => '^(\\+[0-9]{8,}|[0-9]{0,9})$', 'sensitive' => true, ], 'PlatformApplication' => [ 'type' => 'structure', 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'PlatformApplicationDisabledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'PlatformApplicationDisabled', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'PublishBatchInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'PublishBatchRequestEntries', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'PublishBatchRequestEntries' => [ 'shape' => 'PublishBatchRequestEntryList', ], ], ], 'PublishBatchRequestEntry' => [ 'type' => 'structure', 'required' => [ 'Id', 'Message', ], 'members' => [ 'Id' => [ 'shape' => 'String', ], 'Message' => [ 'shape' => 'message', ], 'Subject' => [ 'shape' => 'subject', ], 'MessageStructure' => [ 'shape' => 'messageStructure', ], 'MessageAttributes' => [ 'shape' => 'MessageAttributeMap', ], 'MessageDeduplicationId' => [ 'shape' => 'String', ], 'MessageGroupId' => [ 'shape' => 'String', ], ], ], 'PublishBatchRequestEntryList' => [ 'type' => 'list', 'member' => [ 'shape' => 'PublishBatchRequestEntry', ], ], 'PublishBatchResponse' => [ 'type' => 'structure', 'members' => [ 'Successful' => [ 'shape' => 'PublishBatchResultEntryList', ], 'Failed' => [ 'shape' => 'BatchResultErrorEntryList', ], ], ], 'PublishBatchResultEntry' => [ 'type' => 'structure', 'members' => [ 'Id' => [ 'shape' => 'String', ], 'MessageId' => [ 'shape' => 'messageId', ], 'SequenceNumber' => [ 'shape' => 'String', ], ], ], 'PublishBatchResultEntryList' => [ 'type' => 'list', 'member' => [ 'shape' => 'PublishBatchResultEntry', ], ], 'PublishInput' => [ 'type' => 'structure', 'required' => [ 'Message', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'TargetArn' => [ 'shape' => 'String', ], 'PhoneNumber' => [ 'shape' => 'PhoneNumber', ], 'Message' => [ 'shape' => 'message', ], 'Subject' => [ 'shape' => 'subject', ], 'MessageStructure' => [ 'shape' => 'messageStructure', ], 'MessageAttributes' => [ 'shape' => 'MessageAttributeMap', ], 'MessageDeduplicationId' => [ 'shape' => 'String', ], 'MessageGroupId' => [ 'shape' => 'String', ], ], ], 'PublishResponse' => [ 'type' => 'structure', 'members' => [ 'MessageId' => [ 'shape' => 'messageId', ], 'SequenceNumber' => [ 'shape' => 'String', ], ], ], 'PutDataProtectionPolicyInput' => [ 'type' => 'structure', 'required' => [ 'ResourceArn', 'DataProtectionPolicy', ], 'members' => [ 'ResourceArn' => [ 'shape' => 'topicARN', ], 'DataProtectionPolicy' => [ 'shape' => 'attributeValue', ], ], ], 'RemovePermissionInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'Label', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'Label' => [ 'shape' => 'label', ], ], ], 'ReplayLimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'ReplayLimitExceeded', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'ResourceNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'ResourceNotFound', 'httpStatusCode' => 404, 'senderFault' => true, ], 'exception' => true, ], 'RouteType' => [ 'type' => 'string', 'enum' => [ 'Transactional', 'Promotional', 'Premium', ], ], 'SMSSandboxPhoneNumber' => [ 'type' => 'structure', 'members' => [ 'PhoneNumber' => [ 'shape' => 'PhoneNumberString', ], 'Status' => [ 'shape' => 'SMSSandboxPhoneNumberVerificationStatus', ], ], ], 'SMSSandboxPhoneNumberList' => [ 'type' => 'list', 'member' => [ 'shape' => 'SMSSandboxPhoneNumber', ], ], 'SMSSandboxPhoneNumberVerificationStatus' => [ 'type' => 'string', 'enum' => [ 'Pending', 'Verified', ], ], 'SetEndpointAttributesInput' => [ 'type' => 'structure', 'required' => [ 'EndpointArn', 'Attributes', ], 'members' => [ 'EndpointArn' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'SetPlatformApplicationAttributesInput' => [ 'type' => 'structure', 'required' => [ 'PlatformApplicationArn', 'Attributes', ], 'members' => [ 'PlatformApplicationArn' => [ 'shape' => 'String', ], 'Attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'SetSMSAttributesInput' => [ 'type' => 'structure', 'required' => [ 'attributes', ], 'members' => [ 'attributes' => [ 'shape' => 'MapStringToString', ], ], ], 'SetSMSAttributesResponse' => [ 'type' => 'structure', 'members' => [], ], 'SetSubscriptionAttributesInput' => [ 'type' => 'structure', 'required' => [ 'SubscriptionArn', 'AttributeName', ], 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], 'AttributeName' => [ 'shape' => 'attributeName', ], 'AttributeValue' => [ 'shape' => 'attributeValue', ], ], ], 'SetTopicAttributesInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'AttributeName', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'AttributeName' => [ 'shape' => 'attributeName', ], 'AttributeValue' => [ 'shape' => 'attributeValue', ], ], ], 'StaleTagException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'StaleTag', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'String' => [ 'type' => 'string', ], 'SubscribeInput' => [ 'type' => 'structure', 'required' => [ 'TopicArn', 'Protocol', ], 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], 'Protocol' => [ 'shape' => 'protocol', ], 'Endpoint' => [ 'shape' => 'endpoint', ], 'Attributes' => [ 'shape' => 'SubscriptionAttributesMap', ], 'ReturnSubscriptionArn' => [ 'shape' => 'boolean', ], ], ], 'SubscribeResponse' => [ 'type' => 'structure', 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], ], ], 'Subscription' => [ 'type' => 'structure', 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], 'Owner' => [ 'shape' => 'account', ], 'Protocol' => [ 'shape' => 'protocol', ], 'Endpoint' => [ 'shape' => 'endpoint', ], 'TopicArn' => [ 'shape' => 'topicARN', ], ], ], 'SubscriptionAttributesMap' => [ 'type' => 'map', 'key' => [ 'shape' => 'attributeName', ], 'value' => [ 'shape' => 'attributeValue', ], ], 'SubscriptionLimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'SubscriptionLimitExceeded', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'SubscriptionsList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Subscription', ], ], 'Tag' => [ 'type' => 'structure', 'required' => [ 'Key', 'Value', ], 'members' => [ 'Key' => [ 'shape' => 'TagKey', ], 'Value' => [ 'shape' => 'TagValue', ], ], ], 'TagKey' => [ 'type' => 'string', 'max' => 128, 'min' => 1, ], 'TagKeyList' => [ 'type' => 'list', 'member' => [ 'shape' => 'TagKey', ], ], 'TagLimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'TagLimitExceeded', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'TagList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Tag', ], ], 'TagPolicyException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'TagPolicy', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'TagResourceRequest' => [ 'type' => 'structure', 'required' => [ 'ResourceArn', 'Tags', ], 'members' => [ 'ResourceArn' => [ 'shape' => 'AmazonResourceName', ], 'Tags' => [ 'shape' => 'TagList', ], ], ], 'TagResourceResponse' => [ 'type' => 'structure', 'members' => [], ], 'TagValue' => [ 'type' => 'string', 'max' => 256, 'min' => 0, ], 'ThrottledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'Throttled', 'httpStatusCode' => 429, 'senderFault' => true, ], 'exception' => true, ], 'Timestamp' => [ 'type' => 'timestamp', ], 'TooManyEntriesInBatchRequestException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'TooManyEntriesInBatchRequest', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'Topic' => [ 'type' => 'structure', 'members' => [ 'TopicArn' => [ 'shape' => 'topicARN', ], ], ], 'TopicAttributesMap' => [ 'type' => 'map', 'key' => [ 'shape' => 'attributeName', ], 'value' => [ 'shape' => 'attributeValue', ], ], 'TopicLimitExceededException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'TopicLimitExceeded', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'TopicsList' => [ 'type' => 'list', 'member' => [ 'shape' => 'Topic', ], ], 'UnsubscribeInput' => [ 'type' => 'structure', 'required' => [ 'SubscriptionArn', ], 'members' => [ 'SubscriptionArn' => [ 'shape' => 'subscriptionARN', ], ], ], 'UntagResourceRequest' => [ 'type' => 'structure', 'required' => [ 'ResourceArn', 'TagKeys', ], 'members' => [ 'ResourceArn' => [ 'shape' => 'AmazonResourceName', ], 'TagKeys' => [ 'shape' => 'TagKeyList', ], ], ], 'UntagResourceResponse' => [ 'type' => 'structure', 'members' => [], ], 'UserErrorException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'UserError', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'ValidationException' => [ 'type' => 'structure', 'required' => [ 'Message', ], 'members' => [ 'Message' => [ 'shape' => 'string', ], ], 'error' => [ 'code' => 'ValidationException', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'VerificationException' => [ 'type' => 'structure', 'required' => [ 'Message', 'Status', ], 'members' => [ 'Message' => [ 'shape' => 'string', ], 'Status' => [ 'shape' => 'string', ], ], 'exception' => true, ], 'VerifySMSSandboxPhoneNumberInput' => [ 'type' => 'structure', 'required' => [ 'PhoneNumber', 'OneTimePassword', ], 'members' => [ 'PhoneNumber' => [ 'shape' => 'PhoneNumberString', ], 'OneTimePassword' => [ 'shape' => 'OTPCode', ], ], ], 'VerifySMSSandboxPhoneNumberResult' => [ 'type' => 'structure', 'members' => [], ], 'account' => [ 'type' => 'string', ], 'action' => [ 'type' => 'string', ], 'attributeName' => [ 'type' => 'string', ], 'attributeValue' => [ 'type' => 'string', ], 'authenticateOnUnsubscribe' => [ 'type' => 'string', ], 'boolean' => [ 'type' => 'boolean', ], 'delegate' => [ 'type' => 'string', ], 'endpoint' => [ 'type' => 'string', ], 'label' => [ 'type' => 'string', ], 'message' => [ 'type' => 'string', ], 'messageId' => [ 'type' => 'string', ], 'messageStructure' => [ 'type' => 'string', ], 'nextToken' => [ 'type' => 'string', ], 'protocol' => [ 'type' => 'string', ], 'string' => [ 'type' => 'string', ], 'subject' => [ 'type' => 'string', ], 'subscriptionARN' => [ 'type' => 'string', ], 'token' => [ 'type' => 'string', ], 'topicARN' => [ 'type' => 'string', ], 'topicName' => [ 'type' => 'string', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..96f2c6378 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Invalid Configuration: FIPS and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'Invalid Configuration: Dualstack and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [], 'endpoint' => [ 'url' => [ 'ref' => 'Endpoint', ], 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sns-fips.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS and DualStack are enabled, but this partition does not support one or both', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-gov-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://sns.us-gov-east-1.amazonaws.com', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-gov-west-1', ], ], ], 'endpoint' => [ 'url' => 'https://sns.us-gov-west-1.amazonaws.com', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sns-fips.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS is enabled but this partition does not support FIPS', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sns.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'DualStack is enabled but this partition does not support DualStack', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sns.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Configuration: Missing Region', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/paginators-1.json.php new file mode 100644 index 000000000..2b74cc9b3 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/paginators-1.json.php @@ -0,0 +1,3 @@ + [ 'ListEndpointsByPlatformApplication' => [ 'input_token' => 'NextToken', 'output_token' => 'NextToken', 'result_key' => 'Endpoints', ], 'ListOriginationNumbers' => [ 'input_token' => 'NextToken', 'limit_key' => 'MaxResults', 'output_token' => 'NextToken', 'result_key' => 'PhoneNumbers', ], 'ListPhoneNumbersOptedOut' => [ 'input_token' => 'nextToken', 'output_token' => 'nextToken', 'result_key' => 'phoneNumbers', ], 'ListPlatformApplications' => [ 'input_token' => 'NextToken', 'output_token' => 'NextToken', 'result_key' => 'PlatformApplications', ], 'ListSMSSandboxPhoneNumbers' => [ 'input_token' => 'NextToken', 'limit_key' => 'MaxResults', 'output_token' => 'NextToken', 'result_key' => 'PhoneNumbers', ], 'ListSubscriptions' => [ 'input_token' => 'NextToken', 'output_token' => 'NextToken', 'result_key' => 'Subscriptions', ], 'ListSubscriptionsByTopic' => [ 'input_token' => 'NextToken', 'output_token' => 'NextToken', 'result_key' => 'Subscriptions', ], 'ListTopics' => [ 'input_token' => 'NextToken', 'output_token' => 'NextToken', 'result_key' => 'Topics', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/smoke.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/smoke.json.php new file mode 100644 index 000000000..789d75740 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sns/2010-03-31/smoke.json.php @@ -0,0 +1,3 @@ + 1, 'defaultRegion' => 'us-west-2', 'testCases' => [ [ 'operationName' => 'ListTopics', 'input' => [], 'errorExpectedFromService' => false, ], [ 'operationName' => 'Publish', 'input' => [ 'Message' => 'hello', 'TopicArn' => 'fake_topic', ], 'errorExpectedFromService' => true, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/api-2.json.php new file mode 100644 index 000000000..28a7ccc4c --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2019-06-10', 'endpointPrefix' => 'oidc', 'jsonVersion' => '1.1', 'protocol' => 'rest-json', 'protocols' => [ 'rest-json', ], 'serviceAbbreviation' => 'SSO OIDC', 'serviceFullName' => 'AWS SSO OIDC', 'serviceId' => 'SSO OIDC', 'signatureVersion' => 'v4', 'signingName' => 'sso-oauth', 'uid' => 'sso-oidc-2019-06-10', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'CreateToken' => [ 'name' => 'CreateToken', 'http' => [ 'method' => 'POST', 'requestUri' => '/token', ], 'input' => [ 'shape' => 'CreateTokenRequest', ], 'output' => [ 'shape' => 'CreateTokenResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'InvalidClientException', ], [ 'shape' => 'InvalidGrantException', ], [ 'shape' => 'UnauthorizedClientException', ], [ 'shape' => 'UnsupportedGrantTypeException', ], [ 'shape' => 'InvalidScopeException', ], [ 'shape' => 'AuthorizationPendingException', ], [ 'shape' => 'SlowDownException', ], [ 'shape' => 'AccessDeniedException', ], [ 'shape' => 'ExpiredTokenException', ], [ 'shape' => 'InternalServerException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'CreateTokenWithIAM' => [ 'name' => 'CreateTokenWithIAM', 'http' => [ 'method' => 'POST', 'requestUri' => '/token?aws_iam=t', ], 'input' => [ 'shape' => 'CreateTokenWithIAMRequest', ], 'output' => [ 'shape' => 'CreateTokenWithIAMResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'InvalidClientException', ], [ 'shape' => 'InvalidGrantException', ], [ 'shape' => 'UnauthorizedClientException', ], [ 'shape' => 'UnsupportedGrantTypeException', ], [ 'shape' => 'InvalidScopeException', ], [ 'shape' => 'AuthorizationPendingException', ], [ 'shape' => 'SlowDownException', ], [ 'shape' => 'AccessDeniedException', ], [ 'shape' => 'ExpiredTokenException', ], [ 'shape' => 'InternalServerException', ], [ 'shape' => 'InvalidRequestRegionException', ], ], ], 'RegisterClient' => [ 'name' => 'RegisterClient', 'http' => [ 'method' => 'POST', 'requestUri' => '/client/register', ], 'input' => [ 'shape' => 'RegisterClientRequest', ], 'output' => [ 'shape' => 'RegisterClientResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'InvalidScopeException', ], [ 'shape' => 'InvalidClientMetadataException', ], [ 'shape' => 'InternalServerException', ], [ 'shape' => 'InvalidRedirectUriException', ], [ 'shape' => 'UnsupportedGrantTypeException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'StartDeviceAuthorization' => [ 'name' => 'StartDeviceAuthorization', 'http' => [ 'method' => 'POST', 'requestUri' => '/device_authorization', ], 'input' => [ 'shape' => 'StartDeviceAuthorizationRequest', ], 'output' => [ 'shape' => 'StartDeviceAuthorizationResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'InvalidClientException', ], [ 'shape' => 'UnauthorizedClientException', ], [ 'shape' => 'SlowDownException', ], [ 'shape' => 'InternalServerException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], ], 'shapes' => [ 'AccessDeniedException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'AccessToken' => [ 'type' => 'string', 'sensitive' => true, ], 'ArnType' => [ 'type' => 'string', ], 'Assertion' => [ 'type' => 'string', 'sensitive' => true, ], 'AuthCode' => [ 'type' => 'string', ], 'AuthorizationPendingException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'AwsAdditionalDetails' => [ 'type' => 'structure', 'members' => [ 'identityContext' => [ 'shape' => 'IdentityContext', ], ], ], 'ClientId' => [ 'type' => 'string', ], 'ClientName' => [ 'type' => 'string', ], 'ClientSecret' => [ 'type' => 'string', 'sensitive' => true, ], 'ClientType' => [ 'type' => 'string', ], 'CodeVerifier' => [ 'type' => 'string', 'sensitive' => true, ], 'CreateTokenRequest' => [ 'type' => 'structure', 'required' => [ 'clientId', 'clientSecret', 'grantType', ], 'members' => [ 'clientId' => [ 'shape' => 'ClientId', ], 'clientSecret' => [ 'shape' => 'ClientSecret', ], 'grantType' => [ 'shape' => 'GrantType', ], 'deviceCode' => [ 'shape' => 'DeviceCode', ], 'code' => [ 'shape' => 'AuthCode', ], 'refreshToken' => [ 'shape' => 'RefreshToken', ], 'scope' => [ 'shape' => 'Scopes', ], 'redirectUri' => [ 'shape' => 'URI', ], 'codeVerifier' => [ 'shape' => 'CodeVerifier', ], ], ], 'CreateTokenResponse' => [ 'type' => 'structure', 'members' => [ 'accessToken' => [ 'shape' => 'AccessToken', ], 'tokenType' => [ 'shape' => 'TokenType', ], 'expiresIn' => [ 'shape' => 'ExpirationInSeconds', ], 'refreshToken' => [ 'shape' => 'RefreshToken', ], 'idToken' => [ 'shape' => 'IdToken', ], ], ], 'CreateTokenWithIAMRequest' => [ 'type' => 'structure', 'required' => [ 'clientId', 'grantType', ], 'members' => [ 'clientId' => [ 'shape' => 'ClientId', ], 'grantType' => [ 'shape' => 'GrantType', ], 'code' => [ 'shape' => 'AuthCode', ], 'refreshToken' => [ 'shape' => 'RefreshToken', ], 'assertion' => [ 'shape' => 'Assertion', ], 'scope' => [ 'shape' => 'Scopes', ], 'redirectUri' => [ 'shape' => 'URI', ], 'subjectToken' => [ 'shape' => 'SubjectToken', ], 'subjectTokenType' => [ 'shape' => 'TokenTypeURI', ], 'requestedTokenType' => [ 'shape' => 'TokenTypeURI', ], 'codeVerifier' => [ 'shape' => 'CodeVerifier', ], ], ], 'CreateTokenWithIAMResponse' => [ 'type' => 'structure', 'members' => [ 'accessToken' => [ 'shape' => 'AccessToken', ], 'tokenType' => [ 'shape' => 'TokenType', ], 'expiresIn' => [ 'shape' => 'ExpirationInSeconds', ], 'refreshToken' => [ 'shape' => 'RefreshToken', ], 'idToken' => [ 'shape' => 'IdToken', ], 'issuedTokenType' => [ 'shape' => 'TokenTypeURI', ], 'scope' => [ 'shape' => 'Scopes', ], 'awsAdditionalDetails' => [ 'shape' => 'AwsAdditionalDetails', ], ], ], 'DeviceCode' => [ 'type' => 'string', ], 'Error' => [ 'type' => 'string', ], 'ErrorDescription' => [ 'type' => 'string', ], 'ExpirationInSeconds' => [ 'type' => 'integer', ], 'ExpiredTokenException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'GrantType' => [ 'type' => 'string', ], 'GrantTypes' => [ 'type' => 'list', 'member' => [ 'shape' => 'GrantType', ], ], 'IdToken' => [ 'type' => 'string', 'sensitive' => true, ], 'IdentityContext' => [ 'type' => 'string', ], 'InternalServerException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 500, ], 'exception' => true, 'fault' => true, ], 'IntervalInSeconds' => [ 'type' => 'integer', ], 'InvalidClientException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 401, ], 'exception' => true, ], 'InvalidClientMetadataException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidGrantException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidRedirectUriException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidRequestException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidRequestRegionException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], 'endpoint' => [ 'shape' => 'Location', ], 'region' => [ 'shape' => 'Region', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'InvalidScopeException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'Location' => [ 'type' => 'string', ], 'LongTimeStampType' => [ 'type' => 'long', ], 'RedirectUris' => [ 'type' => 'list', 'member' => [ 'shape' => 'URI', ], ], 'RefreshToken' => [ 'type' => 'string', 'sensitive' => true, ], 'Region' => [ 'type' => 'string', ], 'RegisterClientRequest' => [ 'type' => 'structure', 'required' => [ 'clientName', 'clientType', ], 'members' => [ 'clientName' => [ 'shape' => 'ClientName', ], 'clientType' => [ 'shape' => 'ClientType', ], 'scopes' => [ 'shape' => 'Scopes', ], 'redirectUris' => [ 'shape' => 'RedirectUris', ], 'grantTypes' => [ 'shape' => 'GrantTypes', ], 'issuerUrl' => [ 'shape' => 'URI', ], 'entitledApplicationArn' => [ 'shape' => 'ArnType', ], ], ], 'RegisterClientResponse' => [ 'type' => 'structure', 'members' => [ 'clientId' => [ 'shape' => 'ClientId', ], 'clientSecret' => [ 'shape' => 'ClientSecret', ], 'clientIdIssuedAt' => [ 'shape' => 'LongTimeStampType', ], 'clientSecretExpiresAt' => [ 'shape' => 'LongTimeStampType', ], 'authorizationEndpoint' => [ 'shape' => 'URI', ], 'tokenEndpoint' => [ 'shape' => 'URI', ], ], ], 'Scope' => [ 'type' => 'string', ], 'Scopes' => [ 'type' => 'list', 'member' => [ 'shape' => 'Scope', ], ], 'SlowDownException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'StartDeviceAuthorizationRequest' => [ 'type' => 'structure', 'required' => [ 'clientId', 'clientSecret', 'startUrl', ], 'members' => [ 'clientId' => [ 'shape' => 'ClientId', ], 'clientSecret' => [ 'shape' => 'ClientSecret', ], 'startUrl' => [ 'shape' => 'URI', ], ], ], 'StartDeviceAuthorizationResponse' => [ 'type' => 'structure', 'members' => [ 'deviceCode' => [ 'shape' => 'DeviceCode', ], 'userCode' => [ 'shape' => 'UserCode', ], 'verificationUri' => [ 'shape' => 'URI', ], 'verificationUriComplete' => [ 'shape' => 'URI', ], 'expiresIn' => [ 'shape' => 'ExpirationInSeconds', ], 'interval' => [ 'shape' => 'IntervalInSeconds', ], ], ], 'SubjectToken' => [ 'type' => 'string', 'sensitive' => true, ], 'TokenType' => [ 'type' => 'string', ], 'TokenTypeURI' => [ 'type' => 'string', ], 'URI' => [ 'type' => 'string', ], 'UnauthorizedClientException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'UnsupportedGrantTypeException' => [ 'type' => 'structure', 'members' => [ 'error' => [ 'shape' => 'Error', ], 'error_description' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'UserCode' => [ 'type' => 'string', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..970e93b19 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Invalid Configuration: FIPS and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'Invalid Configuration: Dualstack and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [], 'endpoint' => [ 'url' => [ 'ref' => 'Endpoint', ], 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://oidc-fips.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS and DualStack are enabled, but this partition does not support one or both', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'name', ], ], 'aws-us-gov', ], ], ], 'endpoint' => [ 'url' => 'https://oidc.{Region}.amazonaws.com', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://oidc-fips.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS is enabled but this partition does not support FIPS', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://oidc.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'DualStack is enabled but this partition does not support DualStack', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://oidc.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Configuration: Missing Region', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/paginators-1.json.php new file mode 100644 index 000000000..188bff211 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso-oidc/2019-06-10/paginators-1.json.php @@ -0,0 +1,3 @@ + [],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/api-2.json.php new file mode 100644 index 000000000..a32c7d004 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2019-06-10', 'endpointPrefix' => 'portal.sso', 'jsonVersion' => '1.1', 'protocol' => 'rest-json', 'protocols' => [ 'rest-json', ], 'serviceAbbreviation' => 'SSO', 'serviceFullName' => 'AWS Single Sign-On', 'serviceId' => 'SSO', 'signatureVersion' => 'v4', 'signingName' => 'awsssoportal', 'uid' => 'sso-2019-06-10', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'GetRoleCredentials' => [ 'name' => 'GetRoleCredentials', 'http' => [ 'method' => 'GET', 'requestUri' => '/federation/credentials', ], 'input' => [ 'shape' => 'GetRoleCredentialsRequest', ], 'output' => [ 'shape' => 'GetRoleCredentialsResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'UnauthorizedException', ], [ 'shape' => 'TooManyRequestsException', ], [ 'shape' => 'ResourceNotFoundException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'ListAccountRoles' => [ 'name' => 'ListAccountRoles', 'http' => [ 'method' => 'GET', 'requestUri' => '/assignment/roles', ], 'input' => [ 'shape' => 'ListAccountRolesRequest', ], 'output' => [ 'shape' => 'ListAccountRolesResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'UnauthorizedException', ], [ 'shape' => 'TooManyRequestsException', ], [ 'shape' => 'ResourceNotFoundException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'ListAccounts' => [ 'name' => 'ListAccounts', 'http' => [ 'method' => 'GET', 'requestUri' => '/assignment/accounts', ], 'input' => [ 'shape' => 'ListAccountsRequest', ], 'output' => [ 'shape' => 'ListAccountsResponse', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'UnauthorizedException', ], [ 'shape' => 'TooManyRequestsException', ], [ 'shape' => 'ResourceNotFoundException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'Logout' => [ 'name' => 'Logout', 'http' => [ 'method' => 'POST', 'requestUri' => '/logout', ], 'input' => [ 'shape' => 'LogoutRequest', ], 'errors' => [ [ 'shape' => 'InvalidRequestException', ], [ 'shape' => 'UnauthorizedException', ], [ 'shape' => 'TooManyRequestsException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], ], 'shapes' => [ 'AccessKeyType' => [ 'type' => 'string', ], 'AccessTokenType' => [ 'type' => 'string', 'sensitive' => true, ], 'AccountIdType' => [ 'type' => 'string', ], 'AccountInfo' => [ 'type' => 'structure', 'members' => [ 'accountId' => [ 'shape' => 'AccountIdType', ], 'accountName' => [ 'shape' => 'AccountNameType', ], 'emailAddress' => [ 'shape' => 'EmailAddressType', ], ], ], 'AccountListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'AccountInfo', ], ], 'AccountNameType' => [ 'type' => 'string', ], 'EmailAddressType' => [ 'type' => 'string', 'max' => 254, 'min' => 1, ], 'ErrorDescription' => [ 'type' => 'string', ], 'ExpirationTimestampType' => [ 'type' => 'long', ], 'GetRoleCredentialsRequest' => [ 'type' => 'structure', 'required' => [ 'roleName', 'accountId', 'accessToken', ], 'members' => [ 'roleName' => [ 'shape' => 'RoleNameType', 'location' => 'querystring', 'locationName' => 'role_name', ], 'accountId' => [ 'shape' => 'AccountIdType', 'location' => 'querystring', 'locationName' => 'account_id', ], 'accessToken' => [ 'shape' => 'AccessTokenType', 'location' => 'header', 'locationName' => 'x-amz-sso_bearer_token', ], ], ], 'GetRoleCredentialsResponse' => [ 'type' => 'structure', 'members' => [ 'roleCredentials' => [ 'shape' => 'RoleCredentials', ], ], ], 'InvalidRequestException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 400, ], 'exception' => true, ], 'ListAccountRolesRequest' => [ 'type' => 'structure', 'required' => [ 'accessToken', 'accountId', ], 'members' => [ 'nextToken' => [ 'shape' => 'NextTokenType', 'location' => 'querystring', 'locationName' => 'next_token', ], 'maxResults' => [ 'shape' => 'MaxResultType', 'location' => 'querystring', 'locationName' => 'max_result', ], 'accessToken' => [ 'shape' => 'AccessTokenType', 'location' => 'header', 'locationName' => 'x-amz-sso_bearer_token', ], 'accountId' => [ 'shape' => 'AccountIdType', 'location' => 'querystring', 'locationName' => 'account_id', ], ], ], 'ListAccountRolesResponse' => [ 'type' => 'structure', 'members' => [ 'nextToken' => [ 'shape' => 'NextTokenType', ], 'roleList' => [ 'shape' => 'RoleListType', ], ], ], 'ListAccountsRequest' => [ 'type' => 'structure', 'required' => [ 'accessToken', ], 'members' => [ 'nextToken' => [ 'shape' => 'NextTokenType', 'location' => 'querystring', 'locationName' => 'next_token', ], 'maxResults' => [ 'shape' => 'MaxResultType', 'location' => 'querystring', 'locationName' => 'max_result', ], 'accessToken' => [ 'shape' => 'AccessTokenType', 'location' => 'header', 'locationName' => 'x-amz-sso_bearer_token', ], ], ], 'ListAccountsResponse' => [ 'type' => 'structure', 'members' => [ 'nextToken' => [ 'shape' => 'NextTokenType', ], 'accountList' => [ 'shape' => 'AccountListType', ], ], ], 'LogoutRequest' => [ 'type' => 'structure', 'required' => [ 'accessToken', ], 'members' => [ 'accessToken' => [ 'shape' => 'AccessTokenType', 'location' => 'header', 'locationName' => 'x-amz-sso_bearer_token', ], ], ], 'MaxResultType' => [ 'type' => 'integer', 'box' => true, 'max' => 100, 'min' => 1, ], 'NextTokenType' => [ 'type' => 'string', ], 'ResourceNotFoundException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 404, ], 'exception' => true, ], 'RoleCredentials' => [ 'type' => 'structure', 'members' => [ 'accessKeyId' => [ 'shape' => 'AccessKeyType', ], 'secretAccessKey' => [ 'shape' => 'SecretAccessKeyType', ], 'sessionToken' => [ 'shape' => 'SessionTokenType', ], 'expiration' => [ 'shape' => 'ExpirationTimestampType', ], ], ], 'RoleInfo' => [ 'type' => 'structure', 'members' => [ 'roleName' => [ 'shape' => 'RoleNameType', ], 'accountId' => [ 'shape' => 'AccountIdType', ], ], ], 'RoleListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'RoleInfo', ], ], 'RoleNameType' => [ 'type' => 'string', ], 'SecretAccessKeyType' => [ 'type' => 'string', 'sensitive' => true, ], 'SessionTokenType' => [ 'type' => 'string', 'sensitive' => true, ], 'TooManyRequestsException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 429, ], 'exception' => true, ], 'UnauthorizedException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'ErrorDescription', ], ], 'error' => [ 'httpStatusCode' => 401, ], 'exception' => true, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..e166dcaa9 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Invalid Configuration: FIPS and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'Invalid Configuration: Dualstack and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [], 'endpoint' => [ 'url' => [ 'ref' => 'Endpoint', ], 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://portal.sso-fips.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS and DualStack are enabled, but this partition does not support one or both', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'name', ], ], 'aws-us-gov', ], ], ], 'endpoint' => [ 'url' => 'https://portal.sso.{Region}.amazonaws.com', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://portal.sso-fips.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS is enabled but this partition does not support FIPS', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://portal.sso.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'DualStack is enabled but this partition does not support DualStack', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://portal.sso.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Configuration: Missing Region', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/paginators-1.json.php new file mode 100644 index 000000000..38d7738fd --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sso/2019-06-10/paginators-1.json.php @@ -0,0 +1,3 @@ + [ 'ListAccountRoles' => [ 'input_token' => 'nextToken', 'output_token' => 'nextToken', 'limit_key' => 'maxResults', 'result_key' => 'roleList', ], 'ListAccounts' => [ 'input_token' => 'nextToken', 'output_token' => 'nextToken', 'limit_key' => 'maxResults', 'result_key' => 'accountList', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/api-2.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/api-2.json.php new file mode 100644 index 000000000..997cce48e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/api-2.json.php @@ -0,0 +1,3 @@ + '2.0', 'metadata' => [ 'apiVersion' => '2011-06-15', 'endpointPrefix' => 'sts', 'globalEndpoint' => 'sts.amazonaws.com', 'protocol' => 'query', 'protocols' => [ 'query', ], 'serviceAbbreviation' => 'AWS STS', 'serviceFullName' => 'AWS Security Token Service', 'serviceId' => 'STS', 'signatureVersion' => 'v4', 'uid' => 'sts-2011-06-15', 'xmlNamespace' => 'https://sts.amazonaws.com/doc/2011-06-15/', 'auth' => [ 'aws.auth#sigv4', ], ], 'operations' => [ 'AssumeRole' => [ 'name' => 'AssumeRole', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'AssumeRoleRequest', ], 'output' => [ 'shape' => 'AssumeRoleResponse', 'resultWrapper' => 'AssumeRoleResult', ], 'errors' => [ [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'PackedPolicyTooLargeException', ], [ 'shape' => 'RegionDisabledException', ], [ 'shape' => 'ExpiredTokenException', ], ], ], 'AssumeRoleWithSAML' => [ 'name' => 'AssumeRoleWithSAML', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'AssumeRoleWithSAMLRequest', ], 'output' => [ 'shape' => 'AssumeRoleWithSAMLResponse', 'resultWrapper' => 'AssumeRoleWithSAMLResult', ], 'errors' => [ [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'PackedPolicyTooLargeException', ], [ 'shape' => 'IDPRejectedClaimException', ], [ 'shape' => 'InvalidIdentityTokenException', ], [ 'shape' => 'ExpiredTokenException', ], [ 'shape' => 'RegionDisabledException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'AssumeRoleWithWebIdentity' => [ 'name' => 'AssumeRoleWithWebIdentity', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'AssumeRoleWithWebIdentityRequest', ], 'output' => [ 'shape' => 'AssumeRoleWithWebIdentityResponse', 'resultWrapper' => 'AssumeRoleWithWebIdentityResult', ], 'errors' => [ [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'PackedPolicyTooLargeException', ], [ 'shape' => 'IDPRejectedClaimException', ], [ 'shape' => 'IDPCommunicationErrorException', ], [ 'shape' => 'InvalidIdentityTokenException', ], [ 'shape' => 'ExpiredTokenException', ], [ 'shape' => 'RegionDisabledException', ], ], 'authtype' => 'none', 'auth' => [ 'smithy.api#noAuth', ], ], 'AssumeRoot' => [ 'name' => 'AssumeRoot', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'AssumeRootRequest', ], 'output' => [ 'shape' => 'AssumeRootResponse', 'resultWrapper' => 'AssumeRootResult', ], 'errors' => [ [ 'shape' => 'RegionDisabledException', ], [ 'shape' => 'ExpiredTokenException', ], ], ], 'DecodeAuthorizationMessage' => [ 'name' => 'DecodeAuthorizationMessage', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'DecodeAuthorizationMessageRequest', ], 'output' => [ 'shape' => 'DecodeAuthorizationMessageResponse', 'resultWrapper' => 'DecodeAuthorizationMessageResult', ], 'errors' => [ [ 'shape' => 'InvalidAuthorizationMessageException', ], ], ], 'GetAccessKeyInfo' => [ 'name' => 'GetAccessKeyInfo', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetAccessKeyInfoRequest', ], 'output' => [ 'shape' => 'GetAccessKeyInfoResponse', 'resultWrapper' => 'GetAccessKeyInfoResult', ], ], 'GetCallerIdentity' => [ 'name' => 'GetCallerIdentity', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetCallerIdentityRequest', ], 'output' => [ 'shape' => 'GetCallerIdentityResponse', 'resultWrapper' => 'GetCallerIdentityResult', ], ], 'GetFederationToken' => [ 'name' => 'GetFederationToken', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetFederationTokenRequest', ], 'output' => [ 'shape' => 'GetFederationTokenResponse', 'resultWrapper' => 'GetFederationTokenResult', ], 'errors' => [ [ 'shape' => 'MalformedPolicyDocumentException', ], [ 'shape' => 'PackedPolicyTooLargeException', ], [ 'shape' => 'RegionDisabledException', ], ], ], 'GetSessionToken' => [ 'name' => 'GetSessionToken', 'http' => [ 'method' => 'POST', 'requestUri' => '/', ], 'input' => [ 'shape' => 'GetSessionTokenRequest', ], 'output' => [ 'shape' => 'GetSessionTokenResponse', 'resultWrapper' => 'GetSessionTokenResult', ], 'errors' => [ [ 'shape' => 'RegionDisabledException', ], ], ], ], 'shapes' => [ 'AssumeRoleRequest' => [ 'type' => 'structure', 'required' => [ 'RoleArn', 'RoleSessionName', ], 'members' => [ 'RoleArn' => [ 'shape' => 'arnType', ], 'RoleSessionName' => [ 'shape' => 'roleSessionNameType', ], 'PolicyArns' => [ 'shape' => 'policyDescriptorListType', ], 'Policy' => [ 'shape' => 'unrestrictedSessionPolicyDocumentType', ], 'DurationSeconds' => [ 'shape' => 'roleDurationSecondsType', ], 'Tags' => [ 'shape' => 'tagListType', ], 'TransitiveTagKeys' => [ 'shape' => 'tagKeyListType', ], 'ExternalId' => [ 'shape' => 'externalIdType', ], 'SerialNumber' => [ 'shape' => 'serialNumberType', ], 'TokenCode' => [ 'shape' => 'tokenCodeType', ], 'SourceIdentity' => [ 'shape' => 'sourceIdentityType', ], 'ProvidedContexts' => [ 'shape' => 'ProvidedContextsListType', ], ], ], 'AssumeRoleResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], 'AssumedRoleUser' => [ 'shape' => 'AssumedRoleUser', ], 'PackedPolicySize' => [ 'shape' => 'nonNegativeIntegerType', ], 'SourceIdentity' => [ 'shape' => 'sourceIdentityType', ], ], ], 'AssumeRoleWithSAMLRequest' => [ 'type' => 'structure', 'required' => [ 'RoleArn', 'PrincipalArn', 'SAMLAssertion', ], 'members' => [ 'RoleArn' => [ 'shape' => 'arnType', ], 'PrincipalArn' => [ 'shape' => 'arnType', ], 'SAMLAssertion' => [ 'shape' => 'SAMLAssertionType', ], 'PolicyArns' => [ 'shape' => 'policyDescriptorListType', ], 'Policy' => [ 'shape' => 'sessionPolicyDocumentType', ], 'DurationSeconds' => [ 'shape' => 'roleDurationSecondsType', ], ], ], 'AssumeRoleWithSAMLResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], 'AssumedRoleUser' => [ 'shape' => 'AssumedRoleUser', ], 'PackedPolicySize' => [ 'shape' => 'nonNegativeIntegerType', ], 'Subject' => [ 'shape' => 'Subject', ], 'SubjectType' => [ 'shape' => 'SubjectType', ], 'Issuer' => [ 'shape' => 'Issuer', ], 'Audience' => [ 'shape' => 'Audience', ], 'NameQualifier' => [ 'shape' => 'NameQualifier', ], 'SourceIdentity' => [ 'shape' => 'sourceIdentityType', ], ], ], 'AssumeRoleWithWebIdentityRequest' => [ 'type' => 'structure', 'required' => [ 'RoleArn', 'RoleSessionName', 'WebIdentityToken', ], 'members' => [ 'RoleArn' => [ 'shape' => 'arnType', ], 'RoleSessionName' => [ 'shape' => 'roleSessionNameType', ], 'WebIdentityToken' => [ 'shape' => 'clientTokenType', ], 'ProviderId' => [ 'shape' => 'urlType', ], 'PolicyArns' => [ 'shape' => 'policyDescriptorListType', ], 'Policy' => [ 'shape' => 'sessionPolicyDocumentType', ], 'DurationSeconds' => [ 'shape' => 'roleDurationSecondsType', ], ], ], 'AssumeRoleWithWebIdentityResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], 'SubjectFromWebIdentityToken' => [ 'shape' => 'webIdentitySubjectType', ], 'AssumedRoleUser' => [ 'shape' => 'AssumedRoleUser', ], 'PackedPolicySize' => [ 'shape' => 'nonNegativeIntegerType', ], 'Provider' => [ 'shape' => 'Issuer', ], 'Audience' => [ 'shape' => 'Audience', ], 'SourceIdentity' => [ 'shape' => 'sourceIdentityType', ], ], ], 'AssumeRootRequest' => [ 'type' => 'structure', 'required' => [ 'TargetPrincipal', 'TaskPolicyArn', ], 'members' => [ 'TargetPrincipal' => [ 'shape' => 'TargetPrincipalType', ], 'TaskPolicyArn' => [ 'shape' => 'PolicyDescriptorType', ], 'DurationSeconds' => [ 'shape' => 'RootDurationSecondsType', ], ], ], 'AssumeRootResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], 'SourceIdentity' => [ 'shape' => 'sourceIdentityType', ], ], ], 'AssumedRoleUser' => [ 'type' => 'structure', 'required' => [ 'AssumedRoleId', 'Arn', ], 'members' => [ 'AssumedRoleId' => [ 'shape' => 'assumedRoleIdType', ], 'Arn' => [ 'shape' => 'arnType', ], ], ], 'Audience' => [ 'type' => 'string', ], 'Credentials' => [ 'type' => 'structure', 'required' => [ 'AccessKeyId', 'SecretAccessKey', 'SessionToken', 'Expiration', ], 'members' => [ 'AccessKeyId' => [ 'shape' => 'accessKeyIdType', ], 'SecretAccessKey' => [ 'shape' => 'accessKeySecretType', ], 'SessionToken' => [ 'shape' => 'tokenType', ], 'Expiration' => [ 'shape' => 'dateType', ], ], ], 'DecodeAuthorizationMessageRequest' => [ 'type' => 'structure', 'required' => [ 'EncodedMessage', ], 'members' => [ 'EncodedMessage' => [ 'shape' => 'encodedMessageType', ], ], ], 'DecodeAuthorizationMessageResponse' => [ 'type' => 'structure', 'members' => [ 'DecodedMessage' => [ 'shape' => 'decodedMessageType', ], ], ], 'ExpiredTokenException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'expiredIdentityTokenMessage', ], ], 'error' => [ 'code' => 'ExpiredTokenException', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'FederatedUser' => [ 'type' => 'structure', 'required' => [ 'FederatedUserId', 'Arn', ], 'members' => [ 'FederatedUserId' => [ 'shape' => 'federatedIdType', ], 'Arn' => [ 'shape' => 'arnType', ], ], ], 'GetAccessKeyInfoRequest' => [ 'type' => 'structure', 'required' => [ 'AccessKeyId', ], 'members' => [ 'AccessKeyId' => [ 'shape' => 'accessKeyIdType', ], ], ], 'GetAccessKeyInfoResponse' => [ 'type' => 'structure', 'members' => [ 'Account' => [ 'shape' => 'accountType', ], ], ], 'GetCallerIdentityRequest' => [ 'type' => 'structure', 'members' => [], ], 'GetCallerIdentityResponse' => [ 'type' => 'structure', 'members' => [ 'UserId' => [ 'shape' => 'userIdType', ], 'Account' => [ 'shape' => 'accountType', ], 'Arn' => [ 'shape' => 'arnType', ], ], ], 'GetFederationTokenRequest' => [ 'type' => 'structure', 'required' => [ 'Name', ], 'members' => [ 'Name' => [ 'shape' => 'userNameType', ], 'Policy' => [ 'shape' => 'sessionPolicyDocumentType', ], 'PolicyArns' => [ 'shape' => 'policyDescriptorListType', ], 'DurationSeconds' => [ 'shape' => 'durationSecondsType', ], 'Tags' => [ 'shape' => 'tagListType', ], ], ], 'GetFederationTokenResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], 'FederatedUser' => [ 'shape' => 'FederatedUser', ], 'PackedPolicySize' => [ 'shape' => 'nonNegativeIntegerType', ], ], ], 'GetSessionTokenRequest' => [ 'type' => 'structure', 'members' => [ 'DurationSeconds' => [ 'shape' => 'durationSecondsType', ], 'SerialNumber' => [ 'shape' => 'serialNumberType', ], 'TokenCode' => [ 'shape' => 'tokenCodeType', ], ], ], 'GetSessionTokenResponse' => [ 'type' => 'structure', 'members' => [ 'Credentials' => [ 'shape' => 'Credentials', ], ], ], 'IDPCommunicationErrorException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'idpCommunicationErrorMessage', ], ], 'error' => [ 'code' => 'IDPCommunicationError', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'IDPRejectedClaimException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'idpRejectedClaimMessage', ], ], 'error' => [ 'code' => 'IDPRejectedClaim', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'InvalidAuthorizationMessageException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'invalidAuthorizationMessage', ], ], 'error' => [ 'code' => 'InvalidAuthorizationMessageException', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'InvalidIdentityTokenException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'invalidIdentityTokenMessage', ], ], 'error' => [ 'code' => 'InvalidIdentityToken', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'Issuer' => [ 'type' => 'string', ], 'MalformedPolicyDocumentException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'malformedPolicyDocumentMessage', ], ], 'error' => [ 'code' => 'MalformedPolicyDocument', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'NameQualifier' => [ 'type' => 'string', ], 'PackedPolicyTooLargeException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'packedPolicyTooLargeMessage', ], ], 'error' => [ 'code' => 'PackedPolicyTooLarge', 'httpStatusCode' => 400, 'senderFault' => true, ], 'exception' => true, ], 'PolicyDescriptorType' => [ 'type' => 'structure', 'members' => [ 'arn' => [ 'shape' => 'arnType', ], ], ], 'ProvidedContext' => [ 'type' => 'structure', 'members' => [ 'ProviderArn' => [ 'shape' => 'arnType', ], 'ContextAssertion' => [ 'shape' => 'contextAssertionType', ], ], ], 'ProvidedContextsListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'ProvidedContext', ], 'max' => 5, ], 'RegionDisabledException' => [ 'type' => 'structure', 'members' => [ 'message' => [ 'shape' => 'regionDisabledMessage', ], ], 'error' => [ 'code' => 'RegionDisabledException', 'httpStatusCode' => 403, 'senderFault' => true, ], 'exception' => true, ], 'RootDurationSecondsType' => [ 'type' => 'integer', 'max' => 900, 'min' => 0, ], 'SAMLAssertionType' => [ 'type' => 'string', 'max' => 100000, 'min' => 4, 'sensitive' => true, ], 'Subject' => [ 'type' => 'string', ], 'SubjectType' => [ 'type' => 'string', ], 'Tag' => [ 'type' => 'structure', 'required' => [ 'Key', 'Value', ], 'members' => [ 'Key' => [ 'shape' => 'tagKeyType', ], 'Value' => [ 'shape' => 'tagValueType', ], ], ], 'TargetPrincipalType' => [ 'type' => 'string', 'max' => 2048, 'min' => 12, ], 'accessKeyIdType' => [ 'type' => 'string', 'max' => 128, 'min' => 16, 'pattern' => '[\\w]*', ], 'accessKeySecretType' => [ 'type' => 'string', 'sensitive' => true, ], 'accountType' => [ 'type' => 'string', ], 'arnType' => [ 'type' => 'string', 'max' => 2048, 'min' => 20, 'pattern' => '[\\u0009\\u000A\\u000D\\u0020-\\u007E\\u0085\\u00A0-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]+', ], 'assumedRoleIdType' => [ 'type' => 'string', 'max' => 193, 'min' => 2, 'pattern' => '[\\w+=,.@:-]*', ], 'clientTokenType' => [ 'type' => 'string', 'max' => 20000, 'min' => 4, 'sensitive' => true, ], 'contextAssertionType' => [ 'type' => 'string', 'max' => 2048, 'min' => 4, ], 'dateType' => [ 'type' => 'timestamp', ], 'decodedMessageType' => [ 'type' => 'string', ], 'durationSecondsType' => [ 'type' => 'integer', 'max' => 129600, 'min' => 900, ], 'encodedMessageType' => [ 'type' => 'string', 'max' => 10240, 'min' => 1, ], 'expiredIdentityTokenMessage' => [ 'type' => 'string', ], 'externalIdType' => [ 'type' => 'string', 'max' => 1224, 'min' => 2, 'pattern' => '[\\w+=,.@:\\/-]*', ], 'federatedIdType' => [ 'type' => 'string', 'max' => 193, 'min' => 2, 'pattern' => '[\\w+=,.@\\:-]*', ], 'idpCommunicationErrorMessage' => [ 'type' => 'string', ], 'idpRejectedClaimMessage' => [ 'type' => 'string', ], 'invalidAuthorizationMessage' => [ 'type' => 'string', ], 'invalidIdentityTokenMessage' => [ 'type' => 'string', ], 'malformedPolicyDocumentMessage' => [ 'type' => 'string', ], 'nonNegativeIntegerType' => [ 'type' => 'integer', 'min' => 0, ], 'packedPolicyTooLargeMessage' => [ 'type' => 'string', ], 'policyDescriptorListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'PolicyDescriptorType', ], ], 'regionDisabledMessage' => [ 'type' => 'string', ], 'roleDurationSecondsType' => [ 'type' => 'integer', 'max' => 43200, 'min' => 900, ], 'roleSessionNameType' => [ 'type' => 'string', 'max' => 64, 'min' => 2, 'pattern' => '[\\w+=,.@-]*', ], 'serialNumberType' => [ 'type' => 'string', 'max' => 256, 'min' => 9, 'pattern' => '[\\w+=/:,.@-]*', ], 'sessionPolicyDocumentType' => [ 'type' => 'string', 'max' => 2048, 'min' => 1, 'pattern' => '[\\u0009\\u000A\\u000D\\u0020-\\u00FF]+', ], 'sourceIdentityType' => [ 'type' => 'string', 'max' => 64, 'min' => 2, 'pattern' => '[\\w+=,.@-]*', ], 'tagKeyListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'tagKeyType', ], 'max' => 50, ], 'tagKeyType' => [ 'type' => 'string', 'max' => 128, 'min' => 1, 'pattern' => '[\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]+', ], 'tagListType' => [ 'type' => 'list', 'member' => [ 'shape' => 'Tag', ], 'max' => 50, ], 'tagValueType' => [ 'type' => 'string', 'max' => 256, 'min' => 0, 'pattern' => '[\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]*', ], 'tokenCodeType' => [ 'type' => 'string', 'max' => 6, 'min' => 6, 'pattern' => '[\\d]*', ], 'tokenType' => [ 'type' => 'string', ], 'unrestrictedSessionPolicyDocumentType' => [ 'type' => 'string', 'min' => 1, 'pattern' => '[\\u0009\\u000A\\u000D\\u0020-\\u00FF]+', ], 'urlType' => [ 'type' => 'string', 'max' => 2048, 'min' => 4, ], 'userIdType' => [ 'type' => 'string', ], 'userNameType' => [ 'type' => 'string', 'max' => 32, 'min' => 2, 'pattern' => '[\\w+=,.@-]*', ], 'webIdentitySubjectType' => [ 'type' => 'string', 'max' => 255, 'min' => 6, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/endpoint-rule-set-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/endpoint-rule-set-1.json.php new file mode 100644 index 000000000..2429fcafc --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/endpoint-rule-set-1.json.php @@ -0,0 +1,3 @@ + '1.0', 'parameters' => [ 'Region' => [ 'builtIn' => 'AWS::Region', 'required' => false, 'documentation' => 'The AWS region used to dispatch the request.', 'type' => 'String', ], 'UseDualStack' => [ 'builtIn' => 'AWS::UseDualStack', 'required' => true, 'default' => false, 'documentation' => 'When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.', 'type' => 'Boolean', ], 'UseFIPS' => [ 'builtIn' => 'AWS::UseFIPS', 'required' => true, 'default' => false, 'documentation' => 'When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.', 'type' => 'Boolean', ], 'Endpoint' => [ 'builtIn' => 'SDK::Endpoint', 'required' => false, 'documentation' => 'Override the endpoint used to send this request', 'type' => 'String', ], 'UseGlobalEndpoint' => [ 'builtIn' => 'AWS::STS::UseGlobalEndpoint', 'required' => true, 'default' => false, 'documentation' => 'Whether the global endpoint should be used, rather then the regional endpoint for us-east-1.', 'type' => 'Boolean', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseGlobalEndpoint', ], true, ], ], [ 'fn' => 'not', 'argv' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], ], [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], false, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], false, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'ap-northeast-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'ap-south-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'ap-southeast-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'ap-southeast-2', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'ca-central-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'eu-central-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'eu-north-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'eu-west-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'eu-west-2', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'eu-west-3', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'sa-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-east-2', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-west-1', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'us-west-2', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sts.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => '{Region}', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Endpoint', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'error' => 'Invalid Configuration: FIPS and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'error' => 'Invalid Configuration: Dualstack and custom endpoint are not supported', 'type' => 'error', ], [ 'conditions' => [], 'endpoint' => [ 'url' => [ 'ref' => 'Endpoint', ], 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'isSet', 'argv' => [ [ 'ref' => 'Region', ], ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'aws.partition', 'argv' => [ [ 'ref' => 'Region', ], ], 'assign' => 'PartitionResult', ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], ], ], [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sts-fips.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS and DualStack are enabled, but this partition does not support one or both', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseFIPS', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsFIPS', ], ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'name', ], ], 'aws-us-gov', ], ], ], 'endpoint' => [ 'url' => 'https://sts.{Region}.amazonaws.com', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sts-fips.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'FIPS is enabled but this partition does not support FIPS', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ [ 'ref' => 'UseDualStack', ], true, ], ], ], 'rules' => [ [ 'conditions' => [ [ 'fn' => 'booleanEquals', 'argv' => [ true, [ 'fn' => 'getAttr', 'argv' => [ [ 'ref' => 'PartitionResult', ], 'supportsDualStack', ], ], ], ], ], 'rules' => [ [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sts.{Region}.{PartitionResult#dualStackDnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'DualStack is enabled but this partition does not support DualStack', 'type' => 'error', ], ], 'type' => 'tree', ], [ 'conditions' => [ [ 'fn' => 'stringEquals', 'argv' => [ [ 'ref' => 'Region', ], 'aws-global', ], ], ], 'endpoint' => [ 'url' => 'https://sts.amazonaws.com', 'properties' => [ 'authSchemes' => [ [ 'name' => 'sigv4', 'signingName' => 'sts', 'signingRegion' => 'us-east-1', ], ], ], 'headers' => [], ], 'type' => 'endpoint', ], [ 'conditions' => [], 'endpoint' => [ 'url' => 'https://sts.{Region}.{PartitionResult#dnsSuffix}', 'properties' => [], 'headers' => [], ], 'type' => 'endpoint', ], ], 'type' => 'tree', ], ], 'type' => 'tree', ], [ 'conditions' => [], 'error' => 'Invalid Configuration: Missing Region', 'type' => 'error', ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/paginators-1.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/paginators-1.json.php new file mode 100644 index 000000000..d76231321 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/paginators-1.json.php @@ -0,0 +1,3 @@ + [],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/smoke.json.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/smoke.json.php new file mode 100644 index 000000000..28082e83e --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/data/sts/2011-06-15/smoke.json.php @@ -0,0 +1,3 @@ + 1, 'defaultRegion' => 'us-west-2', 'testCases' => [ [ 'operationName' => 'GetSessionToken', 'input' => [], 'errorExpectedFromService' => false, ], [ 'operationName' => 'GetFederationToken', 'input' => [ 'Name' => 'temp', 'Policy' => '{\\"temp\\":true}', ], 'errorExpectedFromService' => true, ], ],]; diff --git a/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/functions.php b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/functions.php new file mode 100644 index 000000000..166e74936 --- /dev/null +++ b/lam/lib/3rdParty/composer/aws/aws-sdk-php/src/functions.php @@ -0,0 +1,573 @@ + true, '..' => true]; + $pathLen = strlen($path) + 1; + $iterator = dir_iterator($path, $context); + $queue = []; + do { + while ($iterator->valid()) { + $file = $iterator->current(); + $iterator->next(); + if (isset($invalid[basename($file)])) { + continue; + } + $fullPath = "{$path}/{$file}"; + yield $fullPath; + if (is_dir($fullPath)) { + $queue[] = $iterator; + $iterator = map( + dir_iterator($fullPath, $context), + function ($file) use ($fullPath, $pathLen) { + return substr("{$fullPath}/{$file}", $pathLen); + } + ); + continue; + } + } + $iterator = array_pop($queue); + } while ($iterator); +} + +//----------------------------------------------------------------------------- +// Misc. functions. +//----------------------------------------------------------------------------- + +/** + * Debug function used to describe the provided value type and class. + * + * @param mixed $input + * + * @return string Returns a string containing the type of the variable and + * if a class is provided, the class name. + */ +function describe_type($input) +{ + switch (gettype($input)) { + case 'object': + return 'object(' . get_class($input) . ')'; + case 'array': + return 'array(' . count($input) . ')'; + default: + ob_start(); + var_dump($input); + // normalize float vs double + return str_replace('double(', 'float(', rtrim(ob_get_clean())); + } +} + +/** + * Creates a default HTTP handler based on the available clients. + * + * @return callable + */ +function default_http_handler() +{ + return new \Aws\Handler\Guzzle\GuzzleHandler(); +} + +/** + * Gets the default user agent string depending on the Guzzle version + * + * @return string + */ +function default_user_agent() +{ + return Utils::defaultUserAgent(); +} + +/** + * Serialize a request for a command but do not send it. + * + * Returns a promise that is fulfilled with the serialized request. + * + * @param CommandInterface $command Command to serialize. + * + * @return RequestInterface + * @throws \RuntimeException + */ +function serialize(CommandInterface $command) +{ + $request = null; + $handlerList = $command->getHandlerList(); + + // Return a mock result. + $handlerList->setHandler( + function (CommandInterface $_, RequestInterface $r) use (&$request) { + $request = $r; + return new FulfilledPromise(new Result([])); + } + ); + + call_user_func($handlerList->resolve(), $command)->wait(); + if (!$request instanceof RequestInterface) { + throw new \RuntimeException( + 'Calling handler did not serialize request' + ); + } + + return $request; +} + +/** + * Retrieves data for a service from the SDK's service manifest file. + * + * Manifest data is stored statically, so it does not need to be loaded more + * than once per process. The JSON data is also cached in opcache. + * + * @param string $service Case-insensitive namespace or endpoint prefix of the + * service for which you are retrieving manifest data. + * + * @return array + * @throws \InvalidArgumentException if the service is not supported. + */ +function manifest($service = null) +{ + // Load the manifest and create aliases for lowercased namespaces + static $manifest = []; + static $aliases = []; + if (empty($manifest)) { + $manifest = load_compiled_json(__DIR__ . '/data/manifest.json'); + foreach ($manifest as $endpoint => $info) { + $alias = strtolower($info['namespace']); + if ($alias !== $endpoint) { + $aliases[$alias] = $endpoint; + } + } + } + + // If no service specified, then return the whole manifest. + if ($service === null) { + return $manifest; + } + + // Look up the service's info in the manifest data. + $service = strtolower($service); + if (isset($manifest[$service])) { + return $manifest[$service] + ['endpoint' => $service]; + } + + if (isset($aliases[$service])) { + return manifest($aliases[$service]); + } + + throw new \InvalidArgumentException( + "The service \"{$service}\" is not provided by the AWS SDK for PHP." + ); +} + +/** + * Checks if supplied parameter is a valid hostname + * + * @param string $hostname + * @return bool + */ +function is_valid_hostname($hostname) +{ + return ( + preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*\.?$/i", $hostname) + && preg_match("/^.{1,253}$/", $hostname) + && preg_match("/^[^\.]{1,63}(\.[^\.]{0,63})*$/", $hostname) + ); +} + +/** + * Checks if supplied parameter is a valid host label + * + * @param $label + * @return bool + */ +function is_valid_hostlabel($label) +{ + return preg_match("/^(?!-)[a-zA-Z0-9-]{1,63}(?=6.0.0", - "yoast/phpunit-polyfills": "^0.1.0" - }, - "autoload": { - "psr-4": { - "Assert\\": "lib/Assert" - }, - "files": [ - "lib/Assert/functions.php" - ] - }, - "autoload-dev": { - "psr-4": { - "Assert\\Tests\\": "tests/Assert/Tests" - }, - "files": [ - "tests/Assert/Tests/Fixtures/functions.php" - ] - }, - "scripts": { - "assert:generate-docs": "php bin/generate_method_docs.php", - "assert:cs-lint": "php-cs-fixer fix --diff -vvv --dry-run", - "assert:cs-fix": "php-cs-fixer fix . -vvv || true", - "assert:sa-code": "vendor/bin/phpstan analyse --configuration=phpstan-code.neon --no-progress --ansi -l 7 bin lib", - "assert:sa-tests": "vendor/bin/phpstan analyse --configuration=phpstan-tests.neon --no-progress --ansi -l 7 tests" - }, - "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php deleted file mode 100644 index 201bce57d..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php +++ /dev/null @@ -1,85 +0,0 @@ -notEmpty()->integer(); - * Assert::that($value)->nullOr()->string()->startsWith("Foo"); - * - * The assertion chain can be stateful, that means be careful when you reuse - * it. You should never pass around the chain. - */ - public static function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain - { - $assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath); - - return $assertionChain->setAssertionClassName(static::$assertionClass); - } - - /** - * Start validation on a set of values, returns {@link AssertionChain}. - * - * @param mixed $values - * @param string|callable|null $defaultMessage - */ - public static function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain - { - return static::that($values, $defaultMessage, $defaultPropertyPath)->all(); - } - - /** - * Start validation and allow NULL, returns {@link AssertionChain}. - * - * @param mixed $value - * @param string|callable|null $defaultMessage - */ - public static function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain - { - return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr(); - } - - /** - * Create a lazy assertion object. - */ - public static function lazy(): LazyAssertion - { - $lazyAssertion = new LazyAssertion(); - - return $lazyAssertion - ->setAssertClass(\get_called_class()) - ->setExceptionClass(static::$lazyAssertionExceptionClass); - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php deleted file mode 100644 index 81bc97809..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php +++ /dev/null @@ -1,2797 +0,0 @@ - - * - * @method static bool allAlnum(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric for all values. - * @method static bool allBase64(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined for all values. - * @method static bool allBetween(mixed[] $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit for all values. - * @method static bool allBetweenExclusive(mixed[] $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit for all values. - * @method static bool allBetweenLength(mixed[] $value, int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths for all values. - * @method static bool allBoolean(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is php boolean for all values. - * @method static bool allChoice(mixed[] $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices for all values. - * @method static bool allChoicesNotEmpty(array[] $values, array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content for all values. - * @method static bool allClassExists(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the class exists for all values. - * @method static bool allContains(mixed[] $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars for all values. - * @method static bool allCount(array[]|Countable[]|ResourceBundle[]|SimpleXMLElement[] $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count for all values. - * @method static bool allDate(string[] $value, string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format for all values. - * @method static bool allDefined(mixed[] $constant, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined for all values. - * @method static bool allDigit(mixed[] $value, string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit for all values. - * @method static bool allDirectory(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that a directory exists for all values. - * @method static bool allE164(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number for all values. - * @method static bool allEmail(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL) for all values. - * @method static bool allEndsWith(mixed[] $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars for all values. - * @method static bool allEq(mixed[] $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==) for all values. - * @method static bool allEqArraySubset(mixed[] $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset for all values. - * @method static bool allExtensionLoaded(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded for all values. - * @method static bool allExtensionVersion(string[] $extension, string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed for all values. - * @method static bool allFalse(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False for all values. - * @method static bool allFile(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that a file exists for all values. - * @method static bool allFloat(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php float for all values. - * @method static bool allGreaterOrEqualThan(mixed[] $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit for all values. - * @method static bool allGreaterThan(mixed[] $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit for all values. - * @method static bool allImplementsInterface(mixed[] $class, string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface for all values. - * @method static bool allInArray(mixed[] $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice() for all values. - * @method static bool allInteger(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer for all values. - * @method static bool allIntegerish(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish for all values. - * @method static bool allInterfaceExists(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the interface exists for all values. - * @method static bool allIp(string[] $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address for all values. - * @method static bool allIpv4(string[] $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address for all values. - * @method static bool allIpv6(string[] $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address for all values. - * @method static bool allIsArray(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array for all values. - * @method static bool allIsArrayAccessible(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object for all values. - * @method static bool allIsCallable(mixed[] $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable for all values. - * @method static bool allIsCountable(array[]|Countable[]|ResourceBundle[]|SimpleXMLElement[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable for all values. - * @method static bool allIsInstanceOf(mixed[] $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name for all values. - * @method static bool allIsJsonString(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string for all values. - * @method static bool allIsObject(mixed[] $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object for all values. - * @method static bool allIsResource(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a resource for all values. - * @method static bool allIsTraversable(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object for all values. - * @method static bool allKeyExists(mixed[] $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array for all values. - * @method static bool allKeyIsset(mixed[] $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset() for all values. - * @method static bool allKeyNotExists(mixed[] $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array for all values. - * @method static bool allLength(mixed[] $value, int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length for all values. - * @method static bool allLessOrEqualThan(mixed[] $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit for all values. - * @method static bool allLessThan(mixed[] $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit for all values. - * @method static bool allMax(mixed[] $value, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit for all values. - * @method static bool allMaxCount(array[]|Countable[]|ResourceBundle[]|SimpleXMLElement[] $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements for all values. - * @method static bool allMaxLength(mixed[] $value, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars for all values. - * @method static bool allMethodExists(string[] $value, mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object for all values. - * @method static bool allMin(mixed[] $value, mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit for all values. - * @method static bool allMinCount(array[]|Countable[]|ResourceBundle[]|SimpleXMLElement[] $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements for all values. - * @method static bool allMinLength(mixed[] $value, int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long for all values. - * @method static bool allNoContent(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty for all values. - * @method static bool allNotBlank(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is not blank for all values. - * @method static bool allNotContains(mixed[] $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars for all values. - * @method static bool allNotEmpty(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is not empty for all values. - * @method static bool allNotEmptyKey(mixed[] $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty for all values. - * @method static bool allNotEq(mixed[] $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==) for all values. - * @method static bool allNotInArray(mixed[] $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices for all values. - * @method static bool allNotIsInstanceOf(mixed[] $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name for all values. - * @method static bool allNotNull(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is not null for all values. - * @method static bool allNotRegex(mixed[] $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex for all values. - * @method static bool allNotSame(mixed[] $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===) for all values. - * @method static bool allNull(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is null for all values. - * @method static bool allNumeric(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is numeric for all values. - * @method static bool allObjectOrClass(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists for all values. - * @method static bool allPhpVersion(string[] $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version for all values. - * @method static bool allPropertiesExist(mixed[] $value, array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist for all values. - * @method static bool allPropertyExists(mixed[] $value, string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists for all values. - * @method static bool allRange(mixed[] $value, mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers for all values. - * @method static bool allReadable(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something readable for all values. - * @method static bool allRegex(mixed[] $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex for all values. - * @method static bool allSame(mixed[] $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===) for all values. - * @method static bool allSatisfy(mixed[] $value, callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback for all values. - * @method static bool allScalar(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar for all values. - * @method static bool allStartsWith(mixed[] $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars for all values. - * @method static bool allString(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is a string for all values. - * @method static bool allSubclassOf(mixed[] $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name for all values. - * @method static bool allTrue(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True for all values. - * @method static bool allUniqueValues(array[] $values, string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality) for all values. - * @method static bool allUrl(mixed[] $value, string|callable $message = null, string $propertyPath = null) Assert that value is an URL for all values. - * @method static bool allUuid(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID for all values. - * @method static bool allVersion(string[] $version1, string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions for all values. - * @method static bool allWriteable(string[] $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable for all values. - * @method static bool nullOrAlnum(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric or that the value is null. - * @method static bool nullOrBase64(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined or that the value is null. - * @method static bool nullOrBetween(mixed|null $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit or that the value is null. - * @method static bool nullOrBetweenExclusive(mixed|null $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit or that the value is null. - * @method static bool nullOrBetweenLength(mixed|null $value, int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths or that the value is null. - * @method static bool nullOrBoolean(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is php boolean or that the value is null. - * @method static bool nullOrChoice(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices or that the value is null. - * @method static bool nullOrChoicesNotEmpty(array|null $values, array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content or that the value is null. - * @method static bool nullOrClassExists(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the class exists or that the value is null. - * @method static bool nullOrContains(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars or that the value is null. - * @method static bool nullOrCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count or that the value is null. - * @method static bool nullOrDate(string|null $value, string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format or that the value is null. - * @method static bool nullOrDefined(mixed|null $constant, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined or that the value is null. - * @method static bool nullOrDigit(mixed|null $value, string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit or that the value is null. - * @method static bool nullOrDirectory(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a directory exists or that the value is null. - * @method static bool nullOrE164(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number or that the value is null. - * @method static bool nullOrEmail(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL) or that the value is null. - * @method static bool nullOrEndsWith(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars or that the value is null. - * @method static bool nullOrEq(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==) or that the value is null. - * @method static bool nullOrEqArraySubset(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset or that the value is null. - * @method static bool nullOrExtensionLoaded(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded or that the value is null. - * @method static bool nullOrExtensionVersion(string|null $extension, string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed or that the value is null. - * @method static bool nullOrFalse(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False or that the value is null. - * @method static bool nullOrFile(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a file exists or that the value is null. - * @method static bool nullOrFloat(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php float or that the value is null. - * @method static bool nullOrGreaterOrEqualThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit or that the value is null. - * @method static bool nullOrGreaterThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit or that the value is null. - * @method static bool nullOrImplementsInterface(mixed|null $class, string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface or that the value is null. - * @method static bool nullOrInArray(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice() or that the value is null. - * @method static bool nullOrInteger(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer or that the value is null. - * @method static bool nullOrIntegerish(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish or that the value is null. - * @method static bool nullOrInterfaceExists(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the interface exists or that the value is null. - * @method static bool nullOrIp(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address or that the value is null. - * @method static bool nullOrIpv4(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address or that the value is null. - * @method static bool nullOrIpv6(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address or that the value is null. - * @method static bool nullOrIsArray(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or that the value is null. - * @method static bool nullOrIsArrayAccessible(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object or that the value is null. - * @method static bool nullOrIsCallable(mixed|null $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable or that the value is null. - * @method static bool nullOrIsCountable(array|Countable|ResourceBundle|SimpleXMLElement|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable or that the value is null. - * @method static bool nullOrIsInstanceOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name or that the value is null. - * @method static bool nullOrIsJsonString(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string or that the value is null. - * @method static bool nullOrIsObject(mixed|null $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object or that the value is null. - * @method static bool nullOrIsResource(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a resource or that the value is null. - * @method static bool nullOrIsTraversable(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object or that the value is null. - * @method static bool nullOrKeyExists(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array or that the value is null. - * @method static bool nullOrKeyIsset(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset() or that the value is null. - * @method static bool nullOrKeyNotExists(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array or that the value is null. - * @method static bool nullOrLength(mixed|null $value, int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length or that the value is null. - * @method static bool nullOrLessOrEqualThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit or that the value is null. - * @method static bool nullOrLessThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit or that the value is null. - * @method static bool nullOrMax(mixed|null $value, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit or that the value is null. - * @method static bool nullOrMaxCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements or that the value is null. - * @method static bool nullOrMaxLength(mixed|null $value, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars or that the value is null. - * @method static bool nullOrMethodExists(string|null $value, mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object or that the value is null. - * @method static bool nullOrMin(mixed|null $value, mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit or that the value is null. - * @method static bool nullOrMinCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements or that the value is null. - * @method static bool nullOrMinLength(mixed|null $value, int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long or that the value is null. - * @method static bool nullOrNoContent(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty or that the value is null. - * @method static bool nullOrNotBlank(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not blank or that the value is null. - * @method static bool nullOrNotContains(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars or that the value is null. - * @method static bool nullOrNotEmpty(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not empty or that the value is null. - * @method static bool nullOrNotEmptyKey(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty or that the value is null. - * @method static bool nullOrNotEq(mixed|null $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==) or that the value is null. - * @method static bool nullOrNotInArray(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices or that the value is null. - * @method static bool nullOrNotIsInstanceOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name or that the value is null. - * @method static bool nullOrNotNull(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not null or that the value is null. - * @method static bool nullOrNotRegex(mixed|null $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex or that the value is null. - * @method static bool nullOrNotSame(mixed|null $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===) or that the value is null. - * @method static bool nullOrNull(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is null or that the value is null. - * @method static bool nullOrNumeric(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is numeric or that the value is null. - * @method static bool nullOrObjectOrClass(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists or that the value is null. - * @method static bool nullOrPhpVersion(string|null $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version or that the value is null. - * @method static bool nullOrPropertiesExist(mixed|null $value, array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist or that the value is null. - * @method static bool nullOrPropertyExists(mixed|null $value, string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists or that the value is null. - * @method static bool nullOrRange(mixed|null $value, mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers or that the value is null. - * @method static bool nullOrReadable(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something readable or that the value is null. - * @method static bool nullOrRegex(mixed|null $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex or that the value is null. - * @method static bool nullOrSame(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===) or that the value is null. - * @method static bool nullOrSatisfy(mixed|null $value, callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback or that the value is null. - * @method static bool nullOrScalar(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar or that the value is null. - * @method static bool nullOrStartsWith(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars or that the value is null. - * @method static bool nullOrString(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a string or that the value is null. - * @method static bool nullOrSubclassOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name or that the value is null. - * @method static bool nullOrTrue(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True or that the value is null. - * @method static bool nullOrUniqueValues(array|null $values, string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality) or that the value is null. - * @method static bool nullOrUrl(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an URL or that the value is null. - * @method static bool nullOrUuid(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID or that the value is null. - * @method static bool nullOrVersion(string|null $version1, string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions or that the value is null. - * @method static bool nullOrWriteable(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable or that the value is null. - */ -class Assertion -{ - const INVALID_FLOAT = 9; - const INVALID_INTEGER = 10; - const INVALID_DIGIT = 11; - const INVALID_INTEGERISH = 12; - const INVALID_BOOLEAN = 13; - const VALUE_EMPTY = 14; - const VALUE_NULL = 15; - const VALUE_NOT_NULL = 25; - const INVALID_STRING = 16; - const INVALID_REGEX = 17; - const INVALID_MIN_LENGTH = 18; - const INVALID_MAX_LENGTH = 19; - const INVALID_STRING_START = 20; - const INVALID_STRING_CONTAINS = 21; - const INVALID_CHOICE = 22; - const INVALID_NUMERIC = 23; - const INVALID_ARRAY = 24; - const INVALID_KEY_EXISTS = 26; - const INVALID_NOT_BLANK = 27; - const INVALID_INSTANCE_OF = 28; - const INVALID_SUBCLASS_OF = 29; - const INVALID_RANGE = 30; - const INVALID_ALNUM = 31; - const INVALID_TRUE = 32; - const INVALID_EQ = 33; - const INVALID_SAME = 34; - const INVALID_MIN = 35; - const INVALID_MAX = 36; - const INVALID_LENGTH = 37; - const INVALID_FALSE = 38; - const INVALID_STRING_END = 39; - const INVALID_UUID = 40; - const INVALID_COUNT = 41; - const INVALID_NOT_EQ = 42; - const INVALID_NOT_SAME = 43; - const INVALID_TRAVERSABLE = 44; - const INVALID_ARRAY_ACCESSIBLE = 45; - const INVALID_KEY_ISSET = 46; - const INVALID_VALUE_IN_ARRAY = 47; - const INVALID_E164 = 48; - const INVALID_BASE64 = 49; - const INVALID_NOT_REGEX = 50; - const INVALID_DIRECTORY = 101; - const INVALID_FILE = 102; - const INVALID_READABLE = 103; - const INVALID_WRITEABLE = 104; - const INVALID_CLASS = 105; - const INVALID_INTERFACE = 106; - const INVALID_FILE_NOT_EXISTS = 107; - const INVALID_EMAIL = 201; - const INTERFACE_NOT_IMPLEMENTED = 202; - const INVALID_URL = 203; - const INVALID_NOT_INSTANCE_OF = 204; - const VALUE_NOT_EMPTY = 205; - const INVALID_JSON_STRING = 206; - const INVALID_OBJECT = 207; - const INVALID_METHOD = 208; - const INVALID_SCALAR = 209; - const INVALID_LESS = 210; - const INVALID_LESS_OR_EQUAL = 211; - const INVALID_GREATER = 212; - const INVALID_GREATER_OR_EQUAL = 213; - const INVALID_DATE = 214; - const INVALID_CALLABLE = 215; - const INVALID_KEY_NOT_EXISTS = 216; - const INVALID_SATISFY = 217; - const INVALID_IP = 218; - const INVALID_BETWEEN = 219; - const INVALID_BETWEEN_EXCLUSIVE = 220; - const INVALID_EXTENSION = 222; - const INVALID_CONSTANT = 221; - const INVALID_VERSION = 223; - const INVALID_PROPERTY = 224; - const INVALID_RESOURCE = 225; - const INVALID_COUNTABLE = 226; - const INVALID_MIN_COUNT = 227; - const INVALID_MAX_COUNT = 228; - const INVALID_STRING_NOT_CONTAINS = 229; - const INVALID_UNIQUE_VALUES = 230; - - /** - * Exception to throw when an assertion failed. - * - * @var string - */ - protected static $exceptionClass = InvalidArgumentException::class; - - /** - * Assert that two values are equal (using ==). - * - * @param mixed $value - * @param mixed $value2 - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function eq($value, $value2, $message = null, ?string $propertyPath = null): bool - { - if ($value != $value2) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" does not equal expected value "%s".'), - static::stringify($value), - static::stringify($value2) - ); - - throw static::createException($value, $message, static::INVALID_EQ, $propertyPath, ['expected' => $value2]); - } - - return true; - } - - /** - * Assert that the array contains the subset. - * - * @param mixed $value - * @param mixed $value2 - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function eqArraySubset($value, $value2, $message = null, ?string $propertyPath = null): bool - { - static::isArray($value, $message, $propertyPath); - static::isArray($value2, $message, $propertyPath); - - $patched = \array_replace_recursive($value, $value2); - static::eq($patched, $value, $message, $propertyPath); - - return true; - } - - /** - * Assert that two values are the same (using ===). - * - * @param mixed $value - * @param mixed $value2 - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-template ExpectedType - * @psalm-param ExpectedType $value2 - * @psalm-assert =ExpectedType $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function same($value, $value2, $message = null, ?string $propertyPath = null): bool - { - if ($value !== $value2) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not the same as expected value "%s".'), - static::stringify($value), - static::stringify($value2) - ); - - throw static::createException($value, $message, static::INVALID_SAME, $propertyPath, ['expected' => $value2]); - } - - return true; - } - - /** - * Assert that two values are not equal (using ==). - * - * @param mixed $value1 - * @param mixed $value2 - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function notEq($value1, $value2, $message = null, ?string $propertyPath = null): bool - { - if ($value1 == $value2) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was not expected to be equal to value "%s".'), - static::stringify($value1), - static::stringify($value2) - ); - throw static::createException($value1, $message, static::INVALID_NOT_EQ, $propertyPath, ['expected' => $value2]); - } - - return true; - } - - /** - * Assert that two values are not the same (using ===). - * - * @param mixed $value1 - * @param mixed $value2 - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-template ExpectedType - * @psalm-param ExpectedType $value2 - * @psalm-assert !=ExpectedType $value1 - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function notSame($value1, $value2, $message = null, ?string $propertyPath = null): bool - { - if ($value1 === $value2) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was not expected to be the same as value "%s".'), - static::stringify($value1), - static::stringify($value2) - ); - throw static::createException($value1, $message, static::INVALID_NOT_SAME, $propertyPath, ['expected' => $value2]); - } - - return true; - } - - /** - * Assert that value is not in array of choices. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function notInArray($value, array $choices, $message = null, ?string $propertyPath = null): bool - { - if (true === \in_array($value, $choices)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was not expected to be an element of the values: %s'), - static::stringify($value), - static::stringify($choices) - ); - throw static::createException($value, $message, static::INVALID_VALUE_IN_ARRAY, $propertyPath, ['choices' => $choices]); - } - - return true; - } - - /** - * Assert that value is a php integer. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert int $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function integer($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_int($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an integer.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_INTEGER, $propertyPath); - } - - return true; - } - - /** - * Assert that value is a php float. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert float $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function float($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_float($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a float.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_FLOAT, $propertyPath); - } - - return true; - } - - /** - * Validates if an integer or integerish is a digit. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =numeric $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function digit($value, $message = null, ?string $propertyPath = null): bool - { - if (!\ctype_digit((string)$value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a digit.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_DIGIT, $propertyPath); - } - - return true; - } - - /** - * Assert that value is a php integer'ish. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function integerish($value, $message = null, ?string $propertyPath = null): bool - { - if ( - \is_resource($value) || - \is_object($value) || - \is_bool($value) || - \is_null($value) || - \is_array($value) || - (\is_string($value) && '' == $value) || - ( - \strval(\intval($value)) !== \strval($value) && - \strval(\intval($value)) !== \strval(\ltrim($value, '0')) && - '' !== \strval(\intval($value)) && - '' !== \strval(\ltrim($value, '0')) - ) - ) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an integer or a number castable to integer.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_INTEGERISH, $propertyPath); - } - - return true; - } - - /** - * Assert that value is php boolean. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert bool $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function boolean($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_bool($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a boolean.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_BOOLEAN, $propertyPath); - } - - return true; - } - - /** - * Assert that value is a PHP scalar. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert scalar $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function scalar($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_scalar($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a scalar.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_SCALAR, $propertyPath); - } - - return true; - } - - /** - * Assert that value is not empty. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert !empty $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function notEmpty($value, $message = null, ?string $propertyPath = null): bool - { - if (empty($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is empty, but non empty value was expected.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::VALUE_EMPTY, $propertyPath); - } - - return true; - } - - /** - * Assert that value is empty. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert empty $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function noContent($value, $message = null, ?string $propertyPath = null): bool - { - if (!empty($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not empty, but empty value was expected.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::VALUE_NOT_EMPTY, $propertyPath); - } - - return true; - } - - /** - * Assert that value is null. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert null $value - * - * @return bool - */ - public static function null($value, $message = null, ?string $propertyPath = null): bool - { - if (null !== $value) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not null, but null value was expected.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::VALUE_NOT_NULL, $propertyPath); - } - - return true; - } - - /** - * Assert that value is not null. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert !null $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function notNull($value, $message = null, ?string $propertyPath = null): bool - { - if (null === $value) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is null, but non null value was expected.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::VALUE_NULL, $propertyPath); - } - - return true; - } - - /** - * Assert that value is a string. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function string($value, $message = null, ?string $propertyPath = null) - { - if (!\is_string($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" expected to be string, type %s given.'), - static::stringify($value), - \gettype($value) - ); - - throw static::createException($value, $message, static::INVALID_STRING, $propertyPath); - } - - return true; - } - - /** - * Assert that value matches a regex. - * - * @param mixed $value - * @param string $pattern - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function regex($value, $pattern, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (!\preg_match($pattern, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" does not match expression.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]); - } - - return true; - } - - /** - * Assert that value does not match a regex. - * - * @param mixed $value - * @param string $pattern - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert !=string $value - * - * @throws AssertionFailedException - */ - public static function notRegex($value, $pattern, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (\preg_match($pattern, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" matches expression.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_NOT_REGEX, $propertyPath, ['pattern' => $pattern]); - } - - return true; - } - - /** - * Assert that string has a given length. - * - * @param mixed $value - * @param int $length - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function length($value, $length, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($value, $message, $propertyPath); - - if (\mb_strlen($value, $encoding) !== $length) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.'), - static::stringify($value), - $length, - \mb_strlen($value, $encoding) - ); - - throw static::createException($value, $message, static::INVALID_LENGTH, $propertyPath, ['length' => $length, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that a string is at least $minLength chars long. - * - * @param mixed $value - * @param int $minLength - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function minLength($value, $minLength, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($value, $message, $propertyPath); - - if (\mb_strlen($value, $encoding) < $minLength) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is too short, it should have at least %d characters, but only has %d characters.'), - static::stringify($value), - $minLength, - \mb_strlen($value, $encoding) - ); - - throw static::createException($value, $message, static::INVALID_MIN_LENGTH, $propertyPath, ['min_length' => $minLength, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that string value is not longer than $maxLength chars. - * - * @param mixed $value - * @param int $maxLength - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function maxLength($value, $maxLength, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($value, $message, $propertyPath); - - if (\mb_strlen($value, $encoding) > $maxLength) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.'), - static::stringify($value), - $maxLength, - \mb_strlen($value, $encoding) - ); - - throw static::createException($value, $message, static::INVALID_MAX_LENGTH, $propertyPath, ['max_length' => $maxLength, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that string length is between min and max lengths. - * - * @param mixed $value - * @param int $minLength - * @param int $maxLength - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function betweenLength($value, $minLength, $maxLength, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($value, $message, $propertyPath); - static::minLength($value, $minLength, $message, $propertyPath, $encoding); - static::maxLength($value, $maxLength, $message, $propertyPath, $encoding); - - return true; - } - - /** - * Assert that string starts with a sequence of chars. - * - * @param mixed $string - * @param string $needle - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $string - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function startsWith($string, $needle, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($string, $message, $propertyPath); - - if (0 !== \mb_strpos($string, $needle, 0, $encoding)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" does not start with "%s".'), - static::stringify($string), - static::stringify($needle) - ); - - throw static::createException($string, $message, static::INVALID_STRING_START, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that string ends with a sequence of chars. - * - * @param mixed $string - * @param string $needle - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $string - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function endsWith($string, $needle, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($string, $message, $propertyPath); - - $stringPosition = \mb_strlen($string, $encoding) - \mb_strlen($needle, $encoding); - - if (\mb_strripos($string, $needle, 0, $encoding) !== $stringPosition) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" does not end with "%s".'), - static::stringify($string), - static::stringify($needle) - ); - - throw static::createException($string, $message, static::INVALID_STRING_END, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that string contains a sequence of chars. - * - * @param mixed $string - * @param string $needle - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $string - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function contains($string, $needle, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($string, $message, $propertyPath); - - if (false === \mb_strpos($string, $needle, 0, $encoding)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" does not contain "%s".'), - static::stringify($string), - static::stringify($needle) - ); - - throw static::createException($string, $message, static::INVALID_STRING_CONTAINS, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that string does not contains a sequence of chars. - * - * @param mixed $string - * @param string $needle - * @param string|callable|null $message - * @param string|null $propertyPath - * @param string $encoding - * - * @psalm-assert =string $string - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function notContains($string, $needle, $message = null, ?string $propertyPath = null, $encoding = 'utf8'): bool - { - static::string($string, $message, $propertyPath); - - if (false !== \mb_strpos($string, $needle, 0, $encoding)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" contains "%s".'), - static::stringify($string), - static::stringify($needle) - ); - - throw static::createException($string, $message, static::INVALID_STRING_NOT_CONTAINS, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]); - } - - return true; - } - - /** - * Assert that value is in array of choices. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function choice($value, array $choices, $message = null, ?string $propertyPath = null): bool - { - if (!\in_array($value, $choices, true)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an element of the valid values: %s'), - static::stringify($value), - \implode(', ', \array_map([\get_called_class(), 'stringify'], $choices)) - ); - - throw static::createException($value, $message, static::INVALID_CHOICE, $propertyPath, ['choices' => $choices]); - } - - return true; - } - - /** - * Assert that value is in array of choices. - * - * This is an alias of {@see choice()}. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function inArray($value, array $choices, $message = null, ?string $propertyPath = null): bool - { - return static::choice($value, $choices, $message, $propertyPath); - } - - /** - * Assert that value is numeric. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert numeric $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function numeric($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_numeric($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not numeric.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_NUMERIC, $propertyPath); - } - - return true; - } - - /** - * Assert that value is a resource. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert resource $value - * - * @return bool - */ - public static function isResource($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_resource($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a resource.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_RESOURCE, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an array. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert array $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isArray($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_array($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an array.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_ARRAY, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an array or a traversable object. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert iterable $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isTraversable($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_array($value) && !$value instanceof Traversable) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an array and does not implement Traversable.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_TRAVERSABLE, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an array or an array-accessible object. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function isArrayAccessible($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_array($value) && !$value instanceof ArrayAccess) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an array and does not implement ArrayAccess.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_ARRAY_ACCESSIBLE, $propertyPath); - } - - return true; - } - - /** - * Assert that value is countable. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert countable $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isCountable($value, $message = null, ?string $propertyPath = null): bool - { - if (\function_exists('is_countable')) { - $assert = \is_countable($value); - } else { - $assert = \is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXMLElement; - } - - if (!$assert) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not an array and does not implement Countable.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_COUNTABLE, $propertyPath); - } - - return true; - } - - /** - * Assert that key exists in an array. - * - * @param mixed $value - * @param string|int $key - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function keyExists($value, $key, $message = null, ?string $propertyPath = null): bool - { - static::isArray($value, $message, $propertyPath); - - if (!\array_key_exists($key, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Array does not contain an element with key "%s"'), - static::stringify($key) - ); - - throw static::createException($value, $message, static::INVALID_KEY_EXISTS, $propertyPath, ['key' => $key]); - } - - return true; - } - - /** - * Assert that key does not exist in an array. - * - * @param mixed $value - * @param string|int $key - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function keyNotExists($value, $key, $message = null, ?string $propertyPath = null): bool - { - static::isArray($value, $message, $propertyPath); - - if (\array_key_exists($key, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Array contains an element with key "%s"'), - static::stringify($key) - ); - - throw static::createException($value, $message, static::INVALID_KEY_NOT_EXISTS, $propertyPath, ['key' => $key]); - } - - return true; - } - - /** - * Assert that values in array are unique (using strict equality). - * - * @param mixed[] $values - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function uniqueValues(array $values, $message = null, ?string $propertyPath = null): bool - { - foreach ($values as $key => $value) { - if (\array_search($value, $values, true) !== $key) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" occurs more than once in array'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_UNIQUE_VALUES, $propertyPath, ['value' => $value]); - } - } - - return true; - } - - /** - * Assert that key exists in an array/array-accessible object using isset(). - * - * @param mixed $value - * @param string|int $key - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function keyIsset($value, $key, $message = null, ?string $propertyPath = null): bool - { - static::isArrayAccessible($value, $message, $propertyPath); - - if (!isset($value[$key])) { - $message = \sprintf( - static::generateMessage($message ?: 'The element with key "%s" was not found'), - static::stringify($key) - ); - - throw static::createException($value, $message, static::INVALID_KEY_ISSET, $propertyPath, ['key' => $key]); - } - - return true; - } - - /** - * Assert that key exists in an array/array-accessible object and its value is not empty. - * - * @param mixed $value - * @param string|int $key - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function notEmptyKey($value, $key, $message = null, ?string $propertyPath = null): bool - { - static::keyIsset($value, $key, $message, $propertyPath); - static::notEmpty($value[$key], $message, $propertyPath); - - return true; - } - - /** - * Assert that value is not blank. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function notBlank($value, $message = null, ?string $propertyPath = null): bool - { - if (false === $value || (empty($value) && '0' != $value) || (\is_string($value) && '' === \trim($value))) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is blank, but was expected to contain a value.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_NOT_BLANK, $propertyPath); - } - - return true; - } - - /** - * Assert that value is instance of given class-name. - * - * @param mixed $value - * @param string $className - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-template ExpectedType of object - * @psalm-param class-string $className - * @psalm-assert ExpectedType $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isInstanceOf($value, $className, $message = null, ?string $propertyPath = null): bool - { - if (!($value instanceof $className)) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.'), - static::stringify($value), - $className - ); - - throw static::createException($value, $message, static::INVALID_INSTANCE_OF, $propertyPath, ['class' => $className]); - } - - return true; - } - - /** - * Assert that value is not instance of given class-name. - * - * @param mixed $value - * @param string $className - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-template ExpectedType of object - * @psalm-param class-string $className - * @psalm-assert !ExpectedType $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function notIsInstanceOf($value, $className, $message = null, ?string $propertyPath = null): bool - { - if ($value instanceof $className) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" was not expected to be instanceof of "%s".'), - static::stringify($value), - $className - ); - - throw static::createException($value, $message, static::INVALID_NOT_INSTANCE_OF, $propertyPath, ['class' => $className]); - } - - return true; - } - - /** - * Assert that value is subclass of given class-name. - * - * @param mixed $value - * @param string $className - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function subclassOf($value, $className, $message = null, ?string $propertyPath = null): bool - { - if (!\is_subclass_of($value, $className)) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" was expected to be subclass of "%s".'), - static::stringify($value), - $className - ); - - throw static::createException($value, $message, static::INVALID_SUBCLASS_OF, $propertyPath, ['class' => $className]); - } - - return true; - } - - /** - * Assert that value is in range of numbers. - * - * @param mixed $value - * @param mixed $minValue - * @param mixed $maxValue - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =numeric $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function range($value, $minValue, $maxValue, $message = null, ?string $propertyPath = null): bool - { - static::numeric($value, $message, $propertyPath); - - if ($value < $minValue || $value > $maxValue) { - $message = \sprintf( - static::generateMessage($message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".'), - static::stringify($value), - static::stringify($minValue), - static::stringify($maxValue) - ); - - throw static::createException($value, $message, static::INVALID_RANGE, $propertyPath, ['min' => $minValue, 'max' => $maxValue]); - } - - return true; - } - - /** - * Assert that a value is at least as big as a given limit. - * - * @param mixed $value - * @param mixed $minValue - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =numeric $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function min($value, $minValue, $message = null, ?string $propertyPath = null): bool - { - static::numeric($value, $message, $propertyPath); - - if ($value < $minValue) { - $message = \sprintf( - static::generateMessage($message ?: 'Number "%s" was expected to be at least "%s".'), - static::stringify($value), - static::stringify($minValue) - ); - - throw static::createException($value, $message, static::INVALID_MIN, $propertyPath, ['min' => $minValue]); - } - - return true; - } - - /** - * Assert that a number is smaller as a given limit. - * - * @param mixed $value - * @param mixed $maxValue - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =numeric $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function max($value, $maxValue, $message = null, ?string $propertyPath = null): bool - { - static::numeric($value, $message, $propertyPath); - - if ($value > $maxValue) { - $message = \sprintf( - static::generateMessage($message ?: 'Number "%s" was expected to be at most "%s".'), - static::stringify($value), - static::stringify($maxValue) - ); - - throw static::createException($value, $message, static::INVALID_MAX, $propertyPath, ['max' => $maxValue]); - } - - return true; - } - - /** - * Assert that a file exists. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function file($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - static::notEmpty($value, $message, $propertyPath); - - if (!\is_file($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'File "%s" was expected to exist.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_FILE, $propertyPath); - } - - return true; - } - - /** - * Assert that a directory exists. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function directory($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (!\is_dir($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Path "%s" was expected to be a directory.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_DIRECTORY, $propertyPath); - } - - return true; - } - - /** - * Assert that the value is something readable. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function readable($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (!\is_readable($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Path "%s" was expected to be readable.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_READABLE, $propertyPath); - } - - return true; - } - - /** - * Assert that the value is something writeable. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function writeable($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (!\is_writable($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Path "%s" was expected to be writeable.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_WRITEABLE, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function email($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - if (!\filter_var($value, FILTER_VALIDATE_EMAIL)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was expected to be a valid e-mail address.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_EMAIL, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an URL. - * - * This code snipped was taken from the Symfony project and modified to the special demands of this method. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - * - * @see https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php - * @see https://github.com/symfony/Validator/blob/master/Constraints/Url.php - */ - public static function url($value, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - - $protocols = ['http', 'https']; - - $pattern = '~^ - (%s):// # protocol - (([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth - ( - ([\pL\pN\pS\-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name - | # or - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address - | # or - \[ - (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::)))) - \] # an IPv6 address - ) - (:[0-9]+)? # a port (optional) - (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%%[0-9A-Fa-f]{2})* )* # a path - (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a query (optional) - (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a fragment (optional) - $~ixu'; - - $pattern = \sprintf($pattern, \implode('|', $protocols)); - - if (!\preg_match($pattern, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was expected to be a valid URL starting with http or https'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_URL, $propertyPath); - } - - return true; - } - - /** - * Assert that value is alphanumeric. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function alnum($value, $message = null, ?string $propertyPath = null): bool - { - try { - static::regex($value, '(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath); - } catch (Throwable $e) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_ALNUM, $propertyPath); - } - - return true; - } - - /** - * Assert that the value is boolean True. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert true $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function true($value, $message = null, ?string $propertyPath = null): bool - { - if (true !== $value) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not TRUE.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_TRUE, $propertyPath); - } - - return true; - } - - /** - * Assert that the value is boolean False. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert false $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function false($value, $message = null, ?string $propertyPath = null): bool - { - if (false !== $value) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not FALSE.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_FALSE, $propertyPath); - } - - return true; - } - - /** - * Assert that the class exists. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert class-string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function classExists($value, $message = null, ?string $propertyPath = null): bool - { - if (!\class_exists($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" does not exist.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_CLASS, $propertyPath); - } - - return true; - } - - /** - * Assert that the interface exists. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert class-string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function interfaceExists($value, $message = null, ?string $propertyPath = null): bool - { - if (!\interface_exists($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Interface "%s" does not exist.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_INTERFACE, $propertyPath); - } - - return true; - } - - /** - * Assert that the class implements the interface. - * - * @param mixed $class - * @param string $interfaceName - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function implementsInterface($class, $interfaceName, $message = null, ?string $propertyPath = null): bool - { - try { - $reflection = new ReflectionClass($class); - if (!$reflection->implementsInterface($interfaceName)) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" does not implement interface "%s".'), - static::stringify($class), - static::stringify($interfaceName) - ); - - throw static::createException($class, $message, static::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]); - } - } catch (ReflectionException $e) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" failed reflection.'), - static::stringify($class) - ); - throw static::createException($class, $message, static::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]); - } - - return true; - } - - /** - * Assert that the given string is a valid json string. - * - * NOTICE: - * Since this does a json_decode to determine its validity - * you probably should consider, when using the variable - * content afterwards, just to decode and check for yourself instead - * of using this assertion. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert =string $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isJsonString($value, $message = null, ?string $propertyPath = null): bool - { - if (null === \json_decode($value) && JSON_ERROR_NONE !== \json_last_error()) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a valid JSON string.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_JSON_STRING, $propertyPath); - } - - return true; - } - - /** - * Assert that the given string is a valid UUID. - * - * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function uuid($value, $message = null, ?string $propertyPath = null): bool - { - $value = \str_replace(['urn:', 'uuid:', '{', '}'], '', $value); - - if ('00000000-0000-0000-0000-000000000000' === $value) { - return true; - } - - if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a valid UUID.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_UUID, $propertyPath); - } - - return true; - } - - /** - * Assert that the given string is a valid E164 Phone Number. - * - * @see https://en.wikipedia.org/wiki/E.164 - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function e164($value, $message = null, ?string $propertyPath = null): bool - { - if (!\preg_match('/^\+?[1-9]\d{1,14}$/', $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" is not a valid E164.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_E164, $propertyPath); - } - - return true; - } - - /** - * Assert that the count of countable is equal to count. - * - * @param array|Countable|ResourceBundle|SimpleXMLElement $countable - * @param int $count - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function count($countable, $count, $message = null, ?string $propertyPath = null): bool - { - if ($count !== \count($countable)) { - $message = \sprintf( - static::generateMessage($message ?: 'List does not contain exactly %d elements (%d given).'), - static::stringify($count), - static::stringify(\count($countable)) - ); - - throw static::createException($countable, $message, static::INVALID_COUNT, $propertyPath, ['count' => $count]); - } - - return true; - } - - /** - * Assert that the countable have at least $count elements. - * - * @param array|Countable|ResourceBundle|SimpleXMLElement $countable - * @param int $count - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function minCount($countable, $count, $message = null, ?string $propertyPath = null): bool - { - if ($count > \count($countable)) { - $message = \sprintf( - static::generateMessage($message ?: 'List should have at least %d elements, but has %d elements.'), - static::stringify($count), - static::stringify(\count($countable)) - ); - - throw static::createException($countable, $message, static::INVALID_MIN_COUNT, $propertyPath, ['count' => $count]); - } - - return true; - } - - /** - * Assert that the countable have at most $count elements. - * - * @param array|Countable|ResourceBundle|SimpleXMLElement $countable - * @param int $count - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function maxCount($countable, $count, $message = null, ?string $propertyPath = null): bool - { - if ($count < \count($countable)) { - $message = \sprintf( - static::generateMessage($message ?: 'List should have at most %d elements, but has %d elements.'), - static::stringify($count), - static::stringify(\count($countable)) - ); - - throw static::createException($countable, $message, static::INVALID_MAX_COUNT, $propertyPath, ['count' => $count]); - } - - return true; - } - - /** - * static call handler to implement: - * - "null or assertion" delegation - * - "all" delegation. - * - * @param string $method - * @param array $args - * - * @return bool|mixed - * - * @throws AssertionFailedException - */ - public static function __callStatic($method, $args) - { - if (0 === \strpos($method, 'nullOr')) { - if (!\array_key_exists(0, $args)) { - throw new BadMethodCallException('Missing the first argument.'); - } - - if (null === $args[0]) { - return true; - } - - $method = \substr($method, 6); - - return \call_user_func_array([\get_called_class(), $method], $args); - } - - if (0 === \strpos($method, 'all')) { - if (!\array_key_exists(0, $args)) { - throw new BadMethodCallException('Missing the first argument.'); - } - - static::isTraversable($args[0]); - - $method = \substr($method, 3); - $values = \array_shift($args); - $calledClass = \get_called_class(); - - foreach ($values as $value) { - \call_user_func_array([$calledClass, $method], \array_merge([$value], $args)); - } - - return true; - } - - throw new BadMethodCallException('No assertion Assertion#'.$method.' exists.'); - } - - /** - * Determines if the values array has every choice as key and that this choice has content. - * - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function choicesNotEmpty(array $values, array $choices, $message = null, ?string $propertyPath = null): bool - { - static::notEmpty($values, $message, $propertyPath); - - foreach ($choices as $choice) { - static::notEmptyKey($values, $choice, $message, $propertyPath); - } - - return true; - } - - /** - * Determines that the named method is defined in the provided object. - * - * @param string $value - * @param mixed $object - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function methodExists($value, $object, $message = null, ?string $propertyPath = null): bool - { - static::isObject($object, $message, $propertyPath); - - if (!\method_exists($object, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Expected "%s" does not exist in provided object.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_METHOD, $propertyPath, ['object' => \get_class($object)]); - } - - return true; - } - - /** - * Determines that the provided value is an object. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert object $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isObject($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_object($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not a valid object.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_OBJECT, $propertyPath); - } - - return true; - } - - /** - * Determines if the value is less than given limit. - * - * @param mixed $value - * @param mixed $limit - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function lessThan($value, $limit, $message = null, ?string $propertyPath = null): bool - { - if ($value >= $limit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not less than "%s".'), - static::stringify($value), - static::stringify($limit) - ); - - throw static::createException($value, $message, static::INVALID_LESS, $propertyPath, ['limit' => $limit]); - } - - return true; - } - - /** - * Determines if the value is less or equal than given limit. - * - * @param mixed $value - * @param mixed $limit - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function lessOrEqualThan($value, $limit, $message = null, ?string $propertyPath = null): bool - { - if ($value > $limit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not less or equal than "%s".'), - static::stringify($value), - static::stringify($limit) - ); - - throw static::createException($value, $message, static::INVALID_LESS_OR_EQUAL, $propertyPath, ['limit' => $limit]); - } - - return true; - } - - /** - * Determines if the value is greater than given limit. - * - * @param mixed $value - * @param mixed $limit - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function greaterThan($value, $limit, $message = null, ?string $propertyPath = null): bool - { - if ($value <= $limit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not greater than "%s".'), - static::stringify($value), - static::stringify($limit) - ); - - throw static::createException($value, $message, static::INVALID_GREATER, $propertyPath, ['limit' => $limit]); - } - - return true; - } - - /** - * Determines if the value is greater or equal than given limit. - * - * @param mixed $value - * @param mixed $limit - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function greaterOrEqualThan($value, $limit, $message = null, ?string $propertyPath = null): bool - { - if ($value < $limit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not greater or equal than "%s".'), - static::stringify($value), - static::stringify($limit) - ); - - throw static::createException($value, $message, static::INVALID_GREATER_OR_EQUAL, $propertyPath, ['limit' => $limit]); - } - - return true; - } - - /** - * Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit. - * - * @param mixed $value - * @param mixed $lowerLimit - * @param mixed $upperLimit - * @param string|callable|null $message - * @param string $propertyPath - * - * @throws AssertionFailedException - */ - public static function between($value, $lowerLimit, $upperLimit, $message = null, ?string $propertyPath = null): bool - { - if ($lowerLimit > $value || $value > $upperLimit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is neither greater than or equal to "%s" nor less than or equal to "%s".'), - static::stringify($value), - static::stringify($lowerLimit), - static::stringify($upperLimit) - ); - - throw static::createException($value, $message, static::INVALID_BETWEEN, $propertyPath, ['lower' => $lowerLimit, 'upper' => $upperLimit]); - } - - return true; - } - - /** - * Assert that a value is greater than a lower limit, and less than an upper limit. - * - * @param mixed $value - * @param mixed $lowerLimit - * @param mixed $upperLimit - * @param string|callable|null $message - * @param string $propertyPath - * - * @throws AssertionFailedException - */ - public static function betweenExclusive($value, $lowerLimit, $upperLimit, $message = null, ?string $propertyPath = null): bool - { - if ($lowerLimit >= $value || $value >= $upperLimit) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is neither greater than "%s" nor less than "%s".'), - static::stringify($value), - static::stringify($lowerLimit), - static::stringify($upperLimit) - ); - - throw static::createException($value, $message, static::INVALID_BETWEEN_EXCLUSIVE, $propertyPath, ['lower' => $lowerLimit, 'upper' => $upperLimit]); - } - - return true; - } - - /** - * Assert that extension is loaded. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function extensionLoaded($value, $message = null, ?string $propertyPath = null): bool - { - if (!\extension_loaded($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Extension "%s" is required.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_EXTENSION, $propertyPath); - } - - return true; - } - - /** - * Assert that date is valid and corresponds to the given format. - * - * @param string $value - * @param string $format supports all of the options date(), except for the following: - * N, w, W, t, L, o, B, a, A, g, h, I, O, P, Z, c, r - * @param string|callable|null $message - * - * @throws AssertionFailedException - * - * @see http://php.net/manual/function.date.php#refsect1-function.date-parameters - */ - public static function date($value, $format, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - static::string($format, $message, $propertyPath); - - $dateTime = DateTime::createFromFormat('!'.$format, $value); - - if (false === $dateTime || $value !== $dateTime->format($format)) { - $message = \sprintf( - static::generateMessage($message ?: 'Date "%s" is invalid or does not match format "%s".'), - static::stringify($value), - static::stringify($format) - ); - - throw static::createException($value, $message, static::INVALID_DATE, $propertyPath, ['format' => $format]); - } - - return true; - } - - /** - * Assert that the value is an object, or a class that exists. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function objectOrClass($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_object($value)) { - static::classExists($value, $message, $propertyPath); - } - - return true; - } - - /** - * Assert that the value is an object or class, and that the property exists. - * - * @param mixed $value - * @param string $property - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function propertyExists($value, $property, $message = null, ?string $propertyPath = null): bool - { - static::objectOrClass($value); - - if (!\property_exists($value, $property)) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" does not have property "%s".'), - static::stringify($value), - static::stringify($property) - ); - - throw static::createException($value, $message, static::INVALID_PROPERTY, $propertyPath, ['property' => $property]); - } - - return true; - } - - /** - * Assert that the value is an object or class, and that the properties all exist. - * - * @param mixed $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function propertiesExist($value, array $properties, $message = null, ?string $propertyPath = null): bool - { - static::objectOrClass($value); - static::allString($properties, $message, $propertyPath); - - $invalidProperties = []; - foreach ($properties as $property) { - if (!\property_exists($value, $property)) { - $invalidProperties[] = $property; - } - } - - if ($invalidProperties) { - $message = \sprintf( - static::generateMessage($message ?: 'Class "%s" does not have these properties: %s.'), - static::stringify($value), - static::stringify(\implode(', ', $invalidProperties)) - ); - - throw static::createException($value, $message, static::INVALID_PROPERTY, $propertyPath, ['properties' => $properties]); - } - - return true; - } - - /** - * Assert comparison of two versions. - * - * @param string $version1 - * @param string $operator - * @param string $version2 - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function version($version1, $operator, $version2, $message = null, ?string $propertyPath = null): bool - { - static::notEmpty($operator, 'versionCompare operator is required and cannot be empty.'); - - if (true !== \version_compare($version1, $version2, $operator)) { - $message = \sprintf( - static::generateMessage($message ?: 'Version "%s" is not "%s" version "%s".'), - static::stringify($version1), - static::stringify($operator), - static::stringify($version2) - ); - - throw static::createException($version1, $message, static::INVALID_VERSION, $propertyPath, ['operator' => $operator, 'version' => $version2]); - } - - return true; - } - - /** - * Assert on PHP version. - * - * @param string $operator - * @param mixed $version - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function phpVersion($operator, $version, $message = null, ?string $propertyPath = null): bool - { - static::defined('PHP_VERSION'); - - return static::version(PHP_VERSION, $operator, $version, $message, $propertyPath); - } - - /** - * Assert that extension is loaded and a specific version is installed. - * - * @param string $extension - * @param string $operator - * @param mixed $version - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function extensionVersion($extension, $operator, $version, $message = null, ?string $propertyPath = null): bool - { - static::extensionLoaded($extension, $message, $propertyPath); - - return static::version(\phpversion($extension), $operator, $version, $message, $propertyPath); - } - - /** - * Determines that the provided value is callable. - * - * @param mixed $value - * @param string|callable|null $message - * @param string|null $propertyPath - * - * @psalm-assert callable $value - * - * @return bool - * - * @throws AssertionFailedException - */ - public static function isCallable($value, $message = null, ?string $propertyPath = null): bool - { - if (!\is_callable($value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is not a callable.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_CALLABLE, $propertyPath); - } - - return true; - } - - /** - * Assert that the provided value is valid according to a callback. - * - * If the callback returns `false` the assertion will fail. - * - * @param mixed $value - * @param callable $callback - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function satisfy($value, $callback, $message = null, ?string $propertyPath = null): bool - { - static::isCallable($callback); - - if (false === \call_user_func($callback, $value)) { - $message = \sprintf( - static::generateMessage($message ?: 'Provided "%s" is invalid according to custom rule.'), - static::stringify($value) - ); - - throw static::createException($value, $message, static::INVALID_SATISFY, $propertyPath); - } - - return true; - } - - /** - * Assert that value is an IPv4 or IPv6 address - * (using input_filter/FILTER_VALIDATE_IP). - * - * @param string $value - * @param int|null $flag - * @param string|callable|null $message - * - * @throws AssertionFailedException - * - * @see http://php.net/manual/filter.filters.flags.php - */ - public static function ip($value, $flag = null, $message = null, ?string $propertyPath = null): bool - { - static::string($value, $message, $propertyPath); - if ($flag === null) { - $filterVarResult = \filter_var($value, FILTER_VALIDATE_IP); - } else { - $filterVarResult = \filter_var($value, FILTER_VALIDATE_IP, $flag); - } - if (!$filterVarResult) { - $message = \sprintf( - static::generateMessage($message ?: 'Value "%s" was expected to be a valid IP address.'), - static::stringify($value) - ); - throw static::createException($value, $message, static::INVALID_IP, $propertyPath, ['flag' => $flag]); - } - - return true; - } - - /** - * Assert that value is an IPv4 address - * (using input_filter/FILTER_VALIDATE_IP). - * - * @param string $value - * @param int|null $flag - * @param string|callable|null $message - * - * @throws AssertionFailedException - * - * @see http://php.net/manual/filter.filters.flags.php - */ - public static function ipv4($value, $flag = null, $message = null, ?string $propertyPath = null): bool - { - static::ip($value, $flag | FILTER_FLAG_IPV4, static::generateMessage($message ?: 'Value "%s" was expected to be a valid IPv4 address.'), $propertyPath); - - return true; - } - - /** - * Assert that value is an IPv6 address - * (using input_filter/FILTER_VALIDATE_IP). - * - * @param string $value - * @param int|null $flag - * @param string|callable|null $message - * - * @throws AssertionFailedException - * - * @see http://php.net/manual/filter.filters.flags.php - */ - public static function ipv6($value, $flag = null, $message = null, ?string $propertyPath = null): bool - { - static::ip($value, $flag | FILTER_FLAG_IPV6, static::generateMessage($message ?: 'Value "%s" was expected to be a valid IPv6 address.'), $propertyPath); - - return true; - } - - /** - * Assert that a constant is defined. - * - * @param mixed $constant - * @param string|callable|null $message - */ - public static function defined($constant, $message = null, ?string $propertyPath = null): bool - { - if (!\defined($constant)) { - $message = \sprintf(static::generateMessage($message ?: 'Value "%s" expected to be a defined constant.'), $constant); - - throw static::createException($constant, $message, static::INVALID_CONSTANT, $propertyPath); - } - - return true; - } - - /** - * Assert that a constant is defined. - * - * @param string $value - * @param string|callable|null $message - * - * @throws AssertionFailedException - */ - public static function base64($value, $message = null, ?string $propertyPath = null): bool - { - if (false === \base64_decode($value, true)) { - $message = \sprintf(static::generateMessage($message ?: 'Value "%s" is not a valid base64 string.'), $value); - - throw static::createException($value, $message, static::INVALID_BASE64, $propertyPath); - } - - return true; - } - - /** - * Helper method that handles building the assertion failure exceptions. - * They are returned from this method so that the stack trace still shows - * the assertions method. - * - * @param mixed $value - * @param string|callable|null $message - * @param int $code - * - * @return mixed - */ - protected static function createException($value, $message, $code, $propertyPath = null, array $constraints = []) - { - $exceptionClass = static::$exceptionClass; - - return new $exceptionClass($message, $code, $propertyPath, $value, $constraints); - } - - /** - * Make a string version of a value. - * - * @param mixed $value - */ - protected static function stringify($value): string - { - $result = \gettype($value); - - if (\is_bool($value)) { - $result = $value ? '' : ''; - } elseif (\is_scalar($value)) { - $val = (string)$value; - - if (\mb_strlen($val) > 100) { - $val = \mb_substr($val, 0, 97).'...'; - } - - $result = $val; - } elseif (\is_array($value)) { - $result = ''; - } elseif (\is_object($value)) { - $result = \get_class($value); - } elseif (\is_resource($value)) { - $result = \get_resource_type($value); - } elseif (null === $value) { - $result = ''; - } - - return $result; - } - - /** - * Generate the message. - * - * @param string|callable|null $message - */ - protected static function generateMessage($message): string - { - if (\is_callable($message)) { - $traces = \debug_backtrace(0); - - $parameters = []; - - try { - $reflection = new ReflectionClass($traces[1]['class']); - $method = $reflection->getMethod($traces[1]['function']); - foreach ($method->getParameters() as $index => $parameter) { - if ('message' !== $parameter->getName()) { - $parameters[$parameter->getName()] = \array_key_exists($index, $traces[1]['args']) - ? $traces[1]['args'][$index] - : $parameter->getDefaultValue(); - } - } - - $parameters['::assertion'] = \sprintf('%s%s%s', $traces[1]['class'], $traces[1]['type'], $traces[1]['function']); - - $message = \call_user_func_array($message, [$parameters]); - } // @codeCoverageIgnoreStart - catch (Throwable $exception) { - $message = \sprintf('Unable to generate message : %s', $exception->getMessage()); - } // @codeCoverageIgnoreEnd - } - - return (string)$message; - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php deleted file mode 100644 index 8d1f1b3c1..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php +++ /dev/null @@ -1,247 +0,0 @@ - - * - * @method AssertionChain alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric. - * @method AssertionChain base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. - * @method AssertionChain between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit. - * @method AssertionChain betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit. - * @method AssertionChain betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths. - * @method AssertionChain boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean. - * @method AssertionChain choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. - * @method AssertionChain choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content. - * @method AssertionChain classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists. - * @method AssertionChain contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars. - * @method AssertionChain count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count. - * @method AssertionChain date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format. - * @method AssertionChain defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. - * @method AssertionChain digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit. - * @method AssertionChain directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists. - * @method AssertionChain e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number. - * @method AssertionChain email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). - * @method AssertionChain endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars. - * @method AssertionChain eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==). - * @method AssertionChain eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset. - * @method AssertionChain extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded. - * @method AssertionChain extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed. - * @method AssertionChain false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False. - * @method AssertionChain file(string|callable $message = null, string $propertyPath = null) Assert that a file exists. - * @method AssertionChain float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float. - * @method AssertionChain greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit. - * @method AssertionChain greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit. - * @method AssertionChain implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface. - * @method AssertionChain inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice(). - * @method AssertionChain integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer. - * @method AssertionChain integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish. - * @method AssertionChain interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists. - * @method AssertionChain ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address. - * @method AssertionChain ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address. - * @method AssertionChain ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address. - * @method AssertionChain isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array. - * @method AssertionChain isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object. - * @method AssertionChain isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable. - * @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable. - * @method AssertionChain isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name. - * @method AssertionChain isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string. - * @method AssertionChain isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object. - * @method AssertionChain isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource. - * @method AssertionChain isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object. - * @method AssertionChain keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array. - * @method AssertionChain keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset(). - * @method AssertionChain keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array. - * @method AssertionChain length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length. - * @method AssertionChain lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit. - * @method AssertionChain lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit. - * @method AssertionChain max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit. - * @method AssertionChain maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements. - * @method AssertionChain maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars. - * @method AssertionChain methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object. - * @method AssertionChain min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit. - * @method AssertionChain minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements. - * @method AssertionChain minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long. - * @method AssertionChain noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty. - * @method AssertionChain notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank. - * @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars. - * @method AssertionChain notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty. - * @method AssertionChain notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty. - * @method AssertionChain notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==). - * @method AssertionChain notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices. - * @method AssertionChain notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name. - * @method AssertionChain notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null. - * @method AssertionChain notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex. - * @method AssertionChain notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===). - * @method AssertionChain null(string|callable $message = null, string $propertyPath = null) Assert that value is null. - * @method AssertionChain numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric. - * @method AssertionChain objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists. - * @method AssertionChain phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version. - * @method AssertionChain propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist. - * @method AssertionChain propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists. - * @method AssertionChain range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers. - * @method AssertionChain readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable. - * @method AssertionChain regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex. - * @method AssertionChain same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===). - * @method AssertionChain satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback. - * @method AssertionChain scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar. - * @method AssertionChain startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars. - * @method AssertionChain string(string|callable $message = null, string $propertyPath = null) Assert that value is a string. - * @method AssertionChain subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name. - * @method AssertionChain true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True. - * @method AssertionChain uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality). - * @method AssertionChain url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL. - * @method AssertionChain uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID. - * @method AssertionChain version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions. - * @method AssertionChain writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable. - */ -class AssertionChain -{ - /** - * @var mixed - */ - private $value; - - /** - * @var string|callable|null - */ - private $defaultMessage; - - /** - * @var string|null - */ - private $defaultPropertyPath; - - /** - * Return each assertion as always valid. - * - * @var bool - */ - private $alwaysValid = false; - - /** - * Perform assertion on every element of array or traversable. - * - * @var bool - */ - private $all = false; - - /** @var string|Assertion Class to use for assertion calls */ - private $assertionClassName = 'Assert\Assertion'; - - /** - * AssertionChain constructor. - * - * @param mixed $value - * @param string|callable|null $defaultMessage - */ - public function __construct($value, $defaultMessage = null, ?string $defaultPropertyPath = null) - { - $this->value = $value; - $this->defaultMessage = $defaultMessage; - $this->defaultPropertyPath = $defaultPropertyPath; - } - - /** - * Call assertion on the current value in the chain. - * - * @param string $methodName - * @param array $args - */ - public function __call($methodName, $args): AssertionChain - { - if (true === $this->alwaysValid) { - return $this; - } - - try { - $method = new \ReflectionMethod($this->assertionClassName, $methodName); - } catch (\ReflectionException $exception) { - throw new \RuntimeException("Assertion '".$methodName."' does not exist."); - } - - \array_unshift($args, $this->value); - $params = $method->getParameters(); - - foreach ($params as $idx => $param) { - if (isset($args[$idx])) { - continue; - } - - switch ($param->getName()) { - case 'message': - $args[$idx] = $this->defaultMessage; - break; - case 'propertyPath': - $args[$idx] = $this->defaultPropertyPath; - break; - } - } - - if ($this->all) { - $methodName = 'all'.$methodName; - } - - \call_user_func_array([$this->assertionClassName, $methodName], $args); - - return $this; - } - - /** - * Switch chain into validation mode for an array of values. - */ - public function all(): AssertionChain - { - $this->all = true; - - return $this; - } - - /** - * Switch chain into mode allowing nulls, ignoring further assertions. - */ - public function nullOr(): AssertionChain - { - if (null === $this->value) { - $this->alwaysValid = true; - } - - return $this; - } - - /** - * @param string $className - * - * @return $this - */ - public function setAssertionClassName($className): AssertionChain - { - if (!\is_string($className)) { - throw new LogicException('Exception class name must be passed as a string'); - } - - if (Assertion::class !== $className && !\is_subclass_of($className, Assertion::class)) { - throw new LogicException($className.' is not (a subclass of) '.Assertion::class); - } - - $this->assertionClassName = $className; - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php deleted file mode 100644 index 7e0b2ec3d..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php +++ /dev/null @@ -1,32 +0,0 @@ -propertyPath = $propertyPath; - $this->value = $value; - $this->constraints = $constraints; - } - - /** - * User controlled way to define a sub-property causing - * the failure of a currently asserted objects. - * - * Useful to transport information about the nature of the error - * back to higher layers. - * - * @return string|null - */ - public function getPropertyPath() - { - return $this->propertyPath; - } - - /** - * Get the value that caused the assertion to fail. - * - * @return mixed - */ - public function getValue() - { - return $this->value; - } - - /** - * Get the constraints that applied to the failed assertion. - */ - public function getConstraints(): array - { - return $this->constraints; - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php deleted file mode 100644 index f7b6cd719..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php +++ /dev/null @@ -1,228 +0,0 @@ - - * - * @method LazyAssertion alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric. - * @method LazyAssertion base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. - * @method LazyAssertion between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit. - * @method LazyAssertion betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit. - * @method LazyAssertion betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths. - * @method LazyAssertion boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean. - * @method LazyAssertion choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. - * @method LazyAssertion choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content. - * @method LazyAssertion classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists. - * @method LazyAssertion contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars. - * @method LazyAssertion count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count. - * @method LazyAssertion date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format. - * @method LazyAssertion defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. - * @method LazyAssertion digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit. - * @method LazyAssertion directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists. - * @method LazyAssertion e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number. - * @method LazyAssertion email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). - * @method LazyAssertion endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars. - * @method LazyAssertion eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==). - * @method LazyAssertion eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset. - * @method LazyAssertion extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded. - * @method LazyAssertion extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed. - * @method LazyAssertion false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False. - * @method LazyAssertion file(string|callable $message = null, string $propertyPath = null) Assert that a file exists. - * @method LazyAssertion float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float. - * @method LazyAssertion greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit. - * @method LazyAssertion greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit. - * @method LazyAssertion implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface. - * @method LazyAssertion inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice(). - * @method LazyAssertion integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer. - * @method LazyAssertion integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish. - * @method LazyAssertion interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists. - * @method LazyAssertion ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address. - * @method LazyAssertion ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address. - * @method LazyAssertion ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address. - * @method LazyAssertion isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array. - * @method LazyAssertion isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object. - * @method LazyAssertion isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable. - * @method LazyAssertion isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable. - * @method LazyAssertion isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name. - * @method LazyAssertion isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string. - * @method LazyAssertion isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object. - * @method LazyAssertion isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource. - * @method LazyAssertion isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object. - * @method LazyAssertion keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array. - * @method LazyAssertion keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset(). - * @method LazyAssertion keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array. - * @method LazyAssertion length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length. - * @method LazyAssertion lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit. - * @method LazyAssertion lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit. - * @method LazyAssertion max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit. - * @method LazyAssertion maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements. - * @method LazyAssertion maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars. - * @method LazyAssertion methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object. - * @method LazyAssertion min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit. - * @method LazyAssertion minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements. - * @method LazyAssertion minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long. - * @method LazyAssertion noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty. - * @method LazyAssertion notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank. - * @method LazyAssertion notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars. - * @method LazyAssertion notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty. - * @method LazyAssertion notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty. - * @method LazyAssertion notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==). - * @method LazyAssertion notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices. - * @method LazyAssertion notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name. - * @method LazyAssertion notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null. - * @method LazyAssertion notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex. - * @method LazyAssertion notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===). - * @method LazyAssertion null(string|callable $message = null, string $propertyPath = null) Assert that value is null. - * @method LazyAssertion numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric. - * @method LazyAssertion objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists. - * @method LazyAssertion phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version. - * @method LazyAssertion propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist. - * @method LazyAssertion propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists. - * @method LazyAssertion range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers. - * @method LazyAssertion readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable. - * @method LazyAssertion regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex. - * @method LazyAssertion same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===). - * @method LazyAssertion satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback. - * @method LazyAssertion scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar. - * @method LazyAssertion startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars. - * @method LazyAssertion string(string|callable $message = null, string $propertyPath = null) Assert that value is a string. - * @method LazyAssertion subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name. - * @method LazyAssertion true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True. - * @method LazyAssertion uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality). - * @method LazyAssertion url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL. - * @method LazyAssertion uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID. - * @method LazyAssertion version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions. - * @method LazyAssertion writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable. - * @method LazyAssertion all() Switch chain into validation mode for an array of values. - * @method LazyAssertion nullOr() Switch chain into mode allowing nulls, ignoring further assertions. - */ -class LazyAssertion -{ - private $currentChainFailed = false; - private $alwaysTryAll = false; - private $thisChainTryAll = false; - private $currentChain; - private $errors = []; - - /** @var string The class to use as AssertionChain factory */ - private $assertClass = Assert::class; - - /** @var string|LazyAssertionException The class to use for exceptions */ - private $exceptionClass = LazyAssertionException::class; - - /** - * @param mixed $value - * @param string|callable|null $defaultMessage - * - * @return static - */ - public function that($value, ?string $propertyPath = null, $defaultMessage = null) - { - $this->currentChainFailed = false; - $this->thisChainTryAll = false; - $assertClass = $this->assertClass; - $this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath); - - return $this; - } - - /** - * @return static - */ - public function tryAll() - { - if (!$this->currentChain) { - $this->alwaysTryAll = true; - } - - $this->thisChainTryAll = true; - - return $this; - } - - /** - * @param string $method - * @param array $args - * - * @return static - */ - public function __call($method, $args) - { - if (false === $this->alwaysTryAll - && false === $this->thisChainTryAll - && true === $this->currentChainFailed - ) { - return $this; - } - - try { - \call_user_func_array([$this->currentChain, $method], $args); - } catch (AssertionFailedException $e) { - $this->errors[] = $e; - $this->currentChainFailed = true; - } - - return $this; - } - - /** - * @throws LazyAssertionException - */ - public function verifyNow(): bool - { - if ($this->errors) { - throw \call_user_func([$this->exceptionClass, 'fromErrors'], $this->errors); - } - - return true; - } - - /** - * @param string $className - * - * @return static - */ - public function setAssertClass(string $className): LazyAssertion - { - if (Assert::class !== $className && !\is_subclass_of($className, Assert::class)) { - throw new LogicException($className.' is not (a subclass of) '.Assert::class); - } - - $this->assertClass = $className; - - return $this; - } - - /** - * @param string $className - * - * @return static - */ - public function setExceptionClass(string $className): LazyAssertion - { - if (LazyAssertionException::class !== $className && !\is_subclass_of($className, LazyAssertionException::class)) { - throw new LogicException($className.' is not (a subclass of) '.LazyAssertionException::class); - } - - $this->exceptionClass = $className; - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php deleted file mode 100644 index 2ba59dd7c..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php +++ /dev/null @@ -1,53 +0,0 @@ -getPropertyPath(), $error->getMessage()); - } - - return new static($message, $errors); - } - - public function __construct($message, array $errors) - { - parent::__construct($message, 0, null, null); - - $this->errors = $errors; - } - - /** - * @return InvalidArgumentException[] - */ - public function getErrorExceptions(): array - { - return $this->errors; - } -} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php deleted file mode 100644 index 77cdcedda..000000000 --- a/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php +++ /dev/null @@ -1,72 +0,0 @@ -notEmpty()->integer(); - * \Assert\that($value)->nullOr()->string()->startsWith("Foo"); - * - * The assertion chain can be stateful, that means be careful when you reuse - * it. You should never pass around the chain. - */ -function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain -{ - return Assert::that($value, $defaultMessage, $defaultPropertyPath); -} - -/** - * Start validation on a set of values, returns {@link AssertionChain}. - * - * @param mixed $values - * @param string|callable|null $defaultMessage - * @param string $defaultPropertyPath - */ -function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain -{ - return Assert::thatAll($values, $defaultMessage, $defaultPropertyPath); -} - -/** - * Start validation and allow NULL, returns {@link AssertionChain}. - * - * @param mixed $value - * @param string|callable|null $defaultMessage - * @param string $defaultPropertyPath - * - * @deprecated In favour of Assert::thatNullOr($value, $defaultMessage = null, $defaultPropertyPath = null) - */ -function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain -{ - return Assert::thatNullOr($value, $defaultMessage, $defaultPropertyPath); -} - -/** - * Create a lazy assertion object. - */ -function lazy(): LazyAssertion -{ - return Assert::lazy(); -} diff --git a/lam/lib/3rdParty/composer/brick/math/CHANGELOG.md b/lam/lib/3rdParty/composer/brick/math/CHANGELOG.md index 03c3d824d..4b47b48dd 100644 --- a/lam/lib/3rdParty/composer/brick/math/CHANGELOG.md +++ b/lam/lib/3rdParty/composer/brick/math/CHANGELOG.md @@ -2,11 +2,75 @@ All notable changes to this project will be documented in this file. +## [0.12.3](https://github.com/brick/math/releases/tag/0.12.3) - 2025-02-28 + +✨ **New features** + +- `BigDecimal::getPrecision()` Returns the number of significant digits in a decimal number + +## [0.12.2](https://github.com/brick/math/releases/tag/0.12.2) - 2025-02-26 + +⚡️ **Performance improvements** + +- Division in `NativeCalculator` is now faster for small divisors, thanks to [@Izumi-kun](https://github.com/Izumi-kun) in [#87](https://github.com/brick/math/pull/87). + +👌 **Improvements** + +- Add missing `RoundingNecessaryException` to the `@throws` annotation of `BigNumber::of()` + +## [0.12.1](https://github.com/brick/math/releases/tag/0.12.1) - 2023-11-29 + +⚡️ **Performance improvements** + +- `BigNumber::of()` is now faster, thanks to [@SebastienDug](https://github.com/SebastienDug) in [#77](https://github.com/brick/math/pull/77). + +## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26 + +💥 **Breaking changes** + +- Minimum PHP version is now 8.1 +- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now +- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization)) +- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses: + - the return type of `BigNumber::of()` is now `static` + - `BigNumber` has a new abstract method `from()` + - all `public` and `protected` functions of `BigNumber` are now `final` + +## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 + +💥 **Breaking changes** + +- Minimum PHP version is now 8.0 +- Methods accepting a union of types are now strongly typed* +- `MathException` now extends `Exception` instead of `RuntimeException` + +* You may now run into type errors if you were passing `Stringable` objects to `of()` or any of the methods +internally calling `of()`, with `strict_types` enabled. You can fix this by casting `Stringable` objects to `string` +first. + +## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11 + +👌 **Improvements** + +- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic + +## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02 + +✨ **New features** + +- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers + +## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18 + +💥 **Breaking changes** + +- Minimum PHP version is now 7.4 + ## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15 🚀 **Compatibility with PHP 8.1** -- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham) +- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (#60) thanks @TRowbotham ## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20 @@ -16,7 +80,7 @@ All notable changes to this project will be documented in this file. ## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19 -✨ New features +✨ **New features** - `BigInteger::not()` returns the bitwise `NOT` value @@ -325,8 +389,8 @@ This release also comes with many performance improvements. - `getFraction()` is renamed to `fraction()` - `divideAndRemainder()` is renamed to `quotientAndRemainder()` - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode - - `toBigInteger()` does not accept a `$roundingMode` parameter any more - - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour + - `toBigInteger()` does not accept a `$roundingMode` parameter anymore + - `toBigRational()` does not simplify the fraction anymore; explicitly add `->simplified()` to get the previous behaviour - `BigRational`: - `getSign()` is renamed to `sign()` - `getNumerator()` is renamed to `numerator()` @@ -400,7 +464,7 @@ Added `BigDecimal::divideAndRemainder()` ## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22 -- `min()` and `max()` do not accept an `array` any more, but a variable number of parameters +- `min()` and `max()` do not accept an `array` anymore, but a variable number of parameters - **minimum PHP version is now 5.6** - continuous integration with PHP 7 diff --git a/lam/lib/3rdParty/composer/brick/math/SECURITY.md b/lam/lib/3rdParty/composer/brick/math/SECURITY.md deleted file mode 100644 index cc8289bb5..000000000 --- a/lam/lib/3rdParty/composer/brick/math/SECURITY.md +++ /dev/null @@ -1,17 +0,0 @@ -# Security Policy - -## Supported Versions - -Only the last two release streams are supported. - -| Version | Supported | -| ------- | ------------------ | -| 0.9.x | :white_check_mark: | -| 0.8.x | :white_check_mark: | -| < 0.8 | :x: | - -## 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. diff --git a/lam/lib/3rdParty/composer/brick/math/composer.json b/lam/lib/3rdParty/composer/brick/math/composer.json index ec196632f..f400aa447 100644 --- a/lam/lib/3rdParty/composer/brick/math/composer.json +++ b/lam/lib/3rdParty/composer/brick/math/composer.json @@ -5,22 +5,26 @@ "keywords": [ "Brick", "Math", + "Mathematics", "Arbitrary-precision", "Arithmetic", "BigInteger", "BigDecimal", "BigRational", - "Bignum" + "BigNumber", + "Bignum", + "Decimal", + "Rational", + "Integer" ], "license": "MIT", "require": { - "php": "^7.1 || ^8.0", - "ext-json": "*" + "php": "^8.1" }, "require-dev": { - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "phpunit/phpunit": "^10.1", "php-coveralls/php-coveralls": "^2.2", - "vimeo/psalm": "4.9.2" + "vimeo/psalm": "6.8.8" }, "autoload": { "psr-4": { diff --git a/lam/lib/3rdParty/composer/brick/math/psalm-baseline.xml b/lam/lib/3rdParty/composer/brick/math/psalm-baseline.xml new file mode 100644 index 000000000..112adf451 --- /dev/null +++ b/lam/lib/3rdParty/composer/brick/math/psalm-baseline.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lam/lib/3rdParty/composer/brick/math/src/BigDecimal.php b/lam/lib/3rdParty/composer/brick/math/src/BigDecimal.php index 78246500c..21d1c4ae3 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/BigDecimal.php +++ b/lam/lib/3rdParty/composer/brick/math/src/BigDecimal.php @@ -8,6 +8,7 @@ use Brick\Math\Exception\DivisionByZeroException; use Brick\Math\Exception\MathException; use Brick\Math\Exception\NegativeNumberException; use Brick\Math\Internal\Calculator; +use Override; /** * Immutable, arbitrary-precision signed decimal numbers. @@ -22,19 +23,15 @@ final class BigDecimal extends BigNumber * This is a string of digits with an optional leading minus sign. * No leading zero must be present. * No leading minus sign must be present if the value is 0. - * - * @var string */ - private $value; + private readonly string $value; /** * The scale (number of digits after the decimal point) of this decimal number. * * This must be zero or more. - * - * @var int */ - private $scale; + private readonly int $scale; /** * Protected constructor. Use a factory method to obtain an instance. @@ -49,19 +46,12 @@ final class BigDecimal extends BigNumber } /** - * Creates a BigDecimal of the given value. - * - * @param BigNumber|int|float|string $value - * - * @return BigDecimal - * - * @throws MathException If the value cannot be converted to a BigDecimal. - * * @psalm-pure */ - public static function of($value) : BigNumber + #[Override] + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigDecimal(); + return $number->toBigDecimal(); } /** @@ -72,13 +62,11 @@ final class BigDecimal extends BigNumber * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger. * @param int $scale The scale of the number, positive or zero. * - * @return BigDecimal - * * @throws \InvalidArgumentException If the scale is negative. * * @psalm-pure */ - public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal + public static function ofUnscaledValue(BigNumber|int|float|string $value, int $scale = 0) : BigDecimal { if ($scale < 0) { throw new \InvalidArgumentException('The scale cannot be negative.'); @@ -90,8 +78,6 @@ final class BigDecimal extends BigNumber /** * Returns a BigDecimal representing zero, with a scale of zero. * - * @return BigDecimal - * * @psalm-pure */ public static function zero() : BigDecimal @@ -112,8 +98,6 @@ final class BigDecimal extends BigNumber /** * Returns a BigDecimal representing one, with a scale of zero. * - * @return BigDecimal - * * @psalm-pure */ public static function one() : BigDecimal @@ -134,8 +118,6 @@ final class BigDecimal extends BigNumber /** * Returns a BigDecimal representing ten, with a scale of zero. * - * @return BigDecimal - * * @psalm-pure */ public static function ten() : BigDecimal @@ -160,11 +142,9 @@ final class BigDecimal extends BigNumber * * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal. * - * @return BigDecimal The result. - * * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. */ - public function plus($that) : BigDecimal + public function plus(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -191,11 +171,9 @@ final class BigDecimal extends BigNumber * * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal. * - * @return BigDecimal The result. - * * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. */ - public function minus($that) : BigDecimal + public function minus(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -218,11 +196,9 @@ final class BigDecimal extends BigNumber * * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal. * - * @return BigDecimal The result. - * * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. */ - public function multipliedBy($that) : BigDecimal + public function multipliedBy(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -245,14 +221,12 @@ final class BigDecimal extends BigNumber * * @param BigNumber|int|float|string $that The divisor. * @param int|null $scale The desired scale, or null to use the scale of this number. - * @param int $roundingMode An optional rounding mode. - * - * @return BigDecimal + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws \InvalidArgumentException If the scale or rounding mode is invalid. * @throws MathException If the number is invalid, is zero, or rounding was necessary. */ - public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { $that = BigDecimal::of($that); @@ -285,12 +259,10 @@ final class BigDecimal extends BigNumber * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. * - * @return BigDecimal The result. - * * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero, * or the result yields an infinite number of digits. */ - public function exactlyDividedBy($that) : BigDecimal + public function exactlyDividedBy(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -326,10 +298,6 @@ final class BigDecimal extends BigNumber * * The result has a scale of `$this->scale * $exponent`. * - * @param int $exponent The exponent. - * - * @return BigDecimal The result. - * * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. */ public function power(int $exponent) : BigDecimal @@ -354,17 +322,15 @@ final class BigDecimal extends BigNumber } /** - * Returns the quotient of the division of this number by this given one. + * Returns the quotient of the division of this number by the given one. * * The quotient has a scale of `0`. * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. * - * @return BigDecimal The quotient. - * * @throws MathException If the divisor is not a valid decimal number, or is zero. */ - public function quotient($that) : BigDecimal + public function quotient(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -381,17 +347,15 @@ final class BigDecimal extends BigNumber } /** - * Returns the remainder of the division of this number by this given one. + * Returns the remainder of the division of this number by the given one. * * The remainder has a scale of `max($this->scale, $that->scale)`. * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. * - * @return BigDecimal The remainder. - * * @throws MathException If the divisor is not a valid decimal number, or is zero. */ - public function remainder($that) : BigDecimal + public function remainder(BigNumber|int|float|string $that) : BigDecimal { $that = BigDecimal::of($that); @@ -418,9 +382,11 @@ final class BigDecimal extends BigNumber * * @return BigDecimal[] An array containing the quotient and the remainder. * + * @psalm-return array{BigDecimal, BigDecimal} + * * @throws MathException If the divisor is not a valid decimal number, or is zero. */ - public function quotientAndRemainder($that) : array + public function quotientAndRemainder(BigNumber|int|float|string $that) : array { $that = BigDecimal::of($that); @@ -444,10 +410,6 @@ final class BigDecimal extends BigNumber /** * Returns the square root of this number, rounded down to the given number of decimals. * - * @param int $scale - * - * @return BigDecimal - * * @throws \InvalidArgumentException If the scale is negative. * @throws NegativeNumberException If this number is negative. */ @@ -488,10 +450,6 @@ final class BigDecimal extends BigNumber /** * Returns a copy of this BigDecimal with the decimal point moved $n places to the left. - * - * @param int $n - * - * @return BigDecimal */ public function withPointMovedLeft(int $n) : BigDecimal { @@ -508,10 +466,6 @@ final class BigDecimal extends BigNumber /** * Returns a copy of this BigDecimal with the decimal point moved $n places to the right. - * - * @param int $n - * - * @return BigDecimal */ public function withPointMovedRight(int $n) : BigDecimal { @@ -538,8 +492,6 @@ final class BigDecimal extends BigNumber /** * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part. - * - * @return BigDecimal */ public function stripTrailingZeros() : BigDecimal { @@ -571,8 +523,6 @@ final class BigDecimal extends BigNumber /** * Returns the absolute value of this number. - * - * @return BigDecimal */ public function abs() : BigDecimal { @@ -581,18 +531,14 @@ final class BigDecimal extends BigNumber /** * Returns the negated value of this number. - * - * @return BigDecimal */ public function negated() : BigDecimal { return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); } - /** - * {@inheritdoc} - */ - public function compareTo($that) : int + #[Override] + public function compareTo(BigNumber|int|float|string $that) : int { $that = BigNumber::of($that); @@ -609,36 +555,53 @@ final class BigDecimal extends BigNumber return - $that->compareTo($this); } - /** - * {@inheritdoc} - */ + #[Override] public function getSign() : int { return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); } - /** - * @return BigInteger - */ public function getUnscaledValue() : BigInteger { - return BigInteger::create($this->value); + return self::newBigInteger($this->value); } - /** - * @return int - */ public function getScale() : int { return $this->scale; } + /** + * Returns the number of significant digits in the number. + * + * This is the number of digits to both sides of the decimal point, stripped of leading zeros. + * The sign has no impact on the result. + * + * Examples: + * 0 => 0 + * 0.0 => 0 + * 123 => 3 + * 123.456 => 6 + * 0.00123 => 3 + * 0.0012300 => 5 + */ + public function getPrecision(): int + { + $value = $this->value; + + if ($value === '0') { + return 0; + } + + $length = \strlen($value); + + return ($value[0] === '-') ? $length - 1 : $length; + } + /** * Returns a string representing the integral part of this decimal number. * * Example: `-123.456` => `-123`. - * - * @return string */ public function getIntegralPart() : string { @@ -657,8 +620,6 @@ final class BigDecimal extends BigNumber * If the scale is zero, an empty string is returned. * * Examples: `-123.456` => '456', `123` => ''. - * - * @return string */ public function getFractionalPart() : string { @@ -673,47 +634,37 @@ final class BigDecimal extends BigNumber /** * Returns whether this decimal number has a non-zero fractional part. - * - * @return bool */ public function hasNonZeroFractionalPart() : bool { return $this->getFractionalPart() !== \str_repeat('0', $this->scale); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigInteger() : BigInteger { $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); - return BigInteger::create($zeroScaleDecimal->value); + return self::newBigInteger($zeroScaleDecimal->value); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigDecimal() : BigDecimal { return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function toBigRational() : BigRational { - $numerator = BigInteger::create($this->value); - $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale)); + $numerator = self::newBigInteger($this->value); + $denominator = self::newBigInteger('1' . \str_repeat('0', $this->scale)); - return BigRational::create($numerator, $denominator, false); + return self::newBigRational($numerator, $denominator, false); } - /** - * {@inheritdoc} - */ - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + #[Override] + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { if ($scale === $this->scale) { return $this; @@ -722,25 +673,19 @@ final class BigDecimal extends BigNumber return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); } - /** - * {@inheritdoc} - */ + #[Override] public function toInt() : int { return $this->toBigInteger()->toInt(); } - /** - * {@inheritdoc} - */ + #[Override] public function toFloat() : float { return (float) (string) $this; } - /** - * {@inheritdoc} - */ + #[Override] public function __toString() : string { if ($this->scale === 0) { @@ -772,8 +717,6 @@ final class BigDecimal extends BigNumber * * @param array{value: string, scale: int} $data * - * @return void - * * @throws \LogicException */ public function __unserialize(array $data): void @@ -786,48 +729,9 @@ final class BigDecimal extends BigNumber $this->scale = $data['scale']; } - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - * - * @return string - */ - public function serialize() : string - { - return $this->value . ':' . $this->scale; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @param string $value - * - * @return void - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->value)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - [$value, $scale] = \explode(':', $value); - - $this->value = $value; - $this->scale = (int) $scale; - } - /** * Puts the internal values of the given decimal numbers on the same scale. * - * @param BigDecimal $x The first decimal number. - * @param BigDecimal $y The second decimal number. - * * @return array{string, string} The scaled integer values of $x and $y. */ private function scaleValues(BigDecimal $x, BigDecimal $y) : array @@ -844,11 +748,6 @@ final class BigDecimal extends BigNumber return [$a, $b]; } - /** - * @param int $scale - * - * @return string - */ private function valueWithMinScale(int $scale) : string { $value = $this->value; @@ -862,8 +761,6 @@ final class BigDecimal extends BigNumber /** * Adds leading zeros if necessary to the unscaled value to represent the full decimal number. - * - * @return string */ private function getUnscaledValueWithLeadingZeros() : string { diff --git a/lam/lib/3rdParty/composer/brick/math/src/BigInteger.php b/lam/lib/3rdParty/composer/brick/math/src/BigInteger.php index f213fbedb..72424810d 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/BigInteger.php +++ b/lam/lib/3rdParty/composer/brick/math/src/BigInteger.php @@ -10,6 +10,7 @@ use Brick\Math\Exception\MathException; use Brick\Math\Exception\NegativeNumberException; use Brick\Math\Exception\NumberFormatException; use Brick\Math\Internal\Calculator; +use Override; /** * An arbitrary-size integer. @@ -26,10 +27,8 @@ final class BigInteger extends BigNumber * * No leading zeros must be present. * No leading minus sign must be present if the number is zero. - * - * @var string */ - private $value; + private readonly string $value; /** * Protected constructor. Use a factory method to obtain an instance. @@ -42,19 +41,12 @@ final class BigInteger extends BigNumber } /** - * Creates a BigInteger of the given value. - * - * @param BigNumber|int|float|string $value - * - * @return BigInteger - * - * @throws MathException If the value cannot be converted to a BigInteger. - * * @psalm-pure */ - public static function of($value) : BigNumber + #[Override] + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigInteger(); + return $number->toBigInteger(); } /** @@ -71,8 +63,6 @@ final class BigInteger extends BigNumber * @param string $number The number to convert, in the given base. * @param int $base The base of the number, between 2 and 36. * - * @return BigInteger - * * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. * @throws \InvalidArgumentException If the base is out of range. * @@ -138,8 +128,6 @@ final class BigInteger extends BigNumber * @param string $number The number to parse. * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. * - * @return BigInteger - * * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet. * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars. * @@ -183,8 +171,6 @@ final class BigInteger extends BigNumber * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading * sign bit. * - * @return BigInteger - * * @throws NumberFormatException If the string is empty. */ public static function fromBytes(string $value, bool $signed = true) : BigInteger @@ -217,15 +203,13 @@ final class BigInteger extends BigNumber * * Using the default random bytes generator, this method is suitable for cryptographic use. * - * @psalm-param callable(int): string $randomBytesGenerator + * @psalm-param (callable(int): string)|null $randomBytesGenerator * * @param int $numBits The number of bits. * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a * string of random bytes of the given length. Defaults to the * `random_bytes()` function. * - * @return BigInteger - * * @throws \InvalidArgumentException If $numBits is negative. */ public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger @@ -239,9 +223,10 @@ final class BigInteger extends BigNumber } if ($randomBytesGenerator === null) { - $randomBytesGenerator = 'random_bytes'; + $randomBytesGenerator = random_bytes(...); } + /** @var int<1, max> $byteLength */ $byteLength = \intdiv($numBits - 1, 8) + 1; $extraBits = ($byteLength * 8 - $numBits); @@ -266,13 +251,14 @@ final class BigInteger extends BigNumber * and returns a string of random bytes of the given length. * Defaults to the `random_bytes()` function. * - * @return BigInteger - * * @throws MathException If one of the parameters cannot be converted to a BigInteger, * or `$min` is greater than `$max`. */ - public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger - { + public static function randomRange( + BigNumber|int|float|string $min, + BigNumber|int|float|string $max, + ?callable $randomBytesGenerator = null + ) : BigInteger { $min = BigInteger::of($min); $max = BigInteger::of($max); @@ -298,8 +284,6 @@ final class BigInteger extends BigNumber /** * Returns a BigInteger representing zero. * - * @return BigInteger - * * @psalm-pure */ public static function zero() : BigInteger @@ -320,8 +304,6 @@ final class BigInteger extends BigNumber /** * Returns a BigInteger representing one. * - * @return BigInteger - * * @psalm-pure */ public static function one() : BigInteger @@ -342,8 +324,6 @@ final class BigInteger extends BigNumber /** * Returns a BigInteger representing ten. * - * @return BigInteger - * * @psalm-pure */ public static function ten() : BigInteger @@ -361,16 +341,29 @@ final class BigInteger extends BigNumber return $ten; } + public static function gcdMultiple(BigInteger $a, BigInteger ...$n): BigInteger + { + $result = $a; + + foreach ($n as $next) { + $result = $result->gcd($next); + + if ($result->isEqualTo(1)) { + return $result; + } + } + + return $result; + } + /** * Returns the sum of this number and the given one. * * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger. * - * @return BigInteger The result. - * * @throws MathException If the number is not valid, or is not convertible to a BigInteger. */ - public function plus($that) : BigInteger + public function plus(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -392,11 +385,9 @@ final class BigInteger extends BigNumber * * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger. * - * @return BigInteger The result. - * * @throws MathException If the number is not valid, or is not convertible to a BigInteger. */ - public function minus($that) : BigInteger + public function minus(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -414,11 +405,9 @@ final class BigInteger extends BigNumber * * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger. * - * @return BigInteger The result. - * * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger. */ - public function multipliedBy($that) : BigInteger + public function multipliedBy(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -439,14 +428,12 @@ final class BigInteger extends BigNumber * Returns the result of the division of this number by the given one. * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. - * @param int $roundingMode An optional rounding mode. - * - * @return BigInteger The result. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero, * or RoundingMode::UNNECESSARY is used and the remainder is not zero. */ - public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger + public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger { $that = BigInteger::of($that); @@ -466,10 +453,6 @@ final class BigInteger extends BigNumber /** * Returns this number exponentiated to the given value. * - * @param int $exponent The exponent. - * - * @return BigInteger The result. - * * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. */ public function power(int $exponent) : BigInteger @@ -498,11 +481,9 @@ final class BigInteger extends BigNumber * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. * - * @return BigInteger - * * @throws DivisionByZeroException If the divisor is zero. */ - public function quotient($that) : BigInteger + public function quotient(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -526,11 +507,9 @@ final class BigInteger extends BigNumber * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. * - * @return BigInteger - * * @throws DivisionByZeroException If the divisor is zero. */ - public function remainder($that) : BigInteger + public function remainder(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -554,9 +533,11 @@ final class BigInteger extends BigNumber * * @return BigInteger[] An array containing the quotient and the remainder. * + * @psalm-return array{BigInteger, BigInteger} + * * @throws DivisionByZeroException If the divisor is zero. */ - public function quotientAndRemainder($that) : array + public function quotientAndRemainder(BigNumber|int|float|string $that) : array { $that = BigInteger::of($that); @@ -582,11 +563,9 @@ final class BigInteger extends BigNumber * * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. * - * @return BigInteger - * * @throws DivisionByZeroException If the divisor is zero. */ - public function mod($that) : BigInteger + public function mod(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -602,10 +581,6 @@ final class BigInteger extends BigNumber /** * Returns the modular multiplicative inverse of this BigInteger modulo $m. * - * @param BigInteger $m - * - * @return BigInteger - * * @throws DivisionByZeroException If $m is zero. * @throws NegativeNumberException If $m is negative. * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger @@ -642,12 +617,10 @@ final class BigInteger extends BigNumber * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero. * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive. * - * @return BigInteger - * * @throws NegativeNumberException If any of the operands is negative. * @throws DivisionByZeroException If the modulus is zero. */ - public function modPow($exp, $mod) : BigInteger + public function modPow(BigNumber|int|float|string $exp, BigNumber|int|float|string $mod) : BigInteger { $exp = BigInteger::of($exp); $mod = BigInteger::of($mod); @@ -671,10 +644,8 @@ final class BigInteger extends BigNumber * The GCD is always positive, unless both operands are zero, in which case it is zero. * * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. - * - * @return BigInteger */ - public function gcd($that) : BigInteger + public function gcd(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -696,8 +667,6 @@ final class BigInteger extends BigNumber * * The result is the largest x such that x² ≤ n. * - * @return BigInteger - * * @throws NegativeNumberException If this number is negative. */ public function sqrt() : BigInteger @@ -713,8 +682,6 @@ final class BigInteger extends BigNumber /** * Returns the absolute value of this number. - * - * @return BigInteger */ public function abs() : BigInteger { @@ -723,8 +690,6 @@ final class BigInteger extends BigNumber /** * Returns the inverse of this number. - * - * @return BigInteger */ public function negated() : BigInteger { @@ -737,10 +702,8 @@ final class BigInteger extends BigNumber * This method returns a negative BigInteger if and only if both operands are negative. * * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. - * - * @return BigInteger */ - public function and($that) : BigInteger + public function and(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -753,10 +716,8 @@ final class BigInteger extends BigNumber * This method returns a negative BigInteger if and only if either of the operands is negative. * * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. - * - * @return BigInteger */ - public function or($that) : BigInteger + public function or(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -769,10 +730,8 @@ final class BigInteger extends BigNumber * This method returns a negative BigInteger if and only if exactly one of the operands is negative. * * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. - * - * @return BigInteger */ - public function xor($that) : BigInteger + public function xor(BigNumber|int|float|string $that) : BigInteger { $that = BigInteger::of($that); @@ -781,8 +740,6 @@ final class BigInteger extends BigNumber /** * Returns the bitwise-not of this BigInteger. - * - * @return BigInteger */ public function not() : BigInteger { @@ -791,10 +748,6 @@ final class BigInteger extends BigNumber /** * Returns the integer left shifted by a given number of bits. - * - * @param int $distance The distance to shift. - * - * @return BigInteger */ public function shiftedLeft(int $distance) : BigInteger { @@ -811,10 +764,6 @@ final class BigInteger extends BigNumber /** * Returns the integer right shifted by a given number of bits. - * - * @param int $distance The distance to shift. - * - * @return BigInteger */ public function shiftedRight(int $distance) : BigInteger { @@ -840,8 +789,6 @@ final class BigInteger extends BigNumber * * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. * Computes (ceil(log2(this < 0 ? -this : this+1))). - * - * @return int */ public function getBitLength() : int { @@ -860,8 +807,6 @@ final class BigInteger extends BigNumber * Returns the index of the rightmost (lowest-order) one bit in this BigInteger. * * Returns -1 if this BigInteger contains no one bits. - * - * @return int */ public function getLowestSetBit() : int { @@ -881,8 +826,6 @@ final class BigInteger extends BigNumber /** * Returns whether this number is even. - * - * @return bool */ public function isEven() : bool { @@ -891,8 +834,6 @@ final class BigInteger extends BigNumber /** * Returns whether this number is odd. - * - * @return bool */ public function isOdd() : bool { @@ -906,8 +847,6 @@ final class BigInteger extends BigNumber * * @param int $n The bit to test, 0-based. * - * @return bool - * * @throws \InvalidArgumentException If the bit to test is negative. */ public function testBit(int $n) : bool @@ -919,10 +858,8 @@ final class BigInteger extends BigNumber return $this->shiftedRight($n)->isOdd(); } - /** - * {@inheritdoc} - */ - public function compareTo($that) : int + #[Override] + public function compareTo(BigNumber|int|float|string $that) : int { $that = BigNumber::of($that); @@ -933,49 +870,37 @@ final class BigInteger extends BigNumber return - $that->compareTo($this); } - /** - * {@inheritdoc} - */ + #[Override] public function getSign() : int { return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigInteger() : BigInteger { return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function toBigDecimal() : BigDecimal { - return BigDecimal::create($this->value); + return self::newBigDecimal($this->value); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigRational() : BigRational { - return BigRational::create($this, BigInteger::one(), false); + return self::newBigRational($this, BigInteger::one(), false); } - /** - * {@inheritdoc} - */ - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + #[Override] + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { return $this->toBigDecimal()->toScale($scale, $roundingMode); } - /** - * {@inheritdoc} - */ + #[Override] public function toInt() : int { $intValue = (int) $this->value; @@ -987,9 +912,7 @@ final class BigInteger extends BigNumber return $intValue; } - /** - * {@inheritdoc} - */ + #[Override] public function toFloat() : float { return (float) $this->value; @@ -1000,10 +923,6 @@ final class BigInteger extends BigNumber * * The output will always be lowercase for bases greater than 10. * - * @param int $base - * - * @return string - * * @throws \InvalidArgumentException If the base is out of range. */ public function toBase(int $base) : string @@ -1027,8 +946,6 @@ final class BigInteger extends BigNumber * * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. * - * @return string - * * @throws NegativeNumberException If this number is negative. * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars. */ @@ -1063,8 +980,6 @@ final class BigInteger extends BigNumber * * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit. * - * @return string - * * @throws NegativeNumberException If $signed is false, and the number is negative. */ public function toBytes(bool $signed = true) : string @@ -1108,9 +1023,7 @@ final class BigInteger extends BigNumber return \hex2bin($hex); } - /** - * {@inheritdoc} - */ + #[Override] public function __toString() : string { return $this->value; @@ -1136,8 +1049,6 @@ final class BigInteger extends BigNumber * * @param array{value: string} $data * - * @return void - * * @throws \LogicException */ public function __unserialize(array $data): void @@ -1148,37 +1059,4 @@ final class BigInteger extends BigNumber $this->value = $data['value']; } - - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - * - * @return string - */ - public function serialize() : string - { - return $this->value; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @param string $value - * - * @return void - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->value)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - $this->value = $value; - } } diff --git a/lam/lib/3rdParty/composer/brick/math/src/BigNumber.php b/lam/lib/3rdParty/composer/brick/math/src/BigNumber.php index 38c8c554e..5dabd314b 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/BigNumber.php +++ b/lam/lib/3rdParty/composer/brick/math/src/BigNumber.php @@ -8,32 +8,36 @@ use Brick\Math\Exception\DivisionByZeroException; use Brick\Math\Exception\MathException; use Brick\Math\Exception\NumberFormatException; use Brick\Math\Exception\RoundingNecessaryException; +use Override; /** * Common interface for arbitrary-precision rational numbers. * * @psalm-immutable */ -abstract class BigNumber implements \Serializable, \JsonSerializable +abstract class BigNumber implements \JsonSerializable { /** - * The regular expression used to parse integer, decimal and rational numbers. + * The regular expression used to parse integer or decimal numbers. */ - private const PARSE_REGEXP = + private const PARSE_REGEXP_NUMERICAL = '/^' . '(?[\-\+])?' . - '(?:' . - '(?:' . - '(?[0-9]+)?' . - '(?\.)?' . - '(?[0-9]+)?' . - '(?:[eE](?[\-\+]?[0-9]+))?' . - ')|(?:' . - '(?[0-9]+)' . - '\/?' . - '(?[0-9]+)' . - ')' . - ')' . + '(?[0-9]+)?' . + '(?\.)?' . + '(?[0-9]+)?' . + '(?:[eE](?[\-\+]?[0-9]+))?' . + '$/'; + + /** + * The regular expression used to parse rational numbers. + */ + private const PARSE_REGEXP_RATIONAL = + '/^' . + '(?[\-\+])?' . + '(?[0-9]+)' . + '\/?' . + '(?[0-9]+)' . '$/'; /** @@ -48,16 +52,33 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * - strings containing a `.` character or using an exponential notation are returned as BigDecimal * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger * - * @param BigNumber|int|float|string $value + * @throws NumberFormatException If the format of the number is not valid. + * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. + * @throws RoundingNecessaryException If the value cannot be converted to an instance of the subclass without rounding. * - * @return BigNumber - * - * @throws NumberFormatException If the format of the number is not valid. + * @psalm-pure + */ + final public static function of(BigNumber|int|float|string $value) : static + { + $value = self::_of($value); + + if (static::class === BigNumber::class) { + // https://github.com/vimeo/psalm/issues/10309 + assert($value instanceof static); + + return $value; + } + + return static::from($value); + } + + /** + * @throws NumberFormatException If the format of the number is not valid. * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. * * @psalm-pure */ - public static function of($value) : BigNumber + private static function _of(BigNumber|int|float|string $value) : BigNumber { if ($value instanceof BigNumber) { return $value; @@ -67,37 +88,25 @@ abstract class BigNumber implements \Serializable, \JsonSerializable return new BigInteger((string) $value); } - /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */ - $value = \is_float($value) ? self::floatToString($value) : (string) $value; - - $throw = static function() use ($value) : void { - throw new NumberFormatException(\sprintf( - 'The given value "%s" does not represent a valid number.', - $value - )); - }; - - if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { - $throw(); + if (is_float($value)) { + $value = (string) $value; } - $getMatch = static function(string $value) use ($matches) : ?string { - return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null; - }; - - $sign = $getMatch('sign'); - $numerator = $getMatch('numerator'); - $denominator = $getMatch('denominator'); - - if ($numerator !== null) { - assert($denominator !== null); - - if ($sign !== null) { - $numerator = $sign . $numerator; + if (str_contains($value, '/')) { + // Rational number + if (\preg_match(self::PARSE_REGEXP_RATIONAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) { + throw NumberFormatException::invalidFormat($value); } - $numerator = self::cleanUp($numerator); - $denominator = self::cleanUp($denominator); + $sign = $matches['sign']; + $numerator = $matches['numerator']; + $denominator = $matches['denominator']; + + assert($numerator !== null); + assert($denominator !== null); + + $numerator = self::cleanUp($sign, $numerator); + $denominator = self::cleanUp(null, $denominator); if ($denominator === '0') { throw DivisionByZeroException::denominatorMustNotBeZero(); @@ -108,88 +117,94 @@ abstract class BigNumber implements \Serializable, \JsonSerializable new BigInteger($denominator), false ); - } - - $point = $getMatch('point'); - $integral = $getMatch('integral'); - $fractional = $getMatch('fractional'); - $exponent = $getMatch('exponent'); - - if ($integral === null && $fractional === null) { - $throw(); - } - - if ($integral === null) { - $integral = '0'; - } - - if ($point !== null || $exponent !== null) { - $fractional = ($fractional ?? ''); - $exponent = ($exponent !== null) ? (int) $exponent : 0; - - if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { - throw new NumberFormatException('Exponent too large.'); + } else { + // Integer or decimal number + if (\preg_match(self::PARSE_REGEXP_NUMERICAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) { + throw NumberFormatException::invalidFormat($value); } - $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional); + $sign = $matches['sign']; + $point = $matches['point']; + $integral = $matches['integral']; + $fractional = $matches['fractional']; + $exponent = $matches['exponent']; - $scale = \strlen($fractional) - $exponent; + if ($integral === null && $fractional === null) { + throw NumberFormatException::invalidFormat($value); + } - if ($scale < 0) { - if ($unscaledValue !== '0') { - $unscaledValue .= \str_repeat('0', - $scale); + if ($integral === null) { + $integral = '0'; + } + + if ($point !== null || $exponent !== null) { + $fractional = ($fractional ?? ''); + $exponent = ($exponent !== null) ? (int)$exponent : 0; + + if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { + throw new NumberFormatException('Exponent too large.'); } - $scale = 0; + + $unscaledValue = self::cleanUp($sign, $integral . $fractional); + + $scale = \strlen($fractional) - $exponent; + + if ($scale < 0) { + if ($unscaledValue !== '0') { + $unscaledValue .= \str_repeat('0', -$scale); + } + $scale = 0; + } + + return new BigDecimal($unscaledValue, $scale); } - return new BigDecimal($unscaledValue, $scale); + $integral = self::cleanUp($sign, $integral); + + return new BigInteger($integral); } - - $integral = self::cleanUp(($sign ?? '') . $integral); - - return new BigInteger($integral); } /** - * Safely converts float to string, avoiding locale-dependent issues. + * Overridden by subclasses to convert a BigNumber to an instance of the subclass. * - * @see https://github.com/brick/math/pull/20 - * - * @param float $float - * - * @return string + * @throws RoundingNecessaryException If the value cannot be converted. * * @psalm-pure - * @psalm-suppress ImpureFunctionCall */ - private static function floatToString(float $float) : string - { - $currentLocale = \setlocale(LC_NUMERIC, '0'); - \setlocale(LC_NUMERIC, 'C'); - - $result = (string) $float; - - \setlocale(LC_NUMERIC, $currentLocale); - - return $result; - } + abstract protected static function from(BigNumber $number): static; /** - * Proxy method to access protected constructors from sibling classes. + * Proxy method to access BigInteger's protected constructor from sibling classes. * * @internal - * - * @param mixed ...$args The arguments to the constructor. - * - * @return static - * * @psalm-pure - * @psalm-suppress TooManyArguments - * @psalm-suppress UnsafeInstantiation */ - protected static function create(... $args) : BigNumber + final protected function newBigInteger(string $value) : BigInteger { - return new static(... $args); + return new BigInteger($value); + } + + /** + * Proxy method to access BigDecimal's protected constructor from sibling classes. + * + * @internal + * @psalm-pure + */ + final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal + { + return new BigDecimal($value, $scale); + } + + /** + * Proxy method to access BigRational's protected constructor from sibling classes. + * + * @internal + * @psalm-pure + */ + final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational + { + return new BigRational($numerator, $denominator, $checkDenominator); } /** @@ -198,16 +213,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible * to an instance of the class this method is called on. * - * @return static The minimum value. - * * @throws \InvalidArgumentException If no values are given. * @throws MathException If an argument is not valid. * - * @psalm-suppress LessSpecificReturnStatement - * @psalm-suppress MoreSpecificReturnType * @psalm-pure */ - public static function min(...$values) : BigNumber + final public static function min(BigNumber|int|float|string ...$values) : static { $min = null; @@ -232,16 +243,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible * to an instance of the class this method is called on. * - * @return static The maximum value. - * * @throws \InvalidArgumentException If no values are given. * @throws MathException If an argument is not valid. * - * @psalm-suppress LessSpecificReturnStatement - * @psalm-suppress MoreSpecificReturnType * @psalm-pure */ - public static function max(...$values) : BigNumber + final public static function max(BigNumber|int|float|string ...$values) : static { $max = null; @@ -266,18 +273,14 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible * to an instance of the class this method is called on. * - * @return static The sum. - * * @throws \InvalidArgumentException If no values are given. * @throws MathException If an argument is not valid. * - * @psalm-suppress LessSpecificReturnStatement - * @psalm-suppress MoreSpecificReturnType * @psalm-pure */ - public static function sum(...$values) : BigNumber + final public static function sum(BigNumber|int|float|string ...$values) : static { - /** @var BigNumber|null $sum */ + /** @var static|null $sum */ $sum = null; foreach ($values as $value) { @@ -301,11 +304,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * depending on their ability to perform the operation. This will also require a version bump because we're * potentially breaking custom BigNumber implementations (if any...) * - * @param BigNumber $a - * @param BigNumber $b - * - * @return BigNumber - * * @psalm-pure */ private static function add(BigNumber $a, BigNumber $b) : BigNumber @@ -332,141 +330,100 @@ abstract class BigNumber implements \Serializable, \JsonSerializable } /** - * Removes optional leading zeros and + sign from the given number. + * Removes optional leading zeros and applies sign. * - * @param string $number The number, validated as a non-empty string of digits with optional leading sign. - * - * @return string + * @param string|null $sign The sign, '+' or '-', optional. Null is allowed for convenience and treated as '+'. + * @param string $number The number, validated as a non-empty string of digits. * * @psalm-pure */ - private static function cleanUp(string $number) : string + private static function cleanUp(string|null $sign, string $number) : string { - $firstChar = $number[0]; - - if ($firstChar === '+' || $firstChar === '-') { - $number = \substr($number, 1); - } - $number = \ltrim($number, '0'); if ($number === '') { return '0'; } - if ($firstChar === '-') { - return '-' . $number; - } - - return $number; + return $sign === '-' ? '-' . $number : $number; } /** * Checks if this number is equal to the given one. - * - * @param BigNumber|int|float|string $that - * - * @return bool */ - public function isEqualTo($that) : bool + final public function isEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) === 0; } /** * Checks if this number is strictly lower than the given one. - * - * @param BigNumber|int|float|string $that - * - * @return bool */ - public function isLessThan($that) : bool + final public function isLessThan(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) < 0; } /** * Checks if this number is lower than or equal to the given one. - * - * @param BigNumber|int|float|string $that - * - * @return bool */ - public function isLessThanOrEqualTo($that) : bool + final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) <= 0; } /** * Checks if this number is strictly greater than the given one. - * - * @param BigNumber|int|float|string $that - * - * @return bool */ - public function isGreaterThan($that) : bool + final public function isGreaterThan(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) > 0; } /** * Checks if this number is greater than or equal to the given one. - * - * @param BigNumber|int|float|string $that - * - * @return bool */ - public function isGreaterThanOrEqualTo($that) : bool + final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool { return $this->compareTo($that) >= 0; } /** * Checks if this number equals zero. - * - * @return bool */ - public function isZero() : bool + final public function isZero() : bool { return $this->getSign() === 0; } /** * Checks if this number is strictly negative. - * - * @return bool */ - public function isNegative() : bool + final public function isNegative() : bool { return $this->getSign() < 0; } /** * Checks if this number is negative or zero. - * - * @return bool */ - public function isNegativeOrZero() : bool + final public function isNegativeOrZero() : bool { return $this->getSign() <= 0; } /** * Checks if this number is strictly positive. - * - * @return bool */ - public function isPositive() : bool + final public function isPositive() : bool { return $this->getSign() > 0; } /** * Checks if this number is positive or zero. - * - * @return bool */ - public function isPositiveOrZero() : bool + final public function isPositiveOrZero() : bool { return $this->getSign() >= 0; } @@ -474,6 +431,8 @@ abstract class BigNumber implements \Serializable, \JsonSerializable /** * Returns the sign of this number. * + * @psalm-return -1|0|1 + * * @return int -1 if the number is negative, 0 if zero, 1 if positive. */ abstract public function getSign() : int; @@ -481,19 +440,17 @@ abstract class BigNumber implements \Serializable, \JsonSerializable /** * Compares this number to the given one. * - * @param BigNumber|int|float|string $that + * @psalm-return -1|0|1 * - * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. + * @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`. * * @throws MathException If the number is not valid. */ - abstract public function compareTo($that) : int; + abstract public function compareTo(BigNumber|int|float|string $that) : int; /** * Converts this number to a BigInteger. * - * @return BigInteger The converted number. - * * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. */ abstract public function toBigInteger() : BigInteger; @@ -501,31 +458,25 @@ abstract class BigNumber implements \Serializable, \JsonSerializable /** * Converts this number to a BigDecimal. * - * @return BigDecimal The converted number. - * * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. */ abstract public function toBigDecimal() : BigDecimal; /** * Converts this number to a BigRational. - * - * @return BigRational The converted number. */ abstract public function toBigRational() : BigRational; /** * Converts this number to a BigDecimal with the given scale, using rounding if necessary. * - * @param int $scale The scale of the resulting `BigDecimal`. - * @param int $roundingMode A `RoundingMode` constant. - * - * @return BigDecimal + * @param int $scale The scale of the resulting `BigDecimal`. + * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY. * * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. * This only applies when RoundingMode::UNNECESSARY is used. */ - abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; + abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; /** * Returns the exact value of this number as a native integer. @@ -533,8 +484,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * If this number cannot be converted to a native integer without losing precision, an exception is thrown. * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit. * - * @return int The converted value. - * * @throws MathException If this number cannot be exactly converted to a native integer. */ abstract public function toInt() : int; @@ -547,8 +496,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * * If the number is greater than the largest representable floating point number, positive infinity is returned. * If the number is less than the smallest representable floating point number, negative infinity is returned. - * - * @return float The converted value. */ abstract public function toFloat() : float; @@ -557,15 +504,11 @@ abstract class BigNumber implements \Serializable, \JsonSerializable * * The output of this method can be parsed by the `of()` factory method; * this will yield an object equal to this one, without any information loss. - * - * @return string */ abstract public function __toString() : string; - /** - * {@inheritdoc} - */ - public function jsonSerialize() : string + #[Override] + final public function jsonSerialize() : string { return $this->__toString(); } diff --git a/lam/lib/3rdParty/composer/brick/math/src/BigRational.php b/lam/lib/3rdParty/composer/brick/math/src/BigRational.php index bee094f73..fc36e5573 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/BigRational.php +++ b/lam/lib/3rdParty/composer/brick/math/src/BigRational.php @@ -8,6 +8,7 @@ use Brick\Math\Exception\DivisionByZeroException; use Brick\Math\Exception\MathException; use Brick\Math\Exception\NumberFormatException; use Brick\Math\Exception\RoundingNecessaryException; +use Override; /** * An arbitrarily large rational number. @@ -20,17 +21,13 @@ final class BigRational extends BigNumber { /** * The numerator. - * - * @var BigInteger */ - private $numerator; + private readonly BigInteger $numerator; /** * The denominator. Always strictly positive. - * - * @var BigInteger */ - private $denominator; + private readonly BigInteger $denominator; /** * Protected constructor. Use a factory method to obtain an instance. @@ -59,19 +56,12 @@ final class BigRational extends BigNumber } /** - * Creates a BigRational of the given value. - * - * @param BigNumber|int|float|string $value - * - * @return BigRational - * - * @throws MathException If the value cannot be converted to a BigRational. - * * @psalm-pure */ - public static function of($value) : BigNumber + #[Override] + protected static function from(BigNumber $number): static { - return parent::of($value)->toBigRational(); + return $number->toBigRational(); } /** @@ -83,16 +73,16 @@ final class BigRational extends BigNumber * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger. * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger. * - * @return BigRational - * * @throws NumberFormatException If an argument does not represent a valid number. * @throws RoundingNecessaryException If an argument represents a non-integer number. * @throws DivisionByZeroException If the denominator is zero. * * @psalm-pure */ - public static function nd($numerator, $denominator) : BigRational - { + public static function nd( + BigNumber|int|float|string $numerator, + BigNumber|int|float|string $denominator, + ) : BigRational { $numerator = BigInteger::of($numerator); $denominator = BigInteger::of($denominator); @@ -102,8 +92,6 @@ final class BigRational extends BigNumber /** * Returns a BigRational representing zero. * - * @return BigRational - * * @psalm-pure */ public static function zero() : BigRational @@ -124,8 +112,6 @@ final class BigRational extends BigNumber /** * Returns a BigRational representing one. * - * @return BigRational - * * @psalm-pure */ public static function one() : BigRational @@ -146,8 +132,6 @@ final class BigRational extends BigNumber /** * Returns a BigRational representing ten. * - * @return BigRational - * * @psalm-pure */ public static function ten() : BigRational @@ -165,17 +149,11 @@ final class BigRational extends BigNumber return $ten; } - /** - * @return BigInteger - */ public function getNumerator() : BigInteger { return $this->numerator; } - /** - * @return BigInteger - */ public function getDenominator() : BigInteger { return $this->denominator; @@ -183,8 +161,6 @@ final class BigRational extends BigNumber /** * Returns the quotient of the division of the numerator by the denominator. - * - * @return BigInteger */ public function quotient() : BigInteger { @@ -193,8 +169,6 @@ final class BigRational extends BigNumber /** * Returns the remainder of the division of the numerator by the denominator. - * - * @return BigInteger */ public function remainder() : BigInteger { @@ -205,6 +179,8 @@ final class BigRational extends BigNumber * Returns the quotient and remainder of the division of the numerator by the denominator. * * @return BigInteger[] + * + * @psalm-return array{BigInteger, BigInteger} */ public function quotientAndRemainder() : array { @@ -216,11 +192,9 @@ final class BigRational extends BigNumber * * @param BigNumber|int|float|string $that The number to add. * - * @return BigRational The result. - * * @throws MathException If the number is not valid. */ - public function plus($that) : BigRational + public function plus(BigNumber|int|float|string $that) : BigRational { $that = BigRational::of($that); @@ -236,11 +210,9 @@ final class BigRational extends BigNumber * * @param BigNumber|int|float|string $that The number to subtract. * - * @return BigRational The result. - * * @throws MathException If the number is not valid. */ - public function minus($that) : BigRational + public function minus(BigNumber|int|float|string $that) : BigRational { $that = BigRational::of($that); @@ -256,11 +228,9 @@ final class BigRational extends BigNumber * * @param BigNumber|int|float|string $that The multiplier. * - * @return BigRational The result. - * * @throws MathException If the multiplier is not a valid number. */ - public function multipliedBy($that) : BigRational + public function multipliedBy(BigNumber|int|float|string $that) : BigRational { $that = BigRational::of($that); @@ -275,11 +245,9 @@ final class BigRational extends BigNumber * * @param BigNumber|int|float|string $that The divisor. * - * @return BigRational The result. - * * @throws MathException If the divisor is not a valid number, or is zero. */ - public function dividedBy($that) : BigRational + public function dividedBy(BigNumber|int|float|string $that) : BigRational { $that = BigRational::of($that); @@ -292,10 +260,6 @@ final class BigRational extends BigNumber /** * Returns this number exponentiated to the given value. * - * @param int $exponent The exponent. - * - * @return BigRational The result. - * * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. */ public function power(int $exponent) : BigRational @@ -322,8 +286,6 @@ final class BigRational extends BigNumber * * The reciprocal has the numerator and denominator swapped. * - * @return BigRational - * * @throws DivisionByZeroException If the numerator is zero. */ public function reciprocal() : BigRational @@ -333,8 +295,6 @@ final class BigRational extends BigNumber /** * Returns the absolute value of this BigRational. - * - * @return BigRational */ public function abs() : BigRational { @@ -343,8 +303,6 @@ final class BigRational extends BigNumber /** * Returns the negated value of this BigRational. - * - * @return BigRational */ public function negated() : BigRational { @@ -353,8 +311,6 @@ final class BigRational extends BigNumber /** * Returns the simplified value of this BigRational. - * - * @return BigRational */ public function simplified() : BigRational { @@ -366,25 +322,19 @@ final class BigRational extends BigNumber return new BigRational($numerator, $denominator, false); } - /** - * {@inheritdoc} - */ - public function compareTo($that) : int + #[Override] + public function compareTo(BigNumber|int|float|string $that) : int { return $this->minus($that)->getSign(); } - /** - * {@inheritdoc} - */ + #[Override] public function getSign() : int { return $this->numerator->getSign(); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigInteger() : BigInteger { $simplified = $this->simplified(); @@ -396,49 +346,38 @@ final class BigRational extends BigNumber return $simplified->numerator; } - /** - * {@inheritdoc} - */ + #[Override] public function toBigDecimal() : BigDecimal { return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); } - /** - * {@inheritdoc} - */ + #[Override] public function toBigRational() : BigRational { return $this; } - /** - * {@inheritdoc} - */ - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + #[Override] + public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal { return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); } - /** - * {@inheritdoc} - */ + #[Override] public function toInt() : int { return $this->toBigInteger()->toInt(); } - /** - * {@inheritdoc} - */ + #[Override] public function toFloat() : float { - return $this->numerator->toFloat() / $this->denominator->toFloat(); + $simplified = $this->simplified(); + return $simplified->numerator->toFloat() / $simplified->denominator->toFloat(); } - /** - * {@inheritdoc} - */ + #[Override] public function __toString() : string { $numerator = (string) $this->numerator; @@ -448,7 +387,7 @@ final class BigRational extends BigNumber return $numerator; } - return $this->numerator . '/' . $this->denominator; + return $numerator . '/' . $denominator; } /** @@ -471,8 +410,6 @@ final class BigRational extends BigNumber * * @param array{numerator: BigInteger, denominator: BigInteger} $data * - * @return void - * * @throws \LogicException */ public function __unserialize(array $data): void @@ -484,40 +421,4 @@ final class BigRational extends BigNumber $this->numerator = $data['numerator']; $this->denominator = $data['denominator']; } - - /** - * This method is required by interface Serializable and SHOULD NOT be accessed directly. - * - * @internal - * - * @return string - */ - public function serialize() : string - { - return $this->numerator . '/' . $this->denominator; - } - - /** - * This method is only here to implement interface Serializable and cannot be accessed directly. - * - * @internal - * @psalm-suppress RedundantPropertyInitializationCheck - * - * @param string $value - * - * @return void - * - * @throws \LogicException - */ - public function unserialize($value) : void - { - if (isset($this->numerator)) { - throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); - } - - [$numerator, $denominator] = \explode('/', $value); - - $this->numerator = BigInteger::of($numerator); - $this->denominator = BigInteger::of($denominator); - } } diff --git a/lam/lib/3rdParty/composer/brick/math/src/Exception/DivisionByZeroException.php b/lam/lib/3rdParty/composer/brick/math/src/Exception/DivisionByZeroException.php index a4e443176..ce7769ac2 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Exception/DivisionByZeroException.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Exception/DivisionByZeroException.php @@ -10,8 +10,6 @@ namespace Brick\Math\Exception; class DivisionByZeroException extends MathException { /** - * @return DivisionByZeroException - * * @psalm-pure */ public static function divisionByZero() : DivisionByZeroException @@ -20,8 +18,6 @@ class DivisionByZeroException extends MathException } /** - * @return DivisionByZeroException - * * @psalm-pure */ public static function modulusMustNotBeZero() : DivisionByZeroException @@ -30,8 +26,6 @@ class DivisionByZeroException extends MathException } /** - * @return DivisionByZeroException - * * @psalm-pure */ public static function denominatorMustNotBeZero() : DivisionByZeroException diff --git a/lam/lib/3rdParty/composer/brick/math/src/Exception/IntegerOverflowException.php b/lam/lib/3rdParty/composer/brick/math/src/Exception/IntegerOverflowException.php index e0b07d3c7..c73b49097 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Exception/IntegerOverflowException.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Exception/IntegerOverflowException.php @@ -12,10 +12,6 @@ use Brick\Math\BigInteger; class IntegerOverflowException extends MathException { /** - * @param BigInteger $value - * - * @return IntegerOverflowException - * * @psalm-pure */ public static function toIntOverflow(BigInteger $value) : IntegerOverflowException diff --git a/lam/lib/3rdParty/composer/brick/math/src/Exception/MathException.php b/lam/lib/3rdParty/composer/brick/math/src/Exception/MathException.php index 21fda90e1..46e9c3fe4 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Exception/MathException.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Exception/MathException.php @@ -6,9 +6,7 @@ namespace Brick\Math\Exception; /** * Base class for all math exceptions. - * - * This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code. */ -class MathException extends \RuntimeException +class MathException extends \Exception { } diff --git a/lam/lib/3rdParty/composer/brick/math/src/Exception/NumberFormatException.php b/lam/lib/3rdParty/composer/brick/math/src/Exception/NumberFormatException.php index 2fd0be73a..119cadbb4 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Exception/NumberFormatException.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Exception/NumberFormatException.php @@ -9,11 +9,17 @@ namespace Brick\Math\Exception; */ class NumberFormatException extends MathException { + public static function invalidFormat(string $value) : self + { + return new self(\sprintf( + 'The given value "%s" does not represent a valid number.', + $value, + )); + } + /** * @param string $char The failing character. * - * @return NumberFormatException - * * @psalm-pure */ public static function charNotInAlphabet(string $char) : self @@ -30,6 +36,6 @@ class NumberFormatException extends MathException $char = '"' . $char . '"'; } - return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char)); + return new self(\sprintf('Char %s is not a valid character in the given alphabet.', $char)); } } diff --git a/lam/lib/3rdParty/composer/brick/math/src/Exception/RoundingNecessaryException.php b/lam/lib/3rdParty/composer/brick/math/src/Exception/RoundingNecessaryException.php index 1c6100563..57bfcd844 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Exception/RoundingNecessaryException.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Exception/RoundingNecessaryException.php @@ -10,8 +10,6 @@ namespace Brick\Math\Exception; class RoundingNecessaryException extends MathException { /** - * @return RoundingNecessaryException - * * @psalm-pure */ public static function roundingNecessary() : RoundingNecessaryException diff --git a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator.php b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator.php index a6eac799f..44dd66924 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator.php @@ -25,7 +25,7 @@ abstract class Calculator /** * The maximum exponent value allowed for the pow() method. */ - public const MAX_POWER = 1000000; + public const MAX_POWER = 1_000_000; /** * The alphabet for converting from and to base 2 to 36, lowercase. @@ -34,10 +34,8 @@ abstract class Calculator /** * The Calculator instance in use. - * - * @var Calculator|null */ - private static $instance; + private static ?Calculator $instance = null; /** * Sets the Calculator instance to use. @@ -45,8 +43,6 @@ abstract class Calculator * An instance is typically set only in unit tests: the autodetect is usually the best option. * * @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect. - * - * @return void */ final public static function set(?Calculator $calculator) : void { @@ -58,8 +54,6 @@ abstract class Calculator * * If none has been explicitly set, the fastest available implementation will be returned. * - * @return Calculator - * * @psalm-pure * @psalm-suppress ImpureStaticProperty */ @@ -77,8 +71,6 @@ abstract class Calculator * Returns the fastest available Calculator implementation. * * @codeCoverageIgnore - * - * @return Calculator */ private static function detect() : Calculator { @@ -96,9 +88,6 @@ abstract class Calculator /** * Extracts the sign & digits of the operands. * - * @param string $a The first operand. - * @param string $b The second operand. - * * @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits. */ final protected function init(string $a, string $b) : array @@ -114,10 +103,6 @@ abstract class Calculator /** * Returns the absolute value of a number. - * - * @param string $n The number. - * - * @return string The absolute value. */ final public function abs(string $n) : string { @@ -126,10 +111,6 @@ abstract class Calculator /** * Negates a number. - * - * @param string $n The number. - * - * @return string The negated value. */ final public function neg(string $n) : string { @@ -147,10 +128,9 @@ abstract class Calculator /** * Compares two numbers. * - * @param string $a The first number. - * @param string $b The second number. + * @psalm-return -1|0|1 * - * @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number. + * @return int -1 if the first number is less than, 0 if equal to, 1 if greater than the second number. */ final public function cmp(string $a, string $b) : int { @@ -180,31 +160,16 @@ abstract class Calculator /** * Adds two numbers. - * - * @param string $a The augend. - * @param string $b The addend. - * - * @return string The sum. */ abstract public function add(string $a, string $b) : string; /** * Subtracts two numbers. - * - * @param string $a The minuend. - * @param string $b The subtrahend. - * - * @return string The difference. */ abstract public function sub(string $a, string $b) : string; /** * Multiplies two numbers. - * - * @param string $a The multiplicand. - * @param string $b The multiplier. - * - * @return string The product. */ abstract public function mul(string $a, string $b) : string; @@ -234,7 +199,7 @@ abstract class Calculator * @param string $a The dividend. * @param string $b The divisor, must not be zero. * - * @return string[] An array containing the quotient and remainder. + * @return array{string, string} An array containing the quotient and remainder. */ abstract public function divQR(string $a, string $b) : array; @@ -249,10 +214,7 @@ abstract class Calculator abstract public function pow(string $a, int $e) : string; /** - * @param string $a * @param string $b The modulus; must not be zero. - * - * @return string */ public function mod(string $a, string $b) : string { @@ -266,10 +228,7 @@ abstract class Calculator * * This method can be overridden by the concrete implementation if the underlying library has built-in support. * - * @param string $x * @param string $m The modulus; must not be negative or zero. - * - * @return string|null */ public function modInverse(string $x, string $m) : ?string { @@ -283,9 +242,7 @@ abstract class Calculator $modVal = $this->mod($x, $m); } - $x = '0'; - $y = '0'; - $g = $this->gcdExtended($modVal, $m, $x, $y); + [$g, $x] = $this->gcdExtended($modVal, $m); if ($g !== '1') { return null; @@ -300,8 +257,6 @@ abstract class Calculator * @param string $base The base number; must be positive or zero. * @param string $exp The exponent; must be positive or zero. * @param string $mod The modulus; must be strictly positive. - * - * @return string The power. */ abstract public function modPow(string $base, string $exp, string $mod) : string; @@ -311,9 +266,6 @@ abstract class Calculator * This method can be overridden by the concrete implementation if the underlying library * has built-in support for GCD calculations. * - * @param string $a The first number. - * @param string $b The second number. - * * @return string The GCD, always positive, or zero if both arguments are zero. */ public function gcd(string $a, string $b) : string @@ -329,24 +281,21 @@ abstract class Calculator return $this->gcd($b, $this->divR($a, $b)); } - private function gcdExtended(string $a, string $b, string &$x, string &$y) : string + /** + * @return array{string, string, string} GCD, X, Y + */ + private function gcdExtended(string $a, string $b) : array { if ($a === '0') { - $x = '0'; - $y = '1'; - - return $b; + return [$b, '0', '1']; } - $x1 = '0'; - $y1 = '0'; - - $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1); + [$gcd, $x1, $y1] = $this->gcdExtended($this->mod($b, $a), $a); $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); $y = $x1; - return $gcd; + return [$gcd, $x, $y]; } /** @@ -354,10 +303,6 @@ abstract class Calculator * * The result is the largest x such that x² ≤ n. * The input MUST NOT be negative. - * - * @param string $n The number. - * - * @return string The square root. */ abstract public function sqrt(string $n) : string; @@ -485,16 +430,16 @@ abstract class Calculator * * Rounding is performed when the remainder of the division is not zero. * - * @param string $a The dividend. - * @param string $b The divisor, must not be zero. - * @param int $roundingMode The rounding mode. - * - * @return string + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * @param RoundingMode $roundingMode The rounding mode. * * @throws \InvalidArgumentException If the rounding mode is invalid. * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. + * + * @psalm-suppress ImpureFunctionCall */ - final public function divRound(string $a, string $b, int $roundingMode) : string + final public function divRound(string $a, string $b, RoundingMode $roundingMode) : string { [$quotient, $remainder] = $this->divQR($a, $b); @@ -570,11 +515,6 @@ abstract class Calculator * * This method can be overridden by the concrete implementation if the underlying library * has built-in support for bitwise operations. - * - * @param string $a - * @param string $b - * - * @return string */ public function and(string $a, string $b) : string { @@ -586,11 +526,6 @@ abstract class Calculator * * This method can be overridden by the concrete implementation if the underlying library * has built-in support for bitwise operations. - * - * @param string $a - * @param string $b - * - * @return string */ public function or(string $a, string $b) : string { @@ -602,11 +537,6 @@ abstract class Calculator * * This method can be overridden by the concrete implementation if the underlying library * has built-in support for bitwise operations. - * - * @param string $a - * @param string $b - * - * @return string */ public function xor(string $a, string $b) : string { @@ -616,11 +546,9 @@ abstract class Calculator /** * Performs a bitwise operation on a decimal number. * - * @param string $operator The operator to use, must be "and", "or" or "xor". - * @param string $a The left operand. - * @param string $b The right operand. - * - * @return string + * @param 'and'|'or'|'xor' $operator The operator to use. + * @param string $a The left operand. + * @param string $b The right operand. */ private function bitwise(string $operator, string $a, string $b) : string { @@ -645,27 +573,17 @@ abstract class Calculator $bBin = $this->twosComplement($bBin); } - switch ($operator) { - case 'and': - $value = $aBin & $bBin; - $negative = ($aNeg and $bNeg); - break; + $value = match ($operator) { + 'and' => $aBin & $bBin, + 'or' => $aBin | $bBin, + 'xor' => $aBin ^ $bBin, + }; - case 'or': - $value = $aBin | $bBin; - $negative = ($aNeg or $bNeg); - break; - - case 'xor': - $value = $aBin ^ $bBin; - $negative = ($aNeg xor $bNeg); - break; - - // @codeCoverageIgnoreStart - default: - throw new \InvalidArgumentException('Invalid bitwise operator.'); - // @codeCoverageIgnoreEnd - } + $negative = match ($operator) { + 'and' => $aNeg and $bNeg, + 'or' => $aNeg or $bNeg, + 'xor' => $aNeg xor $bNeg, + }; if ($negative) { $value = $this->twosComplement($value); @@ -678,8 +596,6 @@ abstract class Calculator /** * @param string $number A positive, binary number. - * - * @return string */ private function twosComplement(string $number) : string { @@ -709,8 +625,6 @@ abstract class Calculator * Converts a decimal number to a binary string. * * @param string $number The number to convert, positive or zero, only digits. - * - * @return string */ private function toBinary(string $number) : string { @@ -728,8 +642,6 @@ abstract class Calculator * Returns the positive decimal representation of a binary number. * * @param string $bytes The bytes representing the number. - * - * @return string */ private function toDecimal(string $bytes) : string { diff --git a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/BcMathCalculator.php b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/BcMathCalculator.php index 6632b378a..93a27ff81 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/BcMathCalculator.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/BcMathCalculator.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Brick\Math\Internal\Calculator; use Brick\Math\Internal\Calculator; +use Override; /** * Calculator implementation built around the bcmath library. @@ -15,100 +16,58 @@ use Brick\Math\Internal\Calculator; */ class BcMathCalculator extends Calculator { - /** - * {@inheritdoc} - */ + #[Override] public function add(string $a, string $b) : string { return \bcadd($a, $b, 0); } - /** - * {@inheritdoc} - */ + #[Override] public function sub(string $a, string $b) : string { return \bcsub($a, $b, 0); } - /** - * {@inheritdoc} - */ + #[Override] public function mul(string $a, string $b) : string { return \bcmul($a, $b, 0); } - /** - * {@inheritdoc} - * - * @psalm-suppress InvalidNullableReturnType - * @psalm-suppress NullableReturnStatement - */ + #[Override] public function divQ(string $a, string $b) : string { return \bcdiv($a, $b, 0); } - /** - * {@inheritdoc} - * - * @psalm-suppress InvalidNullableReturnType - * @psalm-suppress NullableReturnStatement - */ + #[Override] public function divR(string $a, string $b) : string { - if (version_compare(PHP_VERSION, '7.2') >= 0) { - return \bcmod($a, $b, 0); - } - - return \bcmod($a, $b); + return \bcmod($a, $b, 0); } - /** - * {@inheritdoc} - */ + #[Override] public function divQR(string $a, string $b) : array { $q = \bcdiv($a, $b, 0); - - if (version_compare(PHP_VERSION, '7.2') >= 0) { - $r = \bcmod($a, $b, 0); - } else { - $r = \bcmod($a, $b); - } - - assert($q !== null); - assert($r !== null); + $r = \bcmod($a, $b, 0); return [$q, $r]; } - /** - * {@inheritdoc} - */ + #[Override] public function pow(string $a, int $e) : string { return \bcpow($a, (string) $e, 0); } - /** - * {@inheritdoc} - * - * @psalm-suppress InvalidNullableReturnType - * @psalm-suppress NullableReturnStatement - */ + #[Override] public function modPow(string $base, string $exp, string $mod) : string { return \bcpowmod($base, $exp, $mod, 0); } - /** - * {@inheritDoc} - * - * @psalm-suppress NullableReturnStatement - * @psalm-suppress InvalidNullableReturnType - */ + #[Override] public function sqrt(string $n) : string { return \bcsqrt($n, 0); diff --git a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/GmpCalculator.php b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/GmpCalculator.php index 52d18800a..0e44deeb3 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/GmpCalculator.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/GmpCalculator.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Brick\Math\Internal\Calculator; use Brick\Math\Internal\Calculator; +use Override; /** * Calculator implementation built around the GMP library. @@ -15,49 +16,37 @@ use Brick\Math\Internal\Calculator; */ class GmpCalculator extends Calculator { - /** - * {@inheritdoc} - */ + #[Override] public function add(string $a, string $b) : string { return \gmp_strval(\gmp_add($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function sub(string $a, string $b) : string { return \gmp_strval(\gmp_sub($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function mul(string $a, string $b) : string { return \gmp_strval(\gmp_mul($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function divQ(string $a, string $b) : string { return \gmp_strval(\gmp_div_q($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function divR(string $a, string $b) : string { return \gmp_strval(\gmp_div_r($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function divQR(string $a, string $b) : array { [$q, $r] = \gmp_div_qr($a, $b); @@ -68,17 +57,13 @@ class GmpCalculator extends Calculator ]; } - /** - * {@inheritdoc} - */ + #[Override] public function pow(string $a, int $e) : string { return \gmp_strval(\gmp_pow($a, $e)); } - /** - * {@inheritdoc} - */ + #[Override] public function modInverse(string $x, string $m) : ?string { $result = \gmp_invert($x, $m); @@ -90,65 +75,49 @@ class GmpCalculator extends Calculator return \gmp_strval($result); } - /** - * {@inheritdoc} - */ + #[Override] public function modPow(string $base, string $exp, string $mod) : string { return \gmp_strval(\gmp_powm($base, $exp, $mod)); } - /** - * {@inheritdoc} - */ + #[Override] public function gcd(string $a, string $b) : string { return \gmp_strval(\gmp_gcd($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function fromBase(string $number, int $base) : string { return \gmp_strval(\gmp_init($number, $base)); } - /** - * {@inheritdoc} - */ + #[Override] public function toBase(string $number, int $base) : string { return \gmp_strval($number, $base); } - /** - * {@inheritdoc} - */ + #[Override] public function and(string $a, string $b) : string { return \gmp_strval(\gmp_and($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function or(string $a, string $b) : string { return \gmp_strval(\gmp_or($a, $b)); } - /** - * {@inheritdoc} - */ + #[Override] public function xor(string $a, string $b) : string { return \gmp_strval(\gmp_xor($a, $b)); } - /** - * {@inheritDoc} - */ + #[Override] public function sqrt(string $n) : string { return \gmp_strval(\gmp_sqrt($n)); diff --git a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/NativeCalculator.php b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/NativeCalculator.php index 020a6338b..f71c55bed 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/NativeCalculator.php +++ b/lam/lib/3rdParty/composer/brick/math/src/Internal/Calculator/NativeCalculator.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Brick\Math\Internal\Calculator; use Brick\Math\Internal\Calculator; +use Override; /** * Calculator implementation using only native PHP code. @@ -19,38 +20,25 @@ class NativeCalculator extends Calculator * The max number of digits the platform can natively add, subtract, multiply or divide without overflow. * For multiplication, this represents the max sum of the lengths of both operands. * - * For addition, it is assumed that an extra digit can hold a carry (1) without overflowing. + * In addition, it is assumed that an extra digit can hold a carry (1) without overflowing. * Example: 32-bit: max number 1,999,999,999 (9 digits + carry) * 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry) - * - * @var int */ - private $maxDigits; + private readonly int $maxDigits; /** - * Class constructor. - * * @codeCoverageIgnore */ public function __construct() { - switch (PHP_INT_SIZE) { - case 4: - $this->maxDigits = 9; - break; - - case 8: - $this->maxDigits = 18; - break; - - default: - throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); - } + $this->maxDigits = match (PHP_INT_SIZE) { + 4 => 9, + 8 => 18, + default => throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.') + }; } - /** - * {@inheritdoc} - */ + #[Override] public function add(string $a, string $b) : string { /** @@ -82,17 +70,13 @@ class NativeCalculator extends Calculator return $result; } - /** - * {@inheritdoc} - */ + #[Override] public function sub(string $a, string $b) : string { return $this->add($a, $this->neg($b)); } - /** - * {@inheritdoc} - */ + #[Override] public function mul(string $a, string $b) : string { /** @@ -136,25 +120,19 @@ class NativeCalculator extends Calculator return $result; } - /** - * {@inheritdoc} - */ + #[Override] public function divQ(string $a, string $b) : string { return $this->divQR($a, $b)[0]; } - /** - * {@inheritdoc} - */ + #[Override] public function divR(string $a, string $b): string { return $this->divQR($a, $b)[1]; } - /** - * {@inheritdoc} - */ + #[Override] public function divQR(string $a, string $b) : array { if ($a === '0') { @@ -183,10 +161,8 @@ class NativeCalculator extends Calculator if (is_int($nb)) { // the only division that may overflow is PHP_INT_MIN / -1, // which cannot happen here as we've already handled a divisor of -1 above. + $q = intdiv($na, $nb); $r = $na % $nb; - $q = ($na - $r) / $nb; - - assert(is_int($q)); return [ (string) $q, @@ -210,9 +186,7 @@ class NativeCalculator extends Calculator return [$q, $r]; } - /** - * {@inheritdoc} - */ + #[Override] public function pow(string $a, int $e) : string { if ($e === 0) { @@ -240,9 +214,8 @@ class NativeCalculator extends Calculator /** * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/ - * - * {@inheritdoc} */ + #[Override] public function modPow(string $base, string $exp, string $mod) : string { // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0) @@ -276,9 +249,8 @@ class NativeCalculator extends Calculator /** * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html - * - * {@inheritDoc} */ + #[Override] public function sqrt(string $n) : string { if ($n === '0') { @@ -306,11 +278,6 @@ class NativeCalculator extends Calculator /** * Performs the addition of two non-signed large integers. - * - * @param string $a The first operand. - * @param string $b The second operand. - * - * @return string */ private function doAdd(string $a, string $b) : string { @@ -363,11 +330,6 @@ class NativeCalculator extends Calculator /** * Performs the subtraction of two non-signed large integers. - * - * @param string $a The first operand. - * @param string $b The second operand. - * - * @return string */ private function doSub(string $a, string $b) : string { @@ -445,11 +407,6 @@ class NativeCalculator extends Calculator /** * Performs the multiplication of two non-signed large integers. - * - * @param string $a The first operand. - * @param string $b The second operand. - * - * @return string */ private function doMul(string $a, string $b) : string { @@ -522,9 +479,6 @@ class NativeCalculator extends Calculator /** * Performs the division of two non-signed large integers. * - * @param string $a The first operand. - * @param string $b The second operand. - * * @return string[] The quotient and remainder. */ private function doDiv(string $a, string $b) : array @@ -544,6 +498,22 @@ class NativeCalculator extends Calculator $r = $a; // remainder $z = $y; // focus length, always $y or $y+1 + /** @psalm-var numeric-string $b */ + $nb = $b * 1; // cast to number + // performance optimization in cases where the remainder will never cause int overflow + if (is_int(($nb - 1) * 10 + 9)) { + $r = (int) \substr($a, 0, $z - 1); + + for ($i = $z - 1; $i < $x; $i++) { + $n = $r * 10 + (int) $a[$i]; + /** @psalm-var int $nb */ + $q .= \intdiv($n, $nb); + $r = $n % $nb; + } + + return [\ltrim($q, '0') ?: '0', (string) $r]; + } + for (;;) { $focus = \substr($a, 0, $z); @@ -583,10 +553,7 @@ class NativeCalculator extends Calculator /** * Compares two non-signed large numbers. * - * @param string $a The first operand. - * @param string $b The second operand. - * - * @return int [-1, 0, 1] + * @psalm-return -1|0|1 */ private function doCmp(string $a, string $b) : int { @@ -599,7 +566,7 @@ class NativeCalculator extends Calculator return $cmp; } - return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] + return \strcmp($a, $b) <=> 0; // enforce -1|0|1 } /** @@ -607,9 +574,6 @@ class NativeCalculator extends Calculator * * The numbers must only consist of digits, without leading minus sign. * - * @param string $a The first operand. - * @param string $b The second operand. - * * @return array{string, string, int} */ private function pad(string $a, string $b) : array diff --git a/lam/lib/3rdParty/composer/brick/math/src/RoundingMode.php b/lam/lib/3rdParty/composer/brick/math/src/RoundingMode.php index 06936d8db..e8ee6a8b4 100644 --- a/lam/lib/3rdParty/composer/brick/math/src/RoundingMode.php +++ b/lam/lib/3rdParty/composer/brick/math/src/RoundingMode.php @@ -13,24 +13,15 @@ namespace Brick\Math; * regardless the digits' contribution to the value of the number. In other words, considered * as a numerical value, the discarded fraction could have an absolute value greater than one. */ -final class RoundingMode +enum RoundingMode { - /** - * Private constructor. This class is not instantiable. - * - * @codeCoverageIgnore - */ - private function __construct() - { - } - /** * Asserts that the requested operation has an exact result, hence no rounding is necessary. * * If this rounding mode is specified on an operation that yields a result that * cannot be represented at the requested scale, a RoundingNecessaryException is thrown. */ - public const UNNECESSARY = 0; + case UNNECESSARY; /** * Rounds away from zero. @@ -38,7 +29,7 @@ final class RoundingMode * Always increments the digit prior to a nonzero discarded fraction. * Note that this rounding mode never decreases the magnitude of the calculated value. */ - public const UP = 1; + case UP; /** * Rounds towards zero. @@ -46,7 +37,7 @@ final class RoundingMode * Never increments the digit prior to a discarded fraction (i.e., truncates). * Note that this rounding mode never increases the magnitude of the calculated value. */ - public const DOWN = 2; + case DOWN; /** * Rounds towards positive infinity. @@ -54,7 +45,7 @@ final class RoundingMode * If the result is positive, behaves as for UP; if negative, behaves as for DOWN. * Note that this rounding mode never decreases the calculated value. */ - public const CEILING = 3; + case CEILING; /** * Rounds towards negative infinity. @@ -62,7 +53,7 @@ final class RoundingMode * If the result is positive, behave as for DOWN; if negative, behave as for UP. * Note that this rounding mode never increases the calculated value. */ - public const FLOOR = 4; + case FLOOR; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up. @@ -70,28 +61,28 @@ final class RoundingMode * Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN. * Note that this is the rounding mode commonly taught at school. */ - public const HALF_UP = 5; + case HALF_UP; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. * * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. */ - public const HALF_DOWN = 6; + case HALF_DOWN; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. * * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. */ - public const HALF_CEILING = 7; + case HALF_CEILING; /** * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. * * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. */ - public const HALF_FLOOR = 8; + case HALF_FLOOR; /** * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. @@ -103,5 +94,5 @@ final class RoundingMode * cumulative error when applied repeatedly over a sequence of calculations. * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. */ - public const HALF_EVEN = 9; + case HALF_EVEN; } diff --git a/lam/lib/3rdParty/composer/composer/autoload_classmap.php b/lam/lib/3rdParty/composer/composer/autoload_classmap.php index 04e043f13..70fbde6bb 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_classmap.php +++ b/lam/lib/3rdParty/composer/composer/autoload_classmap.php @@ -6,7 +6,29 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname($vendorDir))); return array( - 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'AWS\\CRT\\Auth\\AwsCredentials' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php', + 'AWS\\CRT\\Auth\\CredentialsProvider' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php', + 'AWS\\CRT\\Auth\\Signable' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php', + 'AWS\\CRT\\Auth\\SignatureType' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php', + 'AWS\\CRT\\Auth\\SignedBodyHeaderType' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php', + 'AWS\\CRT\\Auth\\Signing' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php', + 'AWS\\CRT\\Auth\\SigningAlgorithm' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php', + 'AWS\\CRT\\Auth\\SigningConfigAWS' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php', + 'AWS\\CRT\\Auth\\SigningResult' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php', + 'AWS\\CRT\\Auth\\StaticCredentialsProvider' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php', + 'AWS\\CRT\\CRT' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/CRT.php', + 'AWS\\CRT\\HTTP\\Headers' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php', + 'AWS\\CRT\\HTTP\\Message' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php', + 'AWS\\CRT\\HTTP\\Request' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php', + 'AWS\\CRT\\HTTP\\Response' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php', + 'AWS\\CRT\\IO\\EventLoopGroup' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php', + 'AWS\\CRT\\IO\\InputStream' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php', + 'AWS\\CRT\\Internal\\Encoding' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php', + 'AWS\\CRT\\Internal\\Extension' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php', + 'AWS\\CRT\\Log' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Log.php', + 'AWS\\CRT\\NativeResource' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/NativeResource.php', + 'AWS\\CRT\\OptionValue' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php', + 'AWS\\CRT\\Options' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php', 'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php', @@ -17,97 +39,7 @@ return array( 'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php', 'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php', 'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', 'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php', - 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php', - 'Safe\\DateTime' => $vendorDir . '/thecodingmachine/safe/lib/DateTime.php', - 'Safe\\DateTimeImmutable' => $vendorDir . '/thecodingmachine/safe/lib/DateTimeImmutable.php', - 'Safe\\Exceptions\\ApacheException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ApacheException.php', - 'Safe\\Exceptions\\ApcException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/ApcException.php', - 'Safe\\Exceptions\\ApcuException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ApcuException.php', - 'Safe\\Exceptions\\ArrayException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ArrayException.php', - 'Safe\\Exceptions\\Bzip2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Bzip2Exception.php', - 'Safe\\Exceptions\\CalendarException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/CalendarException.php', - 'Safe\\Exceptions\\ClassobjException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ClassobjException.php', - 'Safe\\Exceptions\\ComException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ComException.php', - 'Safe\\Exceptions\\CubridException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/CubridException.php', - 'Safe\\Exceptions\\CurlException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/CurlException.php', - 'Safe\\Exceptions\\DatetimeException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/DatetimeException.php', - 'Safe\\Exceptions\\DirException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/DirException.php', - 'Safe\\Exceptions\\EioException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/EioException.php', - 'Safe\\Exceptions\\ErrorfuncException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ErrorfuncException.php', - 'Safe\\Exceptions\\ExecException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ExecException.php', - 'Safe\\Exceptions\\FileinfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FileinfoException.php', - 'Safe\\Exceptions\\FilesystemException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FilesystemException.php', - 'Safe\\Exceptions\\FilterException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FilterException.php', - 'Safe\\Exceptions\\FpmException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FpmException.php', - 'Safe\\Exceptions\\FtpException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FtpException.php', - 'Safe\\Exceptions\\FunchandException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FunchandException.php', - 'Safe\\Exceptions\\GettextException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GettextException.php', - 'Safe\\Exceptions\\GmpException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GmpException.php', - 'Safe\\Exceptions\\GnupgException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GnupgException.php', - 'Safe\\Exceptions\\HashException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/HashException.php', - 'Safe\\Exceptions\\IbaseException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IbaseException.php', - 'Safe\\Exceptions\\IbmDb2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IbmDb2Exception.php', - 'Safe\\Exceptions\\IconvException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IconvException.php', - 'Safe\\Exceptions\\ImageException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ImageException.php', - 'Safe\\Exceptions\\ImapException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ImapException.php', - 'Safe\\Exceptions\\InfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/InfoException.php', - 'Safe\\Exceptions\\InotifyException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/InotifyException.php', - 'Safe\\Exceptions\\JsonException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/JsonException.php', - 'Safe\\Exceptions\\LdapException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LdapException.php', - 'Safe\\Exceptions\\LibeventException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/LibeventException.php', - 'Safe\\Exceptions\\LibxmlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LibxmlException.php', - 'Safe\\Exceptions\\LzfException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LzfException.php', - 'Safe\\Exceptions\\MailparseException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MailparseException.php', - 'Safe\\Exceptions\\MbstringException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MbstringException.php', - 'Safe\\Exceptions\\MiscException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MiscException.php', - 'Safe\\Exceptions\\MssqlException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/MssqlException.php', - 'Safe\\Exceptions\\MysqlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MysqlException.php', - 'Safe\\Exceptions\\MysqliException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/MysqliException.php', - 'Safe\\Exceptions\\NetworkException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/NetworkException.php', - 'Safe\\Exceptions\\Oci8Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Oci8Exception.php', - 'Safe\\Exceptions\\OpcacheException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/OpcacheException.php', - 'Safe\\Exceptions\\OpensslException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/OpensslException.php', - 'Safe\\Exceptions\\OutcontrolException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/OutcontrolException.php', - 'Safe\\Exceptions\\PasswordException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/PasswordException.php', - 'Safe\\Exceptions\\PcntlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PcntlException.php', - 'Safe\\Exceptions\\PcreException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/PcreException.php', - 'Safe\\Exceptions\\PgsqlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PgsqlException.php', - 'Safe\\Exceptions\\PosixException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PosixException.php', - 'Safe\\Exceptions\\PsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PsException.php', - 'Safe\\Exceptions\\PspellException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PspellException.php', - 'Safe\\Exceptions\\ReadlineException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ReadlineException.php', - 'Safe\\Exceptions\\RpminfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/RpminfoException.php', - 'Safe\\Exceptions\\RrdException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/RrdException.php', - 'Safe\\Exceptions\\SafeExceptionInterface' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php', - 'Safe\\Exceptions\\SemException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SemException.php', - 'Safe\\Exceptions\\SessionException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SessionException.php', - 'Safe\\Exceptions\\ShmopException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ShmopException.php', - 'Safe\\Exceptions\\SimplexmlException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/SimplexmlException.php', - 'Safe\\Exceptions\\SocketsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SocketsException.php', - 'Safe\\Exceptions\\SodiumException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SodiumException.php', - 'Safe\\Exceptions\\SolrException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SolrException.php', - 'Safe\\Exceptions\\SplException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SplException.php', - 'Safe\\Exceptions\\SqlsrvException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SqlsrvException.php', - 'Safe\\Exceptions\\SsdeepException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SsdeepException.php', - 'Safe\\Exceptions\\Ssh2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Ssh2Exception.php', - 'Safe\\Exceptions\\StatsException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/StatsException.php', - 'Safe\\Exceptions\\StreamException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/StreamException.php', - 'Safe\\Exceptions\\StringsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/StringsException.php', - 'Safe\\Exceptions\\SwooleException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SwooleException.php', - 'Safe\\Exceptions\\UodbcException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UodbcException.php', - 'Safe\\Exceptions\\UopzException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UopzException.php', - 'Safe\\Exceptions\\UrlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UrlException.php', - 'Safe\\Exceptions\\VarException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/VarException.php', - 'Safe\\Exceptions\\XdiffException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XdiffException.php', - 'Safe\\Exceptions\\XmlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XmlException.php', - 'Safe\\Exceptions\\XmlrpcException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XmlrpcException.php', - 'Safe\\Exceptions\\YamlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/YamlException.php', - 'Safe\\Exceptions\\YazException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/YazException.php', - 'Safe\\Exceptions\\ZipException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ZipException.php', - 'Safe\\Exceptions\\ZlibException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ZlibException.php', - 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', - 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', - 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); diff --git a/lam/lib/3rdParty/composer/composer/autoload_files.php b/lam/lib/3rdParty/composer/composer/autoload_files.php index 87e5ecd7a..12ea9c7fc 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_files.php +++ b/lam/lib/3rdParty/composer/composer/autoload_files.php @@ -6,107 +6,25 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname($vendorDir))); return array( - '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', - '60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php', - 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', - 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', - 'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php', - '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', + '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', + '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php', + '2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php', '09f6b20656683369174dd6fa83b7e5fb' => $vendorDir . '/symfony/polyfill-uuid/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', 'c2b3214084883d700175de676a4fc127' => $vendorDir . '/facile-it/php-jose-verifier/src/functions/derived_key.php', '16040cf78e404de30085045d3863ed51' => $vendorDir . '/facile-it/php-jose-verifier/src/functions/jose_secret_key.php', - '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', - '51fcf4e06c07cc00c920b44bcd900e7a' => $vendorDir . '/thecodingmachine/safe/deprecated/apc.php', - '288267919fedd3829a7732b5fb202197' => $vendorDir . '/thecodingmachine/safe/deprecated/array.php', - 'a88cd08cfbf1600f7d5de6e587eee1fa' => $vendorDir . '/thecodingmachine/safe/deprecated/datetime.php', - '47f619d9197b36cf5ab70738d7743fe2' => $vendorDir . '/thecodingmachine/safe/deprecated/libevent.php', - 'f1f7d69cca064c8f779d4a4cba463e11' => $vendorDir . '/thecodingmachine/safe/deprecated/misc.php', - '213c1c2258e2e5aa409a0af3e993b3a9' => $vendorDir . '/thecodingmachine/safe/deprecated/password.php', - 'ea6bb8a12ef9b68f6ada99058e530760' => $vendorDir . '/thecodingmachine/safe/deprecated/mssql.php', - '9a29089eb3ce41a446744c68a00f118c' => $vendorDir . '/thecodingmachine/safe/deprecated/stats.php', - 'd5947c9df62650029c674c79176af68d' => $vendorDir . '/thecodingmachine/safe/deprecated/strings.php', - '72243e5536b63e298acb6476f01f1aff' => $vendorDir . '/thecodingmachine/safe/lib/special_cases.php', - '09f92ed6301edc510574c196c2b7d1af' => $vendorDir . '/thecodingmachine/safe/deprecated/mysqli.php', - '3f648889e687f31c52f949ba8a9d0873' => $vendorDir . '/thecodingmachine/safe/generated/apache.php', - 'eeb4581d958421a4244aaa4167c6a575' => $vendorDir . '/thecodingmachine/safe/generated/apcu.php', - '04cb0b3c1dac5b5ddb23c14e3d66dbe9' => $vendorDir . '/thecodingmachine/safe/generated/array.php', - '450b332a74a9a21e043c5e953485a791' => $vendorDir . '/thecodingmachine/safe/generated/bzip2.php', - '6e9b7954ecfd7cbb9ca239319d1acdb6' => $vendorDir . '/thecodingmachine/safe/generated/calendar.php', - '2c6d7e8bd2de9a272a9d4d43b0a4304a' => $vendorDir . '/thecodingmachine/safe/generated/classobj.php', - '0b8231c1ad0865447c988a4c16b4001f' => $vendorDir . '/thecodingmachine/safe/generated/com.php', - '7643a71fe1c3256058c8fee234cb86e5' => $vendorDir . '/thecodingmachine/safe/generated/cubrid.php', - '68e1365710575942efc1d55000032cee' => $vendorDir . '/thecodingmachine/safe/generated/curl.php', - '02fd26bca803106c5b942a7197c3ad8b' => $vendorDir . '/thecodingmachine/safe/generated/datetime.php', - 'f4817dcbd956cd221b1c31f6fbd5749c' => $vendorDir . '/thecodingmachine/safe/generated/dir.php', - '51c3f2d10ca61a70dbcea0e38d8e902d' => $vendorDir . '/thecodingmachine/safe/generated/eio.php', - '1d34f34327ca3e81535963016e3be2c3' => $vendorDir . '/thecodingmachine/safe/generated/errorfunc.php', - '4fd0ba2d3717b0424d474bebfdafa2b4' => $vendorDir . '/thecodingmachine/safe/generated/exec.php', - '98f4dae054bc7fb19c13be14935cbdd3' => $vendorDir . '/thecodingmachine/safe/generated/fileinfo.php', - '5530ae063ba88323eaf0a07904efdf85' => $vendorDir . '/thecodingmachine/safe/generated/filesystem.php', - '633f4f134975d70e97bddad83348e91a' => $vendorDir . '/thecodingmachine/safe/generated/filter.php', - 'fbd163fc68c5faf73d5ed4002ffd836d' => $vendorDir . '/thecodingmachine/safe/generated/fpm.php', - '21b511999d61411fab0692ff8795bbed' => $vendorDir . '/thecodingmachine/safe/generated/ftp.php', - '85fbd73fc92365cd90526b0ea03cae3a' => $vendorDir . '/thecodingmachine/safe/generated/funchand.php', - 'a2e4c6dfdbf36f56f1945ddcbd54e289' => $vendorDir . '/thecodingmachine/safe/generated/gettext.php', - '51df9c146e0b7dcbdf358d8abd24dbdc' => $vendorDir . '/thecodingmachine/safe/generated/gmp.php', - '93bb7fe678d7dcfb1322f8e3475a48b0' => $vendorDir . '/thecodingmachine/safe/generated/gnupg.php', - 'c171ba99cf316379ff66468392bf4950' => $vendorDir . '/thecodingmachine/safe/generated/hash.php', - '5ab4aad4c28e468209fbfcceb2e5e6a5' => $vendorDir . '/thecodingmachine/safe/generated/ibase.php', - '4d57409c5e8e576b0c64c08d9d731cfb' => $vendorDir . '/thecodingmachine/safe/generated/ibmDb2.php', - 'eeb246d5403972a9d62106e4a4883496' => $vendorDir . '/thecodingmachine/safe/generated/iconv.php', - 'c28a05f498c01b810a714f7214b7a8da' => $vendorDir . '/thecodingmachine/safe/generated/image.php', - '8063cd92acdf00fd978b5599eb7cc142' => $vendorDir . '/thecodingmachine/safe/generated/imap.php', - '8bd26dbe768e9c9599edad7b198e5446' => $vendorDir . '/thecodingmachine/safe/generated/info.php', - 'd4362910bde43c0f956b52527effd7d4' => $vendorDir . '/thecodingmachine/safe/generated/inotify.php', - '696ba49197d9b55f0428a12bb5a818e1' => $vendorDir . '/thecodingmachine/safe/generated/json.php', - '9818aaa99c8647c63f8ef62b7a368160' => $vendorDir . '/thecodingmachine/safe/generated/ldap.php', - 'bcf523ff2a195eb08e0fbb668ed784d0' => $vendorDir . '/thecodingmachine/safe/generated/libxml.php', - '68be68a9a8b95bb56cab6109ff03bc88' => $vendorDir . '/thecodingmachine/safe/generated/lzf.php', - 'bdca804bb0904ea9f53f328dfc0bb8a5' => $vendorDir . '/thecodingmachine/safe/generated/mailparse.php', - 'b0a3fcac3eaf55445796d6af26b89366' => $vendorDir . '/thecodingmachine/safe/generated/mbstring.php', - '98de16b8db03eb0cb4d318b4402215a6' => $vendorDir . '/thecodingmachine/safe/generated/misc.php', - '7cefd81607cd21b8b3a15656eb6465f5' => $vendorDir . '/thecodingmachine/safe/generated/mysql.php', - 'cbac956836b72483dcff1ac39d5c0a0f' => $vendorDir . '/thecodingmachine/safe/generated/network.php', - '6c8f89dfbdc117d7871f572269363f25' => $vendorDir . '/thecodingmachine/safe/generated/oci8.php', - '169a669966a45c06bf55ed029122729b' => $vendorDir . '/thecodingmachine/safe/generated/opcache.php', - 'def61bf4fecd4d4bca7354919cd69302' => $vendorDir . '/thecodingmachine/safe/generated/openssl.php', - '26bb010649a6d32d4120181458aa6ef2' => $vendorDir . '/thecodingmachine/safe/generated/outcontrol.php', - '002ebcb842e2c0d5b7f67fe64cc93158' => $vendorDir . '/thecodingmachine/safe/generated/pcntl.php', - '86df38612982dade72c7085ce7eca81f' => $vendorDir . '/thecodingmachine/safe/generated/pcre.php', - '1fc22f445c69ea8706e82fce301c0831' => $vendorDir . '/thecodingmachine/safe/generated/pgsql.php', - 'c70b42561584f7144bff38cd63c4eef3' => $vendorDir . '/thecodingmachine/safe/generated/posix.php', - '9923214639c32ca5173db03a177d3b63' => $vendorDir . '/thecodingmachine/safe/generated/ps.php', - '7e9c3f8eae2b5bf42205c4f1295cb7a7' => $vendorDir . '/thecodingmachine/safe/generated/pspell.php', - '91aa91f6245c349c2e2e88bd0025f199' => $vendorDir . '/thecodingmachine/safe/generated/readline.php', - 'd43773cacb9e5e8e897aa255e32007d1' => $vendorDir . '/thecodingmachine/safe/generated/rpminfo.php', - 'f053a3849e9e8383762b34b91db0320b' => $vendorDir . '/thecodingmachine/safe/generated/rrd.php', - '775b964f72f827a1bf87c65ab5b10800' => $vendorDir . '/thecodingmachine/safe/generated/sem.php', - '816428bd69c29ab5e1ed622af5dca0cd' => $vendorDir . '/thecodingmachine/safe/generated/session.php', - '5093e233bedbefaef0df262bfbab0a5c' => $vendorDir . '/thecodingmachine/safe/generated/shmop.php', - 'b080617b1d949683c2e37f8f01dc0e15' => $vendorDir . '/thecodingmachine/safe/generated/sockets.php', - '2708aa182ddcfe6ce27c96acaaa40f69' => $vendorDir . '/thecodingmachine/safe/generated/sodium.php', - 'f1b96cb260a5baeea9a7285cda82a1ec' => $vendorDir . '/thecodingmachine/safe/generated/solr.php', - '3fd8853757d0fe3557c179efb807afeb' => $vendorDir . '/thecodingmachine/safe/generated/spl.php', - '9312ce96a51c846913fcda5f186d58dd' => $vendorDir . '/thecodingmachine/safe/generated/sqlsrv.php', - 'd3eb383ad0b8b962b29dc4afd29d6715' => $vendorDir . '/thecodingmachine/safe/generated/ssdeep.php', - '42a09bc448f441a0b9f9367ea975c0bf' => $vendorDir . '/thecodingmachine/safe/generated/ssh2.php', - 'ef711077d356d1b33ca0b10b67b0be8f' => $vendorDir . '/thecodingmachine/safe/generated/stream.php', - '764b09f6df081cbb2807b97c6ace3866' => $vendorDir . '/thecodingmachine/safe/generated/strings.php', - 'ef241678769fee4a44aaa288f3b78aa1' => $vendorDir . '/thecodingmachine/safe/generated/swoole.php', - '0efc8f6778cba932b9e2a89e28de2452' => $vendorDir . '/thecodingmachine/safe/generated/uodbc.php', - 'd383d32907b98af53ee9208c62204fd0' => $vendorDir . '/thecodingmachine/safe/generated/uopz.php', - '2fd2e4060f7fe772660f002ce38f0b71' => $vendorDir . '/thecodingmachine/safe/generated/url.php', - '782249e03deebeaf57b9991ff5493aa0' => $vendorDir . '/thecodingmachine/safe/generated/var.php', - '344440cd1cd7200fdb4f12af0d3c587f' => $vendorDir . '/thecodingmachine/safe/generated/xdiff.php', - '3599f369219c658a5fb6c4fe66832f62' => $vendorDir . '/thecodingmachine/safe/generated/xml.php', - '7fcd313da9fae337051b091b3492c21b' => $vendorDir . '/thecodingmachine/safe/generated/xmlrpc.php', - 'd668c74cfa92d893b582356733d9a80e' => $vendorDir . '/thecodingmachine/safe/generated/yaml.php', - '4af1dca6db8c527c6eed27bff85ff0e5' => $vendorDir . '/thecodingmachine/safe/generated/yaz.php', - 'fe43ca06499ac37bc2dedd823af71eb5' => $vendorDir . '/thecodingmachine/safe/generated/zip.php', - '356736db98a6834f0a886b8d509b0ecd' => $vendorDir . '/thecodingmachine/safe/generated/zlib.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + 'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php', + '8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php', 'ba61337b858c088ff9f16a5fc3badbeb' => $vendorDir . '/facile-it/php-openid-client/src/functions/base64url_decode.php', 'd4a8a901fd39fc07eb96403508f8f03f' => $vendorDir . '/facile-it/php-openid-client/src/functions/base64url_encode.php', 'c81c91c32460d498a356b65d5a21fc4c' => $vendorDir . '/facile-it/php-openid-client/src/functions/check_server_response.php', diff --git a/lam/lib/3rdParty/composer/composer/autoload_psr4.php b/lam/lib/3rdParty/composer/composer/autoload_psr4.php index d66def799..be0565ff8 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_psr4.php +++ b/lam/lib/3rdParty/composer/composer/autoload_psr4.php @@ -6,52 +6,56 @@ $vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname($vendorDir))); return array( - 'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'), 'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), 'Webklex\\PHPIMAP\\' => array($vendorDir . '/webklex/php-imap/src'), - 'Webauthn\\MetadataService\\' => array($vendorDir . '/web-auth/metadata-service/src'), 'Webauthn\\' => array($vendorDir . '/web-auth/webauthn-lib/src'), 'Symfony\\Polyfill\\Uuid\\' => array($vendorDir . '/symfony/polyfill-uuid'), 'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'), - 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), 'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'), 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), 'Symfony\\Contracts\\HttpClient\\' => array($vendorDir . '/symfony/http-client-contracts'), 'Symfony\\Component\\Uid\\' => array($vendorDir . '/symfony/uid'), 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), + 'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), 'Symfony\\Component\\HttpClient\\' => array($vendorDir . '/symfony/http-client'), + 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), + 'Symfony\\Component\\Clock\\' => array($vendorDir . '/symfony/clock'), 'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'), + 'SpomkyLabs\\Pki\\' => array($vendorDir . '/spomky-labs/pki-framework/src'), 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), 'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'), + 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), - 'Jose\\Easy\\' => array($vendorDir . '/web-token/jwt-easy'), - 'Jose\\Component\\Signature\\Algorithm\\' => array($vendorDir . '/web-token/jwt-signature-algorithm-rsa'), - 'Jose\\Component\\Signature\\' => array($vendorDir . '/web-token/jwt-signature'), - 'Jose\\Component\\KeyManagement\\' => array($vendorDir . '/web-token/jwt-key-mgmt'), - 'Jose\\Component\\Encryption\\' => array($vendorDir . '/web-token/jwt-encryption'), - 'Jose\\Component\\Core\\' => array($vendorDir . '/web-token/jwt-core'), - 'Jose\\Component\\Checker\\' => array($vendorDir . '/web-token/jwt-checker'), - 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/support'), + 'Lcobucci\\Clock\\' => array($vendorDir . '/lcobucci/clock/src'), + 'Jose\\Component\\' => array($vendorDir . '/web-token/jwt-library'), + 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), + 'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support'), 'Illuminate\\Pagination\\' => array($vendorDir . '/illuminate/pagination'), 'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'), 'Http\\Factory\\Guzzle\\' => array($vendorDir . '/http-interop/http-factory-guzzle/src'), 'Http\\Discovery\\' => array($vendorDir . '/php-http/discovery/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), + 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), 'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'), 'Facile\\OpenIDClient\\' => array($vendorDir . '/facile-it/php-openid-client/src'), 'Facile\\JoseVerifier\\' => array($vendorDir . '/facile-it/php-jose-verifier/src'), - 'FG\\' => array($vendorDir . '/fgrosse/phpasn1/lib'), 'Duo\\DuoUniversal\\' => array($vendorDir . '/duosecurity/duo_universal_php/src'), 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'), + 'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'), 'Cose\\' => array($vendorDir . '/web-auth/cose-lib/src'), 'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'), 'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'), @@ -59,5 +63,6 @@ return array( 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), 'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'), 'Base32\\' => array($vendorDir . '/christian-riesen/base32/src'), - 'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'), + 'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'), + 'AESKW\\' => array($vendorDir . '/spomky-labs/aes-key-wrap/src'), ); diff --git a/lam/lib/3rdParty/composer/composer/autoload_static.php b/lam/lib/3rdParty/composer/composer/autoload_static.php index b7ea122bf..a122e385f 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_static.php +++ b/lam/lib/3rdParty/composer/composer/autoload_static.php @@ -7,107 +7,25 @@ namespace Composer\Autoload; class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 { public static $files = array ( - '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', - '60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php', - 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', - 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', - 'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php', - '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', + '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php', + '2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php', '09f6b20656683369174dd6fa83b7e5fb' => __DIR__ . '/..' . '/symfony/polyfill-uuid/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', 'c2b3214084883d700175de676a4fc127' => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src/functions/derived_key.php', '16040cf78e404de30085045d3863ed51' => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src/functions/jose_secret_key.php', - '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', - '51fcf4e06c07cc00c920b44bcd900e7a' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/apc.php', - '288267919fedd3829a7732b5fb202197' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/array.php', - 'a88cd08cfbf1600f7d5de6e587eee1fa' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/datetime.php', - '47f619d9197b36cf5ab70738d7743fe2' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/libevent.php', - 'f1f7d69cca064c8f779d4a4cba463e11' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/misc.php', - '213c1c2258e2e5aa409a0af3e993b3a9' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/password.php', - 'ea6bb8a12ef9b68f6ada99058e530760' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mssql.php', - '9a29089eb3ce41a446744c68a00f118c' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/stats.php', - 'd5947c9df62650029c674c79176af68d' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/strings.php', - '72243e5536b63e298acb6476f01f1aff' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/special_cases.php', - '09f92ed6301edc510574c196c2b7d1af' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mysqli.php', - '3f648889e687f31c52f949ba8a9d0873' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apache.php', - 'eeb4581d958421a4244aaa4167c6a575' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apcu.php', - '04cb0b3c1dac5b5ddb23c14e3d66dbe9' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/array.php', - '450b332a74a9a21e043c5e953485a791' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/bzip2.php', - '6e9b7954ecfd7cbb9ca239319d1acdb6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/calendar.php', - '2c6d7e8bd2de9a272a9d4d43b0a4304a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/classobj.php', - '0b8231c1ad0865447c988a4c16b4001f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/com.php', - '7643a71fe1c3256058c8fee234cb86e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/cubrid.php', - '68e1365710575942efc1d55000032cee' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/curl.php', - '02fd26bca803106c5b942a7197c3ad8b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/datetime.php', - 'f4817dcbd956cd221b1c31f6fbd5749c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/dir.php', - '51c3f2d10ca61a70dbcea0e38d8e902d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/eio.php', - '1d34f34327ca3e81535963016e3be2c3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/errorfunc.php', - '4fd0ba2d3717b0424d474bebfdafa2b4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/exec.php', - '98f4dae054bc7fb19c13be14935cbdd3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fileinfo.php', - '5530ae063ba88323eaf0a07904efdf85' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filesystem.php', - '633f4f134975d70e97bddad83348e91a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filter.php', - 'fbd163fc68c5faf73d5ed4002ffd836d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fpm.php', - '21b511999d61411fab0692ff8795bbed' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ftp.php', - '85fbd73fc92365cd90526b0ea03cae3a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/funchand.php', - 'a2e4c6dfdbf36f56f1945ddcbd54e289' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gettext.php', - '51df9c146e0b7dcbdf358d8abd24dbdc' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gmp.php', - '93bb7fe678d7dcfb1322f8e3475a48b0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gnupg.php', - 'c171ba99cf316379ff66468392bf4950' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/hash.php', - '5ab4aad4c28e468209fbfcceb2e5e6a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibase.php', - '4d57409c5e8e576b0c64c08d9d731cfb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibmDb2.php', - 'eeb246d5403972a9d62106e4a4883496' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/iconv.php', - 'c28a05f498c01b810a714f7214b7a8da' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/image.php', - '8063cd92acdf00fd978b5599eb7cc142' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/imap.php', - '8bd26dbe768e9c9599edad7b198e5446' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/info.php', - 'd4362910bde43c0f956b52527effd7d4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/inotify.php', - '696ba49197d9b55f0428a12bb5a818e1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/json.php', - '9818aaa99c8647c63f8ef62b7a368160' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ldap.php', - 'bcf523ff2a195eb08e0fbb668ed784d0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/libxml.php', - '68be68a9a8b95bb56cab6109ff03bc88' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/lzf.php', - 'bdca804bb0904ea9f53f328dfc0bb8a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mailparse.php', - 'b0a3fcac3eaf55445796d6af26b89366' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mbstring.php', - '98de16b8db03eb0cb4d318b4402215a6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/misc.php', - '7cefd81607cd21b8b3a15656eb6465f5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysql.php', - 'cbac956836b72483dcff1ac39d5c0a0f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/network.php', - '6c8f89dfbdc117d7871f572269363f25' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/oci8.php', - '169a669966a45c06bf55ed029122729b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/opcache.php', - 'def61bf4fecd4d4bca7354919cd69302' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/openssl.php', - '26bb010649a6d32d4120181458aa6ef2' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/outcontrol.php', - '002ebcb842e2c0d5b7f67fe64cc93158' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcntl.php', - '86df38612982dade72c7085ce7eca81f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcre.php', - '1fc22f445c69ea8706e82fce301c0831' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pgsql.php', - 'c70b42561584f7144bff38cd63c4eef3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/posix.php', - '9923214639c32ca5173db03a177d3b63' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ps.php', - '7e9c3f8eae2b5bf42205c4f1295cb7a7' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pspell.php', - '91aa91f6245c349c2e2e88bd0025f199' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/readline.php', - 'd43773cacb9e5e8e897aa255e32007d1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rpminfo.php', - 'f053a3849e9e8383762b34b91db0320b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rrd.php', - '775b964f72f827a1bf87c65ab5b10800' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sem.php', - '816428bd69c29ab5e1ed622af5dca0cd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/session.php', - '5093e233bedbefaef0df262bfbab0a5c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/shmop.php', - 'b080617b1d949683c2e37f8f01dc0e15' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sockets.php', - '2708aa182ddcfe6ce27c96acaaa40f69' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sodium.php', - 'f1b96cb260a5baeea9a7285cda82a1ec' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/solr.php', - '3fd8853757d0fe3557c179efb807afeb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/spl.php', - '9312ce96a51c846913fcda5f186d58dd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sqlsrv.php', - 'd3eb383ad0b8b962b29dc4afd29d6715' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssdeep.php', - '42a09bc448f441a0b9f9367ea975c0bf' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssh2.php', - 'ef711077d356d1b33ca0b10b67b0be8f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/stream.php', - '764b09f6df081cbb2807b97c6ace3866' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/strings.php', - 'ef241678769fee4a44aaa288f3b78aa1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/swoole.php', - '0efc8f6778cba932b9e2a89e28de2452' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uodbc.php', - 'd383d32907b98af53ee9208c62204fd0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uopz.php', - '2fd2e4060f7fe772660f002ce38f0b71' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/url.php', - '782249e03deebeaf57b9991ff5493aa0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/var.php', - '344440cd1cd7200fdb4f12af0d3c587f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xdiff.php', - '3599f369219c658a5fb6c4fe66832f62' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xml.php', - '7fcd313da9fae337051b091b3492c21b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xmlrpc.php', - 'd668c74cfa92d893b582356733d9a80e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaml.php', - '4af1dca6db8c527c6eed27bff85ff0e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaz.php', - 'fe43ca06499ac37bc2dedd823af71eb5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zip.php', - '356736db98a6834f0a886b8d509b0ecd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zlib.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + 'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php', + '8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php', 'ba61337b858c088ff9f16a5fc3badbeb' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/base64url_decode.php', 'd4a8a901fd39fc07eb96403508f8f03f' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/base64url_encode.php', 'c81c91c32460d498a356b65d5a21fc4c' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/check_server_response.php', @@ -120,10 +38,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 ); public static $prefixLengthsPsr4 = array ( - 'v' => - array ( - 'voku\\' => 5, - ), 'p' => array ( 'phpseclib3\\' => 11, @@ -131,23 +45,28 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 'W' => array ( 'Webklex\\PHPIMAP\\' => 16, - 'Webauthn\\MetadataService\\' => 25, 'Webauthn\\' => 9, ), 'S' => array ( 'Symfony\\Polyfill\\Uuid\\' => 22, 'Symfony\\Polyfill\\Php83\\' => 23, - 'Symfony\\Polyfill\\Php80\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31, + 'Symfony\\Polyfill\\Ctype\\' => 23, 'Symfony\\Contracts\\Translation\\' => 30, 'Symfony\\Contracts\\Service\\' => 26, 'Symfony\\Contracts\\HttpClient\\' => 29, 'Symfony\\Component\\Uid\\' => 22, 'Symfony\\Component\\Translation\\' => 30, + 'Symfony\\Component\\String\\' => 25, 'Symfony\\Component\\HttpFoundation\\' => 33, 'Symfony\\Component\\HttpClient\\' => 29, + 'Symfony\\Component\\Console\\' => 26, + 'Symfony\\Component\\Clock\\' => 24, 'Symfony\\Bridge\\PsrHttpMessage\\' => 30, + 'SpomkyLabs\\Pki\\' => 15, ), 'P' => array ( @@ -156,8 +75,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 'Psr\\Http\\Server\\' => 16, 'Psr\\Http\\Message\\' => 17, 'Psr\\Http\\Client\\' => 16, + 'Psr\\EventDispatcher\\' => 20, 'Psr\\Container\\' => 14, 'Psr\\Clock\\' => 10, + 'Psr\\Cache\\' => 10, 'ParagonIE\\ConstantTime\\' => 23, 'PHPMailer\\PHPMailer\\' => 20, ), @@ -165,15 +86,14 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 'Monolog\\' => 8, ), + 'L' => + array ( + 'Lcobucci\\Clock\\' => 15, + ), 'J' => array ( - 'Jose\\Easy\\' => 10, - 'Jose\\Component\\Signature\\Algorithm\\' => 35, - 'Jose\\Component\\Signature\\' => 25, - 'Jose\\Component\\KeyManagement\\' => 29, - 'Jose\\Component\\Encryption\\' => 26, - 'Jose\\Component\\Core\\' => 20, - 'Jose\\Component\\Checker\\' => 23, + 'Jose\\Component\\' => 15, + 'JmesPath\\' => 9, ), 'I' => array ( @@ -189,18 +109,20 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 'G' => array ( 'GuzzleHttp\\Psr7\\' => 16, + 'GuzzleHttp\\Promise\\' => 19, + 'GuzzleHttp\\' => 11, ), 'F' => array ( 'Firebase\\JWT\\' => 13, 'Facile\\OpenIDClient\\' => 20, 'Facile\\JoseVerifier\\' => 20, - 'FG\\' => 3, ), 'D' => array ( 'Duo\\DuoUniversal\\' => 17, 'Doctrine\\Inflector\\' => 19, + 'Doctrine\\Common\\Inflector\\' => 26, ), 'C' => array ( @@ -217,15 +139,12 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 ), 'A' => array ( - 'Assert\\' => 7, + 'Aws\\' => 4, + 'AESKW\\' => 6, ), ); public static $prefixDirsPsr4 = array ( - 'voku\\' => - array ( - 0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku', - ), 'phpseclib3\\' => array ( 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', @@ -234,10 +153,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/webklex/php-imap/src', ), - 'Webauthn\\MetadataService\\' => - array ( - 0 => __DIR__ . '/..' . '/web-auth/metadata-service/src', - ), 'Webauthn\\' => array ( 0 => __DIR__ . '/..' . '/web-auth/webauthn-lib/src', @@ -250,14 +165,22 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php83', ), - 'Symfony\\Polyfill\\Php80\\' => - array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', - ), 'Symfony\\Polyfill\\Mbstring\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), 'Symfony\\Contracts\\Translation\\' => array ( 0 => __DIR__ . '/..' . '/symfony/translation-contracts', @@ -278,6 +201,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/symfony/translation', ), + 'Symfony\\Component\\String\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/string', + ), 'Symfony\\Component\\HttpFoundation\\' => array ( 0 => __DIR__ . '/..' . '/symfony/http-foundation', @@ -286,10 +213,22 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/symfony/http-client', ), + 'Symfony\\Component\\Console\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/console', + ), + 'Symfony\\Component\\Clock\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/clock', + ), 'Symfony\\Bridge\\PsrHttpMessage\\' => array ( 0 => __DIR__ . '/..' . '/symfony/psr-http-message-bridge', ), + 'SpomkyLabs\\Pki\\' => + array ( + 0 => __DIR__ . '/..' . '/spomky-labs/pki-framework/src', + ), 'Psr\\SimpleCache\\' => array ( 0 => __DIR__ . '/..' . '/psr/simple-cache/src', @@ -312,6 +251,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/psr/http-client/src', ), + 'Psr\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src', + ), 'Psr\\Container\\' => array ( 0 => __DIR__ . '/..' . '/psr/container/src', @@ -320,6 +263,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/psr/clock/src', ), + 'Psr\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/cache/src', + ), 'ParagonIE\\ConstantTime\\' => array ( 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', @@ -332,40 +279,21 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog', ), - 'Jose\\Easy\\' => + 'Lcobucci\\Clock\\' => array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-easy', + 0 => __DIR__ . '/..' . '/lcobucci/clock/src', ), - 'Jose\\Component\\Signature\\Algorithm\\' => + 'Jose\\Component\\' => array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-signature-algorithm-rsa', + 0 => __DIR__ . '/..' . '/web-token/jwt-library', ), - 'Jose\\Component\\Signature\\' => + 'JmesPath\\' => array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-signature', - ), - 'Jose\\Component\\KeyManagement\\' => - array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-key-mgmt', - ), - 'Jose\\Component\\Encryption\\' => - array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-encryption', - ), - 'Jose\\Component\\Core\\' => - array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-core', - ), - 'Jose\\Component\\Checker\\' => - array ( - 0 => __DIR__ . '/..' . '/web-token/jwt-checker', + 0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src', ), 'Illuminate\\Support\\' => array ( - 0 => __DIR__ . '/..' . '/illuminate/collections', - 1 => __DIR__ . '/..' . '/illuminate/conditionable', - 2 => __DIR__ . '/..' . '/illuminate/macroable', - 3 => __DIR__ . '/..' . '/illuminate/support', + 0 => __DIR__ . '/..' . '/illuminate/support', ), 'Illuminate\\Pagination\\' => array ( @@ -387,6 +315,14 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', ), + 'GuzzleHttp\\Promise\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src', + ), + 'GuzzleHttp\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src', + ), 'Firebase\\JWT\\' => array ( 0 => __DIR__ . '/..' . '/firebase/php-jwt/src', @@ -399,10 +335,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src', ), - 'FG\\' => - array ( - 0 => __DIR__ . '/..' . '/fgrosse/phpasn1/lib', - ), 'Duo\\DuoUniversal\\' => array ( 0 => __DIR__ . '/..' . '/duosecurity/duo_universal_php/src', @@ -411,6 +343,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector', ), + 'Doctrine\\Common\\Inflector\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Common/Inflector', + ), 'Cose\\' => array ( 0 => __DIR__ . '/..' . '/web-auth/cose-lib/src', @@ -439,14 +375,40 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/christian-riesen/base32/src', ), - 'Assert\\' => + 'Aws\\' => array ( - 0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert', + 0 => __DIR__ . '/..' . '/aws/aws-sdk-php/src', + ), + 'AESKW\\' => + array ( + 0 => __DIR__ . '/..' . '/spomky-labs/aes-key-wrap/src', ), ); public static $classMap = array ( - 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'AWS\\CRT\\Auth\\AwsCredentials' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php', + 'AWS\\CRT\\Auth\\CredentialsProvider' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php', + 'AWS\\CRT\\Auth\\Signable' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php', + 'AWS\\CRT\\Auth\\SignatureType' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php', + 'AWS\\CRT\\Auth\\SignedBodyHeaderType' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php', + 'AWS\\CRT\\Auth\\Signing' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php', + 'AWS\\CRT\\Auth\\SigningAlgorithm' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php', + 'AWS\\CRT\\Auth\\SigningConfigAWS' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php', + 'AWS\\CRT\\Auth\\SigningResult' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php', + 'AWS\\CRT\\Auth\\StaticCredentialsProvider' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php', + 'AWS\\CRT\\CRT' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/CRT.php', + 'AWS\\CRT\\HTTP\\Headers' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php', + 'AWS\\CRT\\HTTP\\Message' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php', + 'AWS\\CRT\\HTTP\\Request' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php', + 'AWS\\CRT\\HTTP\\Response' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php', + 'AWS\\CRT\\IO\\EventLoopGroup' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php', + 'AWS\\CRT\\IO\\InputStream' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php', + 'AWS\\CRT\\Internal\\Encoding' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php', + 'AWS\\CRT\\Internal\\Extension' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php', + 'AWS\\CRT\\Log' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Log.php', + 'AWS\\CRT\\NativeResource' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/NativeResource.php', + 'AWS\\CRT\\OptionValue' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php', + 'AWS\\CRT\\Options' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php', 'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php', @@ -457,99 +419,9 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php', 'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php', 'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', 'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php', - 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php', - 'Safe\\DateTime' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/DateTime.php', - 'Safe\\DateTimeImmutable' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/DateTimeImmutable.php', - 'Safe\\Exceptions\\ApacheException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ApacheException.php', - 'Safe\\Exceptions\\ApcException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/ApcException.php', - 'Safe\\Exceptions\\ApcuException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ApcuException.php', - 'Safe\\Exceptions\\ArrayException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ArrayException.php', - 'Safe\\Exceptions\\Bzip2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Bzip2Exception.php', - 'Safe\\Exceptions\\CalendarException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/CalendarException.php', - 'Safe\\Exceptions\\ClassobjException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ClassobjException.php', - 'Safe\\Exceptions\\ComException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ComException.php', - 'Safe\\Exceptions\\CubridException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/CubridException.php', - 'Safe\\Exceptions\\CurlException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/CurlException.php', - 'Safe\\Exceptions\\DatetimeException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/DatetimeException.php', - 'Safe\\Exceptions\\DirException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/DirException.php', - 'Safe\\Exceptions\\EioException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/EioException.php', - 'Safe\\Exceptions\\ErrorfuncException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ErrorfuncException.php', - 'Safe\\Exceptions\\ExecException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ExecException.php', - 'Safe\\Exceptions\\FileinfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FileinfoException.php', - 'Safe\\Exceptions\\FilesystemException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FilesystemException.php', - 'Safe\\Exceptions\\FilterException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FilterException.php', - 'Safe\\Exceptions\\FpmException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FpmException.php', - 'Safe\\Exceptions\\FtpException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FtpException.php', - 'Safe\\Exceptions\\FunchandException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FunchandException.php', - 'Safe\\Exceptions\\GettextException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GettextException.php', - 'Safe\\Exceptions\\GmpException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GmpException.php', - 'Safe\\Exceptions\\GnupgException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GnupgException.php', - 'Safe\\Exceptions\\HashException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/HashException.php', - 'Safe\\Exceptions\\IbaseException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IbaseException.php', - 'Safe\\Exceptions\\IbmDb2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IbmDb2Exception.php', - 'Safe\\Exceptions\\IconvException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IconvException.php', - 'Safe\\Exceptions\\ImageException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ImageException.php', - 'Safe\\Exceptions\\ImapException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ImapException.php', - 'Safe\\Exceptions\\InfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/InfoException.php', - 'Safe\\Exceptions\\InotifyException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/InotifyException.php', - 'Safe\\Exceptions\\JsonException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/JsonException.php', - 'Safe\\Exceptions\\LdapException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LdapException.php', - 'Safe\\Exceptions\\LibeventException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/LibeventException.php', - 'Safe\\Exceptions\\LibxmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LibxmlException.php', - 'Safe\\Exceptions\\LzfException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LzfException.php', - 'Safe\\Exceptions\\MailparseException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MailparseException.php', - 'Safe\\Exceptions\\MbstringException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MbstringException.php', - 'Safe\\Exceptions\\MiscException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MiscException.php', - 'Safe\\Exceptions\\MssqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/MssqlException.php', - 'Safe\\Exceptions\\MysqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MysqlException.php', - 'Safe\\Exceptions\\MysqliException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/MysqliException.php', - 'Safe\\Exceptions\\NetworkException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/NetworkException.php', - 'Safe\\Exceptions\\Oci8Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Oci8Exception.php', - 'Safe\\Exceptions\\OpcacheException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/OpcacheException.php', - 'Safe\\Exceptions\\OpensslException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/OpensslException.php', - 'Safe\\Exceptions\\OutcontrolException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/OutcontrolException.php', - 'Safe\\Exceptions\\PasswordException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/PasswordException.php', - 'Safe\\Exceptions\\PcntlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PcntlException.php', - 'Safe\\Exceptions\\PcreException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/PcreException.php', - 'Safe\\Exceptions\\PgsqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PgsqlException.php', - 'Safe\\Exceptions\\PosixException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PosixException.php', - 'Safe\\Exceptions\\PsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PsException.php', - 'Safe\\Exceptions\\PspellException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PspellException.php', - 'Safe\\Exceptions\\ReadlineException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ReadlineException.php', - 'Safe\\Exceptions\\RpminfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/RpminfoException.php', - 'Safe\\Exceptions\\RrdException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/RrdException.php', - 'Safe\\Exceptions\\SafeExceptionInterface' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php', - 'Safe\\Exceptions\\SemException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SemException.php', - 'Safe\\Exceptions\\SessionException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SessionException.php', - 'Safe\\Exceptions\\ShmopException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ShmopException.php', - 'Safe\\Exceptions\\SimplexmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/SimplexmlException.php', - 'Safe\\Exceptions\\SocketsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SocketsException.php', - 'Safe\\Exceptions\\SodiumException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SodiumException.php', - 'Safe\\Exceptions\\SolrException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SolrException.php', - 'Safe\\Exceptions\\SplException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SplException.php', - 'Safe\\Exceptions\\SqlsrvException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SqlsrvException.php', - 'Safe\\Exceptions\\SsdeepException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SsdeepException.php', - 'Safe\\Exceptions\\Ssh2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Ssh2Exception.php', - 'Safe\\Exceptions\\StatsException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/StatsException.php', - 'Safe\\Exceptions\\StreamException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/StreamException.php', - 'Safe\\Exceptions\\StringsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/StringsException.php', - 'Safe\\Exceptions\\SwooleException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SwooleException.php', - 'Safe\\Exceptions\\UodbcException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UodbcException.php', - 'Safe\\Exceptions\\UopzException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UopzException.php', - 'Safe\\Exceptions\\UrlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UrlException.php', - 'Safe\\Exceptions\\VarException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/VarException.php', - 'Safe\\Exceptions\\XdiffException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XdiffException.php', - 'Safe\\Exceptions\\XmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XmlException.php', - 'Safe\\Exceptions\\XmlrpcException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XmlrpcException.php', - 'Safe\\Exceptions\\YamlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/YamlException.php', - 'Safe\\Exceptions\\YazException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/YazException.php', - 'Safe\\Exceptions\\ZipException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ZipException.php', - 'Safe\\Exceptions\\ZlibException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ZlibException.php', - 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', - 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', - 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/lam/lib/3rdParty/composer/composer/installed.json b/lam/lib/3rdParty/composer/composer/installed.json index 8ebb16ccb..6503c13a9 100644 --- a/lam/lib/3rdParty/composer/composer/installed.json +++ b/lam/lib/3rdParty/composer/composer/installed.json @@ -1,100 +1,186 @@ { "packages": [ { - "name": "beberlei/assert", - "version": "v3.3.3", - "version_normalized": "3.3.3.0", + "name": "aws/aws-crt-php", + "version": "v1.2.7", + "version_normalized": "1.2.7.0", "source": { "type": "git", - "url": "https://github.com/beberlei/assert.git", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd" + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/b5fd8eacd8915a1b627b8bfc027803f1939734dd", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-simplexml": "*", - "php": "^7.1 || ^8.0" + "php": ">=5.5" }, "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": ">=6.0.0", - "yoast/phpunit-polyfills": "^0.1.0" + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." }, - "time": "2024-07-15T13:18:35+00:00", + "time": "2024-10-18T22:15:13+00:00", "type": "library", "installation-source": "dist", "autoload": { - "files": [ - "lib/Assert/functions.php" - ], - "psr-4": { - "Assert\\": "lib/Assert" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "Apache-2.0" ], "authors": [ { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de", - "role": "Lead Developer" - }, - { - "name": "Richard Quadling", - "email": "rquadling@gmail.com", - "role": "Collaborator" + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" } ], - "description": "Thin assertion library for input validation in business models.", + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", "keywords": [ - "assert", - "assertion", - "validation" + "amazon", + "aws", + "crt", + "sdk" ], "support": { - "issues": "https://github.com/beberlei/assert/issues", - "source": "https://github.com/beberlei/assert/tree/v3.3.3" + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" }, - "install-path": "../beberlei/assert" + "install-path": "../aws/aws-crt-php" }, { - "name": "brick/math", - "version": "0.9.3", - "version_normalized": "0.9.3.0", + "name": "aws/aws-sdk-php", + "version": "3.356.8", + "version_normalized": "3.356.8.0", "source": { "type": "git", - "url": "https://github.com/brick/math.git", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3efa8c62c11fedb17b90f60b2d3a9f815b406e63", + "reference": "3efa8c62c11fedb17b90f60b2d3a9f815b406e63", "shasum": "" }, "require": { + "aws/aws-crt-php": "^1.2.3", "ext-json": "*", - "php": "^7.1 || ^8.0" + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "symfony/filesystem": "^v6.4.0 || ^v7.1.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "time": "2025-08-29T18:06:18+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.356.8" + }, + "install-path": "../aws/aws-sdk-php" + }, + { + "name": "brick/math", + "version": "0.12.3", + "version_normalized": "0.12.3.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", + "shasum": "" + }, + "require": { + "php": "^8.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.9.2" + "phpunit/phpunit": "^10.1", + "vimeo/psalm": "6.8.8" }, - "time": "2021-08-15T20:50:18+00:00", + "time": "2025-02-28T13:11:00+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -114,21 +200,22 @@ "arithmetic", "bigdecimal", "bignum", + "bignumber", "brick", - "math" + "decimal", + "integer", + "math", + "mathematics", + "rational" ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.3" + "source": "https://github.com/brick/math/tree/0.12.3" }, "funding": [ { "url": "https://github.com/BenMorel", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" } ], "install-path": "../brick/math" @@ -265,36 +352,41 @@ }, { "name": "doctrine/inflector", - "version": "2.0.10", - "version_normalized": "2.0.10.0", + "version": "1.4.4", + "version_normalized": "1.4.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, - "time": "2024-02-18T20:23:39+00:00", + "time": "2021-04-16T17:34:40+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "installation-source": "dist", "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector", + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -339,7 +431,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/1.4.4" }, "funding": [ { @@ -359,30 +451,30 @@ }, { "name": "duosecurity/duo_universal_php", - "version": "1.0.2", - "version_normalized": "1.0.2.0", + "version": "1.1.1", + "version_normalized": "1.1.1.0", "source": { "type": "git", "url": "https://github.com/duosecurity/duo_universal_php.git", - "reference": "8734a47480d2d2f0539e8ee782675e052025d026" + "reference": "4ee7253863d84653a60a8cad4b03aa3b66fcfd35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/duosecurity/duo_universal_php/zipball/8734a47480d2d2f0539e8ee782675e052025d026", - "reference": "8734a47480d2d2f0539e8ee782675e052025d026", + "url": "https://api.github.com/repos/duosecurity/duo_universal_php/zipball/4ee7253863d84653a60a8cad4b03aa3b66fcfd35", + "reference": "4ee7253863d84653a60a8cad4b03aa3b66fcfd35", "shasum": "" }, "require": { "ext-curl": "*", "ext-json": "*", "firebase/php-jwt": "^6.0", - "php": ">=7.3" + "php": ">=7.4" }, "require-dev": { "phpunit/phpunit": "^9.0", "squizlabs/php_codesniffer": "3.*" }, - "time": "2023-01-13T18:47:58+00:00", + "time": "2025-08-13T14:05:56+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -391,72 +483,76 @@ } }, "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], "description": "A PHP implementation of the Duo Universal SDK.", "homepage": "https://duo.com/", "support": { "email": "support@duosecurity.com", "issues": "https://github.com/duosecurity/duo_universal_php/issues", - "source": "https://github.com/duosecurity/duo_universal_php/tree/1.0.2" + "source": "https://github.com/duosecurity/duo_universal_php/tree/1.1.1" }, "install-path": "../duosecurity/duo_universal_php" }, { "name": "facile-it/php-jose-verifier", - "version": "0.3.0", - "version_normalized": "0.3.0.0", + "version": "0.4.5", + "version_normalized": "0.4.5.0", "source": { "type": "git", "url": "https://github.com/facile-it/php-jose-verifier.git", - "reference": "b6a3d17896dec0c3e383c0ae83b7be855b8fd247" + "reference": "fe7e092f90ad2a624e69ae989a781258805d9ed0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facile-it/php-jose-verifier/zipball/b6a3d17896dec0c3e383c0ae83b7be855b8fd247", - "reference": "b6a3d17896dec0c3e383c0ae83b7be855b8fd247", + "url": "https://api.github.com/repos/facile-it/php-jose-verifier/zipball/fe7e092f90ad2a624e69ae989a781258805d9ed0", + "reference": "fe7e092f90ad2a624e69ae989a781258805d9ed0", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.2 || ^8.0", "php-http/discovery": "^1.7", + "psr/clock": "^1.0", "psr/http-client": "^1.0", - "psr/http-message": "^1.0", - "psr/simple-cache": "^1.0", + "psr/http-message": "^1.0 || 2.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "spomky-labs/base64url": "^2.0.1", "symfony/polyfill-mbstring": "^1.15", - "web-token/jwt-checker": "^2.2.0", - "web-token/jwt-core": "^2.2.0", - "web-token/jwt-easy": "^2.2.0", - "web-token/jwt-key-mgmt": "^2.2.0", - "web-token/jwt-signature": "^2.2.0", - "web-token/jwt-signature-algorithm-rsa": "^2.2.0" + "web-token/jwt-checker": "^2.2.0 || ^3.0", + "web-token/jwt-core": "^2.2.0 || ^3.0", + "web-token/jwt-key-mgmt": "^2.2.0 || ^3.0", + "web-token/jwt-signature": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-rsa": "^2.2.0 || ^3.0" }, "require-dev": { - "facile-it/facile-coding-standard": "^0.4.1", - "friendsofphp/php-cs-fixer": "^2.16.1", - "laminas/laminas-diactoros": "^2.2", + "facile-it/facile-coding-standard": "^0.5", + "friendsofphp/php-cs-fixer": "^3.0", + "laminas/laminas-diactoros": "^2.2 || ^3.0.0", "php-http/curl-client": "^2.1", "phpspec/prophecy-phpunit": "^1.1 || ^2.0", "phpunit/phpunit": "^8.5.14 || ^9.3", - "vimeo/psalm": "^4.4.1", - "web-token/jwt-encryption": "^2.2.0", - "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0", - "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0", - "web-token/jwt-encryption-algorithm-dir": "^2.2.0", - "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0", - "web-token/jwt-encryption-algorithm-experimental": "^2.2.0", - "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0", - "web-token/jwt-encryption-algorithm-rsa": "^2.2.0", - "web-token/jwt-nested-token": "^2.2.0", - "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0", - "web-token/jwt-signature-algorithm-experimental": "^2.2.0", - "web-token/jwt-signature-algorithm-hmac": "^2.2.0", - "web-token/jwt-signature-algorithm-none": "^2.2.0", - "web-token/jwt-util-ecc": "^2.2.0" + "vimeo/psalm": "^4.30.0 || ^5.13.1", + "web-token/jwt-checker": "^2.2.0 || ^3.2.0", + "web-token/jwt-encryption": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-dir": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-rsa": "^2.2.0 || ^3.0", + "web-token/jwt-nested-token": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-hmac": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-none": "^2.2.0 || ^3.0", + "web-token/jwt-util-ecc": "^2.2.0 || ^3.0" }, - "time": "2021-05-05T11:57:42+00:00", + "time": "2024-04-27T09:47:19+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -493,6 +589,10 @@ "validate", "verifier" ], + "support": { + "issues": "https://github.com/facile-it/php-jose-verifier/issues", + "source": "https://github.com/facile-it/php-jose-verifier/tree/0.4.5" + }, "install-path": "../facile-it/php-jose-verifier" }, { @@ -610,98 +710,19 @@ }, "install-path": "../facile-it/php-openid-client" }, - { - "name": "fgrosse/phpasn1", - "version": "v2.5.0", - "version_normalized": "2.5.0.0", - "source": { - "type": "git", - "url": "https://github.com/fgrosse/PHPASN1.git", - "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b", - "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "~2.0", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "suggest": { - "ext-bcmath": "BCmath is the fallback extension for big integer calculations", - "ext-curl": "For loading OID information from the web if they have not bee defined statically", - "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": "2022-12-19T11:08:26+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "FG\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Friedrich Große", - "email": "friedrich.grosse@gmail.com", - "homepage": "https://github.com/FGrosse", - "role": "Author" - }, - { - "name": "All contributors", - "homepage": "https://github.com/FGrosse/PHPASN1/contributors" - } - ], - "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", - "homepage": "https://github.com/FGrosse/PHPASN1", - "keywords": [ - "DER", - "asn.1", - "asn1", - "ber", - "binary", - "decoding", - "encoding", - "x.509", - "x.690", - "x509", - "x690" - ], - "support": { - "issues": "https://github.com/fgrosse/PHPASN1/issues", - "source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0" - }, - "abandoned": true, - "install-path": "../fgrosse/phpasn1" - }, { "name": "firebase/php-jwt", - "version": "v6.10.2", - "version_normalized": "6.10.2.0", + "version": "v6.11.1", + "version_normalized": "6.11.1.0", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b" + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/30c19ed0f3264cb660ea496895cfb6ef7ee3653b", - "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", "shasum": "" }, "require": { @@ -719,7 +740,7 @@ "ext-sodium": "Support EdDSA (Ed25519) signatures", "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" }, - "time": "2024-11-24T11:22:49+00:00", + "time": "2025-04-09T20:32:01+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -751,23 +772,238 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v6.10.2" + "source": "https://github.com/firebase/php-jwt/tree/v6.11.1" }, "install-path": "../firebase/php-jwt" }, { - "name": "guzzlehttp/psr7", - "version": "2.7.0", - "version_normalized": "2.7.0.0", + "name": "guzzlehttp/guzzle", + "version": "7.10.0", + "version_normalized": "7.10.0.0", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "time": "2025-08-23T22:36:01+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "version_normalized": "2.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "time": "2025-08-22T14:34:08+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "version_normalized": "2.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -783,12 +1019,12 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, - "time": "2024-07-18T11:15:46+00:00", + "time": "2025-08-23T21:21:41+00:00", "type": "library", "extra": { "bamarni-bin": { @@ -856,7 +1092,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -935,138 +1171,29 @@ }, "install-path": "../http-interop/http-factory-guzzle" }, - { - "name": "illuminate/collections", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", - "source": { - "type": "git", - "url": "https://github.com/illuminate/collections.git", - "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/48de3d6bc6aa779112ddcb608a3a96fc975d89d8", - "reference": "48de3d6bc6aa779112ddcb608a3a96fc975d89d8", - "shasum": "" - }, - "require": { - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "php": "^8.1" - }, - "suggest": { - "symfony/var-dumper": "Required to use the dump method (^6.2)." - }, - "time": "2024-11-21T14:02:44+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "helpers.php" - ], - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Collections package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "install-path": "../illuminate/collections" - }, - { - "name": "illuminate/conditionable", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", - "source": { - "type": "git", - "url": "https://github.com/illuminate/conditionable.git", - "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", - "reference": "3ee34ac306fafc2a6f19cd7cd68c9af389e432a5", - "shasum": "" - }, - "require": { - "php": "^8.0.2" - }, - "time": "2024-11-21T14:02:44+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Conditionable package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "install-path": "../illuminate/conditionable" - }, { "name": "illuminate/contracts", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", + "version": "v5.4.36", + "version_normalized": "5.4.36.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74" + "reference": "67f642e018f3e95fb0b2ebffc206c3200391b1ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/f90663a69f926105a70b78060a31f3c64e2d1c74", - "reference": "f90663a69f926105a70b78060a31f3c64e2d1c74", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/67f642e018f3e95fb0b2ebffc206c3200391b1ab", + "reference": "67f642e018f3e95fb0b2ebffc206c3200391b1ab", "shasum": "" }, "require": { - "php": "^8.1", - "psr/container": "^1.1.1|^2.0.1", - "psr/simple-cache": "^1.0|^2.0|^3.0" + "php": ">=5.6.4" }, - "time": "2024-11-21T14:02:44+00:00", + "time": "2017-08-26T23:56:53+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "installation-source": "dist", @@ -1093,82 +1220,31 @@ }, "install-path": "../illuminate/contracts" }, - { - "name": "illuminate/macroable", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", - "source": { - "type": "git", - "url": "https://github.com/illuminate/macroable.git", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", - "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "time": "2023-06-05T12:46:42+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "The Illuminate Macroable package.", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "install-path": "../illuminate/macroable" - }, { "name": "illuminate/pagination", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", + "version": "v5.4.36", + "version_normalized": "5.4.36.0", "source": { "type": "git", "url": "https://github.com/illuminate/pagination.git", - "reference": "616874b9607ff35925347e1710a8b5151858cdf2" + "reference": "ae1540acf02c8b642666d6901c18d2deb5606b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/pagination/zipball/616874b9607ff35925347e1710a8b5151858cdf2", - "reference": "616874b9607ff35925347e1710a8b5151858cdf2", + "url": "https://api.github.com/repos/illuminate/pagination/zipball/ae1540acf02c8b642666d6901c18d2deb5606b47", + "reference": "ae1540acf02c8b642666d6901c18d2deb5606b47", "shasum": "" }, "require": { - "ext-filter": "*", - "illuminate/collections": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0", - "php": "^8.1" + "illuminate/contracts": "5.4.*", + "illuminate/support": "5.4.*", + "php": ">=5.6.4" }, - "time": "2024-04-11T14:31:05+00:00", + "time": "2017-07-24T13:37:02+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "installation-source": "dist", @@ -1197,49 +1273,39 @@ }, { "name": "illuminate/support", - "version": "v10.48.25", - "version_normalized": "10.48.25.0", + "version": "v5.4.36", + "version_normalized": "5.4.36.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c" + "reference": "feab1d1495fd6d38970bd6c83586ba2ace8f299a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/64b258f80175c658aef9e22dd3f2ba18c99b243c", - "reference": "64b258f80175c658aef9e22dd3f2ba18c99b243c", + "url": "https://api.github.com/repos/illuminate/support/zipball/feab1d1495fd6d38970bd6c83586ba2ace8f299a", + "reference": "feab1d1495fd6d38970bd6c83586ba2ace8f299a", "shasum": "" }, "require": { - "doctrine/inflector": "^2.0", - "ext-ctype": "*", - "ext-filter": "*", + "doctrine/inflector": "~1.1", "ext-mbstring": "*", - "illuminate/collections": "^10.0", - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "nesbot/carbon": "^2.67", - "php": "^8.1", - "voku/portable-ascii": "^2.0" + "illuminate/contracts": "5.4.*", + "paragonie/random_compat": "~1.4|~2.0", + "php": ">=5.6.4" }, - "conflict": { - "tightenco/collect": "<5.5.33" + "replace": { + "tightenco/collect": "self.version" }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (^10.0).", - "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", - "ramsey/uuid": "Required to use Str::uuid() (^4.7).", - "symfony/process": "Required to use the composer class (^6.2).", - "symfony/uid": "Required to use Str::ulid() (^6.2).", - "symfony/var-dumper": "Required to use the dd function (^6.2).", - "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." + "illuminate/filesystem": "Required to use the composer class (5.2.*).", + "symfony/process": "Required to use the composer class (~3.2).", + "symfony/var-dumper": "Required to use the dd function (~3.2)." }, - "time": "2024-11-21T14:02:44+00:00", + "time": "2017-08-15T13:25:41+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "installation-source": "dist", @@ -1270,18 +1336,85 @@ "install-path": "../illuminate/support" }, { - "name": "monolog/monolog", - "version": "3.8.0", - "version_normalized": "3.8.0.0", + "name": "lcobucci/clock", + "version": "3.0.0", + "version_normalized": "3.0.0.0", "source": { "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" + "url": "https://github.com/lcobucci/clock.git", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", - "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "infection/infection": "^0.26", + "lcobucci/coding-standard": "^9.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-deprecation-rules": "^1.1.1", + "phpstan/phpstan-phpunit": "^1.3.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.27" + }, + "time": "2022-12-19T15:00:24+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/clock" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "version_normalized": "3.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -1328,7 +1461,7 @@ "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, - "time": "2024-11-12T13:57:08+00:00", + "time": "2025-03-24T10:02:05+00:00", "type": "library", "extra": { "branch-alias": { @@ -1361,7 +1494,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.8.0" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -1376,55 +1509,118 @@ "install-path": "../monolog/monolog" }, { - "name": "nesbot/carbon", - "version": "2.72.5", - "version_normalized": "2.72.5.0", + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "version_normalized": "2.8.0.0", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed" + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed", - "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", "shasum": "" }, "require": { - "carbonphp/carbon-doctrine-types": "*", + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "time": "2024-09-04T18:46:31+00:00", + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "install-path": "../mtdowling/jmespath.php" + }, + { + "name": "nesbot/carbon", + "version": "3.10.2", + "version_normalized": "3.10.2.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", "ext-json": "*", - "php": "^7.1.8 || ^8.0", + "php": "^8.1", "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "provide": { "psr/clock-implementation": "1.0" }, "require-dev": { - "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", - "doctrine/orm": "^2.7 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.0", - "kylekatarnls/multi-tester": "^2.0", - "ondrejmirtes/better-reflection": "*", - "phpmd/phpmd": "^2.9", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.99 || ^1.7.14", - "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", - "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", - "squizlabs/php_codesniffer": "^3.4" + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.75.0", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, - "time": "2024-06-03T19:18:41+00:00", + "time": "2025-08-02T09:36:06+00:00", "bin": [ "bin/carbon" ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.x-dev", - "dev-2.x": "2.x-dev" - }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -1434,6 +1630,10 @@ "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" } }, "installation-source": "dist", @@ -1466,8 +1666,8 @@ ], "support": { "docs": "https://carbon.nesbot.com/docs", - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" }, "funding": [ { @@ -1487,27 +1687,27 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v2.7.0", - "version_normalized": "2.7.0.0", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" }, - "time": "2024-05-08T12:18:48+00:00", + "time": "2024-05-08T12:36:18+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1612,6 +1812,100 @@ }, "install-path": "../paragonie/random_compat" }, + { + "name": "paragonie/sodium_compat", + "version": "v2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/sodium_compat.git", + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb", + "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb", + "shasum": "" + }, + "require": { + "php": "^8.1", + "php-64bit": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9", + "vimeo/psalm": "^4|^5" + }, + "suggest": { + "ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + }, + "time": "2024-09-04T12:51:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com" + }, + { + "name": "Frank Denis", + "email": "jedisct1@pureftpd.org" + } + ], + "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists", + "keywords": [ + "Authentication", + "BLAKE2b", + "ChaCha20", + "ChaCha20-Poly1305", + "Chapoly", + "Curve25519", + "Ed25519", + "EdDSA", + "Edwards-curve Digital Signature Algorithm", + "Elliptic Curve Diffie-Hellman", + "Poly1305", + "Pure-PHP cryptography", + "RFC 7748", + "RFC 8032", + "Salpoly", + "Salsa20", + "X25519", + "XChaCha20-Poly1305", + "XSalsa20-Poly1305", + "Xchacha20", + "Xsalsa20", + "aead", + "cryptography", + "ecdh", + "elliptic curve", + "elliptic curve cryptography", + "encryption", + "libsodium", + "php", + "public-key cryptography", + "secret-key cryptography", + "side-channel resistant" + ], + "support": { + "issues": "https://github.com/paragonie/sodium_compat/issues", + "source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0" + }, + "install-path": "../paragonie/sodium_compat" + }, { "name": "php-http/discovery", "version": "1.20.0", @@ -1696,17 +1990,17 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.3", - "version_normalized": "6.9.3.0", + "version": "v6.10.0", + "version_normalized": "6.10.0.0", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", - "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", + "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144", "shasum": "" }, "require": { @@ -1736,7 +2030,7 @@ "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" }, - "time": "2024-11-24T18:04:13+00:00", + "time": "2025-04-24T15:19:31+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1768,7 +2062,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0" }, "funding": [ { @@ -1780,17 +2074,17 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.42", - "version_normalized": "3.0.42.0", + "version": "3.0.46", + "version_normalized": "3.0.46.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98" + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db92f1b1987b12b13f248fe76c3a52cadb67bb98", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", "shasum": "" }, "require": { @@ -1808,7 +2102,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": "2024-09-16T03:06:04+00:00", + "time": "2025-06-26T16:29:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1873,7 +2167,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.42" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" }, "funding": [ { @@ -1891,6 +2185,58 @@ ], "install-path": "../phpseclib/phpseclib" }, + { + "name": "psr/cache", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-02-03T23:26:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "install-path": "../psr/cache" + }, { "name": "psr/clock", "version": "1.0.0", @@ -1998,6 +2344,59 @@ }, "install-path": "../psr/container" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2019-01-08T18:20:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "install-path": "../psr/event-dispatcher" + }, { "name": "psr/http-client", "version": "1.0.3", @@ -2113,27 +2512,27 @@ }, { "name": "psr/http-message", - "version": "1.1", - "version_normalized": "1.1.0.0", + "version": "2.0", + "version_normalized": "2.0.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, - "time": "2023-04-04T09:50:52+00:00", + "time": "2023-04-04T09:54:51+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "installation-source": "dist", @@ -2149,7 +2548,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -2163,7 +2562,7 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, "install-path": "../psr/http-message" }, @@ -2341,27 +2740,27 @@ }, { "name": "psr/simple-cache", - "version": "1.0.1", - "version_normalized": "1.0.1.0", + "version": "3.0.0", + "version_normalized": "3.0.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, - "time": "2017-10-23T01:57:42+00:00", + "time": "2021-10-29T13:26:27+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0.x-dev" } }, "installation-source": "dist", @@ -2377,7 +2776,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for simple caching", @@ -2388,6 +2787,9 @@ "psr-16", "simple-cache" ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, "install-path": "../psr/simple-cache" }, { @@ -2433,6 +2835,85 @@ "description": "A polyfill for getallheaders.", "install-path": "../ralouphie/getallheaders" }, + { + "name": "spomky-labs/aes-key-wrap", + "version": "v7.0.0", + "version_normalized": "7.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/aes-key-wrap.git", + "reference": "fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/aes-key-wrap/zipball/fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae", + "reference": "fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "php": ">=8.0" + }, + "require-dev": { + "infection/infection": "^0.25.4", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-beberlei-assert": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.0", + "rector/rector": "^0.12.5", + "symplify/easy-coding-standard": "^10.0" + }, + "time": "2021-12-08T20:36:59+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "AESKW\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap/contributors" + } + ], + "description": "AES Key Wrap for PHP.", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap", + "keywords": [ + "A128KW", + "A192KW", + "A256KW", + "RFC3394", + "RFC5649", + "aes", + "key", + "padding", + "wrap" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/aes-key-wrap/issues", + "source": "https://github.com/Spomky-Labs/aes-key-wrap/tree/v7.0.0" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "install-path": "../spomky-labs/aes-key-wrap" + }, { "name": "spomky-labs/base64url", "version": "v2.0.4", @@ -2489,38 +2970,38 @@ }, { "name": "spomky-labs/cbor-php", - "version": "3.1.0", - "version_normalized": "3.1.0.0", + "version": "3.1.1", + "version_normalized": "3.1.1.0", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/cbor-php.git", - "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4" + "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", - "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", + "reference": "5404f3e21cbe72f5cf612aa23db2b922fd2f43bf", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11|^0.12", + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", "ext-mbstring": "*", "php": ">=8.0" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0", + "deptrac/deptrac": "^3.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", "ext-json": "*", "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^10.1|^11.0", - "qossmic/deptrac": "^2.0", - "rector/rector": "^1.0", + "phpstan/phpstan": "^1.0|^2.0", + "phpstan/phpstan-beberlei-assert": "^1.0|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.0|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", "roave/security-advisories": "dev-latest", "symfony/var-dumper": "^6.0|^7.0", "symplify/easy-coding-standard": "^12.0" @@ -2529,7 +3010,7 @@ "ext-bcmath": "GMP or BCMath extensions will drastically improve the library performance. BCMath extension needed to handle the Big Float and Decimal Fraction Tags", "ext-gmp": "GMP or BCMath extensions will drastically improve the library performance" }, - "time": "2024-07-18T08:37:03+00:00", + "time": "2025-06-13T11:57:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2559,7 +3040,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/cbor-php/issues", - "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.0" + "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.1" }, "funding": [ { @@ -2574,32 +3055,326 @@ "install-path": "../spomky-labs/cbor-php" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "name": "spomky-labs/pki-framework", + "version": "1.3.0", + "version_normalized": "1.3.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "url": "https://github.com/Spomky-Labs/pki-framework.git", + "reference": "eced5b5ce70518b983ff2be486e902bbd15135ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/eced5b5ce70518b983ff2be486e902bbd15135ae", + "reference": "eced5b5ce70518b983ff2be486e902bbd15135ae", + "shasum": "" + }, + "require": { + "brick/math": "^0.10|^0.11|^0.12|^0.13", + "ext-mbstring": "*", + "php": ">=8.1" + }, + "require-dev": { + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "ext-gmp": "*", + "ext-openssl": "*", + "infection/infection": "^0.28|^0.29", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "^1.3|^2.0", + "phpstan/phpstan": "^1.8|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.3|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", + "roave/security-advisories": "dev-latest", + "symfony/string": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0" + }, + "suggest": { + "ext-bcmath": "For better performance (or GMP)", + "ext-gmp": "For better performance (or BCMath)", + "ext-openssl": "For OpenSSL based cyphering" + }, + "time": "2025-06-13T08:35:04+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SpomkyLabs\\Pki\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joni Eskelinen", + "email": "jonieske@gmail.com", + "role": "Original developer" + }, + { + "name": "Florent Morselli", + "email": "florent.morselli@spomky-labs.com", + "role": "Spomky-Labs PKI Framework developer" + } + ], + "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", + "homepage": "https://github.com/spomky-labs/pki-framework", + "keywords": [ + "DER", + "Private Key", + "ac", + "algorithm identifier", + "asn.1", + "asn1", + "attribute certificate", + "certificate", + "certification request", + "cryptography", + "csr", + "decrypt", + "ec", + "encrypt", + "pem", + "pkcs", + "public key", + "rsa", + "sign", + "signature", + "verify", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/Spomky-Labs/pki-framework/issues", + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "install-path": "../spomky-labs/pki-framework" + }, + { + "name": "symfony/clock", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "reference": "5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "time": "2025-07-10T08:14:14+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v6.4.24" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/clock" + }, + { + "name": "symfony/console", + "version": "v6.4.25", + "version_normalized": "6.4.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "time": "2025-08-22T10:21:53+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.25" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/console" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2024-09-25T14:21:43+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -2625,7 +3400,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -2645,24 +3420,25 @@ }, { "name": "symfony/http-client", - "version": "v6.4.16", - "version_normalized": "6.4.16.0", + "version": "v6.4.25", + "version_normalized": "6.4.25.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "60a113666fa67e598abace38e5f46a0954d8833d" + "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/60a113666fa67e598abace38e5f46a0954d8833d", - "reference": "60a113666fa67e598abace38e5f46a0954d8833d", + "url": "https://api.github.com/repos/symfony/http-client/zipball/b8e9dce2d8acba3c32af467bb58e0c3656886181", + "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.3|^3.5.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -2690,7 +3466,7 @@ "symfony/process": "^5.4|^6.0|^7.0", "symfony/stopwatch": "^5.4|^6.0|^7.0" }, - "time": "2024-11-27T11:52:33+00:00", + "time": "2025-08-27T07:01:16+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2721,7 +3497,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.16" + "source": "https://github.com/symfony/http-client/tree/v6.4.25" }, "funding": [ { @@ -2732,6 +3508,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2741,31 +3521,31 @@ }, { "name": "symfony/http-client-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9" + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/c2f3ad828596624ca39ea40f83617ef51ca8bbf9", - "reference": "c2f3ad828596624ca39ea40f83617ef51ca8bbf9", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-11-25T12:02:18+00:00", + "time": "2025-04-29T11:18:49+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -2802,7 +3582,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { @@ -2822,17 +3602,17 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.16", - "version_normalized": "6.4.16.0", + "version": "v6.4.25", + "version_normalized": "6.4.25.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57" + "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57", - "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6bc974c0035b643aa497c58d46d9e25185e4b272", + "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272", "shasum": "" }, "require": { @@ -2854,7 +3634,7 @@ "symfony/mime": "^5.4|^6.0|^7.0", "symfony/rate-limiter": "^5.4|^6.0|^7.0" }, - "time": "2024-11-13T18:58:10+00:00", + "time": "2025-08-20T06:48:20+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2882,7 +3662,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.16" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.25" }, "funding": [ { @@ -2893,6 +3673,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2901,35 +3685,295 @@ "install-path": "../symfony/http-foundation" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { "php": ">=7.2" }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2025-06-27T09:58:17+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-grapheme" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, "provide": { "ext-mbstring": "*" }, "suggest": { "ext-mbstring": "For best performance" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2024-12-23T08:48:59+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -2965,7 +4009,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -2976,6 +4020,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2983,113 +4031,30 @@ ], "install-path": "../symfony/polyfill-mbstring" }, - { - "name": "symfony/polyfill-php80", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "time": "2024-09-09T11:45:10+00:00", - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "install-path": "../symfony/polyfill-php80" - }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { "php": ">=7.2" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2025-07-08T02:45:35+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -3127,7 +4092,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -3138,6 +4103,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3147,8 +4116,8 @@ }, { "name": "symfony/polyfill-uuid", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -3173,8 +4142,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -3209,7 +4178,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -3220,6 +4189,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3229,17 +4202,17 @@ }, { "name": "symfony/psr-http-message-bridge", - "version": "v6.4.13", - "version_normalized": "6.4.13.0", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec" + "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/c9cf83326a1074f83a738fc5320945abf7fb7fec", - "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/6954b4e8aef0e5d46f8558c90edcf27bb01b4724", + "reference": "6954b4e8aef0e5d46f8558c90edcf27bb01b4724", "shasum": "" }, "require": { @@ -3261,7 +4234,7 @@ "symfony/framework-bundle": "^6.2|^7.0", "symfony/http-kernel": "^6.2|^7.0" }, - "time": "2024-09-25T14:18:03+00:00", + "time": "2025-07-10T08:14:14+00:00", "type": "symfony-bridge", "installation-source": "dist", "autoload": { @@ -3295,7 +4268,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.13" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.24" }, "funding": [ { @@ -3306,6 +4279,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3315,17 +4292,17 @@ }, { "name": "symfony/service-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -3336,15 +4313,15 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2025-04-25T09:37:31+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -3381,7 +4358,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -3400,18 +4377,111 @@ "install-path": "../symfony/service-contracts" }, { - "name": "symfony/translation", - "version": "v6.4.13", - "version_normalized": "6.4.13.0", + "name": "symfony/string", + "version": "v6.4.25", + "version_normalized": "6.4.25.0", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" + "url": "https://github.com/symfony/string.git", + "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", + "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "time": "2025-08-22T12:33:20+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.4.25" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/string" + }, + { + "name": "symfony/translation", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "300b72643e89de0734d99a9e3f8494a3ef6936e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/300b72643e89de0734d99a9e3f8494a3ef6936e1", + "reference": "300b72643e89de0734d99a9e3f8494a3ef6936e1", "shasum": "" }, "require": { @@ -3448,7 +4518,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2024-09-27T18:14:25+00:00", + "time": "2025-07-30T17:30:48+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3479,7 +4549,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.13" + "source": "https://github.com/symfony/translation/tree/v6.4.24" }, "funding": [ { @@ -3490,6 +4560,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3499,31 +4573,31 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2024-09-27T08:32:26+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -3560,7 +4634,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" }, "funding": [ { @@ -3580,17 +4654,17 @@ }, { "name": "symfony/uid", - "version": "v6.4.13", - "version_normalized": "6.4.13.0", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007" + "reference": "17da16a750541a42cf2183935e0f6008316c23f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007", - "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007", + "url": "https://api.github.com/repos/symfony/uid/zipball/17da16a750541a42cf2183935e0f6008316c23f7", + "reference": "17da16a750541a42cf2183935e0f6008316c23f7", "shasum": "" }, "require": { @@ -3600,7 +4674,7 @@ "require-dev": { "symfony/console": "^5.4|^6.0|^7.0" }, - "time": "2024-09-25T14:18:03+00:00", + "time": "2025-07-10T08:14:14+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3637,7 +4711,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.4.13" + "source": "https://github.com/symfony/uid/tree/v6.4.24" }, "funding": [ { @@ -3648,6 +4722,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3655,267 +4733,48 @@ ], "install-path": "../symfony/uid" }, - { - "name": "thecodingmachine/safe", - "version": "v2.5.0", - "version_normalized": "2.5.0.0", - "source": { - "type": "git", - "url": "https://github.com/thecodingmachine/safe.git", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.2", - "thecodingmachine/phpstan-strict-rules": "^1.0" - }, - "time": "2023-04-05T11:54:14+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "deprecated/apc.php", - "deprecated/array.php", - "deprecated/datetime.php", - "deprecated/libevent.php", - "deprecated/misc.php", - "deprecated/password.php", - "deprecated/mssql.php", - "deprecated/stats.php", - "deprecated/strings.php", - "lib/special_cases.php", - "deprecated/mysqli.php", - "generated/apache.php", - "generated/apcu.php", - "generated/array.php", - "generated/bzip2.php", - "generated/calendar.php", - "generated/classobj.php", - "generated/com.php", - "generated/cubrid.php", - "generated/curl.php", - "generated/datetime.php", - "generated/dir.php", - "generated/eio.php", - "generated/errorfunc.php", - "generated/exec.php", - "generated/fileinfo.php", - "generated/filesystem.php", - "generated/filter.php", - "generated/fpm.php", - "generated/ftp.php", - "generated/funchand.php", - "generated/gettext.php", - "generated/gmp.php", - "generated/gnupg.php", - "generated/hash.php", - "generated/ibase.php", - "generated/ibmDb2.php", - "generated/iconv.php", - "generated/image.php", - "generated/imap.php", - "generated/info.php", - "generated/inotify.php", - "generated/json.php", - "generated/ldap.php", - "generated/libxml.php", - "generated/lzf.php", - "generated/mailparse.php", - "generated/mbstring.php", - "generated/misc.php", - "generated/mysql.php", - "generated/network.php", - "generated/oci8.php", - "generated/opcache.php", - "generated/openssl.php", - "generated/outcontrol.php", - "generated/pcntl.php", - "generated/pcre.php", - "generated/pgsql.php", - "generated/posix.php", - "generated/ps.php", - "generated/pspell.php", - "generated/readline.php", - "generated/rpminfo.php", - "generated/rrd.php", - "generated/sem.php", - "generated/session.php", - "generated/shmop.php", - "generated/sockets.php", - "generated/sodium.php", - "generated/solr.php", - "generated/spl.php", - "generated/sqlsrv.php", - "generated/ssdeep.php", - "generated/ssh2.php", - "generated/stream.php", - "generated/strings.php", - "generated/swoole.php", - "generated/uodbc.php", - "generated/uopz.php", - "generated/url.php", - "generated/var.php", - "generated/xdiff.php", - "generated/xml.php", - "generated/xmlrpc.php", - "generated/yaml.php", - "generated/yaz.php", - "generated/zip.php", - "generated/zlib.php" - ], - "classmap": [ - "lib/DateTime.php", - "lib/DateTimeImmutable.php", - "lib/Exceptions/", - "deprecated/Exceptions/", - "generated/Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "support": { - "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v2.5.0" - }, - "install-path": "../thecodingmachine/safe" - }, - { - "name": "voku/portable-ascii", - "version": "2.0.3", - "version_normalized": "2.0.3.0", - "source": { - "type": "git", - "url": "https://github.com/voku/portable-ascii.git", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "shasum": "" - }, - "require": { - "php": ">=7.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" - }, - "suggest": { - "ext-intl": "Use Intl for transliterator_transliterate() support" - }, - "time": "2024-11-21T01:49:47+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "voku\\": "src/voku/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Lars Moelleken", - "homepage": "https://www.moelleken.org/" - } - ], - "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", - "homepage": "https://github.com/voku/portable-ascii", - "keywords": [ - "ascii", - "clean", - "php" - ], - "support": { - "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.3" - }, - "funding": [ - { - "url": "https://www.paypal.me/moelleken", - "type": "custom" - }, - { - "url": "https://github.com/voku", - "type": "github" - }, - { - "url": "https://opencollective.com/portable-ascii", - "type": "open_collective" - }, - { - "url": "https://www.patreon.com/voku", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", - "type": "tidelift" - } - ], - "install-path": "../voku/portable-ascii" - }, { "name": "web-auth/cose-lib", - "version": "4.0.13", - "version_normalized": "4.0.13.0", + "version": "4.4.2", + "version_normalized": "4.4.2.0", "source": { "type": "git", "url": "https://github.com/web-auth/cose-lib.git", - "reference": "fc733974fe12b550b54a94a08e4e184aca0015e5" + "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/fc733974fe12b550b54a94a08e4e184aca0015e5", - "reference": "fc733974fe12b550b54a94a08e4e184aca0015e5", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/a93b61c48fb587855f64a9ec11ad7b60e867cb15", + "reference": "a93b61c48fb587855f64a9ec11ad7b60e867cb15", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10", + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", - "fgrosse/phpasn1": "^2.1", - "php": ">=8.1" + "php": ">=8.1", + "spomky-labs/pki-framework": "^1.0" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0", - "infection/infection": "^0.26.12", + "deptrac/deptrac": "^3.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "^9.5", - "qossmic/deptrac-shim": "^0.24.0", - "rector/rector": "^0.14", - "symfony/phpunit-bridge": "^6.1", - "symplify/easy-coding-standard": "^11.0" + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.7|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0" }, "suggest": { "ext-bcmath": "For better performance, please install either GMP (recommended) or BCMath extension", "ext-gmp": "For better performance, please install either GMP (recommended) or BCMath extension" }, - "time": "2022-09-17T08:34:42+00:00", + "time": "2025-08-14T20:33:29+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3945,7 +4804,7 @@ ], "support": { "issues": "https://github.com/web-auth/cose-lib/issues", - "source": "https://github.com/web-auth/cose-lib/tree/4.0.13" + "source": "https://github.com/web-auth/cose-lib/tree/4.4.2" }, "funding": [ { @@ -3959,121 +4818,57 @@ ], "install-path": "../web-auth/cose-lib" }, - { - "name": "web-auth/metadata-service", - "version": "v4.0.5", - "version_normalized": "4.0.5.0", - "source": { - "type": "git", - "url": "https://github.com/web-auth/webauthn-metadata-service.git", - "reference": "2bc26efc09d280f87777c736f404a2d875d6e7c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/2bc26efc09d280f87777c736f404a2d875d6e7c4", - "reference": "2bc26efc09d280f87777c736f404a2d875d6e7c4", - "shasum": "" - }, - "require": { - "beberlei/assert": "^3.2", - "ext-json": "*", - "paragonie/constant_time_encoding": "^2.4", - "php": ">=8.1", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/log": "^2.0|^3.0" - }, - "suggest": { - "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for fetching Metadata Statement from distant sources", - "web-token/jwt-signature-algorithm-ecdsa": "Mandatory for fetching Metadata Statement from distant sources" - }, - "time": "2022-06-22T11:14:44+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Webauthn\\MetadataService\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-auth/metadata-service/contributors" - } - ], - "description": "Metadata Service for FIDO2/Webauthn", - "homepage": "https://github.com/web-auth", - "keywords": [ - "FIDO2", - "fido", - "webauthn" - ], - "support": { - "source": "https://github.com/web-auth/webauthn-metadata-service/tree/v4.0.5" - }, - "funding": [ - { - "url": "https://github.com/Spomky", - "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "install-path": "../web-auth/metadata-service" - }, { "name": "web-auth/webauthn-lib", - "version": "v4.0.5", - "version_normalized": "4.0.5.0", + "version": "4.9.2", + "version_normalized": "4.9.2.0", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "1b02740ab8539f025419380c9e4c41b090c6cf47" + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/1b02740ab8539f025419380c9e4c41b090c6cf47", - "reference": "1b02740ab8539f025419380c9e4c41b090c6cf47", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/008b25171c27cf4813420d0de31cc059bcc71f1a", + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a", "shasum": "" }, "require": { - "beberlei/assert": "^3.2", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "fgrosse/phpasn1": "^2.1", - "paragonie/constant_time_encoding": "^2.4", + "lcobucci/clock": "^2.2|^3.0", + "paragonie/constant_time_encoding": "^2.6|^3.0", "php": ">=8.1", + "psr/clock": "^1.0", + "psr/event-dispatcher": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "psr/log": "^2.0|^3.0", + "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", - "symfony/uid": "^6.0", - "thecodingmachine/safe": "^2.0", - "web-auth/cose-lib": "^4.0", - "web-auth/metadata-service": "self.version" + "spomky-labs/pki-framework": "^1.0", + "symfony/deprecation-contracts": "^3.2", + "symfony/uid": "^6.1|^7.0", + "web-auth/cose-lib": "^4.2.3" }, "suggest": { + "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", + "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-ecdsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-eddsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-rsa": "Mandatory for the AndroidSafetyNet Attestation Statement support" + "symfony/event-dispatcher": "Recommended to use dispatched events", + "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" }, - "time": "2022-06-23T16:25:36+00:00", + "time": "2025-01-04T09:47:58+00:00", "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/web-auth/webauthn-framework", + "name": "web-auth/webauthn-framework" + } + }, "installation-source": "dist", "autoload": { "psr-4": { @@ -4102,7 +4897,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/v4.0.5" + "source": "https://github.com/web-auth/webauthn-lib/tree/4.9.2" }, "funding": [ { @@ -4118,30 +4913,27 @@ }, { "name": "web-token/jwt-checker", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", + "version": "3.4.8", + "version_normalized": "3.4.8.0", "source": { "type": "git", "url": "https://github.com/web-token/jwt-checker.git", - "reference": "5f31d98155951739e2fae7455e8466ccddd08f50" + "reference": "973ab960dd1761b00fce24a7cf2ec2a328499a58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-checker/zipball/5f31d98155951739e2fae7455e8466ccddd08f50", - "reference": "5f31d98155951739e2fae7455e8466ccddd08f50", + "url": "https://api.github.com/repos/web-token/jwt-checker/zipball/973ab960dd1761b00fce24a7cf2ec2a328499a58", + "reference": "973ab960dd1761b00fce24a7cf2ec2a328499a58", "shasum": "" }, "require": { - "web-token/jwt-core": "^2.1" + "php": ">=8.1", + "psr/clock": "^1.0", + "web-token/jwt-library": "^3.3" }, - "time": "2021-03-17T14:55:52+00:00", + "time": "2024-02-22T07:19:34+00:00", "type": "library", "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Component\\Checker\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4153,10 +4945,10 @@ }, { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-checker/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Checker component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4176,42 +4968,45 @@ "jwt", "symfony" ], + "support": { + "source": "https://github.com/web-token/jwt-checker/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", "install-path": "../web-token/jwt-checker" }, { "name": "web-token/jwt-core", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", + "version": "3.4.8", + "version_normalized": "3.4.8.0", "source": { "type": "git", "url": "https://github.com/web-token/jwt-core.git", - "reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678" + "reference": "0a47aa6096024af3bff8082e47e27219b9889542" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-core/zipball/53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678", - "reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678", + "url": "https://api.github.com/repos/web-token/jwt-core/zipball/0a47aa6096024af3bff8082e47e27219b9889542", + "reference": "0a47aa6096024af3bff8082e47e27219b9889542", "shasum": "" }, "require": { - "brick/math": "^0.8.17|^0.9", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-json": "*", "ext-mbstring": "*", - "fgrosse/phpasn1": "^2.0", - "php": ">=7.2", - "spomky-labs/base64url": "^1.0|^2.0" + "paragonie/constant_time_encoding": "^2.6|^3.0", + "php": ">=8.1", + "spomky-labs/pki-framework": "^1.2.1", + "web-token/jwt-library": "^3.3" }, - "conflict": { - "spomky-labs/jose": "*" - }, - "time": "2021-03-17T14:55:52+00:00", + "time": "2024-06-24T16:31:57+00:00", "type": "library", "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Component\\Core\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4226,7 +5021,7 @@ "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Core component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4246,51 +5041,40 @@ "jwt", "symfony" ], + "support": { + "source": "https://github.com/web-token/jwt-core/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", "install-path": "../web-token/jwt-core" }, { - "name": "web-token/jwt-easy", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", + "name": "web-token/jwt-encryption", + "version": "3.4.8", + "version_normalized": "3.4.8.0", "source": { "type": "git", - "url": "https://github.com/web-token/jwt-easy.git", - "reference": "01db23252bb53d4fd36975b55dd58466bab1bb30" + "url": "https://github.com/web-token/jwt-encryption.git", + "reference": "3e4b1c4080a77a6e97b62b33562805c1fc552b5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-easy/zipball/01db23252bb53d4fd36975b55dd58466bab1bb30", - "reference": "01db23252bb53d4fd36975b55dd58466bab1bb30", + "url": "https://api.github.com/repos/web-token/jwt-encryption/zipball/3e4b1c4080a77a6e97b62b33562805c1fc552b5e", + "reference": "3e4b1c4080a77a6e97b62b33562805c1fc552b5e", "shasum": "" }, "require": { - "web-token/jwt-checker": "^2.1", - "web-token/jwt-encryption": "^2.1", - "web-token/jwt-signature": "^2.1" + "php": ">=8.1", + "web-token/jwt-library": "^3.3" }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "Adds AES-CBC based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "Adds AES-GCM based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "Adds AES-GCM Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "Adds AES Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-dir": "Adds Direct encryption algorithm", - "web-token/jwt-encryption-algorithm-ecdh-es": "Adds ECDH-ES based encryption algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "Adds PBES2 based encryption algorithms", - "web-token/jwt-encryption-algorithm-rsa": "Adds RSA based encryption algorithms", - "web-token/jwt-signature-algorithm-ecdsa": "Adds ECDSA based signature algorithms", - "web-token/jwt-signature-algorithm-eddsa": "Adds EdDSA based signature algorithms", - "web-token/jwt-signature-algorithm-hmac": "Adds HMAC based signature algorithms", - "web-token/jwt-signature-algorithm-none": "Adds none signature algorithms", - "web-token/jwt-signature-algorithm-rsa": "Adds RSA based signature algorithms" - }, - "time": "2021-03-17T14:55:52+00:00", + "time": "2024-02-22T07:19:34+00:00", "type": "library", "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Easy\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4305,7 +5089,7 @@ "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Easy toolset to use the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4325,116 +5109,43 @@ "jwt", "symfony" ], - "install-path": "../web-token/jwt-easy" - }, - { - "name": "web-token/jwt-encryption", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-encryption.git", - "reference": "3b8d67d7c5c013750703e7c27f1001544407bbb2" + "support": { + "source": "https://github.com/web-token/jwt-encryption/tree/3.4.8" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-encryption/zipball/3b8d67d7c5c013750703e7c27f1001544407bbb2", - "reference": "3b8d67d7c5c013750703e7c27f1001544407bbb2", - "shasum": "" - }, - "require": { - "web-token/jwt-core": "^2.1" - }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "AES CBC Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "AES GCM Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "AES GCM Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "AES Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-dir": "Direct Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-ecdh-es": "ECDH-ES Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-experimental": "Experimental Key and Signature Algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "PBES2 Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-rsa": "RSA Based Key Encryption Algorithms" - }, - "time": "2021-03-17T14:55:52+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Component\\Encryption\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-encryption/contributors" + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" } ], - "description": "Encryption component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], + "abandoned": "web-token/jwt-library", "install-path": "../web-token/jwt-encryption" }, { "name": "web-token/jwt-key-mgmt", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", + "version": "3.4.8", + "version_normalized": "3.4.8.0", "source": { "type": "git", "url": "https://github.com/web-token/jwt-key-mgmt.git", - "reference": "0b116379515700d237b4e5de86879078ccb09d8a" + "reference": "4d2a5a1a86477dd50b89aff76962816ddbd64590" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/0b116379515700d237b4e5de86879078ccb09d8a", - "reference": "0b116379515700d237b4e5de86879078ccb09d8a", + "url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/4d2a5a1a86477dd50b89aff76962816ddbd64590", + "reference": "4d2a5a1a86477dd50b89aff76962816ddbd64590", "shasum": "" }, "require": { "ext-openssl": "*", + "php": ">=8.1", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "web-token/jwt-core": "^2.0" + "web-token/jwt-library": "^3.3" }, - "suggest": { - "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", - "php-http/httplug": "To enable JKU/X5U support.", - "php-http/message-factory": "To enable JKU/X5U support.", - "web-token/jwt-util-ecc": "To use EC key analyzers." - }, - "time": "2021-03-17T14:55:52+00:00", + "time": "2024-02-22T07:19:34+00:00", "type": "library", "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Component\\KeyManagement\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -4446,10 +5157,10 @@ }, { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-key-mgmt/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Key Management component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4469,108 +5180,67 @@ "jwt", "symfony" ], + "support": { + "source": "https://github.com/web-token/jwt-key-mgmt/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", "install-path": "../web-token/jwt-key-mgmt" }, { - "name": "web-token/jwt-signature", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", + "name": "web-token/jwt-library", + "version": "3.4.8", + "version_normalized": "3.4.8.0", "source": { "type": "git", - "url": "https://github.com/web-token/jwt-signature.git", - "reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103" + "url": "https://github.com/web-token/jwt-library.git", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/015b59aaf3b6e8fb9f5bd1338845b7464c7d8103", - "reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103", + "url": "https://api.github.com/repos/web-token/jwt-library/zipball/92445671cc788fa5f639898a67c06f9fd0bf491f", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f", "shasum": "" }, "require": { - "web-token/jwt-core": "^2.1" + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "ext-json": "*", + "ext-mbstring": "*", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/clock": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "spomky-labs/pki-framework": "^1.2.1", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.12" }, - "suggest": { - "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms", - "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", - "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", - "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms" - }, - "time": "2021-03-01T19:55:28+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-signature/contributors" - } - ], - "description": "Signature component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "install-path": "../web-token/jwt-signature" - }, - { - "name": "web-token/jwt-signature-algorithm-rsa", - "version": "v2.2.11", - "version_normalized": "2.2.11.0", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-signature-algorithm-rsa.git", - "reference": "513ad90eb5ef1886ff176727a769bda4618141b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-rsa/zipball/513ad90eb5ef1886ff176727a769bda4618141b0", - "reference": "513ad90eb5ef1886ff176727a769bda4618141b0", - "shasum": "" - }, - "require": { - "brick/math": "^0.8.17|^0.9", - "ext-openssl": "*", - "web-token/jwt-signature": "^2.1" + "conflict": { + "spomky-labs/jose": "*" }, "suggest": { "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", - "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance" + "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance", + "ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)", + "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW...)", + "symfony/http-client": "To enable JKU/X5U support." }, - "time": "2021-01-21T19:18:03+00:00", + "time": "2025-05-07T09:11:18+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Jose\\Component\\Signature\\Algorithm\\": "" + "Jose\\Component\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -4587,7 +5257,7 @@ "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "RSA Based Signature Algorithms the JWT Framework.", + "description": "JWT library", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -4607,21 +5277,173 @@ "jwt", "symfony" ], + "support": { + "issues": "https://github.com/web-token/jwt-library/issues", + "source": "https://github.com/web-token/jwt-library/tree/3.4.8" + }, + "funding": [ + { + "url": "https://github.com/Spomky", + "type": "github" + }, + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "install-path": "../web-token/jwt-library" + }, + { + "name": "web-token/jwt-signature", + "version": "3.4.8", + "version_normalized": "3.4.8.0", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-signature.git", + "reference": "eccfd59e658d4118414cf6d14229aa52eec387e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/eccfd59e658d4118414cf6d14229aa52eec387e7", + "reference": "eccfd59e658d4118414cf6d14229aa52eec387e7", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "web-token/jwt-library": "^3.3" + }, + "time": "2024-02-22T07:19:34+00:00", + "type": "library", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-signature/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", + "install-path": "../web-token/jwt-signature" + }, + { + "name": "web-token/jwt-signature-algorithm-rsa", + "version": "3.4.8", + "version_normalized": "3.4.8.0", + "source": { + "type": "git", + "url": "https://github.com/web-token/jwt-signature-algorithm-rsa.git", + "reference": "4408e41671294f0390731e2f84065a03a8089ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-rsa/zipball/4408e41671294f0390731e2f84065a03a8089ace", + "reference": "4408e41671294f0390731e2f84065a03a8089ace", + "shasum": "" + }, + "require": { + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "ext-openssl": "*", + "php": ">=8.1", + "web-token/jwt-library": "^3.3" + }, + "time": "2024-02-22T07:19:34+00:00", + "type": "library", + "installation-source": "dist", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", + "homepage": "https://github.com/web-token", + "keywords": [ + "JOSE", + "JWE", + "JWK", + "JWKSet", + "JWS", + "Jot", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "bundle", + "jwa", + "jwt", + "symfony" + ], + "support": { + "source": "https://github.com/web-token/jwt-signature-algorithm-rsa/tree/3.4.8" + }, + "funding": [ + { + "url": "https://www.patreon.com/FlorentMorselli", + "type": "patreon" + } + ], + "abandoned": "web-token/jwt-library", "install-path": "../web-token/jwt-signature-algorithm-rsa" }, { "name": "webklex/php-imap", - "version": "5.5.0", - "version_normalized": "5.5.0.0", + "version": "6.2.0", + "version_normalized": "6.2.0.0", "source": { "type": "git", "url": "https://github.com/Webklex/php-imap.git", - "reference": "3c23c8f66b772ce8597772816e068326559e7e4b" + "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Webklex/php-imap/zipball/3c23c8f66b772ce8597772816e068326559e7e4b", - "reference": "3c23c8f66b772ce8597772816e068326559e7e4b", + "url": "https://api.github.com/repos/Webklex/php-imap/zipball/6b8ef85d621bbbaf52741b00cca8e9237e2b2e05", + "reference": "6b8ef85d621bbbaf52741b00cca8e9237e2b2e05", "shasum": "" }, "require": { @@ -4633,7 +5455,7 @@ "ext-openssl": "*", "ext-zip": "*", "illuminate/pagination": ">=5.0.0", - "nesbot/carbon": "^2.62.1", + "nesbot/carbon": "^2.62.1|^3.2.4", "php": "^8.0.2", "symfony/http-foundation": ">=2.8.0" }, @@ -4644,11 +5466,11 @@ "symfony/mime": "Recomended for better extension support", "symfony/var-dumper": "Usefull tool for debugging" }, - "time": "2023-06-28T01:57:03+00:00", + "time": "2025-04-25T06:02:37+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "6.0-dev" } }, "installation-source": "dist", @@ -4679,7 +5501,7 @@ ], "support": { "issues": "https://github.com/Webklex/php-imap/issues", - "source": "https://github.com/Webklex/php-imap/tree/5.5.0" + "source": "https://github.com/Webklex/php-imap/tree/6.2.0" }, "funding": [ { diff --git a/lam/lib/3rdParty/composer/composer/installed.php b/lam/lib/3rdParty/composer/composer/installed.php index d19292182..5d551eda0 100644 --- a/lam/lib/3rdParty/composer/composer/installed.php +++ b/lam/lib/3rdParty/composer/composer/installed.php @@ -1,8 +1,8 @@ array( 'name' => 'ldap-account-manager/ldap-account-manager', - 'pretty_version' => '9.0', - 'version' => '9.0.0.0', + 'pretty_version' => '9.3', + 'version' => '9.3.0.0', 'reference' => null, 'type' => 'library', 'install_path' => __DIR__ . '/../../../../', @@ -10,19 +10,28 @@ 'dev' => true, ), 'versions' => array( - 'beberlei/assert' => array( - 'pretty_version' => 'v3.3.3', - 'version' => '3.3.3.0', - 'reference' => 'b5fd8eacd8915a1b627b8bfc027803f1939734dd', + 'aws/aws-crt-php' => array( + 'pretty_version' => 'v1.2.7', + 'version' => '1.2.7.0', + 'reference' => 'd71d9906c7bb63a28295447ba12e74723bd3730e', 'type' => 'library', - 'install_path' => __DIR__ . '/../beberlei/assert', + 'install_path' => __DIR__ . '/../aws/aws-crt-php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'aws/aws-sdk-php' => array( + 'pretty_version' => '3.356.8', + 'version' => '3.356.8.0', + 'reference' => '3efa8c62c11fedb17b90f60b2d3a9f815b406e63', + 'type' => 'library', + 'install_path' => __DIR__ . '/../aws/aws-sdk-php', 'aliases' => array(), 'dev_requirement' => false, ), 'brick/math' => array( - 'pretty_version' => '0.9.3', - 'version' => '0.9.3.0', - 'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae', + 'pretty_version' => '0.12.3', + 'version' => '0.12.3.0', + 'reference' => '866551da34e9a618e64a819ee1e01c20d8a588ba', 'type' => 'library', 'install_path' => __DIR__ . '/../brick/math', 'aliases' => array(), @@ -47,27 +56,27 @@ 'dev_requirement' => false, ), 'doctrine/inflector' => array( - 'pretty_version' => '2.0.10', - 'version' => '2.0.10.0', - 'reference' => '5817d0659c5b50c9b950feb9af7b9668e2c436bc', + 'pretty_version' => '1.4.4', + 'version' => '1.4.4.0', + 'reference' => '4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/inflector', 'aliases' => array(), 'dev_requirement' => false, ), 'duosecurity/duo_universal_php' => array( - 'pretty_version' => '1.0.2', - 'version' => '1.0.2.0', - 'reference' => '8734a47480d2d2f0539e8ee782675e052025d026', + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'reference' => '4ee7253863d84653a60a8cad4b03aa3b66fcfd35', 'type' => 'library', 'install_path' => __DIR__ . '/../duosecurity/duo_universal_php', 'aliases' => array(), 'dev_requirement' => false, ), 'facile-it/php-jose-verifier' => array( - 'pretty_version' => '0.3.0', - 'version' => '0.3.0.0', - 'reference' => 'b6a3d17896dec0c3e383c0ae83b7be855b8fd247', + 'pretty_version' => '0.4.5', + 'version' => '0.4.5.0', + 'reference' => 'fe7e092f90ad2a624e69ae989a781258805d9ed0', 'type' => 'library', 'install_path' => __DIR__ . '/../facile-it/php-jose-verifier', 'aliases' => array(), @@ -82,28 +91,37 @@ 'aliases' => array(), 'dev_requirement' => false, ), - 'fgrosse/phpasn1' => array( - 'pretty_version' => 'v2.5.0', - 'version' => '2.5.0.0', - 'reference' => '42060ed45344789fb9f21f9f1864fc47b9e3507b', - 'type' => 'library', - 'install_path' => __DIR__ . '/../fgrosse/phpasn1', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'firebase/php-jwt' => array( - 'pretty_version' => 'v6.10.2', - 'version' => '6.10.2.0', - 'reference' => '30c19ed0f3264cb660ea496895cfb6ef7ee3653b', + 'pretty_version' => 'v6.11.1', + 'version' => '6.11.1.0', + 'reference' => 'd1e91ecf8c598d073d0995afa8cd5c75c6e19e66', 'type' => 'library', 'install_path' => __DIR__ . '/../firebase/php-jwt', 'aliases' => array(), 'dev_requirement' => false, ), + 'guzzlehttp/guzzle' => array( + 'pretty_version' => '7.10.0', + 'version' => '7.10.0.0', + 'reference' => 'b51ac707cfa420b7bfd4e4d5e510ba8008e822b4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/promises' => array( + 'pretty_version' => '2.3.0', + 'version' => '2.3.0.0', + 'reference' => '481557b130ef3790cf82b713667b43030dc9c957', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/promises', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'guzzlehttp/psr7' => array( - 'pretty_version' => '2.7.0', - 'version' => '2.7.0.0', - 'reference' => 'a70f5c95fb43bc83f07c9c948baa0dc1829bf201', + 'pretty_version' => '2.8.0', + 'version' => '2.8.0.0', + 'reference' => '21dc724a0583619cd1652f673303492272778051', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), @@ -118,63 +136,45 @@ 'aliases' => array(), 'dev_requirement' => false, ), - 'illuminate/collections' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => '48de3d6bc6aa779112ddcb608a3a96fc975d89d8', - 'type' => 'library', - 'install_path' => __DIR__ . '/../illuminate/collections', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'illuminate/conditionable' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => '3ee34ac306fafc2a6f19cd7cd68c9af389e432a5', - 'type' => 'library', - 'install_path' => __DIR__ . '/../illuminate/conditionable', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'illuminate/contracts' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => 'f90663a69f926105a70b78060a31f3c64e2d1c74', + 'pretty_version' => 'v5.4.36', + 'version' => '5.4.36.0', + 'reference' => '67f642e018f3e95fb0b2ebffc206c3200391b1ab', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/contracts', 'aliases' => array(), 'dev_requirement' => false, ), - 'illuminate/macroable' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => 'dff667a46ac37b634dcf68909d9d41e94dc97c27', - 'type' => 'library', - 'install_path' => __DIR__ . '/../illuminate/macroable', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'illuminate/pagination' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => '616874b9607ff35925347e1710a8b5151858cdf2', + 'pretty_version' => 'v5.4.36', + 'version' => '5.4.36.0', + 'reference' => 'ae1540acf02c8b642666d6901c18d2deb5606b47', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/pagination', 'aliases' => array(), 'dev_requirement' => false, ), 'illuminate/support' => array( - 'pretty_version' => 'v10.48.25', - 'version' => '10.48.25.0', - 'reference' => '64b258f80175c658aef9e22dd3f2ba18c99b243c', + 'pretty_version' => 'v5.4.36', + 'version' => '5.4.36.0', + 'reference' => 'feab1d1495fd6d38970bd6c83586ba2ace8f299a', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/support', 'aliases' => array(), 'dev_requirement' => false, ), + 'lcobucci/clock' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => '039ef98c6b57b101d10bd11d8fdfda12cbd996dc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'ldap-account-manager/ldap-account-manager' => array( - 'pretty_version' => '9.0', - 'version' => '9.0.0.0', + 'pretty_version' => '9.3', + 'version' => '9.3.0.0', 'reference' => null, 'type' => 'library', 'install_path' => __DIR__ . '/../../../../', @@ -182,27 +182,36 @@ 'dev_requirement' => false, ), 'monolog/monolog' => array( - 'pretty_version' => '3.8.0', - 'version' => '3.8.0.0', - 'reference' => '32e515fdc02cdafbe4593e30a9350d486b125b67', + 'pretty_version' => '3.9.0', + 'version' => '3.9.0.0', + 'reference' => '10d85740180ecba7896c87e06a166e0c95a0e3b6', 'type' => 'library', 'install_path' => __DIR__ . '/../monolog/monolog', 'aliases' => array(), 'dev_requirement' => false, ), + 'mtdowling/jmespath.php' => array( + 'pretty_version' => '2.8.0', + 'version' => '2.8.0.0', + 'reference' => 'a2a865e05d5f420b50cc2f85bb78d565db12a6bc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mtdowling/jmespath.php', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'nesbot/carbon' => array( - 'pretty_version' => '2.72.5', - 'version' => '2.72.5.0', - 'reference' => 'afd46589c216118ecd48ff2b95d77596af1e57ed', + 'pretty_version' => '3.10.2', + 'version' => '3.10.2.0', + 'reference' => '76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24', 'type' => 'library', 'install_path' => __DIR__ . '/../nesbot/carbon', 'aliases' => array(), 'dev_requirement' => false, ), 'paragonie/constant_time_encoding' => array( - 'pretty_version' => 'v2.7.0', - 'version' => '2.7.0.0', - 'reference' => '52a0d99e69f56b9ec27ace92ba56897fe6993105', + 'pretty_version' => 'v3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'df1e7fde177501eee2037dd159cf04f5f301a512', 'type' => 'library', 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding', 'aliases' => array(), @@ -217,6 +226,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'paragonie/sodium_compat' => array( + 'pretty_version' => 'v2.1.0', + 'version' => '2.1.0.0', + 'reference' => 'a673d5f310477027cead2e2f2b6db5d8368157cb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/sodium_compat', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'php-http/async-client-implementation' => array( 'dev_requirement' => false, 'provided' => array( @@ -239,23 +257,32 @@ 'dev_requirement' => false, ), 'phpmailer/phpmailer' => array( - 'pretty_version' => 'v6.9.3', - 'version' => '6.9.3.0', - 'reference' => '2f5c94fe7493efc213f643c23b1b1c249d40f47e', + 'pretty_version' => 'v6.10.0', + 'version' => '6.10.0.0', + 'reference' => 'bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144', 'type' => 'library', 'install_path' => __DIR__ . '/../phpmailer/phpmailer', 'aliases' => array(), 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( - 'pretty_version' => '3.0.42', - 'version' => '3.0.42.0', - 'reference' => 'db92f1b1987b12b13f248fe76c3a52cadb67bb98', + 'pretty_version' => '3.0.46', + 'version' => '3.0.46.0', + 'reference' => '56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/cache' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'psr/clock' => array( 'pretty_version' => '1.0.0', 'version' => '1.0.0.0', @@ -280,6 +307,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/event-dispatcher' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'psr/http-client' => array( 'pretty_version' => '1.0.3', 'version' => '1.0.3.0', @@ -308,15 +344,15 @@ 'psr/http-factory-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '1.0', - 1 => '^1.0', - 2 => '*', + 0 => '^1.0', + 1 => '*', + 2 => '1.0', ), ), 'psr/http-message' => array( - 'pretty_version' => '1.1', - 'version' => '1.1.0.0', - 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba', + 'pretty_version' => '2.0', + 'version' => '2.0.0.0', + 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-message', 'aliases' => array(), @@ -325,8 +361,8 @@ 'psr/http-message-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '1.0', - 1 => '*', + 0 => '*', + 1 => '1.0', ), ), 'psr/http-server-handler' => array( @@ -360,12 +396,13 @@ 'dev_requirement' => false, 'provided' => array( 0 => '3.0.0', + 1 => '1.0|2.0|3.0', ), ), 'psr/simple-cache' => array( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/simple-cache', 'aliases' => array(), @@ -380,6 +417,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'spomky-labs/aes-key-wrap' => array( + 'pretty_version' => 'v7.0.0', + 'version' => '7.0.0.0', + 'reference' => 'fbeb834b1f83aa8fbdfbd4c12124f71d4c1606ae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../spomky-labs/aes-key-wrap', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'spomky-labs/base64url' => array( 'pretty_version' => 'v2.0.4', 'version' => '2.0.4.0', @@ -390,36 +436,63 @@ 'dev_requirement' => false, ), 'spomky-labs/cbor-php' => array( - 'pretty_version' => '3.1.0', - 'version' => '3.1.0.0', - 'reference' => '499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4', + 'pretty_version' => '3.1.1', + 'version' => '3.1.1.0', + 'reference' => '5404f3e21cbe72f5cf612aa23db2b922fd2f43bf', 'type' => 'library', 'install_path' => __DIR__ . '/../spomky-labs/cbor-php', 'aliases' => array(), 'dev_requirement' => false, ), + 'spomky-labs/pki-framework' => array( + 'pretty_version' => '1.3.0', + 'version' => '1.3.0.0', + 'reference' => 'eced5b5ce70518b983ff2be486e902bbd15135ae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../spomky-labs/pki-framework', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/clock' => array( + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '5e15a9c9aeeb44a99f7cf24aa75aa9607795f6f8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/console' => array( + 'pretty_version' => 'v6.4.25', + 'version' => '6.4.25.0', + 'reference' => '273fd29ff30ba0a88ca5fb83f7cf1ab69306adae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/console', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'symfony/deprecation-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-client' => array( - 'pretty_version' => 'v6.4.16', - 'version' => '6.4.16.0', - 'reference' => '60a113666fa67e598abace38e5f46a0954d8833d', + 'pretty_version' => 'v6.4.25', + 'version' => '6.4.25.0', + 'reference' => 'b8e9dce2d8acba3c32af467bb58e0c3656886181', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-client', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-client-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => 'c2f3ad828596624ca39ea40f83617ef51ca8bbf9', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => '75d7043853a42837e68111812f4d964b01e5101c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-client-contracts', 'aliases' => array(), @@ -432,44 +505,62 @@ ), ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v6.4.16', - 'version' => '6.4.16.0', - 'reference' => '431771b7a6f662f1575b3cfc8fd7617aa9864d57', + 'pretty_version' => 'v6.4.25', + 'version' => '6.4.25.0', + 'reference' => '6bc974c0035b643aa497c58d46d9e25185e4b272', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/polyfill-ctype' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-grapheme' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/polyfill-php80' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8', - 'type' => 'library', - 'install_path' => __DIR__ . '/../symfony/polyfill-php80', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'symfony/polyfill-php83' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '2fb86d65e2d424369ad2905e83b236a8805ba491', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '17f6f9a6b1735c0f163024d959f700cfbc5155e5', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php83', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-uuid' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => '21533be36c24be3f4b1669c4725c7d1d2bab4ae2', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-uuid', @@ -477,36 +568,45 @@ 'dev_requirement' => false, ), 'symfony/psr-http-message-bridge' => array( - 'pretty_version' => 'v6.4.13', - 'version' => '6.4.13.0', - 'reference' => 'c9cf83326a1074f83a738fc5320945abf7fb7fec', + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '6954b4e8aef0e5d46f8558c90edcf27bb01b4724', 'type' => 'symfony-bridge', 'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => 'e53260aabf78fb3d63f8d79d69ece59f80d5eda0', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => 'f021b05a130d35510bd6b25fe9053c2a8a15d5d4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/string' => array( + 'pretty_version' => 'v6.4.25', + 'version' => '6.4.25.0', + 'reference' => '7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/string', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'symfony/translation' => array( - 'pretty_version' => 'v6.4.13', - 'version' => '6.4.13.0', - 'reference' => 'bee9bfabfa8b4045a66bf82520e492cddbaffa66', + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '300b72643e89de0734d99a9e3f8494a3ef6936e1', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/translation-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => '4667ff3bd513750603a09c8dedbea942487fb07c', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => 'df210c7a2573f1913b2d17cc95f90f53a73d8f7d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation-contracts', 'aliases' => array(), @@ -519,126 +619,105 @@ ), ), 'symfony/uid' => array( - 'pretty_version' => 'v6.4.13', - 'version' => '6.4.13.0', - 'reference' => '18eb207f0436a993fffbdd811b5b8fa35fa5e007', + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '17da16a750541a42cf2183935e0f6008316c23f7', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/uid', 'aliases' => array(), 'dev_requirement' => false, ), - 'thecodingmachine/safe' => array( - 'pretty_version' => 'v2.5.0', - 'version' => '2.5.0.0', - 'reference' => '3115ecd6b4391662b4931daac4eba6b07a2ac1f0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../thecodingmachine/safe', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'voku/portable-ascii' => array( - 'pretty_version' => '2.0.3', - 'version' => '2.0.3.0', - 'reference' => 'b1d923f88091c6bf09699efcd7c8a1b1bfd7351d', - 'type' => 'library', - 'install_path' => __DIR__ . '/../voku/portable-ascii', - 'aliases' => array(), + 'tightenco/collect' => array( 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v5.4.36', + ), ), 'web-auth/cose-lib' => array( - 'pretty_version' => '4.0.13', - 'version' => '4.0.13.0', - 'reference' => 'fc733974fe12b550b54a94a08e4e184aca0015e5', + 'pretty_version' => '4.4.2', + 'version' => '4.4.2.0', + 'reference' => 'a93b61c48fb587855f64a9ec11ad7b60e867cb15', 'type' => 'library', 'install_path' => __DIR__ . '/../web-auth/cose-lib', 'aliases' => array(), 'dev_requirement' => false, ), - 'web-auth/metadata-service' => array( - 'pretty_version' => 'v4.0.5', - 'version' => '4.0.5.0', - 'reference' => '2bc26efc09d280f87777c736f404a2d875d6e7c4', - 'type' => 'library', - 'install_path' => __DIR__ . '/../web-auth/metadata-service', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'web-auth/webauthn-lib' => array( - 'pretty_version' => 'v4.0.5', - 'version' => '4.0.5.0', - 'reference' => '1b02740ab8539f025419380c9e4c41b090c6cf47', + 'pretty_version' => '4.9.2', + 'version' => '4.9.2.0', + 'reference' => '008b25171c27cf4813420d0de31cc059bcc71f1a', 'type' => 'library', 'install_path' => __DIR__ . '/../web-auth/webauthn-lib', 'aliases' => array(), 'dev_requirement' => false, ), 'web-token/jwt-checker' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '5f31d98155951739e2fae7455e8466ccddd08f50', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '973ab960dd1761b00fce24a7cf2ec2a328499a58', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-checker', 'aliases' => array(), 'dev_requirement' => false, ), 'web-token/jwt-core' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '0a47aa6096024af3bff8082e47e27219b9889542', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-core', 'aliases' => array(), 'dev_requirement' => false, ), - 'web-token/jwt-easy' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '01db23252bb53d4fd36975b55dd58466bab1bb30', - 'type' => 'library', - 'install_path' => __DIR__ . '/../web-token/jwt-easy', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'web-token/jwt-encryption' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '3b8d67d7c5c013750703e7c27f1001544407bbb2', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '3e4b1c4080a77a6e97b62b33562805c1fc552b5e', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-encryption', 'aliases' => array(), 'dev_requirement' => false, ), 'web-token/jwt-key-mgmt' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '0b116379515700d237b4e5de86879078ccb09d8a', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '4d2a5a1a86477dd50b89aff76962816ddbd64590', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-key-mgmt', 'aliases' => array(), 'dev_requirement' => false, ), + 'web-token/jwt-library' => array( + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '92445671cc788fa5f639898a67c06f9fd0bf491f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../web-token/jwt-library', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'web-token/jwt-signature' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '015b59aaf3b6e8fb9f5bd1338845b7464c7d8103', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => 'eccfd59e658d4118414cf6d14229aa52eec387e7', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-signature', 'aliases' => array(), 'dev_requirement' => false, ), 'web-token/jwt-signature-algorithm-rsa' => array( - 'pretty_version' => 'v2.2.11', - 'version' => '2.2.11.0', - 'reference' => '513ad90eb5ef1886ff176727a769bda4618141b0', + 'pretty_version' => '3.4.8', + 'version' => '3.4.8.0', + 'reference' => '4408e41671294f0390731e2f84065a03a8089ace', 'type' => 'library', 'install_path' => __DIR__ . '/../web-token/jwt-signature-algorithm-rsa', 'aliases' => array(), 'dev_requirement' => false, ), 'webklex/php-imap' => array( - 'pretty_version' => '5.5.0', - 'version' => '5.5.0.0', - 'reference' => '3c23c8f66b772ce8597772816e068326559e7e4b', + 'pretty_version' => '6.2.0', + 'version' => '6.2.0.0', + 'reference' => '6b8ef85d621bbbaf52741b00cca8e9237e2b2e05', 'type' => 'library', 'install_path' => __DIR__ . '/../webklex/php-imap', 'aliases' => array(), diff --git a/lam/lib/3rdParty/composer/doctrine/inflector/README.md b/lam/lib/3rdParty/composer/doctrine/inflector/README.md index 6e3a97f7e..341f8b2a4 100644 --- a/lam/lib/3rdParty/composer/doctrine/inflector/README.md +++ b/lam/lib/3rdParty/composer/doctrine/inflector/README.md @@ -3,5 +3,6 @@ Doctrine Inflector is a small library that can perform string manipulations with regard to uppercase/lowercase and singular/plural forms of words. -[![Build Status](https://github.com/doctrine/inflector/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/inflector/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x) -[![Code Coverage](https://codecov.io/gh/doctrine/inflector/branch/2.0.x/graph/badge.svg)](https://codecov.io/gh/doctrine/inflector/branch/2.0.x) +[![Build Status](https://travis-ci.org/doctrine/inflector.svg)](https://travis-ci.org/doctrine/inflector) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/inflector/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/inflector/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/inflector/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/inflector/?branch=master) diff --git a/lam/lib/3rdParty/composer/doctrine/inflector/composer.json b/lam/lib/3rdParty/composer/doctrine/inflector/composer.json index 91d77071e..6f258ea97 100644 --- a/lam/lib/3rdParty/composer/doctrine/inflector/composer.json +++ b/lam/lib/3rdParty/composer/doctrine/inflector/composer.json @@ -13,29 +13,30 @@ {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} ], "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "autoload": { "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector", "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "autoload-dev": { "psr-4": { + "Doctrine\\Tests\\Common\\Inflector\\": "tests/Doctrine/Tests/Common/Inflector", "Doctrine\\Tests\\Inflector\\": "tests/Doctrine/Tests/Inflector" } }, - "config": { - "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" } } } diff --git a/lam/lib/3rdParty/composer/doctrine/inflector/docs/en/index.rst b/lam/lib/3rdParty/composer/doctrine/inflector/docs/en/index.rst index 29866f4d4..273b04032 100644 --- a/lam/lib/3rdParty/composer/doctrine/inflector/docs/en/index.rst +++ b/lam/lib/3rdParty/composer/doctrine/inflector/docs/en/index.rst @@ -213,7 +213,8 @@ You can unaccent a string of text using the ``unaccent()`` method: Legacy API ========== -The API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0. +As of 1.4.0, the API present in Inflector 1.x has been marked as deprecated. In the 2.x release series, +the legacy API has been dropped completely. Support for languages other than English is available in the 2.0 API only. Acknowledgements diff --git a/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php b/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php new file mode 100644 index 000000000..763b11676 --- /dev/null +++ b/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Common/Inflector/Inflector.php @@ -0,0 +1,284 @@ +. + */ + +namespace Doctrine\Common\Inflector; + +use Doctrine\Inflector\Inflector as InflectorObject; +use Doctrine\Inflector\InflectorFactory; +use Doctrine\Inflector\LanguageInflectorFactory; +use Doctrine\Inflector\Rules\Pattern; +use Doctrine\Inflector\Rules\Patterns; +use Doctrine\Inflector\Rules\Ruleset; +use Doctrine\Inflector\Rules\Substitution; +use Doctrine\Inflector\Rules\Substitutions; +use Doctrine\Inflector\Rules\Transformation; +use Doctrine\Inflector\Rules\Transformations; +use Doctrine\Inflector\Rules\Word; +use InvalidArgumentException; +use function array_keys; +use function array_map; +use function array_unshift; +use function array_values; +use function sprintf; +use function trigger_error; +use const E_USER_DEPRECATED; + +/** + * @deprecated + */ +class Inflector +{ + /** + * @var LanguageInflectorFactory|null + */ + private static $factory; + + /** @var InflectorObject|null */ + private static $instance; + + private static function getInstance() : InflectorObject + { + if (self::$factory === null) { + self::$factory = self::createFactory(); + } + + if (self::$instance === null) { + self::$instance = self::$factory->build(); + } + + return self::$instance; + } + + private static function createFactory() : LanguageInflectorFactory + { + return InflectorFactory::create(); + } + + /** + * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. + * + * @deprecated + */ + public static function tableize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->tableize($word); + } + + /** + * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. + */ + public static function classify(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->classify($word); + } + + /** + * Camelizes a word. This uses the classify() method and turns the first character to lowercase. + * + * @deprecated + */ + public static function camelize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->camelize($word); + } + + /** + * Uppercases words with configurable delimiters between words. + * + * Takes a string and capitalizes all of the words, like PHP's built-in + * ucwords function. This extends that behavior, however, by allowing the + * word delimiters to be configured, rather than only separating on + * whitespace. + * + * Here is an example: + * + * + * + * + * @param string $string The string to operate on. + * @param string $delimiters A list of word separators. + * + * @return string The string with all delimiter-separated words capitalized. + * + * @deprecated + */ + public static function ucwords(string $string, string $delimiters = " \n\t\r\0\x0B-") : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please use the "ucwords" function instead.', __METHOD__), E_USER_DEPRECATED); + + return ucwords($string, $delimiters); + } + + /** + * Clears Inflectors inflected value caches, and resets the inflection + * rules to the initial values. + * + * @deprecated + */ + public static function reset() : void + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + self::$factory = null; + self::$instance = null; + } + + /** + * Adds custom inflection $rules, of either 'plural' or 'singular' $type. + * + * ### Usage: + * + * {{{ + * Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables')); + * Inflector::rules('plural', array( + * 'rules' => array('/^(inflect)ors$/i' => '\1ables'), + * 'uninflected' => array('dontinflectme'), + * 'irregular' => array('red' => 'redlings') + * )); + * }}} + * + * @param string $type The type of inflection, either 'plural' or 'singular' + * @param array|iterable $rules An array of rules to be added. + * @param boolean $reset If true, will unset default inflections for all + * new rules that are being defined in $rules. + * + * @return void + * + * @deprecated + */ + public static function rules(string $type, iterable $rules, bool $reset = false) : void + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + if (self::$factory === null) { + self::$factory = self::createFactory(); + } + + self::$instance = null; + + switch ($type) { + case 'singular': + self::$factory->withSingularRules(self::buildRuleset($rules), $reset); + break; + case 'plural': + self::$factory->withPluralRules(self::buildRuleset($rules), $reset); + break; + default: + throw new InvalidArgumentException(sprintf('Cannot define custom inflection rules for type "%s".', $type)); + } + } + + /** + * @param array|iterable $rules An array of rules to be added. + */ + private static function buildRuleset(iterable $rules) : Ruleset + { + $regular = []; + $irregular = []; + $uninflected = []; + + foreach ($rules as $rule => $pattern) { + if ( ! is_array($pattern)) { + $regular[$rule] = $pattern; + + continue; + } + + switch ($rule) { + case 'uninflected': + $uninflected = $pattern; + break; + case 'irregular': + $irregular = $pattern; + break; + case 'rules': + $regular = $pattern; + break; + } + } + + return new Ruleset( + new Transformations(...array_map( + static function (string $pattern, string $replacement) : Transformation { + return new Transformation(new Pattern($pattern), $replacement); + }, + array_keys($regular), + array_values($regular) + )), + new Patterns(...array_map( + static function (string $pattern) : Pattern { + return new Pattern($pattern); + }, + $uninflected + )), + new Substitutions(...array_map( + static function (string $word, string $to) : Substitution { + return new Substitution(new Word($word), new Word($to)); + }, + array_keys($irregular), + array_values($irregular) + )) + ); + } + + /** + * Returns a word in plural form. + * + * @param string $word The word in singular form. + * + * @return string The word in plural form. + * + * @deprecated + */ + public static function pluralize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->pluralize($word); + } + + /** + * Returns a word in singular form. + * + * @param string $word The word in plural form. + * + * @return string The word in singular form. + * + * @deprecated + */ + public static function singularize(string $word) : string + { + @trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED); + + return self::getInstance()->singularize($word); + } +} diff --git a/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php b/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php index 8bf02a292..8f0919fc9 100644 --- a/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php +++ b/lam/lib/3rdParty/composer/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php @@ -11,7 +11,9 @@ use Doctrine\Inflector\Rules\Word; class Inflectible { - /** @return Transformation[] */ + /** + * @return Transformation[] + */ public static function getSingular(): iterable { yield new Transformation(new Pattern('(s)tatuses$'), '\1\2tatus'); @@ -47,19 +49,19 @@ class Inflectible yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\1\2sis'); yield new Transformation(new Pattern('(tax)a$'), '\1on'); yield new Transformation(new Pattern('(c)riteria$'), '\1riterion'); - yield new Transformation(new Pattern('([ti])a(? ./duo.conf + + - name: Ensure example runs + working-directory: example + run: php index.php diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/LICENSE b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/LICENSE index bedc1a969..6f20f1f73 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/LICENSE +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/LICENSE @@ -1,25 +1,12 @@ Copyright (c) 2022 Cisco Systems, Inc. and/or its affiliates All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/README.md b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/README.md index 0c0f5a13c..622350537 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/README.md +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/README.md @@ -11,7 +11,7 @@ What's included: * `tests` - Test cases ## Getting started -This library requires PHP 7.3 or later +This library requires PHP 7.4 or later To use SDK in your existing developing environment, install it from Packagist ``` @@ -19,6 +19,14 @@ composer require duosecurity/duo_universal_php ``` Once it's installed, see our developer documentation at https://duo.com/docs/duoweb and `sample/index.php` in this repo for guidance on integrating Duo 2FA into your web application. +### TLS 1.2 and 1.3 Support + +Duo_universal_php uses PHP's cURL extension and OpenSSL for TLS operations. TLS support will depend on the versions of multiple libraries: + +TLS 1.2 support requires PHP 5.5 or higher, curl 7.34.0 or higher, and OpenSSL 1.0.1 or higher. + +TLS 1.3 support requires PHP 7.3 or higher, curl 7.61.0 or higher, and OpenSSL 1.1.1 or higher. + ## Contribute To contribute, fork this repo and make a pull request with your changes when they are ready. diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/composer.json b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/composer.json index f436231b7..b5e76bb43 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/composer.json +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/composer.json @@ -2,6 +2,7 @@ "name": "duosecurity/duo_universal_php", "description": "A PHP implementation of the Duo Universal SDK.", "homepage": "https://duo.com/", + "license": "BSD-3-Clause", "support": { "email": "support@duosecurity.com" }, @@ -16,7 +17,7 @@ } }, "require": { - "php": ">=7.3", + "php": ">=7.4", "ext-curl": "*", "ext-json": "*", "firebase/php-jwt": "^6.0" diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/composer.json b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/composer.json index e262db761..9c3ddb147 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/composer.json +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/composer.json @@ -1,9 +1,9 @@ { "require": { - "slim/slim": "4.7.1", - "slim/psr7": "1.3.0", - "slim/php-view": "3.0.0", - "bryanjhv/slim-session": "4.0", + "slim/slim": "4.12.0", + "slim/psr7": "1.6.1", + "slim/php-view": "3.2.0", + "bryanjhv/slim-session": "4.1.2", "duosecurity/duo_universal_php": "@dev" }, "repositories": [ diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/dockerfile b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/dockerfile index 4b63b6ca8..49cec4ac3 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/dockerfile +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/dockerfile @@ -1,9 +1,11 @@ -FROM php:7 +FROM php:8 EXPOSE 8080 RUN apt update && apt install -y unzip wget WORKDIR /root RUN wget https://raw.githubusercontent.com/composer/getcomposer.org/885ece8a6e1370b204b89b7a542169d25aa21177/web/installer -O - -q | php -- --quiet -ADD . /src + +ADD ./composer.json /src/composer.json WORKDIR /src RUN /root/composer.phar update +ADD . /src ENTRYPOINT ["php", "-S", "0.0.0.0:8080"] diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/index.php b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/index.php index f8d446545..fcd0e36db 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/index.php +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/example/index.php @@ -21,7 +21,7 @@ try { $config['api_hostname'], $config['redirect_uri'], true, - $config['http_proxy'], + $config['http_proxy'] ?? null, ); } catch (DuoException $e) { throw new ErrorException("*** Duo config error. Verify the values in duo.conf are correct ***\n" . $e->getMessage()); diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/Client.php b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/Client.php index 8a0da779b..efe8743e6 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/Client.php +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/Client.php @@ -38,7 +38,7 @@ class Client const JWT_LEEWAY = 60; const SUCCESS_STATUS_CODE = 200; - const USER_AGENT = "duo_universal_php/1.0.2"; + const USER_AGENT = "duo_universal_php/1.1.1"; const SIG_ALGORITHM = "HS512"; const GRANT_TYPE = "authorization_code"; const CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"; @@ -63,6 +63,7 @@ class Client public $redirect_url; public $use_duo_code_attribute; private $client_secret; + private $user_agent_extension; /** * Retrieves exception message for DuoException from HTTPS result message. @@ -190,6 +191,34 @@ class Client $this->redirect_url = $redirect_url; $this->use_duo_code_attribute = $use_duo_code_attribute; $this->http_proxy = $http_proxy; + $this->user_agent_extension = null; + } + + /** + * Append custom information to the user agent string. + * + * @param string $user_agent_extension Custom user agent information + * + * @return void + */ + public function appendToUserAgent(string $user_agent_extension): void + { + $this->user_agent_extension = trim($user_agent_extension); + } + + /** + * Build the complete user agent string. + * + * @return string The complete user agent string + */ + private function buildUserAgent(): string + { + $base_user_agent = self::USER_AGENT . " php/" . phpversion() . " " + . php_uname(); + if (!empty($this->user_agent_extension)) { + return $base_user_agent . " " . $this->user_agent_extension; + } + return $base_user_agent; } /** @@ -282,7 +311,7 @@ class Client public function exchangeAuthorizationCodeFor2FAResult(string $duoCode, string $username, ?string $nonce = null): array { $token_endpoint = "https://" . $this->api_host . self::TOKEN_ENDPOINT; - $useragent = self::USER_AGENT . " php/" . phpversion() . " " . php_uname(); + $useragent = $this->buildUserAgent(); $jwt = $this->createJwtPayload($token_endpoint); $request = ["grant_type" => self::GRANT_TYPE, "code" => $duoCode, diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/ca_certs.pem b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/ca_certs.pem index 9cce65184..ef43078e4 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/ca_certs.pem +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/src/ca_certs.pem @@ -1,125 +1,12 @@ -subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- +# Source URL: https://www.amazontrust.com/repository/AmazonRootCA1.cer +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=Amazon Root CA 1,O=Amazon,C=US +# Issuer: CN=Amazon Root CA 1,O=Amazon,C=US +# Expiration Date: 2038-01-17 00:00:00 +# Serial Number: 66C9FCF99BF8C0A39E2F0788A43E696365BCA +# SHA256 Fingerprint: 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e -subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - -subject= /C=US/O=SecureTrust Corporation/CN=SecureTrust CA ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -subject= /C=US/O=SecureTrust Corporation/CN=Secure Global CA ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -subject=C = US, O = Amazon, CN = Amazon Root CA 1 -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 @@ -141,7 +28,16 @@ o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU rqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- -subject=C = US, O = Amazon, CN = Amazon Root CA 2 + +# Source URL: https://www.amazontrust.com/repository/AmazonRootCA2.cer +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=Amazon Root CA 2,O=Amazon,C=US +# Issuer: CN=Amazon Root CA 2,O=Amazon,C=US +# Expiration Date: 2040-05-26 00:00:00 +# Serial Number: 66C9FD29635869F0A0FE58678F85B26BB8A37 +# SHA256 Fingerprint: 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 + -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 @@ -174,7 +70,16 @@ n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE 4PsJYGw= -----END CERTIFICATE----- -subject=C = US, O = Amazon, CN = Amazon Root CA 3 + +# Source URL: https://www.amazontrust.com/repository/AmazonRootCA3.cer +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=Amazon Root CA 3,O=Amazon,C=US +# Issuer: CN=Amazon Root CA 3,O=Amazon,C=US +# Expiration Date: 2040-05-26 00:00:00 +# Serial Number: 66C9FD5749736663F3B0B9AD9E89E7603F24A +# SHA256 Fingerprint: 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 + -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g @@ -188,7 +93,16 @@ BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM YyRIHN8wfdVoOw== -----END CERTIFICATE----- -subject=C = US, O = Amazon, CN = Amazon Root CA 4 + +# Source URL: https://www.amazontrust.com/repository/AmazonRootCA4.cer +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=Amazon Root CA 4,O=Amazon,C=US +# Issuer: CN=Amazon Root CA 4,O=Amazon,C=US +# Expiration Date: 2040-05-26 00:00:00 +# Serial Number: 66C9FD7C1BB104C2943E5717B7B2CC81AC10E +# SHA256 Fingerprint: e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 + -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g @@ -203,37 +117,374 @@ CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW 1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- -subject=C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2 + +# Source URL: https://www.amazontrust.com/repository/SFSRootCAG2.cer +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US +# Issuer: CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US +# Expiration Date: 2037-12-31 23:59:59 +# Serial Number: 0 +# SHA256 Fingerprint: 568d6905a2c88708a4b3025190edcfedb1974a606a13c6e5290fcb2ae63edab5 + -----BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 -----END CERTIFICATE----- + + +# Source URL: https://cacerts.digicert.com/DigiCertHighAssuranceEVRootCA.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Issuer: CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Expiration Date: 2031-11-10 00:00:00 +# Serial Number: 2AC5C266A0B409B8F0B79F2AE462577 +# SHA256 Fingerprint: 7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf + +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + + +# Source URL: https://cacerts.digicert.com/DigiCertTLSECCP384RootG5.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=DigiCert TLS ECC P384 Root G5,O=DigiCert\, Inc.,C=US +# Issuer: CN=DigiCert TLS ECC P384 Root G5,O=DigiCert\, Inc.,C=US +# Expiration Date: 2046-01-14 23:59:59 +# Serial Number: 9E09365ACF7D9C8B93E1C0B042A2EF3 +# SHA256 Fingerprint: 018e13f0772532cf809bd1b17281867283fc48c6e13be9c69812854a490c1b05 + +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + + +# Source URL: https://cacerts.digicert.com/DigiCertTLSRSA4096RootG5.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=DigiCert TLS RSA4096 Root G5,O=DigiCert\, Inc.,C=US +# Issuer: CN=DigiCert TLS RSA4096 Root G5,O=DigiCert\, Inc.,C=US +# Expiration Date: 2046-01-14 23:59:59 +# Serial Number: 8F9B478A8FA7EDA6A333789DE7CCF8A +# SHA256 Fingerprint: 371a00dc0533b3721a7eeb40e8419e70799d2b0a0f2c1d80693165f7cec4ad75 + +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + + +# Source URL: https://secure.globalsign.com/cacert/rootr46.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=GlobalSign Root R46,O=GlobalSign nv-sa,C=BE +# Issuer: CN=GlobalSign Root R46,O=GlobalSign nv-sa,C=BE +# Expiration Date: 2046-03-20 00:00:00 +# Serial Number: 11D2BBB9D723189E405F0A9D2DD0DF2567D1 +# SHA256 Fingerprint: 4fa3126d8d3a11d1c4855a4f807cbad6cf919d3a5a88b03bea2c6372d93c40c9 + +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + + +# Source URL: https://secure.globalsign.com/cacert/roote46.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=GlobalSign Root E46,O=GlobalSign nv-sa,C=BE +# Issuer: CN=GlobalSign Root E46,O=GlobalSign nv-sa,C=BE +# Expiration Date: 2046-03-20 00:00:00 +# Serial Number: 11D2BBBA336ED4BCE62468C50D841D98E843 +# SHA256 Fingerprint: cbb9c44d84b8043e1050ea31a69f514955d7bfd2e2c6b49301019ad61d9f5058 + +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + + +# Source URL: https://i.pki.goog/r2.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=GTS Root R2,O=Google Trust Services LLC,C=US +# Issuer: CN=GTS Root R2,O=Google Trust Services LLC,C=US +# Expiration Date: 2036-06-22 00:00:00 +# Serial Number: 203E5AEC58D04251AAB1125AA +# SHA256 Fingerprint: 8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8 + +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE----- + + +# Source URL: https://i.pki.goog/r4.crt +# Certificate #1 Details: +# Original Format: DER +# Subject: CN=GTS Root R4,O=Google Trust Services LLC,C=US +# Issuer: CN=GTS Root R4,O=Google Trust Services LLC,C=US +# Expiration Date: 2036-06-22 00:00:00 +# Serial Number: 203E5C068EF631A9C72905052 +# SHA256 Fingerprint: 349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d + +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + + +# Source URL: https://www.identrust.com/file-download/download/public/5718 +# Certificate #1 Details: +# Original Format: PKCS7-DER +# Subject: CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US +# Issuer: CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US +# Expiration Date: 2034-01-16 18:12:23 +# Serial Number: A0142800000014523C844B500000002 +# SHA256 Fingerprint: 5d56499be4d2e08bcfcad08a3e38723d50503bde706948e42f55603019e528ae + +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + + +# Source URL: https://www.identrust.com/file-download/download/public/5842 +# Certificate #1 Details: +# Original Format: PKCS7-PEM +# Subject: CN=IdenTrust Commercial Root TLS ECC CA 2,O=IdenTrust,C=US +# Issuer: CN=IdenTrust Commercial Root TLS ECC CA 2,O=IdenTrust,C=US +# Expiration Date: 2039-04-11 21:11:10 +# Serial Number: 40018ECF000DE911D7447B73E4C1F82E +# SHA256 Fingerprint: 983d826ba9c87f653ff9e8384c5413e1d59acf19ddc9c98cecae5fdea2ac229c + +-----BEGIN CERTIFICATE----- +MIICbDCCAc2gAwIBAgIQQAGOzwAN6RHXRHtz5MH4LjAKBggqhkjOPQQDBDBSMQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MS8wLQYDVQQDEyZJZGVuVHJ1 +c3QgQ29tbWVyY2lhbCBSb290IFRMUyBFQ0MgQ0EgMjAeFw0yNDA0MTEyMTExMTFa +Fw0zOTA0MTEyMTExMTBaMFIxCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1 +c3QxLzAtBgNVBAMTJklkZW5UcnVzdCBDb21tZXJjaWFsIFJvb3QgVExTIEVDQyBD +QSAyMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBwomiZTgLg8KqEImMmnO5rNPb +Oo9sv5w4nJh45CXs9Gcu8YET9ulxsyVBCVSfSYeppdtXFEWYyBi0QRCAlp5YZHQB +H675v5rWVKRXvhzsuUNi9Xw0Zy1bAXaikmsrY/J0L52j2RulW4q4WvE7f23VFwZu +d82J8k0YG+M4MpmdOho1rsKjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBQhNGgGrnXhVx/FuQqjXpuH+IlbwzAKBggqhkjOPQQD +BAOBjAAwgYgCQgDc9F4WOxAgci2uQWfsX9cjeIvDXaaeVjDz31Ycc+ZdPrK1JKrB +f6CuTwWy8VojtGxdM3PJMkJC4LGPuhcvkHLo4gJCAV5h+PXe4bDJ3QxE8hkGFoUW +Ak6KtMCIpbLyt5pHrROi+YW9MpScoNGJkg96G1ETvJTWz6dv0uQYjKXt3jlOfQ7g +-----END CERTIFICATE----- + + +# Source URL: https://ssl-ccp.secureserver.net/repository/sfroot-g2.crt +# Certificate #1 Details: +# Original Format: PEM +# Subject: CN=Starfield Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US +# Issuer: CN=Starfield Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US +# Expiration Date: 2037-12-31 23:59:59 +# Serial Number: 0 +# SHA256 Fingerprint: 2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5 + +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + + diff --git a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/tests/ClientTest.php b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/tests/ClientTest.php index ddb6c3227..82095c976 100644 --- a/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/tests/ClientTest.php +++ b/lam/lib/3rdParty/composer/duosecurity/duo_universal_php/tests/ClientTest.php @@ -514,4 +514,144 @@ final class ClientTest extends TestCase $this->assertStringContainsString("scope=openid", $duo_uri); $this->assertStringContainsString($expected_redir_uri, $duo_uri); } + + /** + * Test that the user agent extension can be set and is included in requests. + */ + public function testAppendToUserAgent(): void + { + $custom_extension = "MyApp/1.0.0"; + $id_token = $this->createIdToken(); + $result = $this->createTokenResult($id_token); + + // Mock the client to capture the user agent sent in HTTP requests + $client = $this->getMockBuilder(Client::class) + ->setConstructorArgs([$this->client_id, $this->client_secret, $this->api_host, $this->redirect_url]) + ->setMethods(['makeHttpsCall']) + ->getMock(); + + // Set up the mock to capture the user agent parameter + $captured_user_agent = null; + $client->method('makeHttpsCall') + ->willReturnCallback(function ($endpoint, $request, $user_agent = null) use (&$captured_user_agent, $result) { + $captured_user_agent = $user_agent; + return $result; + }); + + // Append custom user agent extension + $client->appendToUserAgent($custom_extension); + + // Make a call that uses the user agent + $client->exchangeAuthorizationCodeFor2FAResult($this->code, $this->username); + + // Verify the user agent includes our custom extension + $this->assertNotNull($captured_user_agent); + $this->assertStringContainsString($custom_extension, $captured_user_agent); + $this->assertStringContainsString(Client::USER_AGENT, $captured_user_agent); + $this->assertStringContainsString("php/" . phpversion(), $captured_user_agent); + } + + /** + * Test that user agent works correctly without any extension. + */ + public function testUserAgentWithoutExtension(): void + { + $id_token = $this->createIdToken(); + $result = $this->createTokenResult($id_token); + + // Mock the client to capture the user agent sent in HTTP requests + $client = $this->getMockBuilder(Client::class) + ->setConstructorArgs([$this->client_id, $this->client_secret, $this->api_host, $this->redirect_url]) + ->setMethods(['makeHttpsCall']) + ->getMock(); + + // Set up the mock to capture the user agent parameter + $captured_user_agent = null; + $client->method('makeHttpsCall') + ->willReturnCallback(function ($endpoint, $request, $user_agent = null) use (&$captured_user_agent, $result) { + $captured_user_agent = $user_agent; + return $result; + }); + + // Make a call without setting any custom user agent extension + $client->exchangeAuthorizationCodeFor2FAResult($this->code, $this->username); + + // Verify the user agent contains default information but no custom extension + $this->assertNotNull($captured_user_agent); + $this->assertStringContainsString(Client::USER_AGENT, $captured_user_agent); + $this->assertStringContainsString("php/" . phpversion(), $captured_user_agent); + $this->assertStringContainsString(php_uname(), $captured_user_agent); + } + + /** + * Test that empty user agent extension is handled correctly. + */ + public function testAppendToUserAgentEmpty(): void + { + $id_token = $this->createIdToken(); + $result = $this->createTokenResult($id_token); + + // Mock the client to capture the user agent sent in HTTP requests + $client = $this->getMockBuilder(Client::class) + ->setConstructorArgs([$this->client_id, $this->client_secret, $this->api_host, $this->redirect_url]) + ->setMethods(['makeHttpsCall']) + ->getMock(); + + // Set up the mock to capture the user agent parameter + $captured_user_agent = null; + $client->method('makeHttpsCall') + ->willReturnCallback(function ($endpoint, $request, $user_agent = null) use (&$captured_user_agent, $result) { + $captured_user_agent = $user_agent; + return $result; + }); + + // Append empty user agent extension + $client->appendToUserAgent(""); + + // Make a call + $client->exchangeAuthorizationCodeFor2FAResult($this->code, $this->username); + + // Verify the user agent contains default information but no trailing space + $this->assertNotNull($captured_user_agent); + $this->assertStringContainsString(Client::USER_AGENT, $captured_user_agent); + $this->assertStringContainsString("php/" . phpversion(), $captured_user_agent); + $this->assertStringContainsString(php_uname(), $captured_user_agent); + // Ensure no trailing spaces from empty extension + $expected_base = Client::USER_AGENT . " php/" . phpversion() . " " . php_uname(); + $this->assertEquals($expected_base, $captured_user_agent); + } + + /** + * Test that whitespace-only user agent extension is handled correctly. + */ + public function testAppendToUserAgentWhitespace(): void + { + $id_token = $this->createIdToken(); + $result = $this->createTokenResult($id_token); + + // Mock the client to capture the user agent sent in HTTP requests + $client = $this->getMockBuilder(Client::class) + ->setConstructorArgs([$this->client_id, $this->client_secret, $this->api_host, $this->redirect_url]) + ->setMethods(['makeHttpsCall']) + ->getMock(); + + // Set up the mock to capture the user agent parameter + $captured_user_agent = null; + $client->method('makeHttpsCall') + ->willReturnCallback(function ($endpoint, $request, $user_agent = null) use (&$captured_user_agent, $result) { + $captured_user_agent = $user_agent; + return $result; + }); + + // Append whitespace-only user agent extension + $client->appendToUserAgent(" "); + + // Make a call + $client->exchangeAuthorizationCodeFor2FAResult($this->code, $this->username); + + // Verify the user agent contains default information but no extra whitespace + $this->assertNotNull($captured_user_agent); + $expected_base = Client::USER_AGENT . " php/" . phpversion() . " " . php_uname(); + $this->assertEquals($expected_base, $captured_user_agent); + } } diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.gitignore b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.gitignore index fc8ec0b77..2a1146104 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.gitignore +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.gitignore @@ -1,4 +1,4 @@ /vendor/ /.phpunit.result.cache -/.php_cs.cache +/.php-cs-fixer.cache /composer.lock \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.php-cs-fixer.dist.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.php-cs-fixer.dist.php new file mode 100644 index 000000000..04e97c0fb --- /dev/null +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/.php-cs-fixer.dist.php @@ -0,0 +1,60 @@ + true, + 'heredoc_indentation' => true, + 'heredoc_to_nowdoc' => true, + 'no_null_property_initialization' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + 'constant_case' => true, + 'declare_strict_types' => true, + 'indentation_type' => true, + 'no_superfluous_phpdoc_tags' => [ + 'allow_mixed' => true, + ], + 'phpdoc_line_span' => [ + 'const' => 'single', + 'method' => 'multi', + 'property' => 'single', + ], + 'phpdoc_trim_consecutive_blank_line_separation' => true, + // risky rules + 'fopen_flag_order' => true, + 'fopen_flags' => true, + 'ereg_to_preg' => true, + 'implode_call' => true, + 'no_unset_on_property' => true, + // custom + 'comment_to_phpdoc' => true, + 'phpdoc_to_comment' => false, +]; +$rulesProvider = new Facile\CodingStandards\Rules\CompositeRulesProvider([ + new Facile\CodingStandards\Rules\DefaultRulesProvider(), + new Facile\CodingStandards\Rules\ArrayRulesProvider($additionalRules), +]); + +$config = new PhpCsFixer\Config(); +$config->setRules($rulesProvider->getRules()); + +$finder = new PhpCsFixer\Finder(); + +/* + * You can set manually these paths: + */ +$autoloadPathProvider = new Facile\CodingStandards\AutoloadPathProvider(); +$finder->in($autoloadPathProvider->getPaths()); + +$config->setFinder($finder); + +return $config; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/composer.json b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/composer.json index a187bfee0..2f9d04417 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/composer.json +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/composer.json @@ -11,7 +11,11 @@ ], "minimum-stability": "stable", "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "facile-it/facile-coding-standard": true, + "php-http/discovery": true + } }, "keywords": [ "jwt", @@ -31,17 +35,17 @@ "php": "^7.2 || ^8.0", "ext-json": "*", "php-http/discovery": "^1.7", + "psr/clock": "^1.0", "psr/http-client": "^1.0", - "psr/http-message": "^1.0", - "psr/simple-cache": "^1.0", + "psr/http-message": "^1.0 || 2.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", "spomky-labs/base64url": "^2.0.1", "symfony/polyfill-mbstring": "^1.15", - "web-token/jwt-checker": "^2.2.0", - "web-token/jwt-core": "^2.2.0", - "web-token/jwt-easy": "^2.2.0", - "web-token/jwt-key-mgmt": "^2.2.0", - "web-token/jwt-signature": "^2.2.0", - "web-token/jwt-signature-algorithm-rsa": "^2.2.0" + "web-token/jwt-checker": "^2.2.0 || ^3.0", + "web-token/jwt-core": "^2.2.0 || ^3.0", + "web-token/jwt-key-mgmt": "^2.2.0 || ^3.0", + "web-token/jwt-signature": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-rsa": "^2.2.0 || ^3.0" }, "autoload": { "files": [ @@ -58,34 +62,35 @@ } }, "require-dev": { - "facile-it/facile-coding-standard": "^0.4.1", - "friendsofphp/php-cs-fixer": "^2.16.1", - "laminas/laminas-diactoros": "^2.2", + "facile-it/facile-coding-standard": "^0.5", + "friendsofphp/php-cs-fixer": "^3.0", + "laminas/laminas-diactoros": "^2.2 || ^3.0.0", "php-http/curl-client": "^2.1", "phpspec/prophecy-phpunit": "^1.1 || ^2.0", "phpunit/phpunit": "^8.5.14 || ^9.3", - "vimeo/psalm": "^4.4.1", - "web-token/jwt-encryption": "^2.2.0", - "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0", - "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0", - "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0", - "web-token/jwt-encryption-algorithm-dir": "^2.2.0", - "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0", - "web-token/jwt-encryption-algorithm-experimental": "^2.2.0", - "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0", - "web-token/jwt-encryption-algorithm-rsa": "^2.2.0", - "web-token/jwt-nested-token": "^2.2.0", - "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0", - "web-token/jwt-signature-algorithm-experimental": "^2.2.0", - "web-token/jwt-signature-algorithm-hmac": "^2.2.0", - "web-token/jwt-signature-algorithm-none": "^2.2.0", - "web-token/jwt-util-ecc": "^2.2.0" + "vimeo/psalm": "^4.30.0 || ^5.13.1", + "web-token/jwt-checker": "^2.2.0 || ^3.2.0", + "web-token/jwt-encryption": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aescbc": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-aeskw": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-dir": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-pbes2": "^2.2.0 || ^3.0", + "web-token/jwt-encryption-algorithm-rsa": "^2.2.0 || ^3.0", + "web-token/jwt-nested-token": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-ecdsa": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-experimental": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-hmac": "^2.2.0 || ^3.0", + "web-token/jwt-signature-algorithm-none": "^2.2.0 || ^3.0", + "web-token/jwt-util-ecc": "^2.2.0 || ^3.0" }, "scripts": { "cs-check": "php-cs-fixer fix --dry-run --diff --allow-risky=yes", "cs-fix": "php-cs-fixer fix --diff --allow-risky=yes", - "psalm": "psalm", + "psalm": "psalm --php-version=8.2", "test": "phpunit", "test-coverage": "phpunit --coverage-text", "check": [ diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifier.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifier.php index b1279cda4..9d0c83e97 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifier.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifier.php @@ -4,9 +4,10 @@ declare(strict_types=1); namespace Facile\JoseVerifier; -use Facile\JoseVerifier\ClaimChecker\AuthTimeChecker; -use Facile\JoseVerifier\ClaimChecker\AzpChecker; -use Facile\JoseVerifier\ClaimChecker\NonceChecker; +use Facile\JoseVerifier\Checker\AuthTimeChecker; +use Facile\JoseVerifier\Checker\AzpChecker; +use Facile\JoseVerifier\Checker\InternalClock; +use Facile\JoseVerifier\Checker\NonceChecker; use Facile\JoseVerifier\Decrypter\TokenDecrypterInterface; use Facile\JoseVerifier\Exception\InvalidArgumentException; use Facile\JoseVerifier\Exception\InvalidTokenException; @@ -15,10 +16,17 @@ use Facile\JoseVerifier\JWK\JwksProviderInterface; use Facile\JoseVerifier\JWK\MemoryJwksProvider; use Facile\JoseVerifier\Validate\Validate; use function is_array; +use Jose\Component\Checker\AlgorithmChecker; +use Jose\Component\Checker\AudienceChecker; +use Jose\Component\Checker\ExpirationTimeChecker; +use Jose\Component\Checker\IssuedAtChecker; +use Jose\Component\Checker\IssuerChecker; +use Jose\Component\Checker\NotBeforeChecker; use Jose\Component\Core\JWK; use Jose\Component\Core\JWKSet; use Jose\Component\Core\Util\JsonConverter; use Jose\Component\Signature\Serializer\CompactSerializer; +use Psr\Clock\ClockInterface; use function str_replace; use function strpos; use Throwable; @@ -65,12 +73,16 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface /** @var TokenDecrypterInterface|null */ protected $decrypter; - public function __construct(string $issuer, string $clientId, ?TokenDecrypterInterface $decrypter = null) + /** @var ClockInterface */ + protected $clock; + + public function __construct(string $issuer, string $clientId, ?TokenDecrypterInterface $decrypter = null, ?ClockInterface $clock = null) { $this->issuer = $issuer; $this->clientId = $clientId; $this->jwksProvider = new MemoryJwksProvider(); $this->decrypter = $decrypter; + $this->clock = $clock ?: new InternalClock(); } /** @@ -181,6 +193,9 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface return $this->decrypter->decrypt($jwt) ?? '{}'; } + /** + * @psalm-suppress TooManyArguments + */ protected function create(string $jwt): Validate { $mandatoryClaims = []; @@ -189,38 +204,37 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface if ($this->aadIssValidation) { $payload = $this->getPayload($jwt); - $expectedIssuer = str_replace('{tenantid}', $payload['tid'] ?? '', $expectedIssuer); + $expectedIssuer = str_replace('{tenantid}', (string) ($payload['tid'] ?? ''), $expectedIssuer); } $validator = Validate::token($jwt) ->keyset($this->buildJwks($jwt)) - ->iss($expectedIssuer) - ->iat($this->clockTolerance) - ->aud($this->clientId) - ->exp($this->clockTolerance) - ->nbf($this->clockTolerance); + ->claim(new IssuerChecker([$expectedIssuer], true)) + ->claim(new IssuedAtChecker($this->clockTolerance, true, $this->clock)) + ->claim(new AudienceChecker($this->clientId, true)) + ->claim(new ExpirationTimeChecker($this->clockTolerance, false, $this->clock)) + ->claim(new NotBeforeChecker($this->clockTolerance, true, $this->clock)); if (null !== $this->azp) { - $validator = $validator->claim('azp', new AzpChecker($this->azp)); + $validator = $validator->claim(new AzpChecker($this->azp)); } if (null !== $this->expectedAlg) { - $validator = $validator->alg($this->expectedAlg); + $validator = $validator->header(new AlgorithmChecker([$this->expectedAlg], true)); } if (null !== $this->nonce) { - $validator = $validator->claim('nonce', new NonceChecker($this->nonce)); + $validator = $validator->claim(new NonceChecker($this->nonce)); } if (null !== $this->maxAge) { - $validator = $validator->claim('auth_time', new AuthTimeChecker($this->maxAge, $this->clockTolerance)); + $validator = $validator->claim(new AuthTimeChecker($this->maxAge, $this->clockTolerance)); } if ((int) $this->maxAge > 0 || null !== $this->maxAge) { $mandatoryClaims[] = 'auth_time'; } - /** @var Validate $validator */ $validator = $validator->mandatory($mandatoryClaims); return $validator; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifierBuilder.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifierBuilder.php index 1e8377add..df62d91f3 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifierBuilder.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/AbstractTokenVerifierBuilder.php @@ -13,21 +13,25 @@ use Facile\JoseVerifier\JWK\MemoryJwksProvider; /** * @psalm-import-type ClientMetadataObject from Psalm\PsalmTypes - * @psalm-import-type IssuerMetadataObject from Psalm\PsalmTypes * @psalm-import-type JWKSetObject from Psalm\PsalmTypes + * @psalm-import-type IssuerMetadataObject from TokenVerifierBuilderInterface + * * @template TVerifier of AbstractTokenVerifier + * * @template-implements TokenVerifierBuilderInterface */ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInterface { /** * @var null|array + * * @psalm-var null|ClientMetadataObject */ protected $clientMetadata; /** * @var null|array + * * @psalm-var null|IssuerMetadataObject */ protected $issuerMetadata; @@ -49,6 +53,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter /** * @param array $clientMetadata + * * @psalm-param ClientMetadataObject $clientMetadata */ public function setClientMetadata(array $clientMetadata): void @@ -58,6 +63,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter /** * @param array $issuerMetadata + * * @psalm-param IssuerMetadataObject $issuerMetadata */ public function setIssuerMetadata(array $issuerMetadata): void @@ -105,10 +111,11 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter return $this->clientJwksProvider; } - /** @var JWKSetObject $jwks */ + /** @psalm-var JWKSetObject $jwks */ $jwks = ['keys' => []]; if ($this->clientMetadata) { + /** @psalm-var JWKSetObject $jwks */ $jwks = $this->clientMetadata['jwks'] ?? $jwks; } @@ -133,6 +140,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter /** * @return array + * * @psalm-return ClientMetadataObject */ protected function getClientMetadata(): array @@ -146,6 +154,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter /** * @return array + * * @psalm-return IssuerMetadataObject */ protected function getIssuerMetadata(): array diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AbstractHashChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AbstractHashChecker.php similarity index 94% rename from lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AbstractHashChecker.php rename to lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AbstractHashChecker.php index edc95963f..de706c286 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AbstractHashChecker.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AbstractHashChecker.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Facile\JoseVerifier\ClaimChecker; +namespace Facile\JoseVerifier\Checker; use Base64Url\Base64Url; use function hash; @@ -13,6 +13,9 @@ use function sprintf; use function strlen; use function substr; +/** + * @internal + */ abstract class AbstractHashChecker implements ClaimChecker { /** @var string */ @@ -45,7 +48,7 @@ abstract class AbstractHashChecker implements ClaimChecker } /** - * {@inheritdoc} + * @param mixed $value */ public function checkClaim($value): void { diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AtHashChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AtHashChecker.php similarity index 78% rename from lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AtHashChecker.php rename to lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AtHashChecker.php index 14949bf43..80494862a 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AtHashChecker.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AtHashChecker.php @@ -2,8 +2,11 @@ declare(strict_types=1); -namespace Facile\JoseVerifier\ClaimChecker; +namespace Facile\JoseVerifier\Checker; +/** + * @internal + */ final class AtHashChecker extends AbstractHashChecker { private const CLAIM_NAME = 'at_hash'; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AuthTimeChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AuthTimeChecker.php new file mode 100644 index 000000000..b42a27daa --- /dev/null +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AuthTimeChecker.php @@ -0,0 +1,53 @@ +maxAge = $maxAge; + $this->allowedTimeDrift = $allowedTimeDrift; + $this->clock = $clock ?: new InternalClock(); + } + + /** + * @param mixed $value + */ + public function checkClaim($value): void + { + if (! is_int($value)) { + throw new InvalidClaimException('"auth_time" must be an integer.', self::CLAIM_NAME, $value); + } + + if ($value + $this->maxAge < $this->clock->now()->getTimestamp() - $this->allowedTimeDrift) { + throw new InvalidClaimException('Too much time has elapsed since the last End-User authentication.', self::CLAIM_NAME, $value); + } + } + + public function supportedClaim(): string + { + return self::CLAIM_NAME; + } +} diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AzpChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AzpChecker.php similarity index 89% rename from lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AzpChecker.php rename to lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AzpChecker.php index 1316c8896..35f131710 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/AzpChecker.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/AzpChecker.php @@ -2,12 +2,15 @@ declare(strict_types=1); -namespace Facile\JoseVerifier\ClaimChecker; +namespace Facile\JoseVerifier\Checker; use Jose\Component\Checker\ClaimChecker; use Jose\Component\Checker\InvalidClaimException; use function sprintf; +/** + * @internal + */ final class AzpChecker implements ClaimChecker { private const CLAIM_NAME = 'azp'; @@ -21,7 +24,7 @@ final class AzpChecker implements ClaimChecker } /** - * {@inheritdoc} + * @param mixed $value */ public function checkClaim($value): void { diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/CHashChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CHashChecker.php similarity index 78% rename from lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/CHashChecker.php rename to lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CHashChecker.php index e287411ea..15aa76768 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/ClaimChecker/CHashChecker.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CHashChecker.php @@ -2,8 +2,11 @@ declare(strict_types=1); -namespace Facile\JoseVerifier\ClaimChecker; +namespace Facile\JoseVerifier\Checker; +/** + * @internal + */ final class CHashChecker extends AbstractHashChecker { private const CLAIM_NAME = 'c_hash'; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CallableChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CallableChecker.php new file mode 100644 index 000000000..5ad1523fd --- /dev/null +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/CallableChecker.php @@ -0,0 +1,76 @@ +key = $key; + $this->callable = $callable; + } + + /** + * @param mixed $value + * + * @throws InvalidClaimException if the claim is invalid + */ + public function checkClaim($value): void + { + $callable = $this->callable; + $isValid = $callable($value); + if (! $isValid) { + throw new InvalidClaimException(sprintf('Invalid claim "%s"', $this->key), $this->key, $value); + } + } + + public function supportedClaim(): string + { + return $this->key; + } + + /** + * @param mixed $value + */ + public function checkHeader($value): void + { + $callable = $this->callable; + $isValid = $callable($value); + if (! $isValid) { + throw new InvalidHeaderException(sprintf('Invalid header "%s"', $this->key), $this->key, $value); + } + } + + public function supportedHeader(): string + { + return $this->key; + } + + public function protectedHeaderOnly(): bool + { + return true; + } +} diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/ContentEncryptionAlgorithmChecker.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/ContentEncryptionAlgorithmChecker.php new file mode 100644 index 000000000..b5419953c --- /dev/null +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/ContentEncryptionAlgorithmChecker.php @@ -0,0 +1,59 @@ +supportedAlgorithms = $supportedAlgorithms; + $this->protectedHeader = $protectedHeader; + } + + /** + * @param mixed $value + * + * @throws InvalidHeaderException if the header is invalid + */ + public function checkHeader($value): void + { + if (! is_string($value)) { + throw new InvalidHeaderException('"enc" must be a string.', self::HEADER_NAME, $value); + } + if (! in_array($value, $this->supportedAlgorithms, true)) { + throw new InvalidHeaderException('Unsupported algorithm.', self::HEADER_NAME, $value); + } + } + + public function supportedHeader(): string + { + return self::HEADER_NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeader; + } +} diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/InternalClock.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/InternalClock.php new file mode 100644 index 000000000..cdb572bb9 --- /dev/null +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Checker/InternalClock.php @@ -0,0 +1,19 @@ +maxAge = $maxAge; - $this->allowedTimeDrift = $allowedTimeDrift; - } - - /** - * {@inheritdoc} - */ - public function checkClaim($value): void - { - if (! is_int($value)) { - throw new InvalidClaimException('"auth_time" must be an integer.', self::CLAIM_NAME, $value); - } - - if ($value + $this->maxAge < time() - $this->allowedTimeDrift) { - throw new InvalidClaimException('Too much time has elapsed since the last End-User authentication.', self::CLAIM_NAME, $value); - } - } - - public function supportedClaim(): string - { - return self::CLAIM_NAME; - } -} diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Decrypter/TokenDecrypter.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Decrypter/TokenDecrypter.php index 4ae7df9da..17b631767 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Decrypter/TokenDecrypter.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Decrypter/TokenDecrypter.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Facile\JoseVerifier\Decrypter; use function class_exists; +use Facile\JoseVerifier\Checker\ContentEncryptionAlgorithmChecker; use Facile\JoseVerifier\Exception\InvalidTokenException; use Facile\JoseVerifier\Exception\LogicException; use function Facile\JoseVerifier\jose_secret_key; @@ -24,8 +25,6 @@ use Jose\Component\Encryption\JWELoader; use Jose\Component\Encryption\JWETokenSupport; use Jose\Component\Encryption\Serializer\CompactSerializer; use Jose\Component\Encryption\Serializer\JWESerializerManager; -use Jose\Easy\AlgorithmProvider; -use Jose\Easy\ContentEncryptionAlgorithmChecker; use function preg_match; use Throwable; @@ -44,7 +43,7 @@ class TokenDecrypter implements TokenDecrypterInterface private $clientSecret; /** @var Algorithm[] */ - private $algorithms; + private $algorithms = []; public function withExpectedAlg(?string $expectedAlg): self { @@ -81,9 +80,15 @@ class TokenDecrypter implements TokenDecrypterInterface public function __construct() { $this->jwksProvider = new MemoryJwksProvider(); - $this->algorithms = (new AlgorithmProvider($this->getAlgorithmMap())) - ->getAvailableAlgorithms() - ; + foreach ($this->getAlgorithmMap() as $algorithmClass) { + if (class_exists($algorithmClass)) { + try { + $this->algorithms[] = new $algorithmClass(); + } catch (Throwable $throwable) { + //does nothing + } + } + } } private function buildJwks(string $jwt): JWKSet @@ -145,6 +150,7 @@ class TokenDecrypter implements TokenDecrypterInterface /** * @return string[] + * * @psalm-return list> */ protected function getAlgorithmMap(): array diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/IdTokenVerifier.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/IdTokenVerifier.php index 9b5deeb52..e87c0f084 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/IdTokenVerifier.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/IdTokenVerifier.php @@ -4,13 +4,12 @@ declare(strict_types=1); namespace Facile\JoseVerifier; -use Facile\JoseVerifier\ClaimChecker\AtHashChecker; -use Facile\JoseVerifier\ClaimChecker\CHashChecker; -use Facile\JoseVerifier\ClaimChecker\SHashChecker; +use Facile\JoseVerifier\Checker\AtHashChecker; +use Facile\JoseVerifier\Checker\CHashChecker; +use Facile\JoseVerifier\Checker\SHashChecker; use Facile\JoseVerifier\Exception\InvalidTokenException; use InvalidArgumentException; use Jose\Component\Signature\Serializer\CompactSerializer; -use Jose\Easy\Validate; use Throwable; /** @@ -62,6 +61,7 @@ final class IdTokenVerifier extends AbstractTokenVerifier implements IdTokenVeri /** * @inheritDoc + * * @psalm-suppress MixedReturnTypeCoercion */ public function verify(string $jwt): array @@ -82,24 +82,21 @@ final class IdTokenVerifier extends AbstractTokenVerifier implements IdTokenVeri $alg = $header['alg'] ?? null; if (null !== $this->accessToken) { - $requiredClaims[] = 'at_hash'; - $validator = $validator->claim('at_hash', new AtHashChecker($this->accessToken, $alg ?: '')); + $validator = $validator->claim(new AtHashChecker($this->accessToken, $alg ?: '')); } if (null !== $this->code) { - $requiredClaims[] = 'c_hash'; - $validator = $validator->claim('c_hash', new CHashChecker($this->code, $alg ?: '')); + $validator = $validator->claim(new CHashChecker($this->code, $alg ?: '')); } if (null !== $this->state) { - $validator = $validator->claim('s_hash', new SHashChecker($this->state, $alg ?: '')); + $validator = $validator->claim(new SHashChecker($this->state, $alg ?: '')); } - /** @var Validate $validator */ $validator = $validator->mandatory($requiredClaims); try { - return $validator->run()->claims->all(); + return $validator->run(); } catch (Throwable $e) { throw $this->processException($e); } diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/CachedJwksProvider.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/CachedJwksProvider.php index 4bc95881c..a42cce81c 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/CachedJwksProvider.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/CachedJwksProvider.php @@ -35,9 +35,6 @@ class CachedJwksProvider implements JwksProviderInterface $this->ttl = $ttl; } - /** - * @inheritDoc - */ public function getJwks(): array { /** @var null|string $cached */ diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/JwksProviderBuilder.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/JwksProviderBuilder.php index c069c4ca8..c965e5687 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/JwksProviderBuilder.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/JwksProviderBuilder.php @@ -20,6 +20,7 @@ class JwksProviderBuilder { /** * @var array|null + * * @psalm-var null|JWKSetObject */ private $jwks; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/MemoryJwksProvider.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/MemoryJwksProvider.php index e97367b48..f46d64cf7 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/MemoryJwksProvider.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/MemoryJwksProvider.php @@ -11,6 +11,7 @@ class MemoryJwksProvider implements JwksProviderInterface { /** * @var array + * * @psalm-var JWKSetObject */ private $jwks; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/RemoteJwksProvider.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/RemoteJwksProvider.php index c073dad1c..5d469d6b6 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/RemoteJwksProvider.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWK/RemoteJwksProvider.php @@ -45,8 +45,6 @@ class RemoteJwksProvider implements JwksProviderInterface /** * @param array $headers - * - * @return RemoteJwksProvider */ public function withHeaders(array $headers): self { @@ -88,6 +86,7 @@ class RemoteJwksProvider implements JwksProviderInterface /** * @param mixed $data + * * @psalm-assert-if-true JWKSetObject $data */ private function isJWKSet($data): bool diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWTVerifier.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWTVerifier.php index 9933195e9..1c3e70d67 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWTVerifier.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/JWTVerifier.php @@ -4,24 +4,23 @@ declare(strict_types=1); namespace Facile\JoseVerifier; -use Jose\Easy\Validate; use Throwable; final class JWTVerifier extends AbstractTokenVerifier { /** * @inheritDoc + * * @psalm-suppress MixedReturnTypeCoercion */ public function verify(string $jwt): array { $jwt = $this->decrypt($jwt); - /** @var Validate $validator */ $validator = $this->create($jwt) ->mandatory(['iss', 'sub', 'aud', 'exp', 'iat']); try { - return $validator->run()->claims->all(); + return $validator->run(); } catch (Throwable $e) { throw $this->processException($e); } diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/Plugin.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/Plugin.php index fa9ed5155..406cca1ec 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/Plugin.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/Plugin.php @@ -16,6 +16,8 @@ use SimpleXMLElement; /** * @internal + * + * @codeCoverageIgnore */ final class Plugin implements PluginEntryPointInterface { @@ -41,7 +43,7 @@ final class Plugin implements PluginEntryPointInterface { $dir = new RecursiveDirectoryIterator($folder); $ite = new RecursiveIteratorIterator($dir); - /** @psalm-var \FilterIterator $files */ + /** @psalm-var \Iterator $files */ $files = new RegexIterator($ite, $pattern, RegexIterator::GET_MATCH); return array_merge([], ...array_values(iterator_to_array($files))); diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/PsalmTypes.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/PsalmTypes.php index 69a02d948..7ae9696bc 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/PsalmTypes.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Psalm/PsalmTypes.php @@ -6,6 +6,7 @@ namespace Facile\JoseVerifier\Psalm; /** * @internal + * * @psalm-type JWKObject = array{kty: "RSA"|"EC"|"oct"|string, use?: "sig"|"enc"|string, key_ops?: list<"sign"|"verify"|"encrypt"|"decrypt"|"wrapKey"|"unwrapKey"|"deriveKey"|"deriveBits"|string>, kid?: string, alg?: string, x5u?: string, x5c?: list, x5t?: string, x5t#S256?: string, crv?: string, x?: string, y?: string, k?: string, n?: string, e?: string, d?: string, p?: string, q?: string, dp?: string, dq?: string, qi?: string} * @psalm-type JWKSetObject = array{keys: list} * @psalm-type OpenIdDisplayType = non-empty-string @@ -16,10 +17,10 @@ namespace Facile\JoseVerifier\Psalm; * @psalm-type OpenIdApplicationType = "web"|"native" * @psalm-type OpenIdSubjectType = "pairwise"|"public" * @psalm-type OpenIdAuthMethod = "client_secret_post"|"client_secret_basic"|"client_secret_jwt"|"private_key_jwt"|"none"|"tls_client_auth"|"self_signed_tls_client_auth" - * @psalm-type ClientMetadataObject = array{client_id: non-empty-string, client_secret?: string, redirect_uris?: list, jwks?: JWKSetObject, jwks_uri?: non-empty-string, response_types?: list, grant_types?: list, application_type?: OpenIdApplicationType, contacts?: list, client_name?: string, logo_uri?: non-empty-string, client_uri?: non-empty-string, policy_uri?: non-empty-string, tos_uri?: non-empty-string, sector_identifier_uri?: non-empty-string, subject_type?: OpenIdSubjectType, authorization_signed_response_alg?: non-empty-string, authorization_encrypted_response_alg?: non-empty-string, authorization_encrypted_response_enc?: non-empty-string, id_token_signed_response_alg?: non-empty-string, id_token_encrypted_response_alg?: non-empty-string, id_token_encrypted_response_enc?: non-empty-string, userinfo_signed_response_alg?: non-empty-string, userinfo_encrypted_response_alg?: non-empty-string, userinfo_encrypted_response_enc?: non-empty-string, request_object_signing_alg?: non-empty-string, request_object_encryption_alg?: non-empty-string, request_object_encryption_enc?: non-empty-string, token_endpoint_auth_method?: OpenIdAuthMethod, token_endpoint_auth_signing_alg?: non-empty-string, default_max_age?: int, require_auth_time?: bool, default_acr_values?: list, initiate_login_uri?: non-empty-string, request_uris?: list, scope?: string, software_id?: non-empty-string, software_version?: non-empty-string, introspection_endpoint_auth_method?: non-empty-string, revocation_endpoint_auth_method?: non-empty-string} + * @psalm-type ClientMetadataObject = array{client_id: non-empty-string, client_secret?: string, redirect_uris?: list, jwks?: JWKSetObject, jwks_uri?: non-empty-string, response_types?: list, grant_types?: list, application_type?: OpenIdApplicationType, contacts?: list, client_name?: string, logo_uri?: non-empty-string, client_uri?: non-empty-string, policy_uri?: non-empty-string, tos_uri?: non-empty-string, sector_identifier_uri?: non-empty-string, subject_type?: OpenIdSubjectType, authorization_signed_response_alg?: non-empty-string, authorization_encrypted_response_alg?: non-empty-string, authorization_encrypted_response_enc?: non-empty-string, id_token_signed_response_alg?: non-empty-string, id_token_encrypted_response_alg?: non-empty-string, id_token_encrypted_response_enc?: non-empty-string, userinfo_signed_response_alg?: non-empty-string, userinfo_encrypted_response_alg?: non-empty-string, userinfo_encrypted_response_enc?: non-empty-string, request_object_signing_alg?: non-empty-string, request_object_encryption_alg?: non-empty-string, request_object_encryption_enc?: non-empty-string, token_endpoint_auth_method?: OpenIdAuthMethod, token_endpoint_auth_signing_alg?: non-empty-string, default_max_age?: int, require_auth_time?: bool, default_acr_values?: list, initiate_login_uri?: non-empty-string, request_uris?: list, scope?: string, software_id?: non-empty-string, software_version?: non-empty-string, introspection_endpoint_auth_method?: non-empty-string, revocation_endpoint_auth_method?: non-empty-string}&array * @psalm-type IssuerMetadataObject = array{issuer: non-empty-string, authorization_endpoint: non-empty-string, token_endpoint?: non-empty-string, userinfo_endpoint?: non-empty-string, jwks_uri: non-empty-string, registration_endpoint?: non-empty-string, scopes_supported?: list, response_types_supported: non-empty-list, response_modes_supported?: list, grant_types_supported?: list, acr_values_supported?: list, subject_types_supported?: list, id_token_signing_alg_values_supported: non-empty-list, id_token_encryption_alg_values_supported?: list, id_token_encryption_enc_values_supported?: list, userinfo_signing_alg_values_supported?: list, userinfo_encryption_alg_values_supported?: list, userinfo_encryption_enc_values_supported?: list, request_object_signing_alg_values_supported?: list, request_object_encryption_alg_values_supported?: list, request_object_encryption_enc_values_supported?: list, token_endpoint_auth_methods_supported?: list, token_endpoint_auth_signing_alg_values_supported?: list, display_values_supported?: list, claim_types_supported?: list, claims_supported?: list, service_documentation?: non-empty-string, claims_locales_supported?: list, ui_locales_supported?: list, claims_parameter_supported?: bool, request_parameter_supported?: bool, request_uri_parameter_supported?: bool, require_request_uri_registration?: bool, op_policy_uri?: non-empty-string, op_tos_uri?: non-empty-string, check_session_iframe?: non-empty-string, code_challenge_methods_supported?: list, authorization_signing_alg_values_supported?: list, authorization_encryption_alg_values_supported?: list, authorization_encryption_enc_values_supported?: list, introspection_endpoint?: non-empty-string, introspection_endpoint_auth_methods_supported?: list, introspection_endpoint_auth_signing_alg_values_supported?: list, introspection_signing_alg_values_supported?: list, introspection_encryption_alg_values_supported?: list, introspection_encryption_enc_values_supported?: list, revocation_endpoint?: non-empty-string, revocation_endpoint_auth_methods_supported?: list, revocation_endpoint_auth_signing_alg_values_supported?: list, end_session_iframe?: non-empty-string, frontchannel_logout_supported?: bool, frontchannel_logout_session_supported?: bool, backchannel_logout_supported?: bool, backchannel_logout_session_supported?: bool, mtls_endpoint_aliases?: array, tls_client_certificate_bound_access_tokens?: bool}&array * @psalm-type JWTHeaderObject = array{alg?: non-empty-string, enc?: non-empty-string, jku?: non-empty-string, jwk?: non-empty-string, kid?: non-empty-string, x5u?: non-empty-string, x5c?: non-empty-string, x5t?: non-empty-string, "x5t#S256"?: non-empty-string, typ?: non-empty-string, cty?: non-empty-string, crit?: non-empty-string} - * @psalm-type JWTPayloadObject = array{tid?: string}&array + * @psalm-type JWTPayloadObject = array */ interface PsalmTypes { diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierBuilderInterface.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierBuilderInterface.php index c134a6887..cb3c1fb26 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierBuilderInterface.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierBuilderInterface.php @@ -8,19 +8,23 @@ use Facile\JoseVerifier\JWK\JwksProviderInterface; /** * @template TVerifier of TokenVerifierInterface + * * @psalm-import-type ClientMetadataObject from Psalm\PsalmTypes - * @psalm-import-type IssuerMetadataObject from Psalm\PsalmTypes + * + * @psalm-type IssuerMetadataObject = array{issuer: string, jwks_uri: string}&array */ interface TokenVerifierBuilderInterface { /** * @param array $clientMetadata + * * @psalm-param ClientMetadataObject $clientMetadata */ public function setClientMetadata(array $clientMetadata): void; /** * @param array $issuerMetadata + * * @psalm-param IssuerMetadataObject $issuerMetadata */ public function setIssuerMetadata(array $issuerMetadata): void; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierInterface.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierInterface.php index 70c16c73a..b5908b4e8 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierInterface.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/TokenVerifierInterface.php @@ -27,6 +27,7 @@ interface TokenVerifierInterface * @throws InvalidTokenException * * @return array The JWT Payload + * * @psalm-return JWTPayloadObject */ public function verify(string $jwt): array; diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/UserInfoVerifier.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/UserInfoVerifier.php index 09d23d1ab..096d894f6 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/UserInfoVerifier.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/UserInfoVerifier.php @@ -4,23 +4,22 @@ declare(strict_types=1); namespace Facile\JoseVerifier; -use Jose\Easy\Validate; use Throwable; final class UserInfoVerifier extends AbstractTokenVerifier { /** * @inheritDoc + * * @psalm-suppress MixedReturnTypeCoercion */ public function verify(string $jwt): array { $jwt = $this->decrypt($jwt); - /** @var Validate $validator */ $validator = $this->create($jwt)->mandatory(['sub']); try { - return $validator->run()->claims->all(); + return $validator->run(); } catch (Throwable $e) { throw $this->processException($e); } diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Validate/Validate.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Validate/Validate.php index aa73878ac..1a3c749d9 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Validate/Validate.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/Validate/Validate.php @@ -4,30 +4,70 @@ declare(strict_types=1); namespace Facile\JoseVerifier\Validate; -use function count; use Facile\JoseVerifier\Exception\RuntimeException; use Jose\Component\Checker; use Jose\Component\Core\AlgorithmManager; +use Jose\Component\Core\JWKSet; use Jose\Component\Core\Util\JsonConverter; use Jose\Component\Signature\Algorithm; use Jose\Component\Signature\JWSTokenSupport; use Jose\Component\Signature\JWSVerifier; use Jose\Component\Signature\Serializer\CompactSerializer; -use Jose\Easy\AbstractLoader; -use Jose\Easy\JWT; +use Throwable; -class Validate extends AbstractLoader +/** + * @internal + */ +final class Validate { + /** @var string */ + protected $token; + + /** @var JWKSet */ + protected $jwkset; + + /** @var Checker\HeaderChecker[] */ + protected $headerCheckers = []; + + /** @var Checker\ClaimChecker[] */ + protected $claimCheckers = []; + + /** @var \Jose\Component\Core\Algorithm[] */ + protected $algorithms = []; + + /** @var string[] */ + protected $mandatoryClaims = []; + + protected function __construct(string $token) + { + $this->token = $token; + $this->jwkset = new JWKSet([]); + $this->claimCheckers = []; + + foreach ($this->getAlgorithmMap() as $algorithmClass) { + if (class_exists($algorithmClass)) { + try { + $this->algorithms[] = new $algorithmClass(); + } catch (Throwable $throwable) { + //does nothing + } + } + } + } + public static function token(string $token): self { return new self($token); } - public function run(): JWT + /** + * @throws Checker\InvalidClaimException + * @throws Checker\MissingMandatoryClaimException + * + * @return array + */ + public function run(): array { - if (0 !== count($this->allowedAlgorithms)) { - $this->headerCheckers[] = new Checker\AlgorithmChecker($this->allowedAlgorithms, true); - } $jws = (new CompactSerializer())->unserialize($this->token); $headerChecker = new Checker\HeaderCheckerManager($this->headerCheckers, [new JWSTokenSupport()]); $headerChecker->check($jws, 0); @@ -37,21 +77,23 @@ class Validate extends AbstractLoader throw new RuntimeException('Invalid signature'); } - $jwt = new JWT(); - $jwt->header->replace($jws->getSignature(0)->getProtectedHeader()); /** @var array $claims */ $claims = JsonConverter::decode($jws->getPayload() ?? '{}'); - $jwt->claims->replace($claims); $claimChecker = new Checker\ClaimCheckerManager($this->claimCheckers); - $claimChecker->check($jwt->claims->all(), $this->mandatoryClaims); + $claimChecker->check($claims, $this->mandatoryClaims); - return $jwt; + return $claims; } /** * @return string[] + * + * @psalm-return list> + * * @psalm-suppress UndefinedClass + * @psalm-suppress InvalidReturnStatement + * @psalm-suppress InvalidReturnType */ protected function getAlgorithmMap(): array { @@ -72,4 +114,41 @@ class Validate extends AbstractLoader Algorithm\EdDSA::class, ]; } + + /** + * @param string[] $mandatoryClaims + */ + public function mandatory(array $mandatoryClaims): self + { + $clone = clone $this; + $clone->mandatoryClaims = $mandatoryClaims; + + return $clone; + } + + public function claim(Checker\ClaimChecker $checker): self + { + $clone = clone $this; + + $clone->claimCheckers[] = $checker; + + return $clone; + } + + public function header(Checker\HeaderChecker $checker): self + { + $clone = clone $this; + + $clone->headerCheckers[] = $checker; + + return $clone; + } + + public function keyset(JWKSet $jwkset): self + { + $clone = clone $this; + $clone->jwkset = $jwkset; + + return $clone; + } } diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/derived_key.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/derived_key.php index d7c80ec23..93225a07c 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/derived_key.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/derived_key.php @@ -10,6 +10,9 @@ use Jose\Component\Core\JWK; use function round; use function substr; +/** + * @internal + */ function derived_key(string $secret, int $length): JWK { $hash = substr(hash('sha256', $secret, true), 0, (int) round($length / 8)); diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/jose_secret_key.php b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/jose_secret_key.php index c9dc3df28..9d09122bc 100644 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/jose_secret_key.php +++ b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/src/functions/jose_secret_key.php @@ -8,6 +8,9 @@ use Base64Url\Base64Url; use Jose\Component\Core\JWK; use function preg_match; +/** + * @internal + */ function jose_secret_key(string $secret, ?string $alg = null): JWK { if (null !== $alg && (bool) preg_match('/^A(\d{3})(?:GCM)?KW$/', $alg, $matches)) { diff --git a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/stubs/Jose/Easy/AlgorithmProvider.phpstub b/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/stubs/Jose/Easy/AlgorithmProvider.phpstub deleted file mode 100644 index 8e49a5bb7..000000000 --- a/lam/lib/3rdParty/composer/facile-it/php-jose-verifier/stubs/Jose/Easy/AlgorithmProvider.phpstub +++ /dev/null @@ -1,32 +0,0 @@ -> $algorithmClasses - */ - public function __construct(array $algorithmClasses) - { - } - - /** - * @return list> - */ - public function getAlgorithmClasses(): array - { - } - - /** - * @return list - */ - public function getAvailableAlgorithms(): array - { - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md b/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md deleted file mode 100644 index e4552acd2..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md +++ /dev/null @@ -1,61 +0,0 @@ -#### v2.5.0 (2022-12) -* Support PHP 8.2 [#99](https://github.com/fgrosse/PHPASN1/pull/99) -* PHP 8 compatibility fix for DateTime::getLastErrors [#98](https://github.com/fgrosse/PHPASN1/pull/98) -* Support more OIDs [#95](https://github.com/fgrosse/PHPASN1/pull/95) -* FINAL RELEASE. Library is now no longer actively maintained and marked as archived on GitHub - -#### v2.4.0 (2021-12) -* Drop support for PHP 7.0 [#89](https://github.com/fgrosse/PHPASN1/pull/89) - -#### v2.3.1 (2021-12) -* Add `#[\ReturnTypeWillChange]` attributes for PHP 8.1 compatibility [#87](https://github.com/fgrosse/PHPASN1/pull/87) - -#### v2.3.0 (2021-04) -* Allow creating an unsigned CSR and adding the signature later [#82](https://github.com/fgrosse/PHPASN1/pull/82) - -#### v2.2.0 (2020-08) -* support polyfills for bcmath and gmp, and add a composer.json - suggestion for the `phpseclib/bcmath_polyfill` for servers unable - to install PHP the gmp or bcmath extensions. - -#### v.2.1.1 & &v.2.0.2 (2018-12) -* add stricter validation around some structures, highlighed - by wycheproof test suite - -#### v.2.1.0 (2018-03) -* add support for `bcmath` extension (making `gmp` optional) [#68](https://github.com/fgrosse/PHPASN1/pull/68) - -#### v.2.0.1 & v.1.5.3 (2017-12) -* add .gitattributes file to prevent examples and tests to be installed via composer when --prefer-dist was set - -#### v.2.0.0 (2017-08) -* rename `FG\ASN1\Object` to `FG\ASN1\ASNObject` because `Object` is a special class name in the next major PHP release - - when you upgrade you have to adapt all corresponding `use` and `extends` statements as well as type hints and all - usages of `Object::fromBinary(…)`. -* generally drop PHP 5.6 support - -#### v.1.5.2 (2016-10-29) -* allow empty octet strings - -#### v.1.5.1 (2015-10-02) -* add keywords to composer.json (this is a version on its own so the keywords are found on a stable version at packagist.org) - -#### v.1.5.0 (2015-10-30) -* fix a bug that would prevent you from decoding context specific tags on multiple objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) - - `ExplicitlyTaggedObject::__construct` does now accept multiple objects to be tagged with a single tag - - `ExplicitlyTaggedObject::getContent` will now always return an array (even if only one object is tagged) - -#### v.1.4.2 (2015-09-29) -* fix a bug that would prevent you from decoding empty tagged objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) - -#### v.1.4.1 -* improve exception messages and general error handling [#55](https ://github.com/fgrosse/PHPASN1/pull/55) - -#### v.1.4.0 -* **require PHP 5.6** -* support big integers (closes #1 and #37) -* enforce one code style via [styleci.io][9] -* track code coverage via [coveralls.io][10] -* replace obsolete `FG\ASN1\Exception\GeneralException` with `\Exception` -* `Construct` (`Sequence`, `Set`) does now implement `ArrayAccess`, `Countable` and `Iterator` so its easier to use -* add [`TemplateParser`][11] diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE b/lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE deleted file mode 100644 index 1e17eb03e..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2012-2015 Friedrich Große - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md b/lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md deleted file mode 100644 index 5c380dbf4..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md +++ /dev/null @@ -1,169 +0,0 @@ -PHPASN1 -======= - -[![Build Status](https://github.com/fgrosse/PHPASN1/actions/workflows/phpunit.yml/badge.svg)](https://github.com/fgrosse/PHPASN1/actions/workflows/phpunit.yml) -[![PHP 7 ready](http://php7ready.timesplinter.ch/fgrosse/PHPASN1/badge.svg)](https://travis-ci.org/fgrosse/PHPASN1) -[![Coverage Status](https://coveralls.io/repos/fgrosse/PHPASN1/badge.svg?branch=master&service=github)](https://coveralls.io/github/fgrosse/PHPASN1?branch=master) - -[![Latest Stable Version](https://poser.pugx.org/fgrosse/phpasn1/v/stable.png)](https://packagist.org/packages/fgrosse/phpasn1) -[![Total Downloads](https://poser.pugx.org/fgrosse/phpasn1/downloads.png)](https://packagist.org/packages/fgrosse/phpasn1) -[![Latest Unstable Version](https://poser.pugx.org/fgrosse/phpasn1/v/unstable.png)](https://packagist.org/packages/fgrosse/phpasn1) -[![License](https://poser.pugx.org/fgrosse/phpasn1/license.png)](https://packagist.org/packages/fgrosse/phpasn1) - ---- - -

    Notice: This library is no longer actively maintained!

    -If you are currently using PHPASN1, this might not be an immediate problem for you, since this library was always rather stable. - -However, you are advised to migrate to alternative packages to ensure that your applications remain functional also with newer PHP versions. - ---- - -A PHP Framework that allows you to encode and decode arbitrary [ASN.1][3] structures -using the [ITU-T X.690 Encoding Rules][4]. -This encoding is very frequently used in [X.509 PKI environments][5] or the communication between heterogeneous computer systems. - -The API allows you to encode ASN.1 structures to create binary data such as certificate -signing requests (CSR), X.509 certificates or certificate revocation lists (CRL). -PHPASN1 can also read [BER encoded][6] binary data into separate PHP objects that can be manipulated by the user and reencoded afterwards. - -The **changelog** can now be found at [CHANGELOG.md](CHANGELOG.md). - -## Dependencies - -PHPASN1 requires at least `PHP 7.0` and either the `gmp` or `bcmath` extension. -Support for older PHP versions (i.e. PHP 5.6) was dropped starting with `v2.0`. -If you must use an outdated PHP version consider using [PHPASN v1.5][13]. - -For the loading of object identifier names directly from the web [curl][7] is used. - -## Installation - -The preferred way to install this library is to rely on [Composer][2]: - -```bash -$ composer require fgrosse/phpasn1 -``` - -## Usage - -### Encoding ASN.1 Structures - -PHPASN1 offers you a class for each of the implemented ASN.1 universal types. -The constructors should be pretty self explanatory so you should have no big trouble getting started. -All data will be encoded using [DER encoding][8] - -```php -use FG\ASN1\OID; -use FG\ASN1\Universal\Integer; -use FG\ASN1\Universal\Boolean; -use FG\ASN1\Universal\Enumerated; -use FG\ASN1\Universal\IA5String; -use FG\ASN1\Universal\ObjectIdentifier; -use FG\ASN1\Universal\PrintableString; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\Set; -use FG\ASN1\Universal\NullObject; - -$integer = new Integer(123456); -$boolean = new Boolean(true); -$enum = new Enumerated(1); -$ia5String = new IA5String('Hello world'); - -$asnNull = new NullObject(); -$objectIdentifier1 = new ObjectIdentifier('1.2.250.1.16.9'); -$objectIdentifier2 = new ObjectIdentifier(OID::RSA_ENCRYPTION); -$printableString = new PrintableString('Foo bar'); - -$sequence = new Sequence($integer, $boolean, $enum, $ia5String); -$set = new Set($sequence, $asnNull, $objectIdentifier1, $objectIdentifier2, $printableString); - -$myBinary = $sequence->getBinary(); -$myBinary .= $set->getBinary(); - -echo base64_encode($myBinary); -``` - - -### Decoding binary data - -Decoding BER encoded binary data is just as easy as encoding it: - -```php -use FG\ASN1\ASNObject; - -$base64String = ... -$binaryData = base64_decode($base64String); -$asnObject = ASNObject::fromBinary($binaryData); - - -// do stuff -``` - -If you already know exactly how your expected data should look like you can use the `FG\ASN1\TemplateParser`: - -```php -use FG\ASN1\TemplateParser; - -// first define your template -$template = [ - Identifier::SEQUENCE => [ - Identifier::SET => [ - Identifier::OBJECT_IDENTIFIER, - Identifier::SEQUENCE => [ - Identifier::INTEGER, - Identifier::BITSTRING, - ] - ] - ] -]; - -// if your binary data is not matching the template you provided this will throw an `\Exception`: -$parser = new TemplateParser(); -$object = $parser->parseBinary($data, $template); - -// there is also a convenience function if you parse binary data from base64: -$object = $parser->parseBase64($data, $template); -``` - -You can use this function to make sure your data has exactly the format you are expecting. - -### Navigating decoded data - -All constructed classes (i.e. `Sequence` and `Set`) can be navigated by array access or using an iterator. -You can find examples -[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L148-148), -[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L121) and -[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/TemplateParserTest.php#L45). - - -### Give me more examples! - -To see some example usage of the API classes or some generated output check out the [examples](https://github.com/fgrosse/PHPASN1/tree/master/examples). - - -### How do I contribute? - -This project is no longer maintained and thus does not accept any new contributions. - -### Thanks - -To [all contributors][1] so far! - -## License - -This library is distributed under the [MIT License](LICENSE). - -[1]: https://github.com/fgrosse/PHPASN1/graphs/contributors -[2]: https://getcomposer.org/ -[3]: http://www.itu.int/ITU-T/asn1/ -[4]: http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.690 -[5]: http://en.wikipedia.org/wiki/X.509 -[6]: http://en.wikipedia.org/wiki/X.690#BER_encoding -[7]: http://php.net/manual/en/book.curl.php -[8]: http://en.wikipedia.org/wiki/X.690#DER_encoding -[9]: https://styleci.io -[10]: https://coveralls.io/github/fgrosse/PHPASN1 -[11]: https://github.com/fgrosse/PHPASN1/blob/master/tests/ASN1/TemplateParserTest.php#L16 -[12]: https://groups.google.com/d/forum/phpasn1 -[13]: https://packagist.org/packages/fgrosse/phpasn1#1.5.2 diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json b/lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json deleted file mode 100644 index 130dc8f4d..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "fgrosse/phpasn1", - "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", - "type": "library", - "homepage": "https://github.com/FGrosse/PHPASN1", - "license": "MIT", - "authors": [ - { - "name": "Friedrich Große", - "email": "friedrich.grosse@gmail.com", - "homepage": "https://github.com/FGrosse", - "role": "Author" - }, - { - "name": "All contributors", - "homepage": "https://github.com/FGrosse/PHPASN1/contributors" - } - ], - "keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ], - - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", - "php-coveralls/php-coveralls": "~2.0" - }, - "suggest": { - "ext-gmp": "GMP is the preferred extension for big integer calculations", - "ext-bcmath": "BCmath is the fallback extension for big integer calculations", - "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available", - "ext-curl": "For loading OID information from the web if they have not bee defined statically" - }, - "autoload": { - "psr-4": { - "FG\\": "lib/" - } - }, - "autoload-dev": { - "psr-4": { - "FG\\Test\\": "tests/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php deleted file mode 100644 index 3b7f16215..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php +++ /dev/null @@ -1,355 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use FG\ASN1\Exception\ParserException; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\Boolean; -use FG\ASN1\Universal\Enumerated; -use FG\ASN1\Universal\GeneralizedTime; -use FG\ASN1\Universal\Integer; -use FG\ASN1\Universal\NullObject; -use FG\ASN1\Universal\ObjectIdentifier; -use FG\ASN1\Universal\RelativeObjectIdentifier; -use FG\ASN1\Universal\OctetString; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\Set; -use FG\ASN1\Universal\UTCTime; -use FG\ASN1\Universal\IA5String; -use FG\ASN1\Universal\PrintableString; -use FG\ASN1\Universal\NumericString; -use FG\ASN1\Universal\UTF8String; -use FG\ASN1\Universal\UniversalString; -use FG\ASN1\Universal\CharacterString; -use FG\ASN1\Universal\GeneralString; -use FG\ASN1\Universal\VisibleString; -use FG\ASN1\Universal\GraphicString; -use FG\ASN1\Universal\BMPString; -use FG\ASN1\Universal\T61String; -use FG\ASN1\Universal\ObjectDescriptor; -use FG\Utility\BigInteger; -use LogicException; - -/** - * Class ASNObject is the base class for all concrete ASN.1 objects. - */ -abstract class ASNObject implements Parsable -{ - private $contentLength; - private $nrOfLengthOctets; - - /** - * Must return the number of octets of the content part. - * - * @return int - */ - abstract protected function calculateContentLength(); - - /** - * Encode the object using DER encoding. - * - * @see http://en.wikipedia.org/wiki/X.690#DER_encoding - * - * @return string the binary representation of an objects value - */ - abstract protected function getEncodedValue(); - - /** - * Return the content of this object in a non encoded form. - * This can be used to print the value in human readable form. - * - * @return mixed - */ - abstract public function getContent(); - - /** - * Return the object type octet. - * This should use the class constants of Identifier. - * - * @see Identifier - * - * @return int - */ - abstract public function getType(); - - /** - * Returns all identifier octets. If an inheriting class models a tag with - * the long form identifier format, it MUST reimplement this method to - * return all octets of the identifier. - * - * @throws LogicException If the identifier format is long form - * - * @return string Identifier as a set of octets - */ - public function getIdentifier() - { - $firstOctet = $this->getType(); - - if (Identifier::isLongForm($firstOctet)) { - throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this))); - } - - return chr($firstOctet); - } - - /** - * Encode this object using DER encoding. - * - * @return string the full binary representation of the complete object - */ - public function getBinary() - { - $result = $this->getIdentifier(); - $result .= $this->createLengthPart(); - $result .= $this->getEncodedValue(); - - return $result; - } - - private function createLengthPart() - { - $contentLength = $this->getContentLength(); - $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); - - if ($nrOfLengthOctets == 1) { - return chr($contentLength); - } else { - // the first length octet determines the number subsequent length octets - $lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1)); - for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) { - $lengthOctets .= chr($contentLength >> $shiftLength); - } - - return $lengthOctets; - } - } - - protected function getNumberOfLengthOctets($contentLength = null) - { - if (!isset($this->nrOfLengthOctets)) { - if ($contentLength == null) { - $contentLength = $this->getContentLength(); - } - - $this->nrOfLengthOctets = 1; - if ($contentLength > 127) { - do { // long form - $this->nrOfLengthOctets++; - $contentLength = $contentLength >> 8; - } while ($contentLength > 0); - } - } - - return $this->nrOfLengthOctets; - } - - protected function getContentLength() - { - if (!isset($this->contentLength)) { - $this->contentLength = $this->calculateContentLength(); - } - - return $this->contentLength; - } - - protected function setContentLength($newContentLength) - { - $this->contentLength = $newContentLength; - $this->getNumberOfLengthOctets($newContentLength); - } - - /** - * Returns the length of the whole object (including the identifier and length octets). - */ - public function getObjectLength() - { - $nrOfIdentifierOctets = strlen($this->getIdentifier()); - $contentLength = $this->getContentLength(); - $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); - - return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength; - } - - public function __toString() - { - return $this->getContent(); - } - - /** - * Returns the name of the ASN.1 Type of this object. - * - * @see Identifier::getName() - */ - public function getTypeName() - { - return Identifier::getName($this->getType()); - } - - /** - * @param string $binaryData - * @param int $offsetIndex - * - * @throws ParserException - * - * @return \FG\ASN1\ASNObject - */ - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - if (strlen($binaryData) <= $offsetIndex) { - throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex); - } - - $identifierOctet = ord($binaryData[$offsetIndex]); - if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) { - return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex); - } - - switch ($identifierOctet) { - case Identifier::BITSTRING: - return BitString::fromBinary($binaryData, $offsetIndex); - case Identifier::BOOLEAN: - return Boolean::fromBinary($binaryData, $offsetIndex); - case Identifier::ENUMERATED: - return Enumerated::fromBinary($binaryData, $offsetIndex); - case Identifier::INTEGER: - return Integer::fromBinary($binaryData, $offsetIndex); - case Identifier::NULL: - return NullObject::fromBinary($binaryData, $offsetIndex); - case Identifier::OBJECT_IDENTIFIER: - return ObjectIdentifier::fromBinary($binaryData, $offsetIndex); - case Identifier::RELATIVE_OID: - return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex); - case Identifier::OCTETSTRING: - return OctetString::fromBinary($binaryData, $offsetIndex); - case Identifier::SEQUENCE: - return Sequence::fromBinary($binaryData, $offsetIndex); - case Identifier::SET: - return Set::fromBinary($binaryData, $offsetIndex); - case Identifier::UTC_TIME: - return UTCTime::fromBinary($binaryData, $offsetIndex); - case Identifier::GENERALIZED_TIME: - return GeneralizedTime::fromBinary($binaryData, $offsetIndex); - case Identifier::IA5_STRING: - return IA5String::fromBinary($binaryData, $offsetIndex); - case Identifier::PRINTABLE_STRING: - return PrintableString::fromBinary($binaryData, $offsetIndex); - case Identifier::NUMERIC_STRING: - return NumericString::fromBinary($binaryData, $offsetIndex); - case Identifier::UTF8_STRING: - return UTF8String::fromBinary($binaryData, $offsetIndex); - case Identifier::UNIVERSAL_STRING: - return UniversalString::fromBinary($binaryData, $offsetIndex); - case Identifier::CHARACTER_STRING: - return CharacterString::fromBinary($binaryData, $offsetIndex); - case Identifier::GENERAL_STRING: - return GeneralString::fromBinary($binaryData, $offsetIndex); - case Identifier::VISIBLE_STRING: - return VisibleString::fromBinary($binaryData, $offsetIndex); - case Identifier::GRAPHIC_STRING: - return GraphicString::fromBinary($binaryData, $offsetIndex); - case Identifier::BMP_STRING: - return BMPString::fromBinary($binaryData, $offsetIndex); - case Identifier::T61_STRING: - return T61String::fromBinary($binaryData, $offsetIndex); - case Identifier::OBJECT_DESCRIPTOR: - return ObjectDescriptor::fromBinary($binaryData, $offsetIndex); - default: - // At this point the identifier may be >1 byte. - if (Identifier::isConstructed($identifierOctet)) { - return new UnknownConstructedObject($binaryData, $offsetIndex); - } else { - $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); - $lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex); - $offsetIndex += $lengthOfUnknownObject; - - return new UnknownObject($identifier, $lengthOfUnknownObject); - } - } - } - - protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling) - { - if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) { - $identifierOctet = ord($identifierOctet); - } - - if ($identifierOctet != $expectedIdentifier) { - $message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet); - throw new ParserException($message, $offsetForExceptionHandling); - } - } - - protected static function parseBinaryIdentifier($binaryData, &$offsetIndex) - { - if (strlen($binaryData) <= $offsetIndex) { - throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex); - } - - $identifier = $binaryData[$offsetIndex++]; - - if (Identifier::isLongForm(ord($identifier)) == false) { - return $identifier; - } - - while (true) { - if (strlen($binaryData) <= $offsetIndex) { - throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex); - } - $nextOctet = $binaryData[$offsetIndex++]; - $identifier .= $nextOctet; - - if ((ord($nextOctet) & 0x80) === 0) { - // the most significant bit is 0 to we have reached the end of the identifier - break; - } - } - - return $identifier; - } - - protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0) - { - if (strlen($binaryData) <= $offsetIndex) { - throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex); - } - - $contentLength = ord($binaryData[$offsetIndex++]); - if (($contentLength & 0x80) != 0) { - // bit 8 is set -> this is the long form - $nrOfLengthOctets = $contentLength & 0x7F; - $contentLength = BigInteger::create(0x00); - for ($i = 0; $i < $nrOfLengthOctets; $i++) { - if (strlen($binaryData) <= $offsetIndex) { - throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex); - } - $contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++])); - } - - if ($contentLength->compare(PHP_INT_MAX) > 0) { - throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex); - } - - $contentLength = $contentLength->toInteger(); - } - - if ($contentLength < $minimumLength) { - throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex); - } - - $lenDataRemaining = strlen($binaryData) - $offsetIndex; - - if ($lenDataRemaining < $contentLength) { - throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex); - } - - return $contentLength; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.php deleted file mode 100644 index 7e0d7ddbb..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.php +++ /dev/null @@ -1,136 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use Exception; - -abstract class AbstractString extends ASNObject implements Parsable -{ - /** @var string */ - protected $value; - private $checkStringForIllegalChars = true; - private $allowedCharacters = []; - - /** - * The abstract base class for ASN.1 classes which represent some string of character. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - } - - public function getContent() - { - return $this->value; - } - - protected function allowCharacter($character) - { - $this->allowedCharacters[] = $character; - } - - protected function allowCharacters(...$characters) - { - foreach ($characters as $character) { - $this->allowedCharacters[] = $character; - } - } - - protected function allowNumbers() - { - foreach (range('0', '9') as $char) { - $this->allowedCharacters[] = (string) $char; - } - } - - protected function allowAllLetters() - { - $this->allowSmallLetters(); - $this->allowCapitalLetters(); - } - - protected function allowSmallLetters() - { - foreach (range('a', 'z') as $char) { - $this->allowedCharacters[] = $char; - } - } - - protected function allowCapitalLetters() - { - foreach (range('A', 'Z') as $char) { - $this->allowedCharacters[] = $char; - } - } - - protected function allowSpaces() - { - $this->allowedCharacters[] = ' '; - } - - protected function allowAll() - { - $this->checkStringForIllegalChars = false; - } - - protected function calculateContentLength() - { - return strlen($this->value); - } - - protected function getEncodedValue() - { - if ($this->checkStringForIllegalChars) { - $this->checkString(); - } - - return $this->value; - } - - protected function checkString() - { - $stringLength = $this->getContentLength(); - for ($i = 0; $i < $stringLength; $i++) { - if (in_array($this->value[$i], $this->allowedCharacters) == false) { - $typeName = Identifier::getName($this->getType()); - throw new Exception("Could not create a {$typeName} from the character sequence '{$this->value}'."); - } - } - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - $parsedObject = new static(''); - - self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - $string = substr($binaryData, $offsetIndex, $contentLength); - $offsetIndex += $contentLength; - - $parsedObject->value = $string; - $parsedObject->setContentLength($contentLength); - return $parsedObject; - } - - public static function isValid($string) - { - $testObject = new static($string); - try { - $testObject->checkString(); - - return true; - } catch (Exception $exception) { - return false; - } - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php deleted file mode 100644 index 8e721ae89..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use DateInterval; -use DateTime; -use DateTimeZone; -use Exception; - -abstract class AbstractTime extends ASNObject -{ - /** @var DateTime */ - protected $value; - - public function __construct($dateTime = null, $dateTimeZone = 'UTC') - { - if ($dateTime == null || is_string($dateTime)) { - $timeZone = new DateTimeZone($dateTimeZone); - $dateTimeObject = new DateTime($dateTime, $timeZone); - if ($dateTimeObject == false) { - $errorMessage = $this->getLastDateTimeErrors(); - $className = Identifier::getName($this->getType()); - throw new Exception(sprintf("Could not create %s from date time string '%s': %s", $className, $dateTime, $errorMessage)); - } - $dateTime = $dateTimeObject; - } elseif (!$dateTime instanceof DateTime) { - throw new Exception('Invalid first argument for some instance of AbstractTime constructor'); - } - - $this->value = $dateTime; - } - - public function getContent() - { - return $this->value; - } - - protected function getLastDateTimeErrors() - { - $messages = ''; - $lastErrors = DateTime::getLastErrors() ?: ['errors' => []]; - foreach ($lastErrors['errors'] as $errorMessage) { - $messages .= "{$errorMessage}, "; - } - - return substr($messages, 0, -2); - } - - public function __toString() - { - return $this->value->format("Y-m-d\tH:i:s"); - } - - protected static function extractTimeZoneData(&$binaryData, &$offsetIndex, DateTime $dateTime) - { - $sign = $binaryData[$offsetIndex++]; - $timeOffsetHours = intval(substr($binaryData, $offsetIndex, 2)); - $timeOffsetMinutes = intval(substr($binaryData, $offsetIndex + 2, 2)); - $offsetIndex += 4; - - $interval = new DateInterval("PT{$timeOffsetHours}H{$timeOffsetMinutes}M"); - if ($sign == '+') { - $dateTime->sub($interval); - } else { - $dateTime->add($interval); - } - - return $dateTime; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php deleted file mode 100644 index 119ee7b9c..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php +++ /dev/null @@ -1,63 +0,0 @@ -modulus(0x80)->toInteger()); - - $value = $value->shiftRight(7); - while ($value->compare(0) > 0) { - $octets .= chr(0x80 | $value->modulus(0x80)->toInteger()); - $value = $value->shiftRight(7); - } - - return strrev($octets); - } - - /** - * @param string $octets - * - * @throws InvalidArgumentException if the given octets represent a malformed base-128 value or the decoded value would exceed the the maximum integer length - * - * @return int - */ - public static function decode($octets) - { - $bitsPerOctet = 7; - $value = BigInteger::create(0); - $i = 0; - - while (true) { - if (!isset($octets[$i])) { - throw new InvalidArgumentException(sprintf('Malformed base-128 encoded value (0x%s).', strtoupper(bin2hex($octets)) ?: '0')); - } - - $octet = ord($octets[$i++]); - - $l1 = $value->shiftLeft($bitsPerOctet); - $r1 = $octet & 0x7f; - $value = $l1->add($r1); - - if (0 === ($octet & 0x80)) { - break; - } - } - - return (string)$value; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php deleted file mode 100644 index 3f4027c25..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Composite; - -use FG\ASN1\ASNObject; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\ObjectIdentifier; - -class AttributeTypeAndValue extends Sequence -{ - /** - * @param ObjectIdentifier|string $objIdentifier - * @param \FG\ASN1\ASNObject $value - */ - public function __construct($objIdentifier, ASNObject $value) - { - if ($objIdentifier instanceof ObjectIdentifier == false) { - $objIdentifier = new ObjectIdentifier($objIdentifier); - } - parent::__construct($objIdentifier, $value); - } - - public function __toString() - { - return $this->children[0].': '.$this->children[1]; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php deleted file mode 100644 index e95e7acd3..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Composite; - -use FG\ASN1\Universal\PrintableString; -use FG\ASN1\Universal\IA5String; -use FG\ASN1\Universal\UTF8String; - -class RDNString extends RelativeDistinguishedName -{ - /** - * @param string|\FG\ASN1\Universal\ObjectIdentifier $objectIdentifierString - * @param string|\FG\ASN1\ASNObject $value - */ - public function __construct($objectIdentifierString, $value) - { - if (PrintableString::isValid($value)) { - $value = new PrintableString($value); - } else { - if (IA5String::isValid($value)) { - $value = new IA5String($value); - } else { - $value = new UTF8String($value); - } - } - - parent::__construct($objectIdentifierString, $value); - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php deleted file mode 100644 index 4185f41a1..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Composite; - -use FG\ASN1\Exception\NotImplementedException; -use FG\ASN1\ASNObject; -use FG\ASN1\Universal\Set; - -class RelativeDistinguishedName extends Set -{ - /** - * @param string|\FG\ASN1\Universal\ObjectIdentifier $objIdentifierString - * @param \FG\ASN1\ASNObject $value - */ - public function __construct($objIdentifierString, ASNObject $value) - { - // TODO: This does only support one element in the RelativeDistinguishedName Set but it it is defined as follows: - // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue - parent::__construct(new AttributeTypeAndValue($objIdentifierString, $value)); - } - - public function getContent() - { - /** @var \FG\ASN1\ASNObject $firstObject */ - $firstObject = $this->children[0]; - return $firstObject->__toString(); - } - - /** - * At the current version this code can not work since the implementation of Construct requires - * the class to support a constructor without arguments. - * - * @deprecated this function is not yet implemented! Feel free to submit a pull request on github - * @param string $binaryData - * @param int $offsetIndex - * @throws NotImplementedException - */ - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - throw new NotImplementedException(); - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php deleted file mode 100644 index cedf422e5..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php +++ /dev/null @@ -1,202 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use ArrayAccess; -use ArrayIterator; -use Countable; -use FG\ASN1\Exception\ParserException; -use Iterator; - -abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable -{ - /** @var \FG\ASN1\ASNObject[] */ - protected $children; - private $iteratorPosition; - - /** - * @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858 - */ - public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children) - { - $this->children = $children; - $this->iteratorPosition = 0; - } - - public function getContent() - { - return $this->children; - } - - #[\ReturnTypeWillChange] - public function rewind() - { - $this->iteratorPosition = 0; - } - - #[\ReturnTypeWillChange] - public function current() - { - return $this->children[$this->iteratorPosition]; - } - - #[\ReturnTypeWillChange] - public function key() - { - return $this->iteratorPosition; - } - - #[\ReturnTypeWillChange] - public function next() - { - $this->iteratorPosition++; - } - - #[\ReturnTypeWillChange] - public function valid() - { - return isset($this->children[$this->iteratorPosition]); - } - - #[\ReturnTypeWillChange] - public function offsetExists($offset) - { - return array_key_exists($offset, $this->children); - } - - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - return $this->children[$offset]; - } - - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if ($offset === null) { - $offset = count($this->children); - } - - $this->children[$offset] = $value; - } - - #[\ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->children[$offset]); - } - - protected function calculateContentLength() - { - $length = 0; - foreach ($this->children as $component) { - $length += $component->getObjectLength(); - } - - return $length; - } - - protected function getEncodedValue() - { - $result = ''; - foreach ($this->children as $component) { - $result .= $component->getBinary(); - } - - return $result; - } - - public function addChild(ASNObject $child) - { - $this->children[] = $child; - } - - public function addChildren(array $children) - { - foreach ($children as $child) { - $this->addChild($child); - } - } - - public function __toString() - { - $nrOfChildren = $this->getNumberOfChildren(); - $childString = $nrOfChildren == 1 ? 'child' : 'children'; - - return "[{$nrOfChildren} {$childString}]"; - } - - public function getNumberOfChildren() - { - return count($this->children); - } - - /** - * @return \FG\ASN1\ASNObject[] - */ - public function getChildren() - { - return $this->children; - } - - /** - * @return \FG\ASN1\ASNObject - */ - public function getFirstChild() - { - return $this->children[0]; - } - - /** - * @param string $binaryData - * @param int $offsetIndex - * - * @throws Exception\ParserException - * - * @return Construct|static - */ - #[\ReturnTypeWillChange] - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - $parsedObject = new static(); - self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - $startIndex = $offsetIndex; - - $children = []; - $octetsToRead = $contentLength; - while ($octetsToRead > 0) { - $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); - $octetsToRead -= $newChild->getObjectLength(); - $children[] = $newChild; - } - - if ($octetsToRead !== 0) { - throw new ParserException("Sequence length incorrect", $startIndex); - } - - $parsedObject->addChildren($children); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } - - #[\ReturnTypeWillChange] - public function count($mode = COUNT_NORMAL) - { - return count($this->children, $mode); - } - - public function getIterator() - { - return new ArrayIterator($this->children); - } -} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php deleted file mode 100644 index c9f8e82e6..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php +++ /dev/null @@ -1,15 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Exception; - -class NotImplementedException extends \Exception -{ -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php deleted file mode 100644 index 4bda4e872..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Exception; - -class ParserException extends \Exception -{ - private $errorMessage; - private $offset; - - public function __construct($errorMessage, $offset) - { - $this->errorMessage = $errorMessage; - $this->offset = $offset; - parent::__construct("ASN.1 Parser Exception at offset {$this->offset}: {$this->errorMessage}"); - } - - public function getOffset() - { - return $this->offset; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php deleted file mode 100644 index b947a9599..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php +++ /dev/null @@ -1,131 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use FG\ASN1\Exception\ParserException; - -/** - * Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about - * its context specific meaning. - * - * Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER: - * >>> An RSA Laboratories Technical Note - * >>> Burton S. Kaliski Jr. - * >>> Revised November 1, 1993 - * - * [...] - * Explicitly tagged types are derived from other types by adding an outer tag to the underlying type. - * In effect, explicitly tagged types are structured types consisting of one component, the underlying type. - * Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2). - * [...] - * - * @see http://luca.ntop.org/Teaching/Appunti/asn1.html - */ -class ExplicitlyTaggedObject extends ASNObject -{ - /** @var \FG\ASN1\ASNObject[] */ - private $decoratedObjects; - private $tag; - - /** - * @param int $tag - * @param \FG\ASN1\ASNObject $objects,... - */ - public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects) - { - $this->tag = $tag; - $this->decoratedObjects = $objects; - } - - protected function calculateContentLength() - { - $length = 0; - foreach ($this->decoratedObjects as $object) { - $length += $object->getObjectLength(); - } - - return $length; - } - - protected function getEncodedValue() - { - $encoded = ''; - foreach ($this->decoratedObjects as $object) { - $encoded .= $object->getBinary(); - } - - return $encoded; - } - - public function getContent() - { - return $this->decoratedObjects; - } - - public function __toString() - { - switch ($length = count($this->decoratedObjects)) { - case 0: - return "Context specific empty object with tag [{$this->tag}]"; - case 1: - $decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType()); - return "Context specific $decoratedType with tag [{$this->tag}]"; - default: - return "$length context specific objects with tag [{$this->tag}]"; - } - } - - public function getType() - { - return ord($this->getIdentifier()); - } - - public function getIdentifier() - { - $identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag); - - return is_int($identifier) ? chr($identifier) : $identifier; - } - - public function getTag() - { - return $this->tag; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); - $firstIdentifierOctet = ord($identifier); - assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class'); - assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object'); - $tag = Identifier::getTagNumber($identifier); - - $totalContentLength = self::parseContentLength($binaryData, $offsetIndex); - $remainingContentLength = $totalContentLength; - - $offsetIndexOfDecoratedObject = $offsetIndex; - $decoratedObjects = []; - - while ($remainingContentLength > 0) { - $nextObject = ASNObject::fromBinary($binaryData, $offsetIndex); - $remainingContentLength -= $nextObject->getObjectLength(); - $decoratedObjects[] = $nextObject; - } - - if ($remainingContentLength != 0) { - throw new ParserException("Context-Specific explicitly tagged object [$tag] starting at offset $offsetIndexOfDecoratedObject specifies a length of $totalContentLength octets but $remainingContentLength remain after parsing the content", $offsetIndexOfDecoratedObject); - } - - $parsedObject = new self($tag, ...$decoratedObjects); - $parsedObject->setContentLength($totalContentLength); - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php deleted file mode 100644 index b21caa34c..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php +++ /dev/null @@ -1,339 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use Exception; - -/** - * The Identifier encodes the ASN.1 tag (class and number) of the type of a data value. - * - * Every identifier whose number is in the range 0 to 30 has the following structure: - * - * Bits: 8 7 6 5 4 3 2 1 - * | Class | P/C | Tag number | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Bits 8 and 7 define the class of this type ( Universal, Application, Context-specific or Private). - * Bit 6 encoded whether this type is primitive or constructed - * The remaining bits 5 - 1 encode the tag number - */ -class Identifier -{ - const CLASS_UNIVERSAL = 0x00; - const CLASS_APPLICATION = 0x01; - const CLASS_CONTEXT_SPECIFIC = 0x02; - const CLASS_PRIVATE = 0x03; - - const EOC = 0x00; // unsupported for now - const BOOLEAN = 0x01; - const INTEGER = 0x02; - const BITSTRING = 0x03; - const OCTETSTRING = 0x04; - const NULL = 0x05; - const OBJECT_IDENTIFIER = 0x06; - const OBJECT_DESCRIPTOR = 0x07; - const EXTERNAL = 0x08; // unsupported for now - const REAL = 0x09; // unsupported for now - const ENUMERATED = 0x0A; - const EMBEDDED_PDV = 0x0B; // unsupported for now - const UTF8_STRING = 0x0C; - const RELATIVE_OID = 0x0D; - // value 0x0E and 0x0F are reserved for future use - - const SEQUENCE = 0x30; - const SET = 0x31; - const NUMERIC_STRING = 0x12; - const PRINTABLE_STRING = 0x13; - const T61_STRING = 0x14; // sometimes referred to as TeletextString - const VIDEOTEXT_STRING = 0x15; - const IA5_STRING = 0x16; - const UTC_TIME = 0x17; - const GENERALIZED_TIME = 0x18; - const GRAPHIC_STRING = 0x19; - const VISIBLE_STRING = 0x1A; - const GENERAL_STRING = 0x1B; - const UNIVERSAL_STRING = 0x1C; - const CHARACTER_STRING = 0x1D; // Unrestricted character type - const BMP_STRING = 0x1E; - - const LONG_FORM = 0x1F; - const IS_CONSTRUCTED = 0x20; - - /** - * Creates an identifier. Short form identifiers are returned as integers - * for BC, long form identifiers will be returned as a string of octets. - * - * @param int $class - * @param bool $isConstructed - * @param int $tagNumber - * - * @throws Exception if the given arguments are invalid - * - * @return int|string - */ - public static function create($class, $isConstructed, $tagNumber) - { - if (!is_numeric($class) || $class < self::CLASS_UNIVERSAL || $class > self::CLASS_PRIVATE) { - throw new Exception(sprintf('Invalid class %d given', $class)); - } - - if (!is_bool($isConstructed)) { - throw new Exception("\$isConstructed must be a boolean value ($isConstructed given)"); - } - - $tagNumber = self::makeNumeric($tagNumber); - if ($tagNumber < 0) { - throw new Exception(sprintf('Invalid $tagNumber %d given. You can only use positive integers.', $tagNumber)); - } - - if ($tagNumber < self::LONG_FORM) { - return ($class << 6) | ($isConstructed << 5) | $tagNumber; - } - - $firstOctet = ($class << 6) | ($isConstructed << 5) | self::LONG_FORM; - - // Tag numbers formatted in long form are base-128 encoded. See X.609#8.1.2.4 - return chr($firstOctet).Base128::encode($tagNumber); - } - - public static function isConstructed($identifierOctet) - { - return ($identifierOctet & self::IS_CONSTRUCTED) === self::IS_CONSTRUCTED; - } - - public static function isLongForm($identifierOctet) - { - return ($identifierOctet & self::LONG_FORM) === self::LONG_FORM; - } - - /** - * Return the name of the mapped ASN.1 type with a preceding "ASN.1 ". - * - * Example: ASN.1 Octet String - * - * @see Identifier::getShortName() - * - * @param int|string $identifier - * - * @return string - */ - public static function getName($identifier) - { - $identifierOctet = self::makeNumeric($identifier); - - $typeName = static::getShortName($identifier); - - if (($identifierOctet & self::LONG_FORM) < self::LONG_FORM) { - $typeName = "ASN.1 {$typeName}"; - } - - return $typeName; - } - - /** - * Return the short version of the type name. - * - * If the given identifier octet can be mapped to a known universal type this will - * return its name. Else Identifier::getClassDescription() is used to retrieve - * information about the identifier. - * - * @see Identifier::getName() - * @see Identifier::getClassDescription() - * - * @param int|string $identifier - * - * @return string - */ - public static function getShortName($identifier) - { - $identifierOctet = self::makeNumeric($identifier); - - switch ($identifierOctet) { - case self::EOC: - return 'End-of-contents octet'; - case self::BOOLEAN: - return 'Boolean'; - case self::INTEGER: - return 'Integer'; - case self::BITSTRING: - return 'Bit String'; - case self::OCTETSTRING: - return 'Octet String'; - case self::NULL: - return 'NULL'; - case self::OBJECT_IDENTIFIER: - return 'Object Identifier'; - case self::OBJECT_DESCRIPTOR: - return 'Object Descriptor'; - case self::EXTERNAL: - return 'External Type'; - case self::REAL: - return 'Real'; - case self::ENUMERATED: - return 'Enumerated'; - case self::EMBEDDED_PDV: - return 'Embedded PDV'; - case self::UTF8_STRING: - return 'UTF8 String'; - case self::RELATIVE_OID: - return 'Relative OID'; - case self::SEQUENCE: - return 'Sequence'; - case self::SET: - return 'Set'; - case self::NUMERIC_STRING: - return 'Numeric String'; - case self::PRINTABLE_STRING: - return 'Printable String'; - case self::T61_STRING: - return 'T61 String'; - case self::VIDEOTEXT_STRING: - return 'Videotext String'; - case self::IA5_STRING: - return 'IA5 String'; - case self::UTC_TIME: - return 'UTC Time'; - case self::GENERALIZED_TIME: - return 'Generalized Time'; - case self::GRAPHIC_STRING: - return 'Graphic String'; - case self::VISIBLE_STRING: - return 'Visible String'; - case self::GENERAL_STRING: - return 'General String'; - case self::UNIVERSAL_STRING: - return 'Universal String'; - case self::CHARACTER_STRING: - return 'Character String'; - case self::BMP_STRING: - return 'BMP String'; - - case 0x0E: - return 'RESERVED (0x0E)'; - case 0x0F: - return 'RESERVED (0x0F)'; - - case self::LONG_FORM: - default: - $classDescription = self::getClassDescription($identifier); - - if (is_int($identifier)) { - $identifier = chr($identifier); - } - - return "$classDescription (0x".strtoupper(bin2hex($identifier)).')'; - } - } - - /** - * Returns a textual description of the information encoded in a given identifier octet. - * - * The first three (most significant) bytes are evaluated to determine if this is a - * constructed or primitive type and if it is either universal, application, context-specific or - * private. - * - * Example: - * Constructed context-specific - * Primitive universal - * - * @param int|string $identifier - * - * @return string - */ - public static function getClassDescription($identifier) - { - $identifierOctet = self::makeNumeric($identifier); - - if (self::isConstructed($identifierOctet)) { - $classDescription = 'Constructed '; - } else { - $classDescription = 'Primitive '; - } - $classBits = $identifierOctet >> 6; - switch ($classBits) { - case self::CLASS_UNIVERSAL: - $classDescription .= 'universal'; - break; - case self::CLASS_APPLICATION: - $classDescription .= 'application'; - break; - case self::CLASS_CONTEXT_SPECIFIC: - $tagNumber = self::getTagNumber($identifier); - $classDescription = "[$tagNumber] Context-specific"; - break; - case self::CLASS_PRIVATE: - $classDescription .= 'private'; - break; - - default: - return "INVALID IDENTIFIER OCTET: {$identifierOctet}"; - } - - return $classDescription; - } - - /** - * @param int|string $identifier - * - * @return int - */ - public static function getTagNumber($identifier) - { - $firstOctet = self::makeNumeric($identifier); - $tagNumber = $firstOctet & self::LONG_FORM; - - if ($tagNumber < self::LONG_FORM) { - return $tagNumber; - } - - if (is_numeric($identifier)) { - $identifier = chr($identifier); - } - return Base128::decode(substr($identifier, 1)); - } - - public static function isUniversalClass($identifier) - { - $identifier = self::makeNumeric($identifier); - - return $identifier >> 6 == self::CLASS_UNIVERSAL; - } - - public static function isApplicationClass($identifier) - { - $identifier = self::makeNumeric($identifier); - - return $identifier >> 6 == self::CLASS_APPLICATION; - } - - public static function isContextSpecificClass($identifier) - { - $identifier = self::makeNumeric($identifier); - - return $identifier >> 6 == self::CLASS_CONTEXT_SPECIFIC; - } - - public static function isPrivateClass($identifier) - { - $identifier = self::makeNumeric($identifier); - - return $identifier >> 6 == self::CLASS_PRIVATE; - } - - private static function makeNumeric($identifierOctet) - { - if (!is_numeric($identifierOctet)) { - return ord($identifierOctet); - } else { - return $identifierOctet; - } - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php deleted file mode 100644 index bfaeae17e..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php +++ /dev/null @@ -1,1023 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -class OID -{ - const RSA_ENCRYPTION = '1.2.840.113549.1.1.1'; - const MD5_WITH_RSA_ENCRYPTION = '1.2.840.113549.1.1.4'; - const SHA1_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.5'; - const SHA256_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.11'; - const PKCS9_EMAIL = '1.2.840.113549.1.9.1'; - const PKCS9_UNSTRUCTURED_NAME = '1.2.840.113549.1.9.2'; - const PKCS9_CONTENT_TYPE = '1.2.840.113549.1.9.3'; - const PKCS9_MESSAGE_DIGEST = '1.2.840.113549.1.9.4'; - const PKCS9_SIGNING_TIME = '1.2.840.113549.1.9.5'; - const PKCS9_EXTENSION_REQUEST = '1.2.840.113549.1.9.14'; - - // certificate extension identifier - const CERT_EXT_SUBJECT_DIRECTORY_ATTR = '2.5.29.9'; - const CERT_EXT_SUBJECT_KEY_IDENTIFIER = '2.5.29.14'; - const CERT_EXT_KEY_USAGE = '2.5.29.15'; - const CERT_EXT_PRIVATE_KEY_USAGE_PERIOD = '2.5.29.16'; - const CERT_EXT_SUBJECT_ALT_NAME = '2.5.29.17'; - const CERT_EXT_ISSUER_ALT_NAME = '2.5.29.18'; - const CERT_EXT_BASIC_CONSTRAINTS = '2.5.29.19'; - const CERT_EXT_CRL_NUMBER = '2.5.29.20'; - const CERT_EXT_REASON_CODE = '2.5.29.21'; - const CERT_EXT_INVALIDITY_DATE = '2.5.29.24'; - const CERT_EXT_DELTA_CRL_INDICATOR = '2.5.29.27'; - const CERT_EXT_ISSUING_DIST_POINT = '2.5.29.28'; - const CERT_EXT_CERT_ISSUER = '2.5.29.29'; - const CERT_EXT_NAME_CONSTRAINTS = '2.5.29.30'; - const CERT_EXT_CRL_DISTRIBUTION_POINTS = '2.5.29.31'; - const CERT_EXT_CERT_POLICIES = '2.5.29.32'; - const CERT_EXT_AUTHORITY_KEY_IDENTIFIER = '2.5.29.35'; - const CERT_EXT_EXTENDED_KEY_USAGE = '2.5.29.37'; - - // standard certificate files - const COMMON_NAME = '2.5.4.3'; - const SURNAME = '2.5.4.4'; - const SERIAL_NUMBER = '2.5.4.5'; - const COUNTRY_NAME = '2.5.4.6'; - const LOCALITY_NAME = '2.5.4.7'; - const STATE_OR_PROVINCE_NAME = '2.5.4.8'; - const STREET_ADDRESS = '2.5.4.9'; - const ORGANIZATION_NAME = '2.5.4.10'; - const OU_NAME = '2.5.4.11'; - const TITLE = '2.5.4.12'; - const DESCRIPTION = '2.5.4.13'; - const POSTAL_ADDRESS = '2.5.4.16'; - const POSTAL_CODE = '2.5.4.17'; - const AUTHORITY_REVOCATION_LIST = '2.5.4.38'; - - const AUTHORITY_INFORMATION_ACCESS = '1.3.6.1.5.5.7.1.1'; - - /** - * Returns the name of the given object identifier. - * - * Some OIDs are saved as class constants in this class. - * If the wanted oidString is not among them, this method will - * query http://oid-info.com for the right name. - * This behavior can be suppressed by setting the second method parameter to false. - * - * @param string $oidString - * @param bool $loadFromWeb - * - * @see self::loadFromWeb($oidString) - * - * @return string - */ - public static function getName($oidString, $loadFromWeb = true) - { - $oids = [ - '1.2' => 'ISO Member Body', - '1.3' => 'org', - '1.3.6.1.5.5.8.1.1' => 'hmac-md5', - '1.3.6.1.5.5.8.1.2' => 'hmac-sha1', - '1.3.132' => 'certicom-arc', - '2.23' => 'International Organizations', - '2.23.43' => 'wap', - '2.23.43.1' => 'wap-wsg', - '2.5.1.5' => 'Selected Attribute Types', - '2.5.1.5.55' => 'clearance', - '1.2.840' => 'ISO US Member Body', - '1.2.840.10040' => 'X9.57', - '1.2.840.10040.4' => 'X9.57 CM ?', - '1.2.840.10040.4.1' => 'dsaEncryption', - '1.2.840.10040.4.3' => 'dsaWithSHA1', - '1.2.840.10045' => 'ANSI X9.62', - '1.2.840.10045.1' => 'X9-62_id-fieldType', - '1.2.840.10045.1.1' => 'X9-62_prime-field', - '1.2.840.10045.1.2' => 'X9-62_characteristic-two-field', - '1.2.840.10045.1.2.3' => 'X9-62_id-characteristic-two-basis', - '1.2.840.10045.1.2.3.1' => 'X9-62_onBasis', - '1.2.840.10045.1.2.3.2' => 'X9-62_tpBasis', - '1.2.840.10045.1.2.3.3' => 'X9-62_ppBasis', - '1.2.840.10045.2' => 'X9-62_id-publicKeyType', - '1.2.840.10045.2.1' => 'X9-62_id-ecPublicKey', - '1.2.840.10045.3' => 'X9-62_ellipticCurve', - '1.2.840.10045.3.0' => 'X9-62_c-TwoCurve', - '1.2.840.10045.3.0.1' => 'X9-62_c2pnb163v1', - '1.2.840.10045.3.0.2' => 'X9-62_c2pnb163v2', - '1.2.840.10045.3.0.3' => 'X9-62_c2pnb163v3', - '1.2.840.10045.3.0.4' => 'X9-62_c2pnb176v1', - '1.2.840.10045.3.0.5' => 'X9-62_c2tnb191v1', - '1.2.840.10045.3.0.6' => 'X9-62_c2tnb191v2', - '1.2.840.10045.3.0.7' => 'X9-62_c2tnb191v3', - '1.2.840.10045.3.0.8' => 'X9-62_c2onb191v4', - '1.2.840.10045.3.0.9' => 'X9-62_c2onb191v5', - '1.2.840.10045.3.0.10' => 'X9-62_c2pnb208w1', - '1.2.840.10045.3.0.11' => 'X9-62_c2tnb239v1', - '1.2.840.10045.3.0.12' => 'X9-62_c2tnb239v2', - '1.2.840.10045.3.0.13' => 'X9-62_c2tnb239v3', - '1.2.840.10045.3.0.14' => 'X9-62_c2onb239v4', - '1.2.840.10045.3.0.15' => 'X9-62_c2onb239v5', - '1.2.840.10045.3.0.16' => 'X9-62_c2pnb272w1', - '1.2.840.10045.3.0.17' => 'X9-62_c2pnb304w1', - '1.2.840.10045.3.0.18' => 'X9-62_c2tnb359v1', - '1.2.840.10045.3.0.19' => 'X9-62_c2pnb368w1', - '1.2.840.10045.3.0.20' => 'X9-62_c2tnb431r1', - '1.2.840.10045.3.1' => 'X9-62_primeCurve', - '1.2.840.10045.3.1.1' => 'X9-62_prime192v1', - '1.2.840.10045.3.1.2' => 'X9-62_prime192v2', - '1.2.840.10045.3.1.3' => 'X9-62_prime192v3', - '1.2.840.10045.3.1.4' => 'X9-62_prime239v1', - '1.2.840.10045.3.1.5' => 'X9-62_prime239v2', - '1.2.840.10045.3.1.6' => 'X9-62_prime239v3', - '1.2.840.10045.3.1.7' => 'X9-62_prime256v1', - '1.2.840.10045.4' => 'X9-62_id-ecSigType', - '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', - '1.2.840.10045.4.2' => 'ecdsa-with-Recommended', - '1.2.840.10045.4.3' => 'ecdsa-with-Specified', - '1.2.840.10045.4.3.1' => 'ecdsa-with-SHA224', - '1.2.840.10045.4.3.2' => 'ecdsa-with-SHA256', - '1.2.840.10045.4.3.3' => 'ecdsa-with-SHA384', - '1.2.840.10045.4.3.4' => 'ecdsa-with-SHA512', - '1.3.132.0' => 'secg_ellipticCurve', - '2.23.43.1.4' => 'wap-wsg-idm-ecid', - '2.23.43.1.4.1' => 'wap-wsg-idm-ecid-wtls1', - '2.23.43.1.4.3' => 'wap-wsg-idm-ecid-wtls3', - '2.23.43.1.4.4' => 'wap-wsg-idm-ecid-wtls4', - '2.23.43.1.4.5' => 'wap-wsg-idm-ecid-wtls5', - '2.23.43.1.4.6' => 'wap-wsg-idm-ecid-wtls6', - '2.23.43.1.4.7' => 'wap-wsg-idm-ecid-wtls7', - '2.23.43.1.4.8' => 'wap-wsg-idm-ecid-wtls8', - '2.23.43.1.4.9' => 'wap-wsg-idm-ecid-wtls9', - '2.23.43.1.4.10' => 'wap-wsg-idm-ecid-wtls10', - '2.23.43.1.4.11' => 'wap-wsg-idm-ecid-wtls11', - '2.23.43.1.4.12' => 'wap-wsg-idm-ecid-wtls12', - '1.2.840.113533.7.66.10' => 'cast5-cbc', - '1.2.840.113533.7.66.12' => 'pbeWithMD5AndCast5CBC', - '1.2.840.113533.7.66.13' => 'password based MAC', - '1.2.840.113533.7.66.30' => 'Diffie-Hellman based MAC', - '1.2.840.113549' => 'RSA Data Security, Inc.', - '1.2.840.113549.1' => 'RSA Data Security, Inc. PKCS', - '1.2.840.113549.1.1' => 'pkcs1', - '1.2.840.113549.1.1.1' => 'rsaEncryption', - '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', - '1.2.840.113549.1.1.3' => 'md4WithRSAEncryption', - '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', - '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', - '1.2.840.113549.1.1.7' => 'rsaesOaep', - '1.2.840.113549.1.1.8' => 'mgf1', - '1.2.840.113549.1.1.9' => 'pSpecified', - '1.2.840.113549.1.1.10' => 'rsassaPss', - '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', - '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', - '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', - '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', - '1.2.840.113549.1.3' => 'pkcs3', - '1.2.840.113549.1.3.1' => 'dhKeyAgreement', - '1.2.840.113549.1.5' => 'pkcs5', - '1.2.840.113549.1.5.1' => 'pbeWithMD2AndDES-CBC', - '1.2.840.113549.1.5.3' => 'pbeWithMD5AndDES-CBC', - '1.2.840.113549.1.5.4' => 'pbeWithMD2AndRC2-CBC', - '1.2.840.113549.1.5.6' => 'pbeWithMD5AndRC2-CBC', - '1.2.840.113549.1.5.10' => 'pbeWithSHA1AndDES-CBC', - '1.2.840.113549.1.5.11' => 'pbeWithSHA1AndRC2-CBC', - '1.2.840.113549.1.5.12' => 'PBKDF2', - '1.2.840.113549.1.5.13' => 'PBES2', - '1.2.840.113549.1.5.14' => 'PBMAC1', - '1.2.840.113549.1.7' => 'pkcs7', - '1.2.840.113549.1.7.1' => 'pkcs7-data', - '1.2.840.113549.1.7.2' => 'pkcs7-signedData', - '1.2.840.113549.1.7.3' => 'pkcs7-envelopedData', - '1.2.840.113549.1.7.4' => 'pkcs7-signedAndEnvelopedData', - '1.2.840.113549.1.7.5' => 'pkcs7-digestData', - '1.2.840.113549.1.7.6' => 'pkcs7-encryptedData', - '1.2.840.113549.1.9' => 'pkcs9', - '1.2.840.113549.1.9.1' => 'emailAddress', - '1.2.840.113549.1.9.2' => 'unstructuredName', - '1.2.840.113549.1.9.3' => 'contentType', - '1.2.840.113549.1.9.4' => 'messageDigest', - '1.2.840.113549.1.9.5' => 'signingTime', - '1.2.840.113549.1.9.6' => 'countersignature', - '1.2.840.113549.1.9.7' => 'challengePassword', - '1.2.840.113549.1.9.8' => 'unstructuredAddress', - '1.2.840.113549.1.9.9' => 'extendedCertificateAttributes', - '1.2.840.113549.1.9.14' => 'Extension Request', - '1.2.840.113549.1.9.15' => 'S/MIME Capabilities', - '1.2.840.113549.1.9.16' => 'S/MIME', - '1.2.840.113549.1.9.16.0' => 'id-smime-mod', - '1.2.840.113549.1.9.16.1' => 'id-smime-ct', - '1.2.840.113549.1.9.16.2' => 'id-smime-aa', - '1.2.840.113549.1.9.16.3' => 'id-smime-alg', - '1.2.840.113549.1.9.16.4' => 'id-smime-cd', - '1.2.840.113549.1.9.16.5' => 'id-smime-spq', - '1.2.840.113549.1.9.16.6' => 'id-smime-cti', - '1.2.840.113549.1.9.16.0.1' => 'id-smime-mod-cms', - '1.2.840.113549.1.9.16.0.2' => 'id-smime-mod-ess', - '1.2.840.113549.1.9.16.0.3' => 'id-smime-mod-oid', - '1.2.840.113549.1.9.16.0.4' => 'id-smime-mod-msg-v3', - '1.2.840.113549.1.9.16.0.5' => 'id-smime-mod-ets-eSignature-88', - '1.2.840.113549.1.9.16.0.6' => 'id-smime-mod-ets-eSignature-97', - '1.2.840.113549.1.9.16.0.7' => 'id-smime-mod-ets-eSigPolicy-88', - '1.2.840.113549.1.9.16.0.8' => 'id-smime-mod-ets-eSigPolicy-97', - '1.2.840.113549.1.9.16.1.1' => 'id-smime-ct-receipt', - '1.2.840.113549.1.9.16.1.2' => 'id-smime-ct-authData', - '1.2.840.113549.1.9.16.1.3' => 'id-smime-ct-publishCert', - '1.2.840.113549.1.9.16.1.4' => 'id-smime-ct-TSTInfo', - '1.2.840.113549.1.9.16.1.5' => 'id-smime-ct-TDTInfo', - '1.2.840.113549.1.9.16.1.6' => 'id-smime-ct-contentInfo', - '1.2.840.113549.1.9.16.1.7' => 'id-smime-ct-DVCSRequestData', - '1.2.840.113549.1.9.16.1.8' => 'id-smime-ct-DVCSResponseData', - '1.2.840.113549.1.9.16.1.9' => 'id-smime-ct-compressedData', - '1.2.840.113549.1.9.16.1.27' => 'id-ct-asciiTextWithCRLF', - '1.2.840.113549.1.9.16.2.1' => 'id-smime-aa-receiptRequest', - '1.2.840.113549.1.9.16.2.2' => 'id-smime-aa-securityLabel', - '1.2.840.113549.1.9.16.2.3' => 'id-smime-aa-mlExpandHistory', - '1.2.840.113549.1.9.16.2.4' => 'id-smime-aa-contentHint', - '1.2.840.113549.1.9.16.2.5' => 'id-smime-aa-msgSigDigest', - '1.2.840.113549.1.9.16.2.6' => 'id-smime-aa-encapContentType', - '1.2.840.113549.1.9.16.2.7' => 'id-smime-aa-contentIdentifier', - '1.2.840.113549.1.9.16.2.8' => 'id-smime-aa-macValue', - '1.2.840.113549.1.9.16.2.9' => 'id-smime-aa-equivalentLabels', - '1.2.840.113549.1.9.16.2.10' => 'id-smime-aa-contentReference', - '1.2.840.113549.1.9.16.2.11' => 'id-smime-aa-encrypKeyPref', - '1.2.840.113549.1.9.16.2.12' => 'id-smime-aa-signingCertificate', - '1.2.840.113549.1.9.16.2.13' => 'id-smime-aa-smimeEncryptCerts', - '1.2.840.113549.1.9.16.2.14' => 'id-smime-aa-timeStampToken', - '1.2.840.113549.1.9.16.2.15' => 'id-smime-aa-ets-sigPolicyId', - '1.2.840.113549.1.9.16.2.16' => 'id-smime-aa-ets-commitmentType', - '1.2.840.113549.1.9.16.2.17' => 'id-smime-aa-ets-signerLocation', - '1.2.840.113549.1.9.16.2.18' => 'id-smime-aa-ets-signerAttr', - '1.2.840.113549.1.9.16.2.19' => 'id-smime-aa-ets-otherSigCert', - '1.2.840.113549.1.9.16.2.20' => 'id-smime-aa-ets-contentTimestamp', - '1.2.840.113549.1.9.16.2.21' => 'id-smime-aa-ets-CertificateRefs', - '1.2.840.113549.1.9.16.2.22' => 'id-smime-aa-ets-RevocationRefs', - '1.2.840.113549.1.9.16.2.23' => 'id-smime-aa-ets-certValues', - '1.2.840.113549.1.9.16.2.24' => 'id-smime-aa-ets-revocationValues', - '1.2.840.113549.1.9.16.2.25' => 'id-smime-aa-ets-escTimeStamp', - '1.2.840.113549.1.9.16.2.26' => 'id-smime-aa-ets-certCRLTimestamp', - '1.2.840.113549.1.9.16.2.27' => 'id-smime-aa-ets-archiveTimeStamp', - '1.2.840.113549.1.9.16.2.28' => 'id-smime-aa-signatureType', - '1.2.840.113549.1.9.16.2.29' => 'id-smime-aa-dvcs-dvc', - '1.2.840.113549.1.9.16.3.1' => 'id-smime-alg-ESDHwith3DES', - '1.2.840.113549.1.9.16.3.2' => 'id-smime-alg-ESDHwithRC2', - '1.2.840.113549.1.9.16.3.3' => 'id-smime-alg-3DESwrap', - '1.2.840.113549.1.9.16.3.4' => 'id-smime-alg-RC2wrap', - '1.2.840.113549.1.9.16.3.5' => 'id-smime-alg-ESDH', - '1.2.840.113549.1.9.16.3.6' => 'id-smime-alg-CMS3DESwrap', - '1.2.840.113549.1.9.16.3.7' => 'id-smime-alg-CMSRC2wrap', - '1.2.840.113549.1.9.16.3.9' => 'id-alg-PWRI-KEK', - '1.2.840.113549.1.9.16.4.1' => 'id-smime-cd-ldap', - '1.2.840.113549.1.9.16.5.1' => 'id-smime-spq-ets-sqt-uri', - '1.2.840.113549.1.9.16.5.2' => 'id-smime-spq-ets-sqt-unotice', - '1.2.840.113549.1.9.16.6.1' => 'id-smime-cti-ets-proofOfOrigin', - '1.2.840.113549.1.9.16.6.2' => 'id-smime-cti-ets-proofOfReceipt', - '1.2.840.113549.1.9.16.6.3' => 'id-smime-cti-ets-proofOfDelivery', - '1.2.840.113549.1.9.16.6.4' => 'id-smime-cti-ets-proofOfSender', - '1.2.840.113549.1.9.16.6.5' => 'id-smime-cti-ets-proofOfApproval', - '1.2.840.113549.1.9.16.6.6' => 'id-smime-cti-ets-proofOfCreation', - '1.2.840.113549.1.9.20' => 'friendlyName', - '1.2.840.113549.1.9.21' => 'localKeyID', - '1.3.6.1.4.1.311.17.1' => 'Microsoft CSP Name', - '1.3.6.1.4.1.311.17.2' => 'Microsoft Local Key set', - '1.2.840.113549.1.9.22' => 'certTypes', - '1.2.840.113549.1.9.22.1' => 'x509Certificate', - '1.2.840.113549.1.9.22.2' => 'sdsiCertificate', - - '1.2.840.113549.1.9.23' => 'crlTypes', - '1.2.840.113549.1.9.23.1' => 'x509Crl', - '1.2.840.113549.1.12' => 'pkcs12', - '1.2.840.113549.1.12.1' => 'pkcs12-pbeids', - '1.2.840.113549.1.12.1.1' => 'pbeWithSHA1And128BitRC4', - '1.2.840.113549.1.12.1.2' => 'pbeWithSHA1And40BitRC4', - '1.2.840.113549.1.12.1.3' => 'pbeWithSHA1And3-KeyTripleDES-CBC', - '1.2.840.113549.1.12.1.4' => 'pbeWithSHA1And2-KeyTripleDES-CBC', - '1.2.840.113549.1.12.1.5' => 'pbeWithSHA1And128BitRC2-CBC', - '1.2.840.113549.1.12.1.6' => 'pbeWithSHA1And40BitRC2-CBC', - '1.2.840.113549.1.12.10' => 'pkcs12-Version1', - '1.2.840.113549.1.12.10.1' => 'pkcs12-BagIds', - '1.2.840.113549.1.12.10.1.1' => 'keyBag', - '1.2.840.113549.1.12.10.1.2' => 'pkcs8ShroudedKeyBag', - '1.2.840.113549.1.12.10.1.3' => 'certBag', - '1.2.840.113549.1.12.10.1.4' => 'crlBag', - '1.2.840.113549.1.12.10.1.5' => 'secretBag', - '1.2.840.113549.1.12.10.1.6' => 'safeContentsBag', - '1.2.840.113549.2.2' => 'md2', - '1.2.840.113549.2.4' => 'md4', - '1.2.840.113549.2.5' => 'md5', - '1.2.840.113549.2.6' => 'hmacWithMD5', - '1.2.840.113549.2.7' => 'hmacWithSHA1', - '1.2.840.113549.2.8' => 'hmacWithSHA224', - '1.2.840.113549.2.9' => 'hmacWithSHA256', - '1.2.840.113549.2.10' => 'hmacWithSHA384', - '1.2.840.113549.2.11' => 'hmacWithSHA512', - '1.2.840.113549.3.2' => 'rc2-cbc', - '1.2.840.113549.3.4' => 'rc4', - '1.2.840.113549.3.7' => 'des-ede3-cbc', - '1.2.840.113549.3.8' => 'rc5-cbc', - '1.3.6.1.4.1.311.2.1.14' => 'Microsoft Extension Request', - '1.3.6.1.4.1.311.2.1.21' => 'Microsoft Individual Code Signing', - '1.3.6.1.4.1.311.2.1.22' => 'Microsoft Commercial Code Signing', - '1.3.6.1.4.1.311.10.3.1' => 'Microsoft Trust List Signing', - '1.3.6.1.4.1.311.10.3.3' => 'Microsoft Server Gated Crypto', - '1.3.6.1.4.1.311.10.3.4' => 'Microsoft Encrypted File System', - '1.3.6.1.4.1.311.20.2.2' => 'Microsoft Smartcardlogin', - '1.3.6.1.4.1.311.20.2.3' => 'Microsoft Universal Principal Name', - '1.3.6.1.4.1.188.7.1.1.2' => 'idea-cbc', - '1.3.6.1.4.1.3029.1.2' => 'bf-cbc', - '1.3.6.1.5.5.7' => 'PKIX', - '1.3.6.1.5.5.7.0' => 'id-pkix-mod', - '1.3.6.1.5.5.7.1' => 'id-pe', - '1.3.6.1.5.5.7.2' => 'id-qt', - '1.3.6.1.5.5.7.3' => 'id-kp', - '1.3.6.1.5.5.7.4' => 'id-it', - '1.3.6.1.5.5.7.5' => 'id-pkip', - '1.3.6.1.5.5.7.6' => 'id-alg', - '1.3.6.1.5.5.7.7' => 'id-cmc', - '1.3.6.1.5.5.7.8' => 'id-on', - '1.3.6.1.5.5.7.9' => 'id-pda', - '1.3.6.1.5.5.7.10' => 'id-aca', - '1.3.6.1.5.5.7.11' => 'id-qcs', - '1.3.6.1.5.5.7.12' => 'id-cct', - '1.3.6.1.5.5.7.21' => 'id-ppl', - '1.3.6.1.5.5.7.48' => 'id-ad', - '1.3.6.1.5.5.7.0.1' => 'id-pkix1-explicit-88', - '1.3.6.1.5.5.7.0.2' => 'id-pkix1-implicit-88', - '1.3.6.1.5.5.7.0.3' => 'id-pkix1-explicit-93', - '1.3.6.1.5.5.7.0.4' => 'id-pkix1-implicit-93', - '1.3.6.1.5.5.7.0.5' => 'id-mod-crmf', - '1.3.6.1.5.5.7.0.6' => 'id-mod-cmc', - '1.3.6.1.5.5.7.0.7' => 'id-mod-kea-profile-88', - '1.3.6.1.5.5.7.0.8' => 'id-mod-kea-profile-93', - '1.3.6.1.5.5.7.0.9' => 'id-mod-cmp', - '1.3.6.1.5.5.7.0.10' => 'id-mod-qualified-cert-88', - '1.3.6.1.5.5.7.0.11' => 'id-mod-qualified-cert-93', - '1.3.6.1.5.5.7.0.12' => 'id-mod-attribute-cert', - '1.3.6.1.5.5.7.0.13' => 'id-mod-timestamp-protocol', - '1.3.6.1.5.5.7.0.14' => 'id-mod-ocsp', - '1.3.6.1.5.5.7.0.15' => 'id-mod-dvcs', - '1.3.6.1.5.5.7.0.16' => 'id-mod-cmp2000', - '1.3.6.1.5.5.7.1.1' => 'Authority Information Access', - '1.3.6.1.5.5.7.1.2' => 'Biometric Info', - '1.3.6.1.5.5.7.1.3' => 'qcStatements', - '1.3.6.1.5.5.7.1.4' => 'ac-auditEntity', - '1.3.6.1.5.5.7.1.5' => 'ac-targeting', - '1.3.6.1.5.5.7.1.6' => 'aaControls', - '1.3.6.1.5.5.7.1.7' => 'sbgp-ipAddrBlock', - '1.3.6.1.5.5.7.1.8' => 'sbgp-autonomousSysNum', - '1.3.6.1.5.5.7.1.9' => 'sbgp-routerIdentifier', - '1.3.6.1.5.5.7.1.10' => 'ac-proxying', - '1.3.6.1.5.5.7.1.11' => 'Subject Information Access', - '1.3.6.1.5.5.7.1.14' => 'Proxy Certificate Information', - '1.3.6.1.5.5.7.2.1' => 'Policy Qualifier CPS', - '1.3.6.1.5.5.7.2.2' => 'Policy Qualifier User Notice', - '1.3.6.1.5.5.7.2.3' => 'textNotice', - '1.3.6.1.5.5.7.3.1' => 'TLS Web Server Authentication', - '1.3.6.1.5.5.7.3.2' => 'TLS Web Client Authentication', - '1.3.6.1.5.5.7.3.3' => 'Code Signing', - '1.3.6.1.5.5.7.3.4' => 'E-mail Protection', - '1.3.6.1.5.5.7.3.5' => 'IPSec End System', - '1.3.6.1.5.5.7.3.6' => 'IPSec Tunnel', - '1.3.6.1.5.5.7.3.7' => 'IPSec User', - '1.3.6.1.5.5.7.3.8' => 'Time Stamping', - '1.3.6.1.5.5.7.3.9' => 'OCSP Signing', - '1.3.6.1.5.5.7.3.10' => 'dvcs', - '1.3.6.1.5.5.7.4.1' => 'id-it-caProtEncCert', - '1.3.6.1.5.5.7.4.2' => 'id-it-signKeyPairTypes', - '1.3.6.1.5.5.7.4.3' => 'id-it-encKeyPairTypes', - '1.3.6.1.5.5.7.4.4' => 'id-it-preferredSymmAlg', - '1.3.6.1.5.5.7.4.5' => 'id-it-caKeyUpdateInfo', - '1.3.6.1.5.5.7.4.6' => 'id-it-currentCRL', - '1.3.6.1.5.5.7.4.7' => 'id-it-unsupportedOIDs', - '1.3.6.1.5.5.7.4.8' => 'id-it-subscriptionRequest', - '1.3.6.1.5.5.7.4.9' => 'id-it-subscriptionResponse', - '1.3.6.1.5.5.7.4.10' => 'id-it-keyPairParamReq', - '1.3.6.1.5.5.7.4.11' => 'id-it-keyPairParamRep', - '1.3.6.1.5.5.7.4.12' => 'id-it-revPassphrase', - '1.3.6.1.5.5.7.4.13' => 'id-it-implicitConfirm', - '1.3.6.1.5.5.7.4.14' => 'id-it-confirmWaitTime', - '1.3.6.1.5.5.7.4.15' => 'id-it-origPKIMessage', - '1.3.6.1.5.5.7.4.16' => 'id-it-suppLangTags', - '1.3.6.1.5.5.7.5.1' => 'id-regCtrl', - '1.3.6.1.5.5.7.5.2' => 'id-regInfo', - '1.3.6.1.5.5.7.5.1.1' => 'id-regCtrl-regToken', - '1.3.6.1.5.5.7.5.1.2' => 'id-regCtrl-authenticator', - '1.3.6.1.5.5.7.5.1.3' => 'id-regCtrl-pkiPublicationInfo', - '1.3.6.1.5.5.7.5.1.4' => 'id-regCtrl-pkiArchiveOptions', - '1.3.6.1.5.5.7.5.1.5' => 'id-regCtrl-oldCertID', - '1.3.6.1.5.5.7.5.1.6' => 'id-regCtrl-protocolEncrKey', - '1.3.6.1.5.5.7.5.2.1' => 'id-regInfo-utf8Pairs', - '1.3.6.1.5.5.7.5.2.2' => 'id-regInfo-certReq', - '1.3.6.1.5.5.7.6.1' => 'id-alg-des40', - '1.3.6.1.5.5.7.6.2' => 'id-alg-noSignature', - '1.3.6.1.5.5.7.6.3' => 'id-alg-dh-sig-hmac-sha1', - '1.3.6.1.5.5.7.6.4' => 'id-alg-dh-pop', - '1.3.6.1.5.5.7.7.1' => 'id-cmc-statusInfo', - '1.3.6.1.5.5.7.7.2' => 'id-cmc-identification', - '1.3.6.1.5.5.7.7.3' => 'id-cmc-identityProof', - '1.3.6.1.5.5.7.7.4' => 'id-cmc-dataReturn', - '1.3.6.1.5.5.7.7.5' => 'id-cmc-transactionId', - '1.3.6.1.5.5.7.7.6' => 'id-cmc-senderNonce', - '1.3.6.1.5.5.7.7.7' => 'id-cmc-recipientNonce', - '1.3.6.1.5.5.7.7.8' => 'id-cmc-addExtensions', - '1.3.6.1.5.5.7.7.9' => 'id-cmc-encryptedPOP', - '1.3.6.1.5.5.7.7.10' => 'id-cmc-decryptedPOP', - '1.3.6.1.5.5.7.7.11' => 'id-cmc-lraPOPWitness', - '1.3.6.1.5.5.7.7.15' => 'id-cmc-getCert', - '1.3.6.1.5.5.7.7.16' => 'id-cmc-getCRL', - '1.3.6.1.5.5.7.7.17' => 'id-cmc-revokeRequest', - '1.3.6.1.5.5.7.7.18' => 'id-cmc-regInfo', - '1.3.6.1.5.5.7.7.19' => 'id-cmc-responseInfo', - '1.3.6.1.5.5.7.7.21' => 'id-cmc-queryPending', - '1.3.6.1.5.5.7.7.22' => 'id-cmc-popLinkRandom', - '1.3.6.1.5.5.7.7.23' => 'id-cmc-popLinkWitness', - '1.3.6.1.5.5.7.7.24' => 'id-cmc-confirmCertAcceptance', - '1.3.6.1.5.5.7.8.1' => 'id-on-personalData', - '1.3.6.1.5.5.7.8.3' => 'Permanent Identifier', - '1.3.6.1.5.5.7.9.1' => 'id-pda-dateOfBirth', - '1.3.6.1.5.5.7.9.2' => 'id-pda-placeOfBirth', - '1.3.6.1.5.5.7.9.3' => 'id-pda-gender', - '1.3.6.1.5.5.7.9.4' => 'id-pda-countryOfCitizenship', - '1.3.6.1.5.5.7.9.5' => 'id-pda-countryOfResidence', - '1.3.6.1.5.5.7.10.1' => 'id-aca-authenticationInfo', - '1.3.6.1.5.5.7.10.2' => 'id-aca-accessIdentity', - '1.3.6.1.5.5.7.10.3' => 'id-aca-chargingIdentity', - '1.3.6.1.5.5.7.10.4' => 'id-aca-group', - '1.3.6.1.5.5.7.10.5' => 'id-aca-role', - '1.3.6.1.5.5.7.10.6' => 'id-aca-encAttrs', - '1.3.6.1.5.5.7.11.1' => 'id-qcs-pkixQCSyntax-v1', - '1.3.6.1.5.5.7.12.1' => 'id-cct-crs', - '1.3.6.1.5.5.7.12.2' => 'id-cct-PKIData', - '1.3.6.1.5.5.7.12.3' => 'id-cct-PKIResponse', - '1.3.6.1.5.5.7.21.0' => 'Any language', - '1.3.6.1.5.5.7.21.1' => 'Inherit all', - '1.3.6.1.5.5.7.21.2' => 'Independent', - '1.3.6.1.5.5.7.48.1' => 'OCSP', - '1.3.6.1.5.5.7.48.2' => 'CA Issuers', - '1.3.6.1.5.5.7.48.3' => 'AD Time Stamping', - '1.3.6.1.5.5.7.48.4' => 'ad dvcs', - '1.3.6.1.5.5.7.48.5' => 'CA Repository', - '1.3.6.1.5.5.7.48.1.1' => 'Basic OCSP Response', - '1.3.6.1.5.5.7.48.1.2' => 'OCSP Nonce', - '1.3.6.1.5.5.7.48.1.3' => 'OCSP CRL ID', - '1.3.6.1.5.5.7.48.1.4' => 'Acceptable OCSP Responses', - '1.3.6.1.5.5.7.48.1.5' => 'OCSP No Check', - '1.3.6.1.5.5.7.48.1.6' => 'OCSP Archive Cutoff', - '1.3.6.1.5.5.7.48.1.7' => 'OCSP Service Locator', - '1.3.6.1.5.5.7.48.1.8' => 'Extended OCSP Status', - '1.3.6.1.5.5.7.48.1.9' => 'id-pkix-OCSP_valid', - '1.3.6.1.5.5.7.48.1.10' => 'id-pkix-OCSP_path', - '1.3.6.1.5.5.7.48.1.11' => 'Trust Root', - '1.3.14.3.2' => 'algorithm', - '1.3.14.3.2.3' => 'md5WithRSA', - '1.3.14.3.2.6' => 'des-ecb', - '1.3.14.3.2.7' => 'des-cbc', - '1.3.14.3.2.8' => 'des-ofb', - '1.3.14.3.2.9' => 'des-cfb', - '1.3.14.3.2.11' => 'rsaSignature', - '1.3.14.3.2.12' => 'dsaEncryption-old', - '1.3.14.3.2.13' => 'dsaWithSHA', - '1.3.14.3.2.15' => 'shaWithRSAEncryption', - '1.3.14.3.2.17' => 'des-ede', - '1.3.14.3.2.18' => 'sha', - '1.3.14.3.2.26' => 'sha1', - '1.3.14.3.2.27' => 'dsaWithSHA1-old', - '1.3.14.3.2.29' => 'sha1WithRSA', - '1.3.36.3.2.1' => 'ripemd160', - '1.3.36.3.3.1.2' => 'ripemd160WithRSA', - '1.3.101.1.4.1' => 'Strong Extranet ID', - '2.5' => 'directory services (X.500)', - '2.5.4' => 'X509', - '2.5.4.3' => 'commonName', - '2.5.4.4' => 'surname', - '2.5.4.5' => 'serialNumber', - '2.5.4.6' => 'countryName', - '2.5.4.7' => 'localityName', - '2.5.4.8' => 'stateOrProvinceName', - '2.5.4.9' => 'streetAddress', - '2.5.4.10' => 'organizationName', - '2.5.4.11' => 'organizationalUnitName', - '2.5.4.12' => 'title', - '2.5.4.13' => 'description', - '2.5.4.14' => 'searchGuide', - '2.5.4.15' => 'businessCategory', - '2.5.4.16' => 'postalAddress', - '2.5.4.17' => 'postalCode', - '2.5.4.18' => 'postOfficeBox', - '2.5.4.19' => 'physicalDeliveryOfficeName', - '2.5.4.20' => 'telephoneNumber', - '2.5.4.21' => 'telexNumber', - '2.5.4.22' => 'teletexTerminalIdentifier', - '2.5.4.23' => 'facsimileTelephoneNumber', - '2.5.4.24' => 'x121Address', - '2.5.4.25' => 'internationaliSDNNumber', - '2.5.4.26' => 'registeredAddress', - '2.5.4.27' => 'destinationIndicator', - '2.5.4.28' => 'preferredDeliveryMethod', - '2.5.4.29' => 'presentationAddress', - '2.5.4.30' => 'supportedApplicationContext', - '2.5.4.31' => 'member', - '2.5.4.32' => 'owner', - '2.5.4.33' => 'roleOccupant', - '2.5.4.34' => 'seeAlso', - '2.5.4.35' => 'userPassword', - '2.5.4.36' => 'userCertificate', - '2.5.4.37' => 'cACertificate', - '2.5.4.38' => 'authorityRevocationList', - '2.5.4.39' => 'certificateRevocationList', - '2.5.4.40' => 'crossCertificatePair', - '2.5.4.41' => 'name', - '2.5.4.42' => 'givenName', - '2.5.4.43' => 'initials', - '2.5.4.44' => 'generationQualifier', - '2.5.4.45' => 'x500UniqueIdentifier', - '2.5.4.46' => 'dnQualifier', - '2.5.4.47' => 'enhancedSearchGuide', - '2.5.4.48' => 'protocolInformation', - '2.5.4.49' => 'distinguishedName', - '2.5.4.50' => 'uniqueMember', - '2.5.4.51' => 'houseIdentifier', - '2.5.4.52' => 'supportedAlgorithms', - '2.5.4.53' => 'deltaRevocationList', - '2.5.4.54' => 'dmdName', - '2.5.4.65' => 'pseudonym', - '2.5.4.72' => 'role', - '2.5.8' => 'directory services - algorithms', - '2.5.8.1.1' => 'rsa', - '2.5.8.3.100' => 'mdc2WithRSA', - '2.5.8.3.101' => 'mdc2', - '2.5.29' => 'id-ce', - '2.5.29.9' => 'X509v3 Subject Directory Attributes', - '2.5.29.14' => 'X509v3 Subject Key Identifier', - '2.5.29.15' => 'X509v3 Key Usage', - '2.5.29.16' => 'X509v3 Private Key Usage Period', - '2.5.29.17' => 'X509v3 Subject Alternative Name', - '2.5.29.18' => 'X509v3 Issuer Alternative Name', - '2.5.29.19' => 'X509v3 Basic Constraints', - '2.5.29.20' => 'X509v3 CRL Number', - '2.5.29.21' => 'X509v3 CRL Reason Code', - '2.5.29.24' => 'Invalidity Date', - '2.5.29.27' => 'X509v3 Delta CRL Indicator', - '2.5.29.28' => 'X509v3 Issuing Distribution Point', - '2.5.29.29' => 'X509v3 Certificate Issuer', - '2.5.29.30' => 'X509v3 Name Constraints', - '2.5.29.31' => 'X509v3 CRL Distribution Points', - '2.5.29.32' => 'X509v3 Certificate Policies', - '2.5.29.32.0' => 'X509v3 Any Policy', - '2.5.29.33' => 'X509v3 Policy Mappings', - '2.5.29.35' => 'X509v3 Authority Key Identifier', - '2.5.29.36' => 'X509v3 Policy Constraints', - '2.5.29.37' => 'X509v3 Extended Key Usage', - '2.5.29.46' => 'X509v3 Freshest CRL', - '2.5.29.54' => 'X509v3 Inhibit Any Policy', - '2.5.29.55' => 'X509v3 AC Targeting', - '2.5.29.56' => 'X509v3 No Revocation Available', - '2.5.29.37.0' => 'Any Extended Key Usage', - '2.16.840.1.113730' => 'Netscape Communications Corp.', - '2.16.840.1.113730.1' => 'Netscape Certificate Extension', - '2.16.840.1.113730.2' => 'Netscape Data Type', - '2.16.840.1.113730.1.1' => 'Netscape Cert Type', - '2.16.840.1.113730.1.2' => 'Netscape Base Url', - '2.16.840.1.113730.1.3' => 'Netscape Revocation Url', - '2.16.840.1.113730.1.4' => 'Netscape CA Revocation Url', - '2.16.840.1.113730.1.7' => 'Netscape Renewal Url', - '2.16.840.1.113730.1.8' => 'Netscape CA Policy Url', - '2.16.840.1.113730.1.12' => 'Netscape SSL Server Name', - '2.16.840.1.113730.1.13' => 'Netscape Comment', - '2.16.840.1.113730.2.5' => 'Netscape Certificate Sequence', - '2.16.840.1.113730.4.1' => 'Netscape Server Gated Crypto', - '1.3.6' => 'dod', - '1.3.6.1' => 'iana', - '1.3.6.1.1' => 'Directory', - '1.3.6.1.2' => 'Management', - '1.3.6.1.3' => 'Experimental', - '1.3.6.1.4' => 'Private', - '1.3.6.1.5' => 'Security', - '1.3.6.1.6' => 'SNMPv2', - '1.3.6.1.7' => 'Mail', - '1.3.6.1.4.1' => 'Enterprises', - '1.3.6.1.4.1.1466.344' => 'dcObject', - '1.2.840.113549.1.9.16.3.8' => 'zlib compression', - '2.16.840.1.101.3' => 'csor', - '2.16.840.1.101.3.4' => 'nistAlgorithms', - '2.16.840.1.101.3.4.1' => 'aes', - '2.16.840.1.101.3.4.1.1' => 'aes-128-ecb', - '2.16.840.1.101.3.4.1.2' => 'aes-128-cbc', - '2.16.840.1.101.3.4.1.3' => 'aes-128-ofb', - '2.16.840.1.101.3.4.1.4' => 'aes-128-cfb', - '2.16.840.1.101.3.4.1.5' => 'id-aes128-wrap', - '2.16.840.1.101.3.4.1.6' => 'aes-128-gcm', - '2.16.840.1.101.3.4.1.7' => 'aes-128-ccm', - '2.16.840.1.101.3.4.1.8' => 'id-aes128-wrap-pad', - '2.16.840.1.101.3.4.1.21' => 'aes-192-ecb', - '2.16.840.1.101.3.4.1.22' => 'aes-192-cbc', - '2.16.840.1.101.3.4.1.23' => 'aes-192-ofb', - '2.16.840.1.101.3.4.1.24' => 'aes-192-cfb', - '2.16.840.1.101.3.4.1.25' => 'id-aes192-wrap', - '2.16.840.1.101.3.4.1.26' => 'aes-192-gcm', - '2.16.840.1.101.3.4.1.27' => 'aes-192-ccm', - '2.16.840.1.101.3.4.1.28' => 'id-aes192-wrap-pad', - '2.16.840.1.101.3.4.1.41' => 'aes-256-ecb', - '2.16.840.1.101.3.4.1.42' => 'aes-256-cbc', - '2.16.840.1.101.3.4.1.43' => 'aes-256-ofb', - '2.16.840.1.101.3.4.1.44' => 'aes-256-cfb', - '2.16.840.1.101.3.4.1.45' => 'id-aes256-wrap', - '2.16.840.1.101.3.4.1.46' => 'aes-256-gcm', - '2.16.840.1.101.3.4.1.47' => 'aes-256-ccm', - '2.16.840.1.101.3.4.1.48' => 'id-aes256-wrap-pad', - '2.16.840.1.101.3.4.2' => 'nist_hashalgs', - '2.16.840.1.101.3.4.2.1' => 'sha256', - '2.16.840.1.101.3.4.2.2' => 'sha384', - '2.16.840.1.101.3.4.2.3' => 'sha512', - '2.16.840.1.101.3.4.2.4' => 'sha224', - '2.16.840.1.101.3.4.3' => 'dsa_with_sha2', - '2.16.840.1.101.3.4.3.1' => 'dsa_with_SHA224', - '2.16.840.1.101.3.4.3.2' => 'dsa_with_SHA256', - '2.5.29.23' => 'Hold Instruction Code', - '0.9' => 'data', - '0.9.2342' => 'pss', - '0.9.2342.19200300' => 'ucl', - '0.9.2342.19200300.100' => 'pilot', - '0.9.2342.19200300.100.1' => 'pilotAttributeType', - '0.9.2342.19200300.100.3' => 'pilotAttributeSyntax', - '0.9.2342.19200300.100.4' => 'pilotObjectClass', - '0.9.2342.19200300.100.10' => 'pilotGroups', - '2.23.42' => 'Secure Electronic Transactions', - '2.23.42.0' => 'content types', - '2.23.42.1' => 'message extensions', - '2.23.42.3' => 'set-attr', - '2.23.42.5' => 'set-policy', - '2.23.42.7' => 'certificate extensions', - '2.23.42.8' => 'set-brand', - '2.23.42.0.0' => 'setct-PANData', - '2.23.42.0.1' => 'setct-PANToken', - '2.23.42.0.2' => 'setct-PANOnly', - '2.23.42.0.3' => 'setct-OIData', - '2.23.42.0.4' => 'setct-PI', - '2.23.42.0.5' => 'setct-PIData', - '2.23.42.0.6' => 'setct-PIDataUnsigned', - '2.23.42.0.7' => 'setct-HODInput', - '2.23.42.0.8' => 'setct-AuthResBaggage', - '2.23.42.0.9' => 'setct-AuthRevReqBaggage', - '2.23.42.0.10' => 'setct-AuthRevResBaggage', - '2.23.42.0.11' => 'setct-CapTokenSeq', - '2.23.42.0.12' => 'setct-PInitResData', - '2.23.42.0.13' => 'setct-PI-TBS', - '2.23.42.0.14' => 'setct-PResData', - '2.23.42.0.16' => 'setct-AuthReqTBS', - '2.23.42.0.17' => 'setct-AuthResTBS', - '2.23.42.0.18' => 'setct-AuthResTBSX', - '2.23.42.0.19' => 'setct-AuthTokenTBS', - '2.23.42.0.20' => 'setct-CapTokenData', - '2.23.42.0.21' => 'setct-CapTokenTBS', - '2.23.42.0.22' => 'setct-AcqCardCodeMsg', - '2.23.42.0.23' => 'setct-AuthRevReqTBS', - '2.23.42.0.24' => 'setct-AuthRevResData', - '2.23.42.0.25' => 'setct-AuthRevResTBS', - '2.23.42.0.26' => 'setct-CapReqTBS', - '2.23.42.0.27' => 'setct-CapReqTBSX', - '2.23.42.0.28' => 'setct-CapResData', - '2.23.42.0.29' => 'setct-CapRevReqTBS', - '2.23.42.0.30' => 'setct-CapRevReqTBSX', - '2.23.42.0.31' => 'setct-CapRevResData', - '2.23.42.0.32' => 'setct-CredReqTBS', - '2.23.42.0.33' => 'setct-CredReqTBSX', - '2.23.42.0.34' => 'setct-CredResData', - '2.23.42.0.35' => 'setct-CredRevReqTBS', - '2.23.42.0.36' => 'setct-CredRevReqTBSX', - '2.23.42.0.37' => 'setct-CredRevResData', - '2.23.42.0.38' => 'setct-PCertReqData', - '2.23.42.0.39' => 'setct-PCertResTBS', - '2.23.42.0.40' => 'setct-BatchAdminReqData', - '2.23.42.0.41' => 'setct-BatchAdminResData', - '2.23.42.0.42' => 'setct-CardCInitResTBS', - '2.23.42.0.43' => 'setct-MeAqCInitResTBS', - '2.23.42.0.44' => 'setct-RegFormResTBS', - '2.23.42.0.45' => 'setct-CertReqData', - '2.23.42.0.46' => 'setct-CertReqTBS', - '2.23.42.0.47' => 'setct-CertResData', - '2.23.42.0.48' => 'setct-CertInqReqTBS', - '2.23.42.0.49' => 'setct-ErrorTBS', - '2.23.42.0.50' => 'setct-PIDualSignedTBE', - '2.23.42.0.51' => 'setct-PIUnsignedTBE', - '2.23.42.0.52' => 'setct-AuthReqTBE', - '2.23.42.0.53' => 'setct-AuthResTBE', - '2.23.42.0.54' => 'setct-AuthResTBEX', - '2.23.42.0.55' => 'setct-AuthTokenTBE', - '2.23.42.0.56' => 'setct-CapTokenTBE', - '2.23.42.0.57' => 'setct-CapTokenTBEX', - '2.23.42.0.58' => 'setct-AcqCardCodeMsgTBE', - '2.23.42.0.59' => 'setct-AuthRevReqTBE', - '2.23.42.0.60' => 'setct-AuthRevResTBE', - '2.23.42.0.61' => 'setct-AuthRevResTBEB', - '2.23.42.0.62' => 'setct-CapReqTBE', - '2.23.42.0.63' => 'setct-CapReqTBEX', - '2.23.42.0.64' => 'setct-CapResTBE', - '2.23.42.0.65' => 'setct-CapRevReqTBE', - '2.23.42.0.66' => 'setct-CapRevReqTBEX', - '2.23.42.0.67' => 'setct-CapRevResTBE', - '2.23.42.0.68' => 'setct-CredReqTBE', - '2.23.42.0.69' => 'setct-CredReqTBEX', - '2.23.42.0.70' => 'setct-CredResTBE', - '2.23.42.0.71' => 'setct-CredRevReqTBE', - '2.23.42.0.72' => 'setct-CredRevReqTBEX', - '2.23.42.0.73' => 'setct-CredRevResTBE', - '2.23.42.0.74' => 'setct-BatchAdminReqTBE', - '2.23.42.0.75' => 'setct-BatchAdminResTBE', - '2.23.42.0.76' => 'setct-RegFormReqTBE', - '2.23.42.0.77' => 'setct-CertReqTBE', - '2.23.42.0.78' => 'setct-CertReqTBEX', - '2.23.42.0.79' => 'setct-CertResTBE', - '2.23.42.0.80' => 'setct-CRLNotificationTBS', - '2.23.42.0.81' => 'setct-CRLNotificationResTBS', - '2.23.42.0.82' => 'setct-BCIDistributionTBS', - '2.23.42.1.1' => 'generic cryptogram', - '2.23.42.1.3' => 'merchant initiated auth', - '2.23.42.1.4' => 'setext-pinSecure', - '2.23.42.1.5' => 'setext-pinAny', - '2.23.42.1.7' => 'setext-track2', - '2.23.42.1.8' => 'additional verification', - '2.23.42.5.0' => 'set-policy-root', - '2.23.42.7.0' => 'setCext-hashedRoot', - '2.23.42.7.1' => 'setCext-certType', - '2.23.42.7.2' => 'setCext-merchData', - '2.23.42.7.3' => 'setCext-cCertRequired', - '2.23.42.7.4' => 'setCext-tunneling', - '2.23.42.7.5' => 'setCext-setExt', - '2.23.42.7.6' => 'setCext-setQualf', - '2.23.42.7.7' => 'setCext-PGWYcapabilities', - '2.23.42.7.8' => 'setCext-TokenIdentifier', - '2.23.42.7.9' => 'setCext-Track2Data', - '2.23.42.7.10' => 'setCext-TokenType', - '2.23.42.7.11' => 'setCext-IssuerCapabilities', - '2.23.42.3.0' => 'setAttr-Cert', - '2.23.42.3.1' => 'payment gateway capabilities', - '2.23.42.3.2' => 'setAttr-TokenType', - '2.23.42.3.3' => 'issuer capabilities', - '2.23.42.3.0.0' => 'set-rootKeyThumb', - '2.23.42.3.0.1' => 'set-addPolicy', - '2.23.42.3.2.1' => 'setAttr-Token-EMV', - '2.23.42.3.2.2' => 'setAttr-Token-B0Prime', - '2.23.42.3.3.3' => 'setAttr-IssCap-CVM', - '2.23.42.3.3.4' => 'setAttr-IssCap-T2', - '2.23.42.3.3.5' => 'setAttr-IssCap-Sig', - '2.23.42.3.3.3.1' => 'generate cryptogram', - '2.23.42.3.3.4.1' => 'encrypted track 2', - '2.23.42.3.3.4.2' => 'cleartext track 2', - '2.23.42.3.3.5.1' => 'ICC or token signature', - '2.23.42.3.3.5.2' => 'secure device signature', - '2.23.42.8.1' => 'set-brand-IATA-ATA', - '2.23.42.8.30' => 'set-brand-Diners', - '2.23.42.8.34' => 'set-brand-AmericanExpress', - '2.23.42.8.35' => 'set-brand-JCB', - '2.23.42.8.4' => 'set-brand-Visa', - '2.23.42.8.5' => 'set-brand-MasterCard', - '2.23.42.8.6011' => 'set-brand-Novus', - '1.2.840.113549.3.10' => 'des-cdmf', - '1.2.840.113549.1.1.6' => 'rsaOAEPEncryptionSET', - '1.0.10118.3.0.55' => 'whirlpool', - '1.2.643.2.2' => 'cryptopro', - '1.2.643.2.9' => 'cryptocom', - '1.2.643.2.2.3' => 'GOST R 34.11-94 with GOST R 34.10-2001', - '1.2.643.2.2.4' => 'GOST R 34.11-94 with GOST R 34.10-94', - '1.2.643.2.2.9' => 'GOST R 34.11-94', - '1.2.643.2.2.10' => 'HMAC GOST 34.11-94', - '1.2.643.2.2.19' => 'GOST R 34.10-2001', - '1.2.643.2.2.20' => 'GOST R 34.10-94', - '1.2.643.2.2.21' => 'GOST 28147-89', - '1.2.643.2.2.22' => 'GOST 28147-89 MAC', - '1.2.643.2.2.23' => 'GOST R 34.11-94 PRF', - '1.2.643.2.2.98' => 'GOST R 34.10-2001 DH', - '1.2.643.2.2.99' => 'GOST R 34.10-94 DH', - '1.2.643.2.2.14.1' => 'id-Gost28147-89-CryptoPro-KeyMeshing', - '1.2.643.2.2.14.0' => 'id-Gost28147-89-None-KeyMeshing', - '1.2.643.2.2.30.0' => 'id-GostR3411-94-TestParamSet', - '1.2.643.2.2.30.1' => 'id-GostR3411-94-CryptoProParamSet', - '1.2.643.2.2.31.0' => 'id-Gost28147-89-TestParamSet', - '1.2.643.2.2.31.1' => 'id-Gost28147-89-CryptoPro-A-ParamSet', - '1.2.643.2.2.31.2' => 'id-Gost28147-89-CryptoPro-B-ParamSet', - '1.2.643.2.2.31.3' => 'id-Gost28147-89-CryptoPro-C-ParamSet', - '1.2.643.2.2.31.4' => 'id-Gost28147-89-CryptoPro-D-ParamSet', - '1.2.643.2.2.31.5' => 'id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet', - '1.2.643.2.2.31.6' => 'id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet', - '1.2.643.2.2.31.7' => 'id-Gost28147-89-CryptoPro-RIC-1-ParamSet', - '1.2.643.2.2.32.0' => 'id-GostR3410-94-TestParamSet', - '1.2.643.2.2.32.2' => 'id-GostR3410-94-CryptoPro-A-ParamSet', - '1.2.643.2.2.32.3' => 'id-GostR3410-94-CryptoPro-B-ParamSet', - '1.2.643.2.2.32.4' => 'id-GostR3410-94-CryptoPro-C-ParamSet', - '1.2.643.2.2.32.5' => 'id-GostR3410-94-CryptoPro-D-ParamSet', - '1.2.643.2.2.33.1' => 'id-GostR3410-94-CryptoPro-XchA-ParamSet', - '1.2.643.2.2.33.2' => 'id-GostR3410-94-CryptoPro-XchB-ParamSet', - '1.2.643.2.2.33.3' => 'id-GostR3410-94-CryptoPro-XchC-ParamSet', - '1.2.643.2.2.35.0' => 'id-GostR3410-2001-TestParamSet', - '1.2.643.2.2.35.1' => 'id-GostR3410-2001-CryptoPro-A-ParamSet', - '1.2.643.2.2.35.2' => 'id-GostR3410-2001-CryptoPro-B-ParamSet', - '1.2.643.2.2.35.3' => 'id-GostR3410-2001-CryptoPro-C-ParamSet', - '1.2.643.2.2.36.0' => 'id-GostR3410-2001-CryptoPro-XchA-ParamSet', - '1.2.643.2.2.36.1' => 'id-GostR3410-2001-CryptoPro-XchB-ParamSet', - '1.2.643.2.2.20.1' => 'id-GostR3410-94-a', - '1.2.643.2.2.20.2' => 'id-GostR3410-94-aBis', - '1.2.643.2.2.20.3' => 'id-GostR3410-94-b', - '1.2.643.2.2.20.4' => 'id-GostR3410-94-bBis', - '1.2.643.2.9.1.6.1' => 'GOST 28147-89 Cryptocom ParamSet', - '1.2.643.2.9.1.5.3' => 'GOST 34.10-94 Cryptocom', - '1.2.643.2.9.1.5.4' => 'GOST 34.10-2001 Cryptocom', - '1.2.643.2.9.1.3.3' => 'GOST R 34.11-94 with GOST R 34.10-94 Cryptocom', - '1.2.643.2.9.1.3.4' => 'GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom', - '1.2.643.2.9.1.8.1' => 'GOST R 3410-2001 Parameter Set Cryptocom', - '1.2.392.200011.61.1.1.1.2' => 'camellia-128-cbc', - '1.2.392.200011.61.1.1.1.3' => 'camellia-192-cbc', - '1.2.392.200011.61.1.1.1.4' => 'camellia-256-cbc', - '1.2.392.200011.61.1.1.3.2' => 'id-camellia128-wrap', - '1.2.392.200011.61.1.1.3.3' => 'id-camellia192-wrap', - '1.2.392.200011.61.1.1.3.4' => 'id-camellia256-wrap', - '0.3.4401.5' => 'ntt-ds', - '0.3.4401.5.3.1.9' => 'camellia', - '0.3.4401.5.3.1.9.1' => 'camellia-128-ecb', - '0.3.4401.5.3.1.9.3' => 'camellia-128-ofb', - '0.3.4401.5.3.1.9.4' => 'camellia-128-cfb', - '0.3.4401.5.3.1.9.6' => 'camellia-128-gcm', - '0.3.4401.5.3.1.9.7' => 'camellia-128-ccm', - '0.3.4401.5.3.1.9.9' => 'camellia-128-ctr', - '0.3.4401.5.3.1.9.10' => 'camellia-128-cmac', - '0.3.4401.5.3.1.9.21' => 'camellia-192-ecb', - '0.3.4401.5.3.1.9.23' => 'camellia-192-ofb', - '0.3.4401.5.3.1.9.24' => 'camellia-192-cfb', - '0.3.4401.5.3.1.9.26' => 'camellia-192-gcm', - '0.3.4401.5.3.1.9.27' => 'camellia-192-ccm', - '0.3.4401.5.3.1.9.29' => 'camellia-192-ctr', - '0.3.4401.5.3.1.9.30' => 'camellia-192-cmac', - '0.3.4401.5.3.1.9.41' => 'camellia-256-ecb', - '0.3.4401.5.3.1.9.43' => 'camellia-256-ofb', - '0.3.4401.5.3.1.9.44' => 'camellia-256-cfb', - '0.3.4401.5.3.1.9.46' => 'camellia-256-gcm', - '0.3.4401.5.3.1.9.47' => 'camellia-256-ccm', - '0.3.4401.5.3.1.9.49' => 'camellia-256-ctr', - '0.3.4401.5.3.1.9.50' => 'camellia-256-cmac', - '1.2.410.200004' => 'kisa', - '1.2.410.200004.1.3' => 'seed-ecb', - '1.2.410.200004.1.4' => 'seed-cbc', - '1.2.410.200004.1.5' => 'seed-cfb', - '1.2.410.200004.1.6' => 'seed-ofb', - '1.2.840.10046.2.1' => 'X9.42 DH', - '1.3.36.3.3.2.8.1.1.1' => 'brainpoolP160r1', - '1.3.36.3.3.2.8.1.1.2' => 'brainpoolP160t1', - '1.3.36.3.3.2.8.1.1.3' => 'brainpoolP192r1', - '1.3.36.3.3.2.8.1.1.4' => 'brainpoolP192t1', - '1.3.36.3.3.2.8.1.1.5' => 'brainpoolP224r1', - '1.3.36.3.3.2.8.1.1.6' => 'brainpoolP224t1', - '1.3.36.3.3.2.8.1.1.7' => 'brainpoolP256r1', - '1.3.36.3.3.2.8.1.1.8' => 'brainpoolP256t1', - '1.3.36.3.3.2.8.1.1.9' => 'brainpoolP320r1', - '1.3.36.3.3.2.8.1.1.10' => 'brainpoolP320t1', - '1.3.36.3.3.2.8.1.1.11' => 'brainpoolP384r1', - '1.3.36.3.3.2.8.1.1.12' => 'brainpoolP384t1', - '1.3.36.3.3.2.8.1.1.13' => 'brainpoolP512r1', - '1.3.36.3.3.2.8.1.1.14' => 'brainpoolP512t1', - '1.3.133.16.840.63.0' => 'x9-63-scheme', - '1.3.132.1' => 'secg-scheme', - '1.3.133.16.840.63.0.2' => 'dhSinglePass-stdDH-sha1kdf-scheme', - '1.3.132.1.11.0' => 'dhSinglePass-stdDH-sha224kdf-scheme', - '1.3.132.1.11.1' => 'dhSinglePass-stdDH-sha256kdf-scheme', - '1.3.132.1.11.2' => 'dhSinglePass-stdDH-sha384kdf-scheme', - '1.3.132.1.11.3' => 'dhSinglePass-stdDH-sha512kdf-scheme', - '1.3.133.16.840.63.0.3' => 'dhSinglePass-cofactorDH-sha1kdf-scheme', - '1.3.132.1.14.0' => 'dhSinglePass-cofactorDH-sha224kdf-scheme', - '1.3.132.1.14.1' => 'dhSinglePass-cofactorDH-sha256kdf-scheme', - '1.3.132.1.14.2' => 'dhSinglePass-cofactorDH-sha384kdf-scheme', - '1.3.132.1.14.3' => 'dhSinglePass-cofactorDH-sha512kdf-scheme', - '1.3.6.1.4.1.11129.2.4.2' => 'CT Precertificate SCTs', - '1.3.6.1.4.1.11129.2.4.3' => 'CT Precertificate Poison', - '1.3.6.1.4.1.11129.2.4.4' => 'CT Precertificate Signer', - '1.3.6.1.4.1.11129.2.4.5' => 'CT Certificate SCTs', - '1.3.6.1.4.1.311.60.2.1.1' => 'jurisdictionLocalityName', - '1.3.6.1.4.1.311.60.2.1.2' => 'jurisdictionStateOrProvinceName', - '1.3.6.1.4.1.311.60.2.1.3' => 'jurisdictionCountryName', - '1.3.6.1.4.1.11591.4.11' => 'id-scrypt', - ]; - - if (array_key_exists($oidString, $oids)) { - return $oids[$oidString]; - } - - switch ($oidString) { - case self::RSA_ENCRYPTION: - return 'RSA Encryption'; - case self::MD5_WITH_RSA_ENCRYPTION: - return 'MD5 with RSA Encryption'; - case self::SHA1_WITH_RSA_SIGNATURE: - return 'SHA-1 with RSA Signature'; - - case self::PKCS9_EMAIL: - return 'PKCS #9 Email Address'; - case self::PKCS9_UNSTRUCTURED_NAME: - return 'PKCS #9 Unstructured Name'; - case self::PKCS9_CONTENT_TYPE: - return 'PKCS #9 Content Type'; - case self::PKCS9_MESSAGE_DIGEST: - return 'PKCS #9 Message Digest'; - case self::PKCS9_SIGNING_TIME: - return 'PKCS #9 Signing Time'; - - case self::COMMON_NAME: - return 'Common Name'; - case self::SURNAME: - return 'Surname'; - case self::SERIAL_NUMBER: - return 'Serial Number'; - case self::COUNTRY_NAME: - return 'Country Name'; - case self::LOCALITY_NAME: - return 'Locality Name'; - case self::STATE_OR_PROVINCE_NAME: - return 'State or Province Name'; - case self::STREET_ADDRESS: - return 'Street Address'; - case self::ORGANIZATION_NAME: - return 'Organization Name'; - case self::OU_NAME: - return 'Organization Unit Name'; - case self::TITLE: - return 'Title'; - case self::DESCRIPTION: - return 'Description'; - case self::POSTAL_ADDRESS: - return 'Postal Address'; - case self::POSTAL_CODE: - return 'Postal Code'; - case self::AUTHORITY_REVOCATION_LIST: - return 'Authority Revocation List'; - - case self::CERT_EXT_SUBJECT_DIRECTORY_ATTR: - return 'Subject directory attributes'; - case self::CERT_EXT_SUBJECT_KEY_IDENTIFIER: - return 'Subject key identifier'; - case self::CERT_EXT_KEY_USAGE: - return 'Key usage certificate extension'; - case self::CERT_EXT_PRIVATE_KEY_USAGE_PERIOD: - return 'Private key usage'; - case self::CERT_EXT_SUBJECT_ALT_NAME: - return 'Subject alternative name (SAN)'; - case self::CERT_EXT_ISSUER_ALT_NAME: - return 'Issuer alternative name'; - case self::CERT_EXT_BASIC_CONSTRAINTS: - return 'Basic constraints'; - case self::CERT_EXT_CRL_NUMBER: - return 'CRL number'; - case self::CERT_EXT_REASON_CODE: - return 'Reason code'; - case self::CERT_EXT_INVALIDITY_DATE: - return 'Invalidity code'; - case self::CERT_EXT_DELTA_CRL_INDICATOR: - return 'Delta CRL indicator'; - case self::CERT_EXT_ISSUING_DIST_POINT: - return 'Issuing distribution point'; - case self::CERT_EXT_CERT_ISSUER: - return 'Certificate issuer'; - case self::CERT_EXT_NAME_CONSTRAINTS: - return 'Name constraints'; - case self::CERT_EXT_CRL_DISTRIBUTION_POINTS: - return 'CRL distribution points'; - case self::CERT_EXT_CERT_POLICIES: - return 'Certificate policies '; - case self::CERT_EXT_AUTHORITY_KEY_IDENTIFIER: - return 'Authority key identifier'; - case self::CERT_EXT_EXTENDED_KEY_USAGE: - return 'Extended key usage'; - case self::AUTHORITY_INFORMATION_ACCESS: - return 'Certificate Authority Information Access (AIA)'; - - default: - if ($loadFromWeb) { - return self::loadFromWeb($oidString); - } else { - return $oidString; - } - } - } - - public static function loadFromWeb($oidString) - { - $ch = curl_init("http://oid-info.com/get/{$oidString}"); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $contents = curl_exec($ch); - curl_close($ch); - - // This pattern needs to be updated as soon as the website layout of oid-info.com changes - preg_match_all('#(.+)\(\d+\)#si', $contents, $oidName); - - if (empty($oidName[1])) { - return "{$oidString} (unknown)"; - } - - $oidName = ucfirst(strtolower(preg_replace('/([A-Z][a-z])/', ' $1', $oidName[1][0]))); - $oidName = str_replace('-', ' ', $oidName); - - return "{$oidName} ({$oidString})"; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php deleted file mode 100644 index fa66b558d..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use FG\ASN1\Exception\ParserException; - -/** - * The Parsable interface describes classes that can be parsed from their binary DER representation. - */ -interface Parsable -{ - /** - * Parse an instance of this class from its binary DER encoded representation. - * - * @param string $binaryData - * @param int $offsetIndex the offset at which parsing of the $binaryData is started. This parameter ill be modified - * to contain the offset index of the next object after this object has been parsed - * - * @throws ParserException if the given binary data is either invalid or not currently supported - * - * @return static - */ - public static function fromBinary(&$binaryData, &$offsetIndex = null); -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.php deleted file mode 100644 index 90a40b037..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -use Exception; -use FG\ASN1\Exception\ParserException; -use FG\ASN1\Universal\Sequence; - -class TemplateParser -{ - /** - * @param string $data - * @param array $template - * @return \FG\ASN1\ASNObject|Sequence - * @throws ParserException if there was an issue parsing - */ - public function parseBase64($data, array $template) - { - // TODO test with invalid data - return $this->parseBinary(base64_decode($data), $template); - } - - /** - * @param string $binary - * @param array $template - * @return \FG\ASN1\ASNObject|Sequence - * @throws ParserException if there was an issue parsing - */ - public function parseBinary($binary, array $template) - { - $parsedObject = ASNObject::fromBinary($binary); - - foreach ($template as $key => $value) { - $this->validate($parsedObject, $key, $value); - } - - return $parsedObject; - } - - private function validate(ASNObject $object, $key, $value) - { - if (is_array($value)) { - $this->assertTypeId($key, $object); - - /* @var Construct $object */ - foreach ($value as $key => $child) { - $this->validate($object->current(), $key, $child); - $object->next(); - } - } else { - $this->assertTypeId($value, $object); - } - } - - private function assertTypeId($expectedTypeId, ASNObject $object) - { - $actualType = $object->getType(); - if ($expectedTypeId != $actualType) { - throw new Exception("Expected type ($expectedTypeId) does not match actual type ($actualType"); - } - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php deleted file mode 100644 index 83ec6a910..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class BMPString extends AbstractString -{ - /** - * Creates a new ASN.1 BMP String. - * - * BMPString is a subtype of UniversalString that has its own - * unique tag and contains only the characters in the - * Basic Multilingual Plane (those corresponding to the first - * 64K-2 cells, less cells whose encoding is used to address - * characters outside the Basic Multilingual Plane) of ISO/IEC 10646-1. - * - * TODO The encodable characters of this type are not yet checked. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::BMP_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php deleted file mode 100644 index 226695c59..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use Exception; -use FG\ASN1\Exception\ParserException; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; - -class BitString extends OctetString implements Parsable -{ - private $nrOfUnusedBits; - - /** - * Creates a new ASN.1 BitString object. - * - * @param string|int $value Either the hexadecimal value as a string (spaces are allowed - leading 0x is optional) or a numeric value - * @param int $nrOfUnusedBits the number of unused bits in the last octet [optional]. - * - * @throws Exception if the second parameter is no positive numeric value - */ - public function __construct($value, $nrOfUnusedBits = 0) - { - parent::__construct($value); - - if (!is_numeric($nrOfUnusedBits) || $nrOfUnusedBits < 0) { - throw new Exception('BitString: second parameter needs to be a positive number (or zero)!'); - } - - $this->nrOfUnusedBits = $nrOfUnusedBits; - } - - public function getType() - { - return Identifier::BITSTRING; - } - - protected function calculateContentLength() - { - // add one to the length for the first octet which encodes the number of unused bits in the last octet - return parent::calculateContentLength() + 1; - } - - protected function getEncodedValue() - { - // the first octet determines the number of unused bits - $nrOfUnusedBitsOctet = chr($this->nrOfUnusedBits); - $actualContent = parent::getEncodedValue(); - - return $nrOfUnusedBitsOctet.$actualContent; - } - - public function getNumberOfUnusedBits() - { - return $this->nrOfUnusedBits; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::BITSTRING, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex, 2); - - $nrOfUnusedBits = ord($binaryData[$offsetIndex]); - $value = substr($binaryData, $offsetIndex + 1, $contentLength - 1); - - if ($nrOfUnusedBits > 7 || // no less than 1 used, otherwise non-minimal - ($contentLength - 1) == 1 && $nrOfUnusedBits > 0 || // content length only 1, no - (ord($value[strlen($value)-1])&((1<<$nrOfUnusedBits)-1)) != 0 // unused bits set - ) { - throw new ParserException("Can not parse bit string with invalid padding", $offsetIndex); - } - - $offsetIndex += $contentLength; - - $parsedObject = new self(bin2hex($value), $nrOfUnusedBits); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php deleted file mode 100644 index b73c99f1e..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -class Boolean extends ASNObject implements Parsable -{ - private $value; - - /** - * @param bool $value - */ - public function __construct($value) - { - $this->value = $value; - } - - public function getType() - { - return Identifier::BOOLEAN; - } - - protected function calculateContentLength() - { - return 1; - } - - protected function getEncodedValue() - { - if ($this->value == false) { - return chr(0x00); - } else { - return chr(0xFF); - } - } - - public function getContent() - { - if ($this->value == true) { - return 'TRUE'; - } else { - return 'FALSE'; - } - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::BOOLEAN, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - - if ($contentLength != 1) { - throw new ParserException("An ASN.1 Boolean should not have a length other than one. Extracted length was {$contentLength}", $offsetIndex); - } - - $value = ord($binaryData[$offsetIndex++]); - $booleanValue = $value == 0xFF ? true : false; - - $parsedObject = new self($booleanValue); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php deleted file mode 100644 index bfc170dba..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class CharacterString extends AbstractString -{ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::CHARACTER_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php deleted file mode 100644 index 06d04a3a3..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\Identifier; - -class Enumerated extends Integer -{ - public function getType() - { - return Identifier::ENUMERATED; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php deleted file mode 100644 index fb0346f0a..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class GeneralString extends AbstractString -{ - /** - * Creates a new ASN.1 GeneralString. - * TODO The encodable characters of this type are not yet checked. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::GENERAL_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php deleted file mode 100644 index ca9220972..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php +++ /dev/null @@ -1,134 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractTime; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -/** - * This ASN.1 universal type contains date and time information according to ISO 8601. - * - * The type consists of values representing: - * a) a calendar date, as defined in ISO 8601; and - * b) a time of day, to any of the precisions defined in ISO 8601, except for the hours value 24 which shall not be used; and - * c) the local time differential factor as defined in ISO 8601. - * - * Decoding of this type will accept the Basic Encoding Rules (BER) - * The encoding will comply with the Distinguished Encoding Rules (DER). - */ -class GeneralizedTime extends AbstractTime implements Parsable -{ - private $microseconds; - - public function __construct($dateTime = null, $dateTimeZone = 'UTC') - { - parent::__construct($dateTime, $dateTimeZone); - $this->microseconds = $this->value->format('u'); - if ($this->containsFractionalSecondsElement()) { - // DER requires us to remove trailing zeros - $this->microseconds = preg_replace('/([1-9]+)0+$/', '$1', $this->microseconds); - } - } - - public function getType() - { - return Identifier::GENERALIZED_TIME; - } - - protected function calculateContentLength() - { - $contentSize = 15; // YYYYMMDDHHmmSSZ - - if ($this->containsFractionalSecondsElement()) { - $contentSize += 1 + strlen($this->microseconds); - } - - return $contentSize; - } - - public function containsFractionalSecondsElement() - { - return intval($this->microseconds) > 0; - } - - protected function getEncodedValue() - { - $encodedContent = $this->value->format('YmdHis'); - if ($this->containsFractionalSecondsElement()) { - $encodedContent .= ".{$this->microseconds}"; - } - - return $encodedContent.'Z'; - } - - public function __toString() - { - if ($this->containsFractionalSecondsElement()) { - return $this->value->format("Y-m-d\tH:i:s.uP"); - } else { - return $this->value->format("Y-m-d\tH:i:sP"); - } - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::GENERALIZED_TIME, $offsetIndex++); - $lengthOfMinimumTimeString = 14; // YYYYMMDDHHmmSS - $contentLength = self::parseContentLength($binaryData, $offsetIndex, $lengthOfMinimumTimeString); - $maximumBytesToRead = $contentLength; - - $format = 'YmdGis'; - $content = substr($binaryData, $offsetIndex, $contentLength); - $dateTimeString = substr($content, 0, $lengthOfMinimumTimeString); - $offsetIndex += $lengthOfMinimumTimeString; - $maximumBytesToRead -= $lengthOfMinimumTimeString; - - if ($contentLength == $lengthOfMinimumTimeString) { - $localTimeZone = new \DateTimeZone(date_default_timezone_get()); - $dateTime = \DateTime::createFromFormat($format, $dateTimeString, $localTimeZone); - } else { - if ($binaryData[$offsetIndex] == '.') { - $maximumBytesToRead--; // account for the '.' - $nrOfFractionalSecondElements = 1; // account for the '.' - - while ($maximumBytesToRead > 0 - && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '+' - && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '-' - && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != 'Z') { - $nrOfFractionalSecondElements++; - $maximumBytesToRead--; - } - - $dateTimeString .= substr($binaryData, $offsetIndex, $nrOfFractionalSecondElements); - $offsetIndex += $nrOfFractionalSecondElements; - $format .= '.u'; - } - - $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); - - if ($maximumBytesToRead > 0) { - if ($binaryData[$offsetIndex] == '+' - || $binaryData[$offsetIndex] == '-') { - $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); - } elseif ($binaryData[$offsetIndex++] != 'Z') { - throw new ParserException('Invalid ISO 8601 Time String', $offsetIndex); - } - } - } - - $parsedObject = new self($dateTime); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php deleted file mode 100644 index 4a01d67be..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class GraphicString extends AbstractString -{ - /** - * Creates a new ASN.1 Graphic String. - * TODO The encodable characters of this type are not yet checked. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::GRAPHIC_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php deleted file mode 100644 index 33a806793..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -/** - * The International Alphabet No.5 (IA5) references the encoding of the ASCII characters. - * - * Each character in the data is encoded as 1 byte. - */ -class IA5String extends AbstractString -{ - public function __construct($string) - { - parent::__construct($string); - for ($i = 1; $i < 128; $i++) { - $this->allowCharacter(chr($i)); - } - } - - public function getType() - { - return Identifier::IA5_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php deleted file mode 100644 index fe3806ba7..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php +++ /dev/null @@ -1,130 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use Exception; -use FG\Utility\BigInteger; -use FG\ASN1\Exception\ParserException; -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; - -class Integer extends ASNObject implements Parsable -{ - /** @var int */ - private $value; - - /** - * @param int $value - * - * @throws Exception if the value is not numeric - */ - public function __construct($value) - { - if (is_numeric($value) == false) { - throw new Exception("Invalid VALUE [{$value}] for ASN1_INTEGER"); - } - $this->value = $value; - } - - public function getType() - { - return Identifier::INTEGER; - } - - public function getContent() - { - return $this->value; - } - - protected function calculateContentLength() - { - return strlen($this->getEncodedValue()); - } - - protected function getEncodedValue() - { - $value = BigInteger::create($this->value, 10); - $negative = $value->compare(0) < 0; - if ($negative) { - $value = $value->absoluteValue(); - $limit = 0x80; - } else { - $limit = 0x7f; - } - - $mod = 0xff+1; - $values = []; - while($value->compare($limit) > 0) { - $values[] = $value->modulus($mod)->toInteger(); - $value = $value->shiftRight(8); - } - - $values[] = $value->modulus($mod)->toInteger(); - $numValues = count($values); - - if ($negative) { - for ($i = 0; $i < $numValues; $i++) { - $values[$i] = 0xff - $values[$i]; - } - for ($i = 0; $i < $numValues; $i++) { - $values[$i] += 1; - if ($values[$i] <= 0xff) { - break; - } - assert($i != $numValues - 1); - $values[$i] = 0; - } - if ($values[$numValues - 1] == 0x7f) { - $values[] = 0xff; - } - } - $values = array_reverse($values); - $r = pack("C*", ...$values); - return $r; - } - - private static function ensureMinimalEncoding($binaryData, $offsetIndex) - { - // All the first nine bits cannot equal 0 or 1, which would - // be non-minimal encoding for positive and negative integers respectively - if ((ord($binaryData[$offsetIndex]) == 0x00 && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0) || - (ord($binaryData[$offsetIndex]) == 0xff && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0x80)) { - throw new ParserException("Integer not minimally encoded", $offsetIndex); - } - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - $parsedObject = new static(0); - self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); - - if ($contentLength > 1) { - self::ensureMinimalEncoding($binaryData, $offsetIndex); - } - $isNegative = (ord($binaryData[$offsetIndex]) & 0x80) != 0x00; - $number = BigInteger::create(ord($binaryData[$offsetIndex++]) & 0x7F); - - for ($i = 0; $i < $contentLength - 1; $i++) { - $number = $number->multiply(0x100)->add(ord($binaryData[$offsetIndex++])); - } - - if ($isNegative) { - $number = $number->subtract(BigInteger::create(2)->toPower(8 * $contentLength - 1)); - } - - $parsedObject = new static((string)$number); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php deleted file mode 100644 index b5293e4ba..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -class NullObject extends ASNObject implements Parsable -{ - public function getType() - { - return Identifier::NULL; - } - - protected function calculateContentLength() - { - return 0; - } - - protected function getEncodedValue() - { - return null; - } - - public function getContent() - { - return 'NULL'; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::NULL, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - - if ($contentLength != 0) { - throw new ParserException("An ASN.1 Null should not have a length other than zero. Extracted length was {$contentLength}", $offsetIndex); - } - - $parsedObject = new self(); - $parsedObject->setContentLength(0); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php deleted file mode 100644 index 13fb7c347..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class NumericString extends AbstractString -{ - /** - * Creates a new ASN.1 NumericString. - * - * The following characters are permitted: - * Digits 0,1, ... 9 - * SPACE (space) - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowNumbers(); - $this->allowSpaces(); - } - - public function getType() - { - return Identifier::NUMERIC_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php deleted file mode 100644 index 1c5d3498a..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\Identifier; - -class ObjectDescriptor extends GraphicString -{ - public function __construct($objectDescription) - { - parent::__construct($objectDescription); - } - - public function getType() - { - return Identifier::OBJECT_DESCRIPTOR; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php deleted file mode 100644 index 150ce9c4a..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php +++ /dev/null @@ -1,138 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use Exception; -use FG\ASN1\Base128; -use FG\ASN1\OID; -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -class ObjectIdentifier extends ASNObject implements Parsable -{ - protected $subIdentifiers; - protected $value; - - public function __construct($value) - { - $this->subIdentifiers = explode('.', $value); - $nrOfSubIdentifiers = count($this->subIdentifiers); - - for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { - if (is_numeric($this->subIdentifiers[$i])) { - // enforce the integer type - $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); - } else { - throw new Exception("[{$value}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); - } - } - - // Merge the first to arcs of the OID registration tree (per ASN definition!) - if ($nrOfSubIdentifiers >= 2) { - $this->subIdentifiers[1] = ($this->subIdentifiers[0] * 40) + $this->subIdentifiers[1]; - unset($this->subIdentifiers[0]); - } - - $this->value = $value; - } - - public function getContent() - { - return $this->value; - } - - public function getType() - { - return Identifier::OBJECT_IDENTIFIER; - } - - protected function calculateContentLength() - { - $length = 0; - foreach ($this->subIdentifiers as $subIdentifier) { - do { - $subIdentifier = $subIdentifier >> 7; - $length++; - } while ($subIdentifier > 0); - } - - return $length; - } - - protected function getEncodedValue() - { - $encodedValue = ''; - foreach ($this->subIdentifiers as $subIdentifier) { - $encodedValue .= Base128::encode($subIdentifier); - } - - return $encodedValue; - } - - public function __toString() - { - return OID::getName($this->value); - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::OBJECT_IDENTIFIER, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); - - $firstOctet = ord($binaryData[$offsetIndex++]); - $oidString = floor($firstOctet / 40).'.'.($firstOctet % 40); - $oidString .= '.'.self::parseOid($binaryData, $offsetIndex, $contentLength - 1); - - $parsedObject = new self($oidString); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } - - /** - * Parses an object identifier except for the first octet, which is parsed - * differently. This way relative object identifiers can also be parsed - * using this. - * - * @param $binaryData - * @param $offsetIndex - * @param $octetsToRead - * - * @throws ParserException - * - * @return string - */ - protected static function parseOid(&$binaryData, &$offsetIndex, $octetsToRead) - { - $oid = ''; - - while ($octetsToRead > 0) { - $octets = ''; - - do { - if (0 === $octetsToRead) { - throw new ParserException('Malformed ASN.1 Object Identifier', $offsetIndex - 1); - } - - $octetsToRead--; - $octet = $binaryData[$offsetIndex++]; - $octets .= $octet; - } while (ord($octet) & 0x80); - - $oid .= sprintf('%d.', Base128::decode($octets)); - } - - // Remove trailing '.' - return substr($oid, 0, -1) ?: ''; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php deleted file mode 100644 index 5d69ae7bf..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php +++ /dev/null @@ -1,91 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use Exception; -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; - -class OctetString extends ASNObject implements Parsable -{ - protected $value; - - public function __construct($value) - { - if (is_string($value)) { - // remove gaps between hex digits - $value = preg_replace('/\s|0x/', '', $value); - } elseif (is_numeric($value)) { - $value = dechex($value); - } elseif ($value === null) { - return; - } else { - throw new Exception('OctetString: unrecognized input type!'); - } - - if (strlen($value) % 2 != 0) { - // transform values like 1F2 to 01F2 - $value = '0'.$value; - } - - $this->value = $value; - } - - public function getType() - { - return Identifier::OCTETSTRING; - } - - protected function calculateContentLength() - { - return strlen($this->value) / 2; - } - - protected function getEncodedValue() - { - $value = $this->value; - $result = ''; - - //Actual content - while (strlen($value) >= 2) { - // get the hex value byte by byte from the string and and add it to binary result - $result .= chr(hexdec(substr($value, 0, 2))); - $value = substr($value, 2); - } - - return $result; - } - - public function getContent() - { - return strtoupper($this->value); - } - - public function getBinaryContent() - { - return $this->getEncodedValue(); - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - - $value = substr($binaryData, $offsetIndex, $contentLength); - $offsetIndex += $contentLength; - - $parsedObject = new self(bin2hex($value)); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php deleted file mode 100644 index fe6d4bc02..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class PrintableString extends AbstractString -{ - /** - * Creates a new ASN.1 PrintableString. - * - * The ITU-T X.680 Table 8 permits the following characters: - * Latin capital letters A,B, ... Z - * Latin small letters a,b, ... z - * Digits 0,1, ... 9 - * SPACE (space) - * APOSTROPHE ' - * LEFT PARENTHESIS ( - * RIGHT PARENTHESIS ) - * PLUS SIGN + - * COMMA , - * HYPHEN-MINUS - - * FULL STOP . - * SOLIDUS / - * COLON : - * EQUALS SIGN = - * QUESTION MARK ? - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowNumbers(); - $this->allowAllLetters(); - $this->allowSpaces(); - $this->allowCharacters("'", '(', ')', '+', '-', '.', ',', '/', ':', '=', '?'); - } - - public function getType() - { - return Identifier::PRINTABLE_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php deleted file mode 100644 index 2aa9643a1..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use Exception; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -class RelativeObjectIdentifier extends ObjectIdentifier implements Parsable -{ - public function __construct($subIdentifiers) - { - $this->value = $subIdentifiers; - $this->subIdentifiers = explode('.', $subIdentifiers); - $nrOfSubIdentifiers = count($this->subIdentifiers); - - for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { - if (is_numeric($this->subIdentifiers[$i])) { - // enforce the integer type - $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); - } else { - throw new Exception("[{$subIdentifiers}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); - } - } - } - - public function getType() - { - return Identifier::RELATIVE_OID; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::RELATIVE_OID, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); - - try { - $oidString = self::parseOid($binaryData, $offsetIndex, $contentLength); - } catch (ParserException $e) { - throw new ParserException('Malformed ASN.1 Relative Object Identifier', $e->getOffset()); - } - - $parsedObject = new self($oidString); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php deleted file mode 100644 index 0397cf126..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\Construct; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; - -class Sequence extends Construct implements Parsable -{ - public function getType() - { - return Identifier::SEQUENCE; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.php deleted file mode 100644 index 6e6d346f7..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\Identifier; - -class Set extends Sequence -{ - public function getType() - { - return Identifier::SET; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php deleted file mode 100644 index 56418645f..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class T61String extends AbstractString -{ - /** - * Creates a new ASN.1 T61 String. - * TODO The encodable characters of this type are not yet checked. - * - * @see http://en.wikipedia.org/wiki/ITU_T.61 - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::T61_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php deleted file mode 100644 index c4d303cb7..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractTime; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Exception\ParserException; - -/** - * This ASN.1 universal type contains the calendar date and time. - * - * The precision is one minute or one second and optionally a - * local time differential from coordinated universal time. - * - * Decoding of this type will accept the Basic Encoding Rules (BER) - * The encoding will comply with the Distinguished Encoding Rules (DER). - */ -class UTCTime extends AbstractTime implements Parsable -{ - public function getType() - { - return Identifier::UTC_TIME; - } - - protected function calculateContentLength() - { - return 13; // Content is a string o the following format: YYMMDDhhmmssZ (13 octets) - } - - protected function getEncodedValue() - { - return $this->value->format('ymdHis').'Z'; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::UTC_TIME, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex, 11); - - $format = 'ymdGi'; - $dateTimeString = substr($binaryData, $offsetIndex, 10); - $offsetIndex += 10; - - // extract optional seconds part - if ($binaryData[$offsetIndex] != 'Z' - && $binaryData[$offsetIndex] != '+' - && $binaryData[$offsetIndex] != '-') { - $dateTimeString .= substr($binaryData, $offsetIndex, 2); - $offsetIndex += 2; - $format .= 's'; - } - - $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); - - // extract time zone settings - if ($binaryData[$offsetIndex] == '+' - || $binaryData[$offsetIndex] == '-') { - $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); - } elseif ($binaryData[$offsetIndex++] != 'Z') { - throw new ParserException('Invalid UTC String', $offsetIndex); - } - - $parsedObject = new self($dateTime); - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php deleted file mode 100644 index cba568d33..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class UTF8String extends AbstractString -{ - /** - * Creates a new ASN.1 Universal String. - * TODO The encodable characters of this type are not yet checked. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::UTF8_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php deleted file mode 100644 index 0c3fe1d01..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class UniversalString extends AbstractString -{ - /** - * Creates a new ASN.1 Universal String. - * TODO The encodable characters of this type are not yet checked. - * - * @see http://en.wikipedia.org/wiki/Universal_Character_Set - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::UNIVERSAL_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php deleted file mode 100644 index d9326d3fa..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1\Universal; - -use FG\ASN1\AbstractString; -use FG\ASN1\Identifier; - -class VisibleString extends AbstractString -{ - /** - * Creates a new ASN.1 Visible String. - * TODO The encodable characters of this type are not yet checked. - * - * @param string $string - */ - public function __construct($string) - { - $this->value = $string; - $this->allowAll(); - } - - public function getType() - { - return Identifier::VISIBLE_STRING; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php deleted file mode 100644 index b19a07a18..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -class UnknownConstructedObject extends Construct -{ - private $identifier; - private $contentLength; - - /** - * @param string $binaryData - * @param int $offsetIndex - * - * @throws \FG\ASN1\Exception\ParserException - */ - public function __construct($binaryData, &$offsetIndex) - { - $this->identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); - $this->contentLength = self::parseContentLength($binaryData, $offsetIndex); - - $children = []; - $octetsToRead = $this->contentLength; - while ($octetsToRead > 0) { - $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); - $octetsToRead -= $newChild->getObjectLength(); - $children[] = $newChild; - } - - parent::__construct(...$children); - } - - public function getType() - { - return ord($this->identifier); - } - - public function getIdentifier() - { - return $this->identifier; - } - - protected function calculateContentLength() - { - return $this->contentLength; - } - - protected function getEncodedValue() - { - return ''; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php deleted file mode 100644 index 4ac536a9b..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\ASN1; - -class UnknownObject extends ASNObject -{ - /** @var string */ - private $value; - - private $identifier; - - /** - * @param string|int $identifier Either the first identifier octet as int or all identifier bytes as a string - * @param int $contentLength - */ - public function __construct($identifier, $contentLength) - { - if (is_int($identifier)) { - $identifier = chr($identifier); - } - - $this->identifier = $identifier; - $this->value = "Unparsable Object ({$contentLength} bytes)"; - $this->setContentLength($contentLength); - } - - public function getContent() - { - return $this->value; - } - - public function getType() - { - return ord($this->identifier[0]); - } - - public function getIdentifier() - { - return $this->identifier; - } - - protected function calculateContentLength() - { - return $this->getContentLength(); - } - - protected function getEncodedValue() - { - return ''; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php deleted file mode 100644 index 866162cc0..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php +++ /dev/null @@ -1,195 +0,0 @@ -_fromInteger($val); - } - else { - // convert to string, if not already one - $val = (string)$val; - - // validate string - if (!preg_match('/^-?[0-9]+$/', $val)) { - throw new \InvalidArgumentException('Expects a string representation of an integer.'); - } - $ret->_fromString($val); - } - - return $ret; - } - - /** - * BigInteger constructor. - * Prevent directly instantiating object, use BigInteger::create instead. - */ - protected function __construct() - { - - } - - /** - * Subclasses must provide clone functionality. - * @return BigInteger - */ - abstract public function __clone(); - - /** - * Assign the instance value from base 10 string. - * @param string $str - */ - abstract protected function _fromString($str); - - /** - * Assign the instance value from an integer type. - * @param int $integer - */ - abstract protected function _fromInteger($integer); - - /** - * Must provide string implementation that returns base 10 number. - * @return string - */ - abstract public function __toString(); - - /* INFORMATIONAL FUNCTIONS */ - - /** - * Return integer, if possible. Throws an exception if the number can not be represented as a native integer. - * @return int - * @throws \OverflowException - */ - abstract public function toInteger(); - - /** - * Is represented integer negative? - * @return bool - */ - abstract public function isNegative(); - - /** - * Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is - * equal to number and returns a positive integer if $this is greater than number. - * @param BigInteger|string|int $number - * @return int - */ - abstract public function compare($number); - - /* MODIFY */ - - /** - * Add another integer $b and returns the result. - * @param BigInteger|string|int $b - * @return BigInteger - */ - abstract public function add($b); - - /** - * Subtract $b from $this and returns the result. - * @param BigInteger|string|int $b - * @return BigInteger - */ - abstract public function subtract($b); - - /** - * Multiply value. - * @param BigInteger|string|int $b - * @return BigInteger - */ - abstract public function multiply($b); - - /** - * The value $this modulus $b. - * @param BigInteger|string|int $b - * @return BigInteger - */ - abstract public function modulus($b); - - /** - * Raise $this to the power of $b and returns the result. - * @param BigInteger|string|int $b - * @return BigInteger - */ - abstract public function toPower($b); - - /** - * Shift the value to the right by a set number of bits and returns the result. - * @param int $bits - * @return BigInteger - */ - abstract public function shiftRight($bits = 8); - - /** - * Shift the value to the left by a set number of bits and returns the result. - * @param int $bits - * @return BigInteger - */ - abstract public function shiftLeft($bits = 8); - - /** - * Returns the absolute value. - * @return BigInteger - */ - abstract public function absoluteValue(); -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php deleted file mode 100644 index 25ad89164..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php +++ /dev/null @@ -1,133 +0,0 @@ -_str = (string)$str; - } - - protected function _fromInteger($integer) - { - $this->_str = (string)$integer; - } - - public function __toString() - { - return $this->_str; - } - - public function toInteger() - { - if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { - throw new \OverflowException(sprintf('Can not represent %s as integer.', $this->_str)); - } - return (int)$this->_str; - } - - public function isNegative() - { - return bccomp($this->_str, '0', 0) < 0; - } - - protected function _unwrap($number) - { - if ($number instanceof self) { - return $number->_str; - } - return $number; - } - - public function compare($number) - { - return bccomp($this->_str, $this->_unwrap($number), 0); - } - - public function add($b) - { - $ret = new self(); - $ret->_str = bcadd($this->_str, $this->_unwrap($b), 0); - return $ret; - } - - public function subtract($b) - { - $ret = new self(); - $ret->_str = bcsub($this->_str, $this->_unwrap($b), 0); - return $ret; - } - - public function multiply($b) - { - $ret = new self(); - $ret->_str = bcmul($this->_str, $this->_unwrap($b), 0); - return $ret; - } - - public function modulus($b) - { - $ret = new self(); - if ($this->isNegative()) { - // bcmod handles negative numbers differently - $b = $this->_unwrap($b); - $ret->_str = bcsub($b, bcmod(bcsub('0', $this->_str, 0), $b), 0); - } - else { - $ret->_str = bcmod($this->_str, $this->_unwrap($b)); - } - return $ret; - } - - public function toPower($b) - { - $ret = new self(); - $ret->_str = bcpow($this->_str, $this->_unwrap($b), 0); - return $ret; - } - - public function shiftRight($bits = 8) - { - $ret = new self(); - $ret->_str = bcdiv($this->_str, bcpow('2', $bits)); - return $ret; - } - - public function shiftLeft($bits = 8) { - $ret = new self(); - $ret->_str = bcmul($this->_str, bcpow('2', $bits)); - return $ret; - } - - public function absoluteValue() - { - $ret = new self(); - if (-1 === bccomp($this->_str, '0', 0)) { - $ret->_str = bcsub('0', $this->_str, 0); - } - else { - $ret->_str = $this->_str; - } - return $ret; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php deleted file mode 100644 index 0791226a5..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php +++ /dev/null @@ -1,133 +0,0 @@ -_rh = gmp_add($this->_rh, 0); - } - - protected function _fromString($str) - { - $this->_rh = gmp_init($str, 10); - } - - protected function _fromInteger($integer) - { - $this->_rh = gmp_init($integer, 10); - } - - public function __toString() - { - return gmp_strval($this->_rh, 10); - } - - public function toInteger() - { - if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { - throw new \OverflowException(sprintf('Can not represent %s as integer.', $this)); - } - return gmp_intval($this->_rh); - } - - public function isNegative() - { - return gmp_sign($this->_rh) === -1; - } - - protected function _unwrap($number) - { - if ($number instanceof self) { - return $number->_rh; - } - return $number; - } - - public function compare($number) - { - return gmp_cmp($this->_rh, $this->_unwrap($number)); - } - - public function add($b) - { - $ret = new self(); - $ret->_rh = gmp_add($this->_rh, $this->_unwrap($b)); - return $ret; - } - - public function subtract($b) - { - $ret = new self(); - $ret->_rh = gmp_sub($this->_rh, $this->_unwrap($b)); - return $ret; - } - - public function multiply($b) - { - $ret = new self(); - $ret->_rh = gmp_mul($this->_rh, $this->_unwrap($b)); - return $ret; - } - - public function modulus($b) - { - $ret = new self(); - $ret->_rh = gmp_mod($this->_rh, $this->_unwrap($b)); - return $ret; - } - - public function toPower($b) - { - if ($b instanceof self) { - // gmp_pow accepts just an integer - if ($b->compare(PHP_INT_MAX) > 0) { - throw new \UnexpectedValueException('Unable to raise to power greater than PHP_INT_MAX.'); - } - $b = gmp_intval($b->_rh); - } - $ret = new self(); - $ret->_rh = gmp_pow($this->_rh, $b); - return $ret; - } - - public function shiftRight($bits=8) - { - $ret = new self(); - $ret->_rh = gmp_div($this->_rh, gmp_pow(2, $bits)); - return $ret; - } - - public function shiftLeft($bits=8) - { - $ret = new self(); - $ret->_rh = gmp_mul($this->_rh, gmp_pow(2, $bits)); - return $ret; - } - - public function absoluteValue() - { - $ret = new self(); - $ret->_rh = gmp_abs($this->_rh); - return $ret; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php deleted file mode 100644 index a06b56f77..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509; - -use FG\ASN1\Universal\NullObject; -use FG\ASN1\Composite\AttributeTypeAndValue; - -class AlgorithmIdentifier extends AttributeTypeAndValue -{ - public function __construct($objectIdentifierString) - { - parent::__construct($objectIdentifierString, new NullObject()); - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.php deleted file mode 100644 index 5a965e2f8..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.php +++ /dev/null @@ -1,68 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509\CSR; - -use FG\ASN1\ASNObject; -use FG\X509\CertificateExtensions; -use FG\ASN1\OID; -use FG\ASN1\Parsable; -use FG\ASN1\Construct; -use FG\ASN1\Identifier; -use FG\ASN1\Universal\Set; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\ObjectIdentifier; - -class Attributes extends Construct implements Parsable -{ - public function getType() - { - return 0xA0; - } - - public function addAttribute($objectIdentifier, Set $attribute) - { - if (is_string($objectIdentifier)) { - $objectIdentifier = new ObjectIdentifier($objectIdentifier); - } - $attributeSequence = new Sequence($objectIdentifier, $attribute); - $attributeSequence->getNumberOfLengthOctets(); // length and number of length octets is calculated - $this->addChild($attributeSequence); - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], 0xA0, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - $octetsToRead = $contentLength; - - $parsedObject = new self(); - while ($octetsToRead > 0) { - $initialOffset = $offsetIndex; // used to calculate how much bits have been read - self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); - self::parseContentLength($binaryData, $offsetIndex); - - $objectIdentifier = ObjectIdentifier::fromBinary($binaryData, $offsetIndex); - $oidString = $objectIdentifier->getContent(); - if ($oidString == OID::PKCS9_EXTENSION_REQUEST) { - $attribute = CertificateExtensions::fromBinary($binaryData, $offsetIndex); - } else { - $attribute = ASNObject::fromBinary($binaryData, $offsetIndex); - } - - $parsedObject->addAttribute($objectIdentifier, $attribute); - $octetsToRead -= ($offsetIndex - $initialOffset); - } - - $parsedObject->setContentLength($contentLength); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.php deleted file mode 100644 index 8f2a31970..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.php +++ /dev/null @@ -1,159 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509\CSR; - -use FG\ASN1\OID; -use FG\ASN1\Universal\Integer; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\Sequence; -use FG\X509\CertificateSubject; -use FG\X509\AlgorithmIdentifier; -use FG\X509\PublicKey; - -class CSR extends Sequence -{ - const CSR_VERSION_NR = 0; - - protected $subject; - protected $publicKey; - protected $signature; - protected $signatureAlgorithm; - - protected $startSequence; - - /** - * @param string $commonName - * @param string $email - * @param string $organization - * @param string $locality - * @param string $state - * @param string $country - * @param string $organizationalUnit - * @param string $publicKey - * @param string $signature - * @param string $signatureAlgorithm - */ - public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit, $publicKey, $signature = null, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) - { - $this->subject = new CertificateSubject( - $commonName, - $email, - $organization, - $locality, - $state, - $country, - $organizationalUnit - ); - $this->publicKey = $publicKey; - $this->signature = $signature; - $this->signatureAlgorithm = $signatureAlgorithm; - - if (isset($signature)) { - $this->createCSRSequence(); - } - } - - protected function createCSRSequence() - { - $versionNr = new Integer(self::CSR_VERSION_NR); - $publicKey = new PublicKey($this->publicKey); - $signature = new BitString($this->signature); - $signatureAlgorithm = new AlgorithmIdentifier($this->signatureAlgorithm); - - $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); - - // Clear the underlying Construct - $this->rewind(); - $this->children = []; - $this->addChild($certRequestInfo); - $this->addChild($signatureAlgorithm); - $this->addChild($signature); - } - - public function getSignatureSubject() - { - $versionNr = new Integer(self::CSR_VERSION_NR); - $publicKey = new PublicKey($this->publicKey); - - $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); - return $certRequestInfo->getBinary(); - } - - public function setSignature($signature, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) - { - $this->signature = $signature; - $this->signatureAlgorithm = $signatureAlgorithm; - - $this->createCSRSequence(); - } - - public function __toString() - { - $tmp = base64_encode($this->getBinary()); - - for ($i = 0; $i < strlen($tmp); $i++) { - if (($i + 2) % 65 == 0) { - $tmp = substr($tmp, 0, $i + 1)."\n".substr($tmp, $i + 1); - } - } - - $result = '-----BEGIN CERTIFICATE REQUEST-----'.PHP_EOL; - $result .= $tmp.PHP_EOL; - $result .= '-----END CERTIFICATE REQUEST-----'; - - return $result; - } - - public function getVersion() - { - return self::CSR_VERSION_NR; - } - - public function getOrganizationName() - { - return $this->subject->getOrganization(); - } - - public function getLocalName() - { - return $this->subject->getLocality(); - } - - public function getState() - { - return $this->subject->getState(); - } - - public function getCountry() - { - return $this->subject->getCountry(); - } - - public function getOrganizationalUnit() - { - return $this->subject->getOrganizationalUnit(); - } - - public function getPublicKey() - { - return $this->publicKey; - } - - public function getSignature() - { - return $this->signature; - } - - public function getSignatureAlgorithm() - { - return $this->signatureAlgorithm; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php deleted file mode 100644 index 6ed1c6a7c..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php +++ /dev/null @@ -1,100 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509; - -use FG\ASN1\Exception\ParserException; -use FG\ASN1\OID; -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Universal\OctetString; -use FG\ASN1\Universal\Set; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\ObjectIdentifier; -use FG\X509\SAN\SubjectAlternativeNames; - -class CertificateExtensions extends Set implements Parsable -{ - private $innerSequence; - private $extensions = []; - - public function __construct() - { - $this->innerSequence = new Sequence(); - parent::__construct($this->innerSequence); - } - - public function addSubjectAlternativeNames(SubjectAlternativeNames $sans) - { - $this->addExtension(OID::CERT_EXT_SUBJECT_ALT_NAME, $sans); - } - - private function addExtension($oidString, ASNObject $extension) - { - $sequence = new Sequence(); - $sequence->addChild(new ObjectIdentifier($oidString)); - $sequence->addChild($extension); - - $this->innerSequence->addChild($sequence); - $this->extensions[] = $extension; - } - - public function getContent() - { - return $this->extensions; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::SET, $offsetIndex++); - self::parseContentLength($binaryData, $offsetIndex); - - $tmpOffset = $offsetIndex; - $extensions = Sequence::fromBinary($binaryData, $offsetIndex); - $tmpOffset += 1 + $extensions->getNumberOfLengthOctets(); - - $parsedObject = new self(); - foreach ($extensions as $extension) { - if ($extension->getType() != Identifier::SEQUENCE) { - //FIXME wrong offset index - throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Sequence but got '.$extension->getTypeName(), $offsetIndex); - } - - $tmpOffset += 1 + $extension->getNumberOfLengthOctets(); - $children = $extension->getChildren(); - if (count($children) < 2) { - throw new ParserException('Could not parse Certificate Extensions: Needs at least two child elements per extension sequence (object identifier and octet string)', $tmpOffset); - } - /** @var \FG\ASN1\ASNObject $objectIdentifier */ - $objectIdentifier = $children[0]; - - /** @var OctetString $octetString */ - $octetString = $children[1]; - - if ($objectIdentifier->getType() != Identifier::OBJECT_IDENTIFIER) { - throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Object Identifier but got '.$extension->getTypeName(), $tmpOffset); - } - - $tmpOffset += $objectIdentifier->getObjectLength(); - - if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) { - $sans = SubjectAlternativeNames::fromBinary($binaryData, $tmpOffset); - $parsedObject->addSubjectAlternativeNames($sans); - } else { - // can now only parse SANs. There might be more in the future - $tmpOffset += $octetString->getObjectLength(); - } - } - - $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php deleted file mode 100644 index 0a04d5740..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509; - -use FG\ASN1\Composite\RelativeDistinguishedName; -use FG\ASN1\Identifier; -use FG\ASN1\OID; -use FG\ASN1\Parsable; -use FG\ASN1\Composite\RDNString; -use FG\ASN1\Universal\Sequence; - -class CertificateSubject extends Sequence implements Parsable -{ - private $commonName; - private $email; - private $organization; - private $locality; - private $state; - private $country; - private $organizationalUnit; - - /** - * @param string $commonName - * @param string $email - * @param string $organization - * @param string $locality - * @param string $state - * @param string $country - * @param string $organizationalUnit - */ - public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit) - { - parent::__construct( - new RDNString(OID::COUNTRY_NAME, $country), - new RDNString(OID::STATE_OR_PROVINCE_NAME, $state), - new RDNString(OID::LOCALITY_NAME, $locality), - new RDNString(OID::ORGANIZATION_NAME, $organization), - new RDNString(OID::OU_NAME, $organizationalUnit), - new RDNString(OID::COMMON_NAME, $commonName), - new RDNString(OID::PKCS9_EMAIL, $email) - ); - - $this->commonName = $commonName; - $this->email = $email; - $this->organization = $organization; - $this->locality = $locality; - $this->state = $state; - $this->country = $country; - $this->organizationalUnit = $organizationalUnit; - } - - public function getCommonName() - { - return $this->commonName; - } - - public function getEmail() - { - return $this->email; - } - - public function getOrganization() - { - return $this->organization; - } - - public function getLocality() - { - return $this->locality; - } - - public function getState() - { - return $this->state; - } - - public function getCountry() - { - return $this->country; - } - - public function getOrganizationalUnit() - { - return $this->organizationalUnit; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - - $names = []; - $octetsToRead = $contentLength; - while ($octetsToRead > 0) { - $relativeDistinguishedName = RelativeDistinguishedName::fromBinary($binaryData, $offsetIndex); - $octetsToRead -= $relativeDistinguishedName->getObjectLength(); - $names[] = $relativeDistinguishedName; - } - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php deleted file mode 100644 index d57ad8659..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509; - -use FG\ASN1\OID; -use FG\ASN1\Universal\NullObject; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\ObjectIdentifier; - -class PrivateKey extends Sequence -{ - /** - * @param string $hexKey - * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString - */ - public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) - { - parent::__construct( - new Sequence( - new ObjectIdentifier($algorithmIdentifierString), - new NullObject() - ), - new BitString($hexKey) - ); - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php deleted file mode 100644 index ab8b4514b..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509; - -use FG\ASN1\OID; -use FG\ASN1\Universal\NullObject; -use FG\ASN1\Universal\Sequence; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\ObjectIdentifier; - -class PublicKey extends Sequence -{ - /** - * @param string $hexKey - * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString - */ - public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) - { - parent::__construct( - new Sequence( - new ObjectIdentifier($algorithmIdentifierString), - new NullObject() - ), - new BitString($hexKey) - ); - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.php deleted file mode 100644 index 502738b01..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509\SAN; - -use FG\ASN1\Universal\GeneralString; - -class DNSName extends GeneralString -{ - const IDENTIFIER = 0x82; // not sure yet why this is the identifier used in SAN extensions - - public function __construct($dnsNameString) - { - parent::__construct($dnsNameString); - } - - public function getType() - { - return self::IDENTIFIER; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/IPAddress.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/IPAddress.php deleted file mode 100644 index f55be95bb..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/IPAddress.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509\SAN; - -use FG\ASN1\ASNObject; -use FG\ASN1\Parsable; -use FG\ASN1\Exception\ParserException; - -class IPAddress extends ASNObject implements Parsable -{ - const IDENTIFIER = 0x87; // not sure yet why this is the identifier used in SAN extensions - - /** @var string */ - private $value; - - public function __construct($ipAddressString) - { - $this->value = $ipAddressString; - } - - public function getType() - { - return self::IDENTIFIER; - } - - public function getContent() - { - return $this->value; - } - - protected function calculateContentLength() - { - return 4; - } - - protected function getEncodedValue() - { - $ipParts = explode('.', $this->value); - $binary = chr($ipParts[0]); - $binary .= chr($ipParts[1]); - $binary .= chr($ipParts[2]); - $binary .= chr($ipParts[3]); - - return $binary; - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], self::IDENTIFIER, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - if ($contentLength != 4) { - throw new ParserException("A FG\\X509\SAN\IPAddress should have a content length of 4. Extracted length was {$contentLength}", $offsetIndex); - } - - $ipAddressString = ord($binaryData[$offsetIndex++]).'.'; - $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; - $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; - $ipAddressString .= ord($binaryData[$offsetIndex++]); - - $parsedObject = new self($ipAddressString); - $parsedObject->getObjectLength(); - - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php deleted file mode 100644 index 271ddde7b..000000000 --- a/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FG\X509\SAN; - -use FG\ASN1\Exception\ParserException; -use FG\ASN1\ASNObject; -use FG\ASN1\OID; -use FG\ASN1\Parsable; -use FG\ASN1\Identifier; -use FG\ASN1\Universal\Sequence; - -/** - * See section 8.3.2.1 of ITU-T X.509. - */ -class SubjectAlternativeNames extends ASNObject implements Parsable -{ - private $alternativeNamesSequence; - - public function __construct() - { - $this->alternativeNamesSequence = new Sequence(); - } - - protected function calculateContentLength() - { - return $this->alternativeNamesSequence->getObjectLength(); - } - - public function getType() - { - return Identifier::OCTETSTRING; - } - - public function addDomainName(DNSName $domainName) - { - $this->alternativeNamesSequence->addChild($domainName); - } - - public function addIP(IPAddress $ip) - { - $this->alternativeNamesSequence->addChild($ip); - } - - public function getContent() - { - return $this->alternativeNamesSequence->getContent(); - } - - protected function getEncodedValue() - { - return $this->alternativeNamesSequence->getBinary(); - } - - public static function fromBinary(&$binaryData, &$offsetIndex = 0) - { - self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); - $contentLength = self::parseContentLength($binaryData, $offsetIndex); - - if ($contentLength < 2) { - throw new ParserException('Can not parse Subject Alternative Names: The Sequence within the octet string after the Object identifier '.OID::CERT_EXT_SUBJECT_ALT_NAME." is too short ({$contentLength} octets)", $offsetIndex); - } - - $offsetOfSequence = $offsetIndex; - $sequence = Sequence::fromBinary($binaryData, $offsetIndex); - $offsetOfSequence += $sequence->getNumberOfLengthOctets() + 1; - - if ($sequence->getObjectLength() != $contentLength) { - throw new ParserException('Can not parse Subject Alternative Names: The Sequence length does not match the length of the surrounding octet string', $offsetIndex); - } - - $parsedObject = new self(); - /** @var \FG\ASN1\ASNObject $object */ - foreach ($sequence as $object) { - if ($object->getType() == DNSName::IDENTIFIER) { - $domainName = DNSName::fromBinary($binaryData, $offsetOfSequence); - $parsedObject->addDomainName($domainName); - } elseif ($object->getType() == IPAddress::IDENTIFIER) { - $ip = IPAddress::fromBinary($binaryData, $offsetOfSequence); - $parsedObject->addIP($ip); - } else { - throw new ParserException('Could not parse Subject Alternative Name: Only DNSName and IP SANs are currently supported', $offsetIndex); - } - } - - $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) - return $parsedObject; - } -} diff --git a/lam/lib/3rdParty/composer/firebase/php-jwt/CHANGELOG.md b/lam/lib/3rdParty/composer/firebase/php-jwt/CHANGELOG.md index 5feeb5a67..7b5f6ce40 100644 --- a/lam/lib/3rdParty/composer/firebase/php-jwt/CHANGELOG.md +++ b/lam/lib/3rdParty/composer/firebase/php-jwt/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09) + + +### Bug Fixes + +* update error text for consistency ([#528](https://github.com/firebase/php-jwt/issues/528)) ([c11113a](https://github.com/firebase/php-jwt/commit/c11113afa13265e016a669e75494b9203b8a7775)) + +## [6.11.0](https://github.com/firebase/php-jwt/compare/v6.10.2...v6.11.0) (2025-01-23) + + +### Features + +* support octet typed JWK ([#587](https://github.com/firebase/php-jwt/issues/587)) ([7cb8a26](https://github.com/firebase/php-jwt/commit/7cb8a265fa81edf2fa6ef8098f5bc5ae573c33ad)) + + +### Bug Fixes + +* refactor constructor Key to use PHP 8.0 syntax ([#577](https://github.com/firebase/php-jwt/issues/577)) ([29fa2ce](https://github.com/firebase/php-jwt/commit/29fa2ce9e0582cd397711eec1e80c05ce20fabca)) + ## [6.10.2](https://github.com/firebase/php-jwt/compare/v6.10.1...v6.10.2) (2024-11-24) diff --git a/lam/lib/3rdParty/composer/firebase/php-jwt/README.md b/lam/lib/3rdParty/composer/firebase/php-jwt/README.md index 4fd140745..e45ccb808 100644 --- a/lam/lib/3rdParty/composer/firebase/php-jwt/README.md +++ b/lam/lib/3rdParty/composer/firebase/php-jwt/README.md @@ -48,7 +48,8 @@ $decoded = JWT::decode($jwt, new Key($key, 'HS256')); print_r($decoded); // Pass a stdClass in as the third parameter to get the decoded header values -$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers = new stdClass()); +$headers = new stdClass(); +$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers); print_r($headers); /* @@ -290,7 +291,7 @@ $jwks = ['keys' => []]; // JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key // objects. Pass this as the second parameter to JWT::decode. -JWT::decode($payload, JWK::parseKeySet($jwks)); +JWT::decode($jwt, JWK::parseKeySet($jwks)); ``` Using Cached Key Sets @@ -349,7 +350,7 @@ use InvalidArgumentException; use UnexpectedValueException; try { - $decoded = JWT::decode($payload, $keys); + $decoded = JWT::decode($jwt, $keys); } catch (InvalidArgumentException $e) { // provided key/key-array is empty or malformed. } catch (DomainException $e) { @@ -379,7 +380,7 @@ like this: use Firebase\JWT\JWT; use UnexpectedValueException; try { - $decoded = JWT::decode($payload, $keys); + $decoded = JWT::decode($jwt, $keys); } catch (LogicException $e) { // errors having to do with environmental setup or malformed JWT Keys } catch (UnexpectedValueException $e) { @@ -394,7 +395,7 @@ instead, you can do the following: ```php // return type is stdClass -$decoded = JWT::decode($payload, $keys); +$decoded = JWT::decode($jwt, $keys); // cast to array $decoded = json_decode(json_encode($decoded), true); diff --git a/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWK.php b/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWK.php index 6efc2fe38..405dcc49b 100644 --- a/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWK.php +++ b/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWK.php @@ -172,6 +172,12 @@ class JWK // This library works internally with EdDSA keys (Ed25519) encoded in standard base64. $publicKey = JWT::convertBase64urlToBase64($jwk['x']); return new Key($publicKey, $jwk['alg']); + case 'oct': + if (!isset($jwk['k'])) { + throw new UnexpectedValueException('k not set'); + } + + return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']); default: break; } diff --git a/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWT.php b/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWT.php index dd9292a43..833a415e6 100644 --- a/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWT.php +++ b/lam/lib/3rdParty/composer/firebase/php-jwt/src/JWT.php @@ -154,7 +154,7 @@ class JWT // token can actually be used. If it's not yet that time, abort. if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) { $ex = new BeforeValidException( - 'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) $payload->nbf) + 'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) floor($payload->nbf)) ); $ex->setPayload($payload); throw $ex; @@ -165,7 +165,7 @@ class JWT // correctly used the nbf claim). if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) { $ex = new BeforeValidException( - 'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) $payload->iat) + 'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) floor($payload->iat)) ); $ex->setPayload($payload); throw $ex; diff --git a/lam/lib/3rdParty/composer/firebase/php-jwt/src/Key.php b/lam/lib/3rdParty/composer/firebase/php-jwt/src/Key.php index 00cf7f2ed..b34eae258 100644 --- a/lam/lib/3rdParty/composer/firebase/php-jwt/src/Key.php +++ b/lam/lib/3rdParty/composer/firebase/php-jwt/src/Key.php @@ -9,18 +9,13 @@ use TypeError; class Key { - /** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */ - private $keyMaterial; - /** @var string */ - private $algorithm; - /** * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial * @param string $algorithm */ public function __construct( - $keyMaterial, - string $algorithm + private $keyMaterial, + private string $algorithm ) { if ( !\is_string($keyMaterial) @@ -38,10 +33,6 @@ class Key if (empty($algorithm)) { throw new InvalidArgumentException('Algorithm must not be empty'); } - - // TODO: Remove in PHP 8.0 in favor of class constructor property promotion - $this->keyMaterial = $keyMaterial; - $this->algorithm = $algorithm; } /** diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/CHANGELOG.md b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/CHANGELOG.md new file mode 100644 index 000000000..5fe721e03 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/CHANGELOG.md @@ -0,0 +1,1683 @@ +# Change Log + +Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version. + +## 7.10.0 - 2025-08-23 + +### Added + +- Support for PHP 8.5 + +### Changed + +- Adjusted `guzzlehttp/promises` version constraint to `^2.3` +- Adjusted `guzzlehttp/psr7` version constraint to `^2.8` + + +## 7.9.3 - 2025-03-27 + +### Changed + +- Remove explicit content-length header for GET requests +- Improve compatibility with bad servers for boolean cookie values + + +## 7.9.2 - 2024-07-24 + +### Fixed + +- Adjusted handler selection to use cURL if its version is 7.21.2 or higher, rather than 7.34.0 + + +## 7.9.1 - 2024-07-19 + +### Fixed + +- Fix TLS 1.3 check for HTTP/2 requests + + +## 7.9.0 - 2024-07-18 + +### Changed + +- Improve protocol version checks to provide feedback around unsupported protocols +- Only select the cURL handler by default if 7.34.0 or higher is linked +- Improved `CurlMultiHandler` to avoid busy wait if possible +- Dropped support for EOL `guzzlehttp/psr7` v1 +- Improved URI user info redaction in errors + +## 7.8.2 - 2024-07-18 + +### Added + +- Support for PHP 8.4 + + +## 7.8.1 - 2023-12-03 + +### Changed + +- Updated links in docs to their canonical versions +- Replaced `call_user_func*` with native calls + + +## 7.8.0 - 2023-08-27 + +### Added + +- Support for PHP 8.3 +- Added automatic closing of handles on `CurlFactory` object destruction + + +## 7.7.1 - 2023-08-27 + +### Changed + +- Remove the need for `AllowDynamicProperties` in `CurlMultiHandler` + + +## 7.7.0 - 2023-05-21 + +### Added + +- Support `guzzlehttp/promises` v2 + + +## 7.6.1 - 2023-05-15 + +### Fixed + +- Fix `SetCookie::fromString` MaxAge deprecation warning and skip invalid MaxAge values + + +## 7.6.0 - 2023-05-14 + +### Added + +- Support for setting the minimum TLS version in a unified way +- Apply on request the version set in options parameters + + +## 7.5.2 - 2023-05-14 + +### Fixed + +- Fixed set cookie constructor validation +- Fixed handling of files with `'0'` body + +### Changed + +- Corrected docs and default connect timeout value to 300 seconds + + +## 7.5.1 - 2023-04-17 + +### Fixed + +- Fixed `NO_PROXY` settings so that setting the `proxy` option to `no` overrides the env variable + +### Changed + +- Adjusted `guzzlehttp/psr7` version constraint to `^1.9.1 || ^2.4.5` + + +## 7.5.0 - 2022-08-28 + +### Added + +- Support PHP 8.2 +- Add request to delay closure params + + +## 7.4.5 - 2022-06-20 + +### Fixed + +* Fix change in port should be considered a change in origin +* Fix `CURLOPT_HTTPAUTH` option not cleared on change of origin + + +## 7.4.4 - 2022-06-09 + +### Fixed + +* Fix failure to strip Authorization header on HTTP downgrade +* Fix failure to strip the Cookie header on change in host or HTTP downgrade + + +## 7.4.3 - 2022-05-25 + +### Fixed + +* Fix cross-domain cookie leakage + + +## 7.4.2 - 2022-03-20 + +### Fixed + +- Remove curl auth on cross-domain redirects to align with the Authorization HTTP header +- Reject non-HTTP schemes in StreamHandler +- Set a default ssl.peer_name context in StreamHandler to allow `force_ip_resolve` + + +## 7.4.1 - 2021-12-06 + +### Changed + +- Replaced implicit URI to string coercion [#2946](https://github.com/guzzle/guzzle/pull/2946) +- Allow `symfony/deprecation-contracts` version 3 [#2961](https://github.com/guzzle/guzzle/pull/2961) + +### Fixed + +- Only close curl handle if it's done [#2950](https://github.com/guzzle/guzzle/pull/2950) + + +## 7.4.0 - 2021-10-18 + +### Added + +- Support PHP 8.1 [#2929](https://github.com/guzzle/guzzle/pull/2929), [#2939](https://github.com/guzzle/guzzle/pull/2939) +- Support `psr/log` version 2 and 3 [#2943](https://github.com/guzzle/guzzle/pull/2943) + +### Fixed + +- Make sure we always call `restore_error_handler()` [#2915](https://github.com/guzzle/guzzle/pull/2915) +- Fix progress parameter type compatibility between the cURL and stream handlers [#2936](https://github.com/guzzle/guzzle/pull/2936) +- Throw `InvalidArgumentException` when an incorrect `headers` array is provided [#2916](https://github.com/guzzle/guzzle/pull/2916), [#2942](https://github.com/guzzle/guzzle/pull/2942) + +### Changed + +- Be more strict with types [#2914](https://github.com/guzzle/guzzle/pull/2914), [#2917](https://github.com/guzzle/guzzle/pull/2917), [#2919](https://github.com/guzzle/guzzle/pull/2919), [#2945](https://github.com/guzzle/guzzle/pull/2945) + + +## 7.3.0 - 2021-03-23 + +### Added + +- Support for DER and P12 certificates [#2413](https://github.com/guzzle/guzzle/pull/2413) +- Support the cURL (http://) scheme for StreamHandler proxies [#2850](https://github.com/guzzle/guzzle/pull/2850) +- Support for `guzzlehttp/psr7:^2.0` [#2878](https://github.com/guzzle/guzzle/pull/2878) + +### Fixed + +- Handle exceptions on invalid header consistently between PHP versions and handlers [#2872](https://github.com/guzzle/guzzle/pull/2872) + + +## 7.2.0 - 2020-10-10 + +### Added + +- Support for PHP 8 [#2712](https://github.com/guzzle/guzzle/pull/2712), [#2715](https://github.com/guzzle/guzzle/pull/2715), [#2789](https://github.com/guzzle/guzzle/pull/2789) +- Support passing a body summarizer to the http errors middleware [#2795](https://github.com/guzzle/guzzle/pull/2795) + +### Fixed + +- Handle exceptions during response creation [#2591](https://github.com/guzzle/guzzle/pull/2591) +- Fix CURLOPT_ENCODING not to be overwritten [#2595](https://github.com/guzzle/guzzle/pull/2595) +- Make sure the Request always has a body object [#2804](https://github.com/guzzle/guzzle/pull/2804) + +### Changed + +- The `TooManyRedirectsException` has a response [#2660](https://github.com/guzzle/guzzle/pull/2660) +- Avoid "functions" from dependencies [#2712](https://github.com/guzzle/guzzle/pull/2712) + +### Deprecated + +- Using environment variable GUZZLE_CURL_SELECT_TIMEOUT [#2786](https://github.com/guzzle/guzzle/pull/2786) + + +## 7.1.1 - 2020-09-30 + +### Fixed + +- Incorrect EOF detection for response body streams on Windows. + +### Changed + +- We dont connect curl `sink` on HEAD requests. +- Removed some PHP 5 workarounds + + +## 7.1.0 - 2020-09-22 + +### Added + +- `GuzzleHttp\MessageFormatterInterface` + +### Fixed + +- Fixed issue that caused cookies with no value not to be stored. +- On redirects, we allow all safe methods like GET, HEAD and OPTIONS. +- Fixed logging on empty responses. +- Make sure MessageFormatter::format returns string + +### Deprecated + +- All functions in `GuzzleHttp` has been deprecated. Use static methods on `Utils` instead. +- `ClientInterface::getConfig()` +- `Client::getConfig()` +- `Client::__call()` +- `Utils::defaultCaBundle()` +- `CurlFactory::LOW_CURL_VERSION_NUMBER` + + +## 7.0.1 - 2020-06-27 + +* Fix multiply defined functions fatal error [#2699](https://github.com/guzzle/guzzle/pull/2699) + + +## 7.0.0 - 2020-06-27 + +No changes since 7.0.0-rc1. + + +## 7.0.0-rc1 - 2020-06-15 + +### Changed + +* Use error level for logging errors in Middleware [#2629](https://github.com/guzzle/guzzle/pull/2629) +* Disabled IDN support by default and require ext-intl to use it [#2675](https://github.com/guzzle/guzzle/pull/2675) + + +## 7.0.0-beta2 - 2020-05-25 + +### Added + +* Using `Utils` class instead of functions in the `GuzzleHttp` namespace. [#2546](https://github.com/guzzle/guzzle/pull/2546) +* `ClientInterface::MAJOR_VERSION` [#2583](https://github.com/guzzle/guzzle/pull/2583) + +### Changed + +* Avoid the `getenv` function when unsafe [#2531](https://github.com/guzzle/guzzle/pull/2531) +* Added real client methods [#2529](https://github.com/guzzle/guzzle/pull/2529) +* Avoid functions due to global install conflicts [#2546](https://github.com/guzzle/guzzle/pull/2546) +* Use Symfony intl-idn polyfill [#2550](https://github.com/guzzle/guzzle/pull/2550) +* Adding methods for HTTP verbs like `Client::get()`, `Client::head()`, `Client::patch()` etc [#2529](https://github.com/guzzle/guzzle/pull/2529) +* `ConnectException` extends `TransferException` [#2541](https://github.com/guzzle/guzzle/pull/2541) +* Updated the default User Agent to "GuzzleHttp/7" [#2654](https://github.com/guzzle/guzzle/pull/2654) + +### Fixed + +* Various intl icu issues [#2626](https://github.com/guzzle/guzzle/pull/2626) + +### Removed + +* Pool option `pool_size` [#2528](https://github.com/guzzle/guzzle/pull/2528) + + +## 7.0.0-beta1 - 2019-12-30 + +The diff might look very big but 95% of Guzzle users will be able to upgrade without modification. +Please see [the upgrade document](UPGRADING.md) that describes all BC breaking changes. + +### Added + +* Implement PSR-18 and dropped PHP 5 support [#2421](https://github.com/guzzle/guzzle/pull/2421) [#2474](https://github.com/guzzle/guzzle/pull/2474) +* PHP 7 types [#2442](https://github.com/guzzle/guzzle/pull/2442) [#2449](https://github.com/guzzle/guzzle/pull/2449) [#2466](https://github.com/guzzle/guzzle/pull/2466) [#2497](https://github.com/guzzle/guzzle/pull/2497) [#2499](https://github.com/guzzle/guzzle/pull/2499) +* IDN support for redirects [2424](https://github.com/guzzle/guzzle/pull/2424) + +### Changed + +* Dont allow passing null as third argument to `BadResponseException::__construct()` [#2427](https://github.com/guzzle/guzzle/pull/2427) +* Use SAPI constant instead of method call [#2450](https://github.com/guzzle/guzzle/pull/2450) +* Use native function invocation [#2444](https://github.com/guzzle/guzzle/pull/2444) +* Better defaults for PHP installations with old ICU lib [2454](https://github.com/guzzle/guzzle/pull/2454) +* Added visibility to all constants [#2462](https://github.com/guzzle/guzzle/pull/2462) +* Dont allow passing `null` as URI to `Client::request()` and `Client::requestAsync()` [#2461](https://github.com/guzzle/guzzle/pull/2461) +* Widen the exception argument to throwable [#2495](https://github.com/guzzle/guzzle/pull/2495) + +### Fixed + +* Logging when Promise rejected with a string [#2311](https://github.com/guzzle/guzzle/pull/2311) + +### Removed + +* Class `SeekException` [#2162](https://github.com/guzzle/guzzle/pull/2162) +* `RequestException::getResponseBodySummary()` [#2425](https://github.com/guzzle/guzzle/pull/2425) +* `CookieJar::getCookieValue()` [#2433](https://github.com/guzzle/guzzle/pull/2433) +* `uri_template()` and `UriTemplate` [#2440](https://github.com/guzzle/guzzle/pull/2440) +* Request options `save_to` and `exceptions` [#2464](https://github.com/guzzle/guzzle/pull/2464) + + +## 6.5.2 - 2019-12-23 + +* idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489) + + +## 6.5.1 - 2019-12-21 + +* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454) +* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424) + + +## 6.5.0 - 2019-12-07 + +* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143) +* Improvement: Added support to pass arbitrary options to `curl_multi_init`. [#2287](https://github.com/guzzle/guzzle/pull/2287) +* Fix: Gracefully handle passing `null` to the `header` option. [#2132](https://github.com/guzzle/guzzle/pull/2132) +* Fix: `RetryMiddleware` did not do exponential delay between retires due unit mismatch. [#2132](https://github.com/guzzle/guzzle/pull/2132) +* Fix: Prevent undefined offset when using array for ssl_key options. [#2348](https://github.com/guzzle/guzzle/pull/2348) +* Deprecated `ClientInterface::VERSION` + + +## 6.4.1 - 2019-10-23 + +* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that +* Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar` + + +## 6.4.0 - 2019-10-23 + +* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108) +* Fix: Test if response is readable before returning a summary in `RequestException::getResponseBodySummary()` [#2081](https://github.com/guzzle/guzzle/pull/2081) +* Fix: Add support for GUZZLE_CURL_SELECT_TIMEOUT environment variable [#2161](https://github.com/guzzle/guzzle/pull/2161) +* Improvement: Added `GuzzleHttp\Exception\InvalidArgumentException` [#2163](https://github.com/guzzle/guzzle/pull/2163) +* Improvement: Added `GuzzleHttp\_current_time()` to use `hrtime()` if that function exists. [#2242](https://github.com/guzzle/guzzle/pull/2242) +* Improvement: Added curl's `appconnect_time` in `TransferStats` [#2284](https://github.com/guzzle/guzzle/pull/2284) +* Improvement: Make GuzzleException extend Throwable wherever it's available [#2273](https://github.com/guzzle/guzzle/pull/2273) +* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335) +* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362) + + +## 6.3.3 - 2018-04-22 + +* Fix: Default headers when decode_content is specified + + +## 6.3.2 - 2018-03-26 + +* Fix: Release process + + +## 6.3.1 - 2018-03-26 + +* Bug fix: Parsing 0 epoch expiry times in cookies [#2014](https://github.com/guzzle/guzzle/pull/2014) +* Improvement: Better ConnectException detection [#2012](https://github.com/guzzle/guzzle/pull/2012) +* Bug fix: Malformed domain that contains a "/" [#1999](https://github.com/guzzle/guzzle/pull/1999) +* Bug fix: Undefined offset when a cookie has no first key-value pair [#1998](https://github.com/guzzle/guzzle/pull/1998) +* Improvement: Support PHPUnit 6 [#1953](https://github.com/guzzle/guzzle/pull/1953) +* Bug fix: Support empty headers [#1915](https://github.com/guzzle/guzzle/pull/1915) +* Bug fix: Ignore case during header modifications [#1916](https://github.com/guzzle/guzzle/pull/1916) + ++ Minor code cleanups, documentation fixes and clarifications. + + +## 6.3.0 - 2017-06-22 + +* Feature: force IP resolution (ipv4 or ipv6) [#1608](https://github.com/guzzle/guzzle/pull/1608), [#1659](https://github.com/guzzle/guzzle/pull/1659) +* Improvement: Don't include summary in exception message when body is empty [#1621](https://github.com/guzzle/guzzle/pull/1621) +* Improvement: Handle `on_headers` option in MockHandler [#1580](https://github.com/guzzle/guzzle/pull/1580) +* Improvement: Added SUSE Linux CA path [#1609](https://github.com/guzzle/guzzle/issues/1609) +* Improvement: Use class reference for getting the name of the class instead of using hardcoded strings [#1641](https://github.com/guzzle/guzzle/pull/1641) +* Feature: Added `read_timeout` option [#1611](https://github.com/guzzle/guzzle/pull/1611) +* Bug fix: PHP 7.x fixes [#1685](https://github.com/guzzle/guzzle/pull/1685), [#1686](https://github.com/guzzle/guzzle/pull/1686), [#1811](https://github.com/guzzle/guzzle/pull/1811) +* Deprecation: BadResponseException instantiation without a response [#1642](https://github.com/guzzle/guzzle/pull/1642) +* Feature: Added NTLM auth [#1569](https://github.com/guzzle/guzzle/pull/1569) +* Feature: Track redirect HTTP status codes [#1711](https://github.com/guzzle/guzzle/pull/1711) +* Improvement: Check handler type during construction [#1745](https://github.com/guzzle/guzzle/pull/1745) +* Improvement: Always include the Content-Length if there's a body [#1721](https://github.com/guzzle/guzzle/pull/1721) +* Feature: Added convenience method to access a cookie by name [#1318](https://github.com/guzzle/guzzle/pull/1318) +* Bug fix: Fill `CURLOPT_CAPATH` and `CURLOPT_CAINFO` properly [#1684](https://github.com/guzzle/guzzle/pull/1684) +* Improvement: Use `\GuzzleHttp\Promise\rejection_for` function instead of object init [#1827](https://github.com/guzzle/guzzle/pull/1827) + ++ Minor code cleanups, documentation fixes and clarifications. + + +## 6.2.3 - 2017-02-28 + +* Fix deprecations with guzzle/psr7 version 1.4 + + +## 6.2.2 - 2016-10-08 + +* Allow to pass nullable Response to delay callable +* Only add scheme when host is present +* Fix drain case where content-length is the literal string zero +* Obfuscate in-URL credentials in exceptions + + +## 6.2.1 - 2016-07-18 + +* Address HTTP_PROXY security vulnerability, CVE-2016-5385: + https://httpoxy.org/ +* Fixing timeout bug with StreamHandler: + https://github.com/guzzle/guzzle/pull/1488 +* Only read up to `Content-Length` in PHP StreamHandler to avoid timeouts when + a server does not honor `Connection: close`. +* Ignore URI fragment when sending requests. + + +## 6.2.0 - 2016-03-21 + +* Feature: added `GuzzleHttp\json_encode` and `GuzzleHttp\json_decode`. + https://github.com/guzzle/guzzle/pull/1389 +* Bug fix: Fix sleep calculation when waiting for delayed requests. + https://github.com/guzzle/guzzle/pull/1324 +* Feature: More flexible history containers. + https://github.com/guzzle/guzzle/pull/1373 +* Bug fix: defer sink stream opening in StreamHandler. + https://github.com/guzzle/guzzle/pull/1377 +* Bug fix: do not attempt to escape cookie values. + https://github.com/guzzle/guzzle/pull/1406 +* Feature: report original content encoding and length on decoded responses. + https://github.com/guzzle/guzzle/pull/1409 +* Bug fix: rewind seekable request bodies before dispatching to cURL. + https://github.com/guzzle/guzzle/pull/1422 +* Bug fix: provide an empty string to `http_build_query` for HHVM workaround. + https://github.com/guzzle/guzzle/pull/1367 + + +## 6.1.1 - 2015-11-22 + +* Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler + https://github.com/guzzle/guzzle/commit/911bcbc8b434adce64e223a6d1d14e9a8f63e4e4 +* Feature: HandlerStack is now more generic. + https://github.com/guzzle/guzzle/commit/f2102941331cda544745eedd97fc8fd46e1ee33e +* Bug fix: setting verify to false in the StreamHandler now disables peer + verification. https://github.com/guzzle/guzzle/issues/1256 +* Feature: Middleware now uses an exception factory, including more error + context. https://github.com/guzzle/guzzle/pull/1282 +* Feature: better support for disabled functions. + https://github.com/guzzle/guzzle/pull/1287 +* Bug fix: fixed regression where MockHandler was not using `sink`. + https://github.com/guzzle/guzzle/pull/1292 + + +## 6.1.0 - 2015-09-08 + +* Feature: Added the `on_stats` request option to provide access to transfer + statistics for requests. https://github.com/guzzle/guzzle/pull/1202 +* Feature: Added the ability to persist session cookies in CookieJars. + https://github.com/guzzle/guzzle/pull/1195 +* Feature: Some compatibility updates for Google APP Engine + https://github.com/guzzle/guzzle/pull/1216 +* Feature: Added support for NO_PROXY to prevent the use of a proxy based on + a simple set of rules. https://github.com/guzzle/guzzle/pull/1197 +* Feature: Cookies can now contain square brackets. + https://github.com/guzzle/guzzle/pull/1237 +* Bug fix: Now correctly parsing `=` inside of quotes in Cookies. + https://github.com/guzzle/guzzle/pull/1232 +* Bug fix: Cusotm cURL options now correctly override curl options of the + same name. https://github.com/guzzle/guzzle/pull/1221 +* Bug fix: Content-Type header is now added when using an explicitly provided + multipart body. https://github.com/guzzle/guzzle/pull/1218 +* Bug fix: Now ignoring Set-Cookie headers that have no name. +* Bug fix: Reason phrase is no longer cast to an int in some cases in the + cURL handler. https://github.com/guzzle/guzzle/pull/1187 +* Bug fix: Remove the Authorization header when redirecting if the Host + header changes. https://github.com/guzzle/guzzle/pull/1207 +* Bug fix: Cookie path matching fixes + https://github.com/guzzle/guzzle/issues/1129 +* Bug fix: Fixing the cURL `body_as_string` setting + https://github.com/guzzle/guzzle/pull/1201 +* Bug fix: quotes are no longer stripped when parsing cookies. + https://github.com/guzzle/guzzle/issues/1172 +* Bug fix: `form_params` and `query` now always uses the `&` separator. + https://github.com/guzzle/guzzle/pull/1163 +* Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set. + https://github.com/guzzle/guzzle/pull/1189 + + +## 6.0.2 - 2015-07-04 + +* Fixed a memory leak in the curl handlers in which references to callbacks + were not being removed by `curl_reset`. +* Cookies are now extracted properly before redirects. +* Cookies now allow more character ranges. +* Decoded Content-Encoding responses are now modified to correctly reflect + their state if the encoding was automatically removed by a handler. This + means that the `Content-Encoding` header may be removed an the + `Content-Length` modified to reflect the message size after removing the + encoding. +* Added a more explicit error message when trying to use `form_params` and + `multipart` in the same request. +* Several fixes for HHVM support. +* Functions are now conditionally required using an additional level of + indirection to help with global Composer installations. + + +## 6.0.1 - 2015-05-27 + +* Fixed a bug with serializing the `query` request option where the `&` + separator was missing. +* Added a better error message for when `body` is provided as an array. Please + use `form_params` or `multipart` instead. +* Various doc fixes. + + +## 6.0.0 - 2015-05-26 + +* See the UPGRADING.md document for more information. +* Added `multipart` and `form_params` request options. +* Added `synchronous` request option. +* Added the `on_headers` request option. +* Fixed `expect` handling. +* No longer adding default middlewares in the client ctor. These need to be + present on the provided handler in order to work. +* Requests are no longer initiated when sending async requests with the + CurlMultiHandler. This prevents unexpected recursion from requests completing + while ticking the cURL loop. +* Removed the semantics of setting `default` to `true`. This is no longer + required now that the cURL loop is not ticked for async requests. +* Added request and response logging middleware. +* No longer allowing self signed certificates when using the StreamHandler. +* Ensuring that `sink` is valid if saving to a file. +* Request exceptions now include a "handler context" which provides handler + specific contextual information. +* Added `GuzzleHttp\RequestOptions` to allow request options to be applied + using constants. +* `$maxHandles` has been removed from CurlMultiHandler. +* `MultipartPostBody` is now part of the `guzzlehttp/psr7` package. + + +## 5.3.0 - 2015-05-19 + +* Mock now supports `save_to` +* Marked `AbstractRequestEvent::getTransaction()` as public. +* Fixed a bug in which multiple headers using different casing would overwrite + previous headers in the associative array. +* Added `Utils::getDefaultHandler()` +* Marked `GuzzleHttp\Client::getDefaultUserAgent` as deprecated. +* URL scheme is now always lowercased. + + +## 6.0.0-beta.1 + +* Requires PHP >= 5.5 +* Updated to use PSR-7 + * Requires immutable messages, which basically means an event based system + owned by a request instance is no longer possible. + * Utilizing the [Guzzle PSR-7 package](https://github.com/guzzle/psr7). + * Removed the dependency on `guzzlehttp/streams`. These stream abstractions + are available in the `guzzlehttp/psr7` package under the `GuzzleHttp\Psr7` + namespace. +* Added middleware and handler system + * Replaced the Guzzle event and subscriber system with a middleware system. + * No longer depends on RingPHP, but rather places the HTTP handlers directly + in Guzzle, operating on PSR-7 messages. + * Retry logic is now encapsulated in `GuzzleHttp\Middleware::retry`, which + means the `guzzlehttp/retry-subscriber` is now obsolete. + * Mocking responses is now handled using `GuzzleHttp\Handler\MockHandler`. +* Asynchronous responses + * No longer supports the `future` request option to send an async request. + Instead, use one of the `*Async` methods of a client (e.g., `requestAsync`, + `getAsync`, etc.). + * Utilizing `GuzzleHttp\Promise` instead of React's promise library to avoid + recursion required by chaining and forwarding react promises. See + https://github.com/guzzle/promises + * Added `requestAsync` and `sendAsync` to send request asynchronously. + * Added magic methods for `getAsync()`, `postAsync()`, etc. to send requests + asynchronously. +* Request options + * POST and form updates + * Added the `form_fields` and `form_files` request options. + * Removed the `GuzzleHttp\Post` namespace. + * The `body` request option no longer accepts an array for POST requests. + * The `exceptions` request option has been deprecated in favor of the + `http_errors` request options. + * The `save_to` request option has been deprecated in favor of `sink` request + option. +* Clients no longer accept an array of URI template string and variables for + URI variables. You will need to expand URI templates before passing them + into a client constructor or request method. +* Client methods `get()`, `post()`, `put()`, `patch()`, `options()`, etc. are + now magic methods that will send synchronous requests. +* Replaced `Utils.php` with plain functions in `functions.php`. +* Removed `GuzzleHttp\Collection`. +* Removed `GuzzleHttp\BatchResults`. Batched pool results are now returned as + an array. +* Removed `GuzzleHttp\Query`. Query string handling is now handled using an + associative array passed into the `query` request option. The query string + is serialized using PHP's `http_build_query`. If you need more control, you + can pass the query string in as a string. +* `GuzzleHttp\QueryParser` has been replaced with the + `GuzzleHttp\Psr7\parse_query`. + + +## 5.2.0 - 2015-01-27 + +* Added `AppliesHeadersInterface` to make applying headers to a request based + on the body more generic and not specific to `PostBodyInterface`. +* Reduced the number of stack frames needed to send requests. +* Nested futures are now resolved in the client rather than the RequestFsm +* Finishing state transitions is now handled in the RequestFsm rather than the + RingBridge. +* Added a guard in the Pool class to not use recursion for request retries. + + +## 5.1.0 - 2014-12-19 + +* Pool class no longer uses recursion when a request is intercepted. +* The size of a Pool can now be dynamically adjusted using a callback. + See https://github.com/guzzle/guzzle/pull/943. +* Setting a request option to `null` when creating a request with a client will + ensure that the option is not set. This allows you to overwrite default + request options on a per-request basis. + See https://github.com/guzzle/guzzle/pull/937. +* Added the ability to limit which protocols are allowed for redirects by + specifying a `protocols` array in the `allow_redirects` request option. +* Nested futures due to retries are now resolved when waiting for synchronous + responses. See https://github.com/guzzle/guzzle/pull/947. +* `"0"` is now an allowed URI path. See + https://github.com/guzzle/guzzle/pull/935. +* `Query` no longer typehints on the `$query` argument in the constructor, + allowing for strings and arrays. +* Exceptions thrown in the `end` event are now correctly wrapped with Guzzle + specific exceptions if necessary. + + +## 5.0.3 - 2014-11-03 + +This change updates query strings so that they are treated as un-encoded values +by default where the value represents an un-encoded value to send over the +wire. A Query object then encodes the value before sending over the wire. This +means that even value query string values (e.g., ":") are url encoded. This +makes the Query class match PHP's http_build_query function. However, if you +want to send requests over the wire using valid query string characters that do +not need to be encoded, then you can provide a string to Url::setQuery() and +pass true as the second argument to specify that the query string is a raw +string that should not be parsed or encoded (unless a call to getQuery() is +subsequently made, forcing the query-string to be converted into a Query +object). + + +## 5.0.2 - 2014-10-30 + +* Added a trailing `\r\n` to multipart/form-data payloads. See + https://github.com/guzzle/guzzle/pull/871 +* Added a `GuzzleHttp\Pool::send()` convenience method to match the docs. +* Status codes are now returned as integers. See + https://github.com/guzzle/guzzle/issues/881 +* No longer overwriting an existing `application/x-www-form-urlencoded` header + when sending POST requests, allowing for customized headers. See + https://github.com/guzzle/guzzle/issues/877 +* Improved path URL serialization. + + * No longer double percent-encoding characters in the path or query string if + they are already encoded. + * Now properly encoding the supplied path to a URL object, instead of only + encoding ' ' and '?'. + * Note: This has been changed in 5.0.3 to now encode query string values by + default unless the `rawString` argument is provided when setting the query + string on a URL: Now allowing many more characters to be present in the + query string without being percent encoded. See + https://datatracker.ietf.org/doc/html/rfc3986#appendix-A + + +## 5.0.1 - 2014-10-16 + +Bugfix release. + +* Fixed an issue where connection errors still returned response object in + error and end events event though the response is unusable. This has been + corrected so that a response is not returned in the `getResponse` method of + these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867 +* Fixed an issue where transfer statistics were not being populated in the + RingBridge. https://github.com/guzzle/guzzle/issues/866 + + +## 5.0.0 - 2014-10-12 + +Adding support for non-blocking responses and some minor API cleanup. + +### New Features + +* Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`. +* Added a public API for creating a default HTTP adapter. +* Updated the redirect plugin to be non-blocking so that redirects are sent + concurrently. Other plugins like this can now be updated to be non-blocking. +* Added a "progress" event so that you can get upload and download progress + events. +* Added `GuzzleHttp\Pool` which implements FutureInterface and transfers + requests concurrently using a capped pool size as efficiently as possible. +* Added `hasListeners()` to EmitterInterface. +* Removed `GuzzleHttp\ClientInterface::sendAll` and marked + `GuzzleHttp\Client::sendAll` as deprecated (it's still there, just not the + recommended way). + +### Breaking changes + +The breaking changes in this release are relatively minor. The biggest thing to +look out for is that request and response objects no longer implement fluent +interfaces. + +* Removed the fluent interfaces (i.e., `return $this`) from requests, + responses, `GuzzleHttp\Collection`, `GuzzleHttp\Url`, + `GuzzleHttp\Query`, `GuzzleHttp\Post\PostBody`, and + `GuzzleHttp\Cookie\SetCookie`. This blog post provides a good outline of + why I did this: https://ocramius.github.io/blog/fluent-interfaces-are-evil/. + This also makes the Guzzle message interfaces compatible with the current + PSR-7 message proposal. +* Removed "functions.php", so that Guzzle is truly PSR-4 compliant. Except + for the HTTP request functions from function.php, these functions are now + implemented in `GuzzleHttp\Utils` using camelCase. `GuzzleHttp\json_decode` + moved to `GuzzleHttp\Utils::jsonDecode`. `GuzzleHttp\get_path` moved to + `GuzzleHttp\Utils::getPath`. `GuzzleHttp\set_path` moved to + `GuzzleHttp\Utils::setPath`. `GuzzleHttp\batch` should now be + `GuzzleHttp\Pool::batch`, which returns an `objectStorage`. Using functions.php + caused problems for many users: they aren't PSR-4 compliant, require an + explicit include, and needed an if-guard to ensure that the functions are not + declared multiple times. +* Rewrote adapter layer. + * Removing all classes from `GuzzleHttp\Adapter`, these are now + implemented as callables that are stored in `GuzzleHttp\Ring\Client`. + * Removed the concept of "parallel adapters". Sending requests serially or + concurrently is now handled using a single adapter. + * Moved `GuzzleHttp\Adapter\Transaction` to `GuzzleHttp\Transaction`. The + Transaction object now exposes the request, response, and client as public + properties. The getters and setters have been removed. +* Removed the "headers" event. This event was only useful for changing the + body a response once the headers of the response were known. You can implement + a similar behavior in a number of ways. One example might be to use a + FnStream that has access to the transaction being sent. For example, when the + first byte is written, you could check if the response headers match your + expectations, and if so, change the actual stream body that is being + written to. +* Removed the `asArray` parameter from + `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header + value as an array, then use the newly added `getHeaderAsArray()` method of + `MessageInterface`. This change makes the Guzzle interfaces compatible with + the PSR-7 interfaces. +* `GuzzleHttp\Message\MessageFactory` no longer allows subclasses to add + custom request options using double-dispatch (this was an implementation + detail). Instead, you should now provide an associative array to the + constructor which is a mapping of the request option name mapping to a + function that applies the option value to a request. +* Removed the concept of "throwImmediately" from exceptions and error events. + This control mechanism was used to stop a transfer of concurrent requests + from completing. This can now be handled by throwing the exception or by + cancelling a pool of requests or each outstanding future request individually. +* Updated to "GuzzleHttp\Streams" 3.0. + * `GuzzleHttp\Stream\StreamInterface::getContents()` no longer accepts a + `maxLen` parameter. This update makes the Guzzle streams project + compatible with the current PSR-7 proposal. + * `GuzzleHttp\Stream\Stream::__construct`, + `GuzzleHttp\Stream\Stream::factory`, and + `GuzzleHttp\Stream\Utils::create` no longer accept a size in the second + argument. They now accept an associative array of options, including the + "size" key and "metadata" key which can be used to provide custom metadata. + + +## 4.2.2 - 2014-09-08 + +* Fixed a memory leak in the CurlAdapter when reusing cURL handles. +* No longer using `request_fulluri` in stream adapter proxies. +* Relative redirects are now based on the last response, not the first response. + +## 4.2.1 - 2014-08-19 + +* Ensuring that the StreamAdapter does not always add a Content-Type header +* Adding automated github releases with a phar and zip + +## 4.2.0 - 2014-08-17 + +* Now merging in default options using a case-insensitive comparison. + Closes https://github.com/guzzle/guzzle/issues/767 +* Added the ability to automatically decode `Content-Encoding` response bodies + using the `decode_content` request option. This is set to `true` by default + to decode the response body if it comes over the wire with a + `Content-Encoding`. Set this value to `false` to disable decoding the + response content, and pass a string to provide a request `Accept-Encoding` + header and turn on automatic response decoding. This feature now allows you + to pass an `Accept-Encoding` header in the headers of a request but still + disable automatic response decoding. + Closes https://github.com/guzzle/guzzle/issues/764 +* Added the ability to throw an exception immediately when transferring + requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760 +* Updating guzzlehttp/streams dependency to ~2.1 +* No longer utilizing the now deprecated namespaced methods from the stream + package. + +## 4.1.8 - 2014-08-14 + +* Fixed an issue in the CurlFactory that caused setting the `stream=false` + request option to throw an exception. + See: https://github.com/guzzle/guzzle/issues/769 +* TransactionIterator now calls rewind on the inner iterator. + See: https://github.com/guzzle/guzzle/pull/765 +* You can now set the `Content-Type` header to `multipart/form-data` + when creating POST requests to force multipart bodies. + See https://github.com/guzzle/guzzle/issues/768 + +## 4.1.7 - 2014-08-07 + +* Fixed an error in the HistoryPlugin that caused the same request and response + to be logged multiple times when an HTTP protocol error occurs. +* Ensuring that cURL does not add a default Content-Type when no Content-Type + has been supplied by the user. This prevents the adapter layer from modifying + the request that is sent over the wire after any listeners may have already + put the request in a desired state (e.g., signed the request). +* Throwing an exception when you attempt to send requests that have the + "stream" set to true in parallel using the MultiAdapter. +* Only calling curl_multi_select when there are active cURL handles. This was + previously changed and caused performance problems on some systems due to PHP + always selecting until the maximum select timeout. +* Fixed a bug where multipart/form-data POST fields were not correctly + aggregated (e.g., values with "&"). + +## 4.1.6 - 2014-08-03 + +* Added helper methods to make it easier to represent messages as strings, + including getting the start line and getting headers as a string. + +## 4.1.5 - 2014-08-02 + +* Automatically retrying cURL "Connection died, retrying a fresh connect" + errors when possible. +* cURL implementation cleanup +* Allowing multiple event subscriber listeners to be registered per event by + passing an array of arrays of listener configuration. + +## 4.1.4 - 2014-07-22 + +* Fixed a bug that caused multi-part POST requests with more than one field to + serialize incorrectly. +* Paths can now be set to "0" +* `ResponseInterface::xml` now accepts a `libxml_options` option and added a + missing default argument that was required when parsing XML response bodies. +* A `save_to` stream is now created lazily, which means that files are not + created on disk unless a request succeeds. + +## 4.1.3 - 2014-07-15 + +* Various fixes to multipart/form-data POST uploads +* Wrapping function.php in an if-statement to ensure Guzzle can be used + globally and in a Composer install +* Fixed an issue with generating and merging in events to an event array +* POST headers are only applied before sending a request to allow you to change + the query aggregator used before uploading +* Added much more robust query string parsing +* Fixed various parsing and normalization issues with URLs +* Fixing an issue where multi-valued headers were not being utilized correctly + in the StreamAdapter + +## 4.1.2 - 2014-06-18 + +* Added support for sending payloads with GET requests + +## 4.1.1 - 2014-06-08 + +* Fixed an issue related to using custom message factory options in subclasses +* Fixed an issue with nested form fields in a multi-part POST +* Fixed an issue with using the `json` request option for POST requests +* Added `ToArrayInterface` to `GuzzleHttp\Cookie\CookieJar` + +## 4.1.0 - 2014-05-27 + +* Added a `json` request option to easily serialize JSON payloads. +* Added a `GuzzleHttp\json_decode()` wrapper to safely parse JSON. +* Added `setPort()` and `getPort()` to `GuzzleHttp\Message\RequestInterface`. +* Added the ability to provide an emitter to a client in the client constructor. +* Added the ability to persist a cookie session using $_SESSION. +* Added a trait that can be used to add event listeners to an iterator. +* Removed request method constants from RequestInterface. +* Fixed warning when invalid request start-lines are received. +* Updated MessageFactory to work with custom request option methods. +* Updated cacert bundle to latest build. + +4.0.2 (2014-04-16) +------------------ + +* Proxy requests using the StreamAdapter now properly use request_fulluri (#632) +* Added the ability to set scalars as POST fields (#628) + +## 4.0.1 - 2014-04-04 + +* The HTTP status code of a response is now set as the exception code of + RequestException objects. +* 303 redirects will now correctly switch from POST to GET requests. +* The default parallel adapter of a client now correctly uses the MultiAdapter. +* HasDataTrait now initializes the internal data array as an empty array so + that the toArray() method always returns an array. + +## 4.0.0 - 2014-03-29 + +* For information on changes and upgrading, see: + https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40 +* Added `GuzzleHttp\batch()` as a convenience function for sending requests in + parallel without needing to write asynchronous code. +* Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`. + You can now pass a callable or an array of associative arrays where each + associative array contains the "fn", "priority", and "once" keys. + +## 4.0.0.rc-2 - 2014-03-25 + +* Removed `getConfig()` and `setConfig()` from clients to avoid confusion + around whether things like base_url, message_factory, etc. should be able to + be retrieved or modified. +* Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface +* functions.php functions were renamed using snake_case to match PHP idioms +* Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and + `GUZZLE_CURL_SELECT_TIMEOUT` environment variables +* Added the ability to specify custom `sendAll()` event priorities +* Added the ability to specify custom stream context options to the stream + adapter. +* Added a functions.php function for `get_path()` and `set_path()` +* CurlAdapter and MultiAdapter now use a callable to generate curl resources +* MockAdapter now properly reads a body and emits a `headers` event +* Updated Url class to check if a scheme and host are set before adding ":" + and "//". This allows empty Url (e.g., "") to be serialized as "". +* Parsing invalid XML no longer emits warnings +* Curl classes now properly throw AdapterExceptions +* Various performance optimizations +* Streams are created with the faster `Stream\create()` function +* Marked deprecation_proxy() as internal +* Test server is now a collection of static methods on a class + +## 4.0.0-rc.1 - 2014-03-15 + +* See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40 + +## 3.8.1 - 2014-01-28 + +* Bug: Always using GET requests when redirecting from a 303 response +* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in + `Guzzle\Http\ClientInterface::setSslVerification()` +* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL +* Bug: The body of a request can now be set to `"0"` +* Sending PHP stream requests no longer forces `HTTP/1.0` +* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of + each sub-exception +* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than + clobbering everything). +* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators) +* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`. + For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`. +* Now properly escaping the regular expression delimiter when matching Cookie domains. +* Network access is now disabled when loading XML documents + +## 3.8.0 - 2013-12-05 + +* Added the ability to define a POST name for a file +* JSON response parsing now properly walks additionalProperties +* cURL error code 18 is now retried automatically in the BackoffPlugin +* Fixed a cURL error when URLs contain fragments +* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were + CurlExceptions +* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e) +* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS` +* Fixed a bug that was encountered when parsing empty header parameters +* UriTemplate now has a `setRegex()` method to match the docs +* The `debug` request parameter now checks if it is truthy rather than if it exists +* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin +* Added the ability to combine URLs using strict RFC 3986 compliance +* Command objects can now return the validation errors encountered by the command +* Various fixes to cache revalidation (#437 and 29797e5) +* Various fixes to the AsyncPlugin +* Cleaned up build scripts + +## 3.7.4 - 2013-10-02 + +* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430) +* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp + (see https://github.com/aws/aws-sdk-php/issues/147) +* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots +* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420) +* Updated the bundled cacert.pem (#419) +* OauthPlugin now supports adding authentication to headers or query string (#425) + +## 3.7.3 - 2013-09-08 + +* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and + `CommandTransferException`. +* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description +* Schemas are only injected into response models when explicitly configured. +* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of + an EntityBody. +* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator. +* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`. +* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody() +* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin +* Bug fix: Visiting XML attributes first before visiting XML children when serializing requests +* Bug fix: Properly parsing headers that contain commas contained in quotes +* Bug fix: mimetype guessing based on a filename is now case-insensitive + +## 3.7.2 - 2013-08-02 + +* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander + See https://github.com/guzzle/guzzle/issues/371 +* Bug fix: Cookie domains are now matched correctly according to RFC 6265 + See https://github.com/guzzle/guzzle/issues/377 +* Bug fix: GET parameters are now used when calculating an OAuth signature +* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted +* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched +* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input. + See https://github.com/guzzle/guzzle/issues/379 +* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See + https://github.com/guzzle/guzzle/pull/380 +* cURL multi cleanup and optimizations + +## 3.7.1 - 2013-07-05 + +* Bug fix: Setting default options on a client now works +* Bug fix: Setting options on HEAD requests now works. See #352 +* Bug fix: Moving stream factory before send event to before building the stream. See #353 +* Bug fix: Cookies no longer match on IP addresses per RFC 6265 +* Bug fix: Correctly parsing header parameters that are in `<>` and quotes +* Added `cert` and `ssl_key` as request options +* `Host` header can now diverge from the host part of a URL if the header is set manually +* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter +* OAuth parameters are only added via the plugin if they aren't already set +* Exceptions are now thrown when a URL cannot be parsed +* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails +* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin + +## 3.7.0 - 2013-06-10 + +* See UPGRADING.md for more information on how to upgrade. +* Requests now support the ability to specify an array of $options when creating a request to more easily modify a + request. You can pass a 'request.options' configuration setting to a client to apply default request options to + every request created by a client (e.g. default query string variables, headers, curl options, etc.). +* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`. + See `Guzzle\Http\StaticClient::mount`. +* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests + created by a command (e.g. custom headers, query string variables, timeout settings, etc.). +* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the + headers of a response +* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key + (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`) +* ServiceBuilders now support storing and retrieving arbitrary data +* CachePlugin can now purge all resources for a given URI +* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource +* CachePlugin now uses the Vary header to determine if a resource is a cache hit +* `Guzzle\Http\Message\Response` now implements `\Serializable` +* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters +* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable +* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()` +* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size +* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message +* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older + Symfony users can still use the old version of Monolog. +* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`. + Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`. +* Several performance improvements to `Guzzle\Common\Collection` +* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +* Added `Guzzle\Stream\StreamInterface::isRepeatable` +* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`. +* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`. +* Removed `Guzzle\Http\ClientInterface::expandTemplate()` +* Removed `Guzzle\Http\ClientInterface::setRequestFactory()` +* Removed `Guzzle\Http\ClientInterface::getCurlMulti()` +* Removed `Guzzle\Http\Message\RequestInterface::canCache` +* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect` +* Removed `Guzzle\Http\Message\RequestInterface::isRedirect` +* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. +* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting + `Guzzle\Common\Version::$emitWarnings` to true. +* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use + `$request->getResponseBody()->isRepeatable()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. + These will work through Guzzle 4.0 +* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params]. +* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`. +* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. +* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +* Marked `Guzzle\Common\Collection::inject()` as deprecated. +* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');` +* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +* Always setting X-cache headers on cached responses +* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +* Added `CacheStorageInterface::purge($url)` +* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +## 3.6.0 - 2013-05-29 + +* ServiceDescription now implements ToArrayInterface +* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters +* Guzzle can now correctly parse incomplete URLs +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess +* Added the ability to cast Model objects to a string to view debug information. + +## 3.5.0 - 2013-05-13 + +* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times +* Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove + itself from the EventDispatcher) +* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values +* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too +* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a + non-existent key +* Bug: All __call() method arguments are now required (helps with mocking frameworks) +* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference + to help with refcount based garbage collection of resources created by sending a request +* Deprecating ZF1 cache and log adapters. These will be removed in the next major version. +* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it's deprecated). Use the + HistoryPlugin for a history. +* Added a `responseBody` alias for the `response_body` location +* Refactored internals to no longer rely on Response::getRequest() +* HistoryPlugin can now be cast to a string +* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests + and responses that are sent over the wire +* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects + +## 3.4.3 - 2013-04-30 + +* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response +* Added a check to re-extract the temp cacert bundle from the phar before sending each request + +## 3.4.2 - 2013-04-29 + +* Bug fix: Stream objects now work correctly with "a" and "a+" modes +* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present +* Bug fix: AsyncPlugin no longer forces HEAD requests +* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter +* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails +* Setting a response on a request will write to the custom request body from the response body if one is specified +* LogPlugin now writes to php://output when STDERR is undefined +* Added the ability to set multiple POST files for the same key in a single call +* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default +* Added the ability to queue CurlExceptions to the MockPlugin +* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send) +* Configuration loading now allows remote files + +## 3.4.1 - 2013-04-16 + +* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti + handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost. +* Exceptions are now properly grouped when sending requests in parallel +* Redirects are now properly aggregated when a multi transaction fails +* Redirects now set the response on the original object even in the event of a failure +* Bug fix: Model names are now properly set even when using $refs +* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax +* Added support for oauth_callback in OAuth signatures +* Added support for oauth_verifier in OAuth signatures +* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection + +## 3.4.0 - 2013-04-11 + +* Bug fix: URLs are now resolved correctly based on https://datatracker.ietf.org/doc/html/rfc3986#section-5.2. #289 +* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289 +* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263 +* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264. +* Bug fix: Added `number` type to service descriptions. +* Bug fix: empty parameters are removed from an OAuth signature +* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header +* Bug fix: Fixed "array to string" error when validating a union of types in a service description +* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream +* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin. +* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs. +* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections. +* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if + the Content-Type can be determined based on the entity body or the path of the request. +* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder. +* Added support for a PSR-3 LogAdapter. +* Added a `command.after_prepare` event +* Added `oauth_callback` parameter to the OauthPlugin +* Added the ability to create a custom stream class when using a stream factory +* Added a CachingEntityBody decorator +* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized. +* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar. +* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies +* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This + means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use + POST fields or files (the latter is only used when emulating a form POST in the browser). +* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest + +## 3.3.1 - 2013-03-10 + +* Added the ability to create PHP streaming responses from HTTP requests +* Bug fix: Running any filters when parsing response headers with service descriptions +* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing +* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across + response location visitors. +* Bug fix: Removed the possibility of creating configuration files with circular dependencies +* RequestFactory::create() now uses the key of a POST file when setting the POST file name +* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set + +## 3.3.0 - 2013-03-03 + +* A large number of performance optimizations have been made +* Bug fix: Added 'wb' as a valid write mode for streams +* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned +* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()` +* BC: Removed `Guzzle\Http\Utils` class +* BC: Setting a service description on a client will no longer modify the client's command factories. +* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using + the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' +* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to + lowercase +* Operation parameter objects are now lazy loaded internally +* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses +* Added support for instantiating responseType=class responseClass classes. Classes must implement + `Guzzle\Service\Command\ResponseClassInterface` +* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These + additional properties also support locations and can be used to parse JSON responses where the outermost part of the + JSON is an array +* Added support for nested renaming of JSON models (rename sentAs to name) +* CachePlugin + * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error + * Debug headers can now added to cached response in the CachePlugin + +## 3.2.0 - 2013-02-14 + +* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients. +* URLs with no path no longer contain a "/" by default +* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url. +* BadResponseException no longer includes the full request and response message +* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface +* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface +* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription +* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list +* xmlEncoding can now be customized for the XML declaration of a XML service description operation +* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value + aggregation and no longer uses callbacks +* The URL encoding implementation of Guzzle\Http\QueryString can now be customized +* Bug fix: Filters were not always invoked for array service description parameters +* Bug fix: Redirects now use a target response body rather than a temporary response body +* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded +* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives + +## 3.1.2 - 2013-01-27 + +* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the + response body. For example, the XmlVisitor now parses the XML response into an array in the before() method. +* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent +* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444) +* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse() +* Setting default headers on a client after setting the user-agent will not erase the user-agent setting + +## 3.1.1 - 2013-01-20 + +* Adding wildcard support to Guzzle\Common\Collection::getPath() +* Adding alias support to ServiceBuilder configs +* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface + +## 3.1.0 - 2013-01-12 + +* BC: CurlException now extends from RequestException rather than BadResponseException +* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse() +* Added getData to ServiceDescriptionInterface +* Added context array to RequestInterface::setState() +* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http +* Bug: Adding required content-type when JSON request visitor adds JSON to a command +* Bug: Fixing the serialization of a service description with custom data +* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing + an array of successful and failed responses +* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection +* Added Guzzle\Http\IoEmittingEntityBody +* Moved command filtration from validators to location visitors +* Added `extends` attributes to service description parameters +* Added getModels to ServiceDescriptionInterface + +## 3.0.7 - 2012-12-19 + +* Fixing phar detection when forcing a cacert to system if null or true +* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()` +* Cleaning up `Guzzle\Common\Collection::inject` method +* Adding a response_body location to service descriptions + +## 3.0.6 - 2012-12-09 + +* CurlMulti performance improvements +* Adding setErrorResponses() to Operation +* composer.json tweaks + +## 3.0.5 - 2012-11-18 + +* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin +* Bug: Response body can now be a string containing "0" +* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert +* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs +* Added support for XML attributes in service description responses +* DefaultRequestSerializer now supports array URI parameter values for URI template expansion +* Added better mimetype guessing to requests and post files + +## 3.0.4 - 2012-11-11 + +* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value +* Bug: Cookies can now be added that have a name, domain, or value set to "0" +* Bug: Using the system cacert bundle when using the Phar +* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures +* Enhanced cookie jar de-duplication +* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added +* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies +* Added the ability to create any sort of hash for a stream rather than just an MD5 hash + +## 3.0.3 - 2012-11-04 + +* Implementing redirects in PHP rather than cURL +* Added PECL URI template extension and using as default parser if available +* Bug: Fixed Content-Length parsing of Response factory +* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams. +* Adding ToArrayInterface throughout library +* Fixing OauthPlugin to create unique nonce values per request + +## 3.0.2 - 2012-10-25 + +* Magic methods are enabled by default on clients +* Magic methods return the result of a command +* Service clients no longer require a base_url option in the factory +* Bug: Fixed an issue with URI templates where null template variables were being expanded + +## 3.0.1 - 2012-10-22 + +* Models can now be used like regular collection objects by calling filter, map, etc. +* Models no longer require a Parameter structure or initial data in the constructor +* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator` + +## 3.0.0 - 2012-10-15 + +* Rewrote service description format to be based on Swagger + * Now based on JSON schema + * Added nested input structures and nested response models + * Support for JSON and XML input and output models + * Renamed `commands` to `operations` + * Removed dot class notation + * Removed custom types +* Broke the project into smaller top-level namespaces to be more component friendly +* Removed support for XML configs and descriptions. Use arrays or JSON files. +* Removed the Validation component and Inspector +* Moved all cookie code to Guzzle\Plugin\Cookie +* Magic methods on a Guzzle\Service\Client now return the command un-executed. +* Calling getResult() or getResponse() on a command will lazily execute the command if needed. +* Now shipping with cURL's CA certs and using it by default +* Added previousResponse() method to response objects +* No longer sending Accept and Accept-Encoding headers on every request +* Only sending an Expect header by default when a payload is greater than 1MB +* Added/moved client options: + * curl.blacklist to curl.option.blacklist + * Added ssl.certificate_authority +* Added a Guzzle\Iterator component +* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin +* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin) +* Added a more robust caching plugin +* Added setBody to response objects +* Updating LogPlugin to use a more flexible MessageFormatter +* Added a completely revamped build process +* Cleaning up Collection class and removing default values from the get method +* Fixed ZF2 cache adapters + +## 2.8.8 - 2012-10-15 + +* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did + +## 2.8.7 - 2012-09-30 + +* Bug: Fixed config file aliases for JSON includes +* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests +* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload +* Bug: Hardening request and response parsing to account for missing parts +* Bug: Fixed PEAR packaging +* Bug: Fixed Request::getInfo +* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail +* Adding the ability for the namespace Iterator factory to look in multiple directories +* Added more getters/setters/removers from service descriptions +* Added the ability to remove POST fields from OAuth signatures +* OAuth plugin now supports 2-legged OAuth + +## 2.8.6 - 2012-09-05 + +* Added the ability to modify and build service descriptions +* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command +* Added a `json` parameter location +* Now allowing dot notation for classes in the CacheAdapterFactory +* Using the union of two arrays rather than an array_merge when extending service builder services and service params +* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references + in service builder config files. +* Services defined in two different config files that include one another will by default replace the previously + defined service, but you can now create services that extend themselves and merge their settings over the previous +* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like + '_default' with a default JSON configuration file. + +## 2.8.5 - 2012-08-29 + +* Bug: Suppressed empty arrays from URI templates +* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching +* Added support for HTTP responses that do not contain a reason phrase in the start-line +* AbstractCommand commands are now invokable +* Added a way to get the data used when signing an Oauth request before a request is sent + +## 2.8.4 - 2012-08-15 + +* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin +* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable. +* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream +* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream +* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5()) +* Added additional response status codes +* Removed SSL information from the default User-Agent header +* DELETE requests can now send an entity body +* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries +* Added the ability of the MockPlugin to consume mocked request bodies +* LogPlugin now exposes request and response objects in the extras array + +## 2.8.3 - 2012-07-30 + +* Bug: Fixed a case where empty POST requests were sent as GET requests +* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body +* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new +* Added multiple inheritance to service description commands +* Added an ApiCommandInterface and added `getParamNames()` and `hasParam()` +* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything +* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles + +## 2.8.2 - 2012-07-24 + +* Bug: Query string values set to 0 are no longer dropped from the query string +* Bug: A Collection object is no longer created each time a call is made to `Guzzle\Service\Command\AbstractCommand::getRequestHeaders()` +* Bug: `+` is now treated as an encoded space when parsing query strings +* QueryString and Collection performance improvements +* Allowing dot notation for class paths in filters attribute of a service descriptions + +## 2.8.1 - 2012-07-16 + +* Loosening Event Dispatcher dependency +* POST redirects can now be customized using CURLOPT_POSTREDIR + +## 2.8.0 - 2012-07-15 + +* BC: Guzzle\Http\Query + * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl) + * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding() + * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool) + * Changed the aggregation functions of QueryString to be static methods + * Can now use fromString() with querystrings that have a leading ? +* cURL configuration values can be specified in service descriptions using `curl.` prefixed parameters +* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body +* Cookies are no longer URL decoded by default +* Bug: URI template variables set to null are no longer expanded + +## 2.7.2 - 2012-07-02 + +* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser. +* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty() +* CachePlugin now allows for a custom request parameter function to check if a request can be cached +* Bug fix: CachePlugin now only caches GET and HEAD requests by default +* Bug fix: Using header glue when transferring headers over the wire +* Allowing deeply nested arrays for composite variables in URI templates +* Batch divisors can now return iterators or arrays + +## 2.7.1 - 2012-06-26 + +* Minor patch to update version number in UA string +* Updating build process + +## 2.7.0 - 2012-06-25 + +* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes. +* BC: Removed magic setX methods from commands +* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method +* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable. +* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity) +* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace +* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin +* Added the ability to set POST fields and files in a service description +* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method +* Adding a command.before_prepare event to clients +* Added BatchClosureTransfer and BatchClosureDivisor +* BatchTransferException now includes references to the batch divisor and transfer strategies +* Fixed some tests so that they pass more reliably +* Added Guzzle\Common\Log\ArrayLogAdapter + +## 2.6.6 - 2012-06-10 + +* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin +* BC: Removing Guzzle\Service\Command\CommandSet +* Adding generic batching system (replaces the batch queue plugin and command set) +* Updating ZF cache and log adapters and now using ZF's composer repository +* Bug: Setting the name of each ApiParam when creating through an ApiCommand +* Adding result_type, result_doc, deprecated, and doc_url to service descriptions +* Bug: Changed the default cookie header casing back to 'Cookie' + +## 2.6.5 - 2012-06-03 + +* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource() +* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from +* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data +* BC: Renaming methods in the CookieJarInterface +* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations +* Making the default glue for HTTP headers ';' instead of ',' +* Adding a removeValue to Guzzle\Http\Message\Header +* Adding getCookies() to request interface. +* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber() + +## 2.6.4 - 2012-05-30 + +* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class. +* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand +* Bug: Fixing magic method command calls on clients +* Bug: Email constraint only validates strings +* Bug: Aggregate POST fields when POST files are present in curl handle +* Bug: Fixing default User-Agent header +* Bug: Only appending or prepending parameters in commands if they are specified +* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes +* Allowing the use of dot notation for class namespaces when using instance_of constraint +* Added any_match validation constraint +* Added an AsyncPlugin +* Passing request object to the calculateWait method of the ExponentialBackoffPlugin +* Allowing the result of a command object to be changed +* Parsing location and type sub values when instantiating a service description rather than over and over at runtime + +## 2.6.3 - 2012-05-23 + +* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options. +* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields. +* You can now use an array of data when creating PUT request bodies in the request factory. +* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable. +* [Http] Adding support for Content-Type in multipart POST uploads per upload +* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1]) +* Adding more POST data operations for easier manipulation of POST data. +* You can now set empty POST fields. +* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files. +* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate. +* CS updates + +## 2.6.2 - 2012-05-19 + +* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method. + +## 2.6.1 - 2012-05-19 + +* [BC] Removing 'path' support in service descriptions. Use 'uri'. +* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache. +* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it. +* [BC] Removing Guzzle\Common\XmlElement. +* All commands, both dynamic and concrete, have ApiCommand objects. +* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits. +* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored. +* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible. + +## 2.6.0 - 2012-05-15 + +* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder +* [BC] Executing a Command returns the result of the command rather than the command +* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed. +* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args. +* [BC] Moving ResourceIterator* to Guzzle\Service\Resource +* [BC] Completely refactored ResourceIterators to iterate over a cloned command object +* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate +* [BC] Guzzle\Guzzle is now deprecated +* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject +* Adding Guzzle\Version class to give version information about Guzzle +* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate() +* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data +* ServiceDescription and ServiceBuilder are now cacheable using similar configs +* Changing the format of XML and JSON service builder configs. Backwards compatible. +* Cleaned up Cookie parsing +* Trimming the default Guzzle User-Agent header +* Adding a setOnComplete() method to Commands that is called when a command completes +* Keeping track of requests that were mocked in the MockPlugin +* Fixed a caching bug in the CacheAdapterFactory +* Inspector objects can be injected into a Command object +* Refactoring a lot of code and tests to be case insensitive when dealing with headers +* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL +* Adding the ability to set global option overrides to service builder configs +* Adding the ability to include other service builder config files from within XML and JSON files +* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method. + +## 2.5.0 - 2012-05-08 + +* Major performance improvements +* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated. +* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component. +* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}" +* Added the ability to passed parameters to all requests created by a client +* Added callback functionality to the ExponentialBackoffPlugin +* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies. +* Rewinding request stream bodies when retrying requests +* Exception is thrown when JSON response body cannot be decoded +* Added configurable magic method calls to clients and commands. This is off by default. +* Fixed a defect that added a hash to every parsed URL part +* Fixed duplicate none generation for OauthPlugin. +* Emitting an event each time a client is generated by a ServiceBuilder +* Using an ApiParams object instead of a Collection for parameters of an ApiCommand +* cache.* request parameters should be renamed to params.cache.* +* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle. +* Added the ability to disable type validation of service descriptions +* ServiceDescriptions and ServiceBuilders are now Serializable diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/LICENSE b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/LICENSE new file mode 100644 index 000000000..fd2375d88 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/LICENSE @@ -0,0 +1,27 @@ +The MIT License (MIT) + +Copyright (c) 2011 Michael Dowling +Copyright (c) 2012 Jeremy Lindblom +Copyright (c) 2014 Graham Campbell +Copyright (c) 2015 Márk Sági-Kazár +Copyright (c) 2015 Tobias Schultze +Copyright (c) 2016 Tobias Nyholm +Copyright (c) 2016 George Mponos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/README.md b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/README.md new file mode 100644 index 000000000..cdaebee3f --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/README.md @@ -0,0 +1,94 @@ +![Guzzle](.github/logo.png?raw=true) + +# Guzzle, PHP HTTP client + +[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases) +[![Build Status](https://img.shields.io/github/actions/workflow/status/guzzle/guzzle/ci.yml?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI) +[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle) + +Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and +trivial to integrate with web services. + +- Simple interface for building query strings, POST requests, streaming large + uploads, streaming large downloads, using HTTP cookies, uploading JSON data, + etc... +- Can send both synchronous and asynchronous requests using the same interface. +- Uses PSR-7 interfaces for requests, responses, and streams. This allows you + to utilize other PSR-7 compatible libraries with Guzzle. +- Supports PSR-18 allowing interoperability between other PSR-18 HTTP Clients. +- Abstracts away the underlying HTTP transport, allowing you to write + environment and transport agnostic code; i.e., no hard dependency on cURL, + PHP streams, sockets, or non-blocking event loops. +- Middleware system allows you to augment and compose client behavior. + +```php +$client = new \GuzzleHttp\Client(); +$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle'); + +echo $response->getStatusCode(); // 200 +echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8' +echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}' + +// Send an asynchronous request. +$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org'); +$promise = $client->sendAsync($request)->then(function ($response) { + echo 'I completed! ' . $response->getBody(); +}); + +$promise->wait(); +``` + +## Help and docs + +We use GitHub issues only to discuss bugs and new features. For support please refer to: + +- [Documentation](https://docs.guzzlephp.org) +- [Stack Overflow](https://stackoverflow.com/questions/tagged/guzzle) +- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](https://slack.httplug.io/) +- [Gitter](https://gitter.im/guzzle/guzzle) + + +## Installing Guzzle + +The recommended way to install Guzzle is through +[Composer](https://getcomposer.org/). + +```bash +composer require guzzlehttp/guzzle +``` + + +## Version Guidance + +| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version | +|---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------| +| 3.x | EOL (2016-10-31) | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 | +| 4.x | EOL (2016-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 | +| 5.x | EOL (2019-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 | +| 6.x | EOL (2023-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 | +| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.5 | + +[guzzle-3-repo]: https://github.com/guzzle/guzzle3 +[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x +[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3 +[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5 +[guzzle-7-repo]: https://github.com/guzzle/guzzle +[guzzle-3-docs]: https://guzzle3.readthedocs.io/ +[guzzle-5-docs]: https://docs.guzzlephp.org/en/5.3/ +[guzzle-6-docs]: https://docs.guzzlephp.org/en/6.5/ +[guzzle-7-docs]: https://docs.guzzlephp.org/en/latest/ + + +## Security + +If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/guzzle/security/policy) for more information. + +## License + +Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information. + +## For Enterprise + +Available as part of the Tidelift Subscription + +The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-guzzle?utm_source=packagist-guzzlehttp-guzzle&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/UPGRADING.md b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/UPGRADING.md new file mode 100644 index 000000000..4efbb5962 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/UPGRADING.md @@ -0,0 +1,1253 @@ +Guzzle Upgrade Guide +==================== + +6.0 to 7.0 +---------- + +In order to take advantage of the new features of PHP, Guzzle dropped the support +of PHP 5. The minimum supported PHP version is now PHP 7.2. Type hints and return +types for functions and methods have been added wherever possible. + +Please make sure: +- You are calling a function or a method with the correct type. +- If you extend a class of Guzzle; update all signatures on methods you override. + +#### Other backwards compatibility breaking changes + +- Class `GuzzleHttp\UriTemplate` is removed. +- Class `GuzzleHttp\Exception\SeekException` is removed. +- Classes `GuzzleHttp\Exception\BadResponseException`, `GuzzleHttp\Exception\ClientException`, + `GuzzleHttp\Exception\ServerException` can no longer be initialized with an empty + Response as argument. +- Class `GuzzleHttp\Exception\ConnectException` now extends `GuzzleHttp\Exception\TransferException` + instead of `GuzzleHttp\Exception\RequestException`. +- Function `GuzzleHttp\Exception\ConnectException::getResponse()` is removed. +- Function `GuzzleHttp\Exception\ConnectException::hasResponse()` is removed. +- Constant `GuzzleHttp\ClientInterface::VERSION` is removed. Added `GuzzleHttp\ClientInterface::MAJOR_VERSION` instead. +- Function `GuzzleHttp\Exception\RequestException::getResponseBodySummary` is removed. + Use `\GuzzleHttp\Psr7\get_message_body_summary` as an alternative. +- Function `GuzzleHttp\Cookie\CookieJar::getCookieValue` is removed. +- Request option `exceptions` is removed. Please use `http_errors`. +- Request option `save_to` is removed. Please use `sink`. +- Pool option `pool_size` is removed. Please use `concurrency`. +- We now look for environment variables in the `$_SERVER` super global, due to thread safety issues with `getenv`. We continue to fallback to `getenv` in CLI environments, for maximum compatibility. +- The `get`, `head`, `put`, `post`, `patch`, `delete`, `getAsync`, `headAsync`, `putAsync`, `postAsync`, `patchAsync`, and `deleteAsync` methods are now implemented as genuine methods on `GuzzleHttp\Client`, with strong typing. The original `__call` implementation remains unchanged for now, for maximum backwards compatibility, but won't be invoked under normal operation. +- The `log` middleware will log the errors with level `error` instead of `notice` +- Support for international domain names (IDN) is now disabled by default, and enabling it requires installing ext-intl, linked against a modern version of the C library (ICU 4.6 or higher). + +#### Native functions calls + +All internal native functions calls of Guzzle are now prefixed with a slash. This +change makes it impossible for method overloading by other libraries or applications. +Example: + +```php +// Before: +curl_version(); + +// After: +\curl_version(); +``` + +For the full diff you can check [here](https://github.com/guzzle/guzzle/compare/6.5.4..master). + +5.0 to 6.0 +---------- + +Guzzle now uses [PSR-7](https://www.php-fig.org/psr/psr-7/) for HTTP messages. +Due to the fact that these messages are immutable, this prompted a refactoring +of Guzzle to use a middleware based system rather than an event system. Any +HTTP message interaction (e.g., `GuzzleHttp\Message\Request`) need to be +updated to work with the new immutable PSR-7 request and response objects. Any +event listeners or subscribers need to be updated to become middleware +functions that wrap handlers (or are injected into a +`GuzzleHttp\HandlerStack`). + +- Removed `GuzzleHttp\BatchResults` +- Removed `GuzzleHttp\Collection` +- Removed `GuzzleHttp\HasDataTrait` +- Removed `GuzzleHttp\ToArrayInterface` +- The `guzzlehttp/streams` dependency has been removed. Stream functionality + is now present in the `GuzzleHttp\Psr7` namespace provided by the + `guzzlehttp/psr7` package. +- Guzzle no longer uses ReactPHP promises and now uses the + `guzzlehttp/promises` library. We use a custom promise library for three + significant reasons: + 1. React promises (at the time of writing this) are recursive. Promise + chaining and promise resolution will eventually blow the stack. Guzzle + promises are not recursive as they use a sort of trampolining technique. + Note: there has been movement in the React project to modify promises to + no longer utilize recursion. + 2. Guzzle needs to have the ability to synchronously block on a promise to + wait for a result. Guzzle promises allows this functionality (and does + not require the use of recursion). + 3. Because we need to be able to wait on a result, doing so using React + promises requires wrapping react promises with RingPHP futures. This + overhead is no longer needed, reducing stack sizes, reducing complexity, + and improving performance. +- `GuzzleHttp\Mimetypes` has been moved to a function in + `GuzzleHttp\Psr7\mimetype_from_extension` and + `GuzzleHttp\Psr7\mimetype_from_filename`. +- `GuzzleHttp\Query` and `GuzzleHttp\QueryParser` have been removed. Query + strings must now be passed into request objects as strings, or provided to + the `query` request option when creating requests with clients. The `query` + option uses PHP's `http_build_query` to convert an array to a string. If you + need a different serialization technique, you will need to pass the query + string in as a string. There are a couple helper functions that will make + working with query strings easier: `GuzzleHttp\Psr7\parse_query` and + `GuzzleHttp\Psr7\build_query`. +- Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware + system based on PSR-7, using RingPHP and it's middleware system as well adds + more complexity than the benefits it provides. All HTTP handlers that were + present in RingPHP have been modified to work directly with PSR-7 messages + and placed in the `GuzzleHttp\Handler` namespace. This significantly reduces + complexity in Guzzle, removes a dependency, and improves performance. RingPHP + will be maintained for Guzzle 5 support, but will no longer be a part of + Guzzle 6. +- As Guzzle now uses a middleware based systems the event system and RingPHP + integration has been removed. Note: while the event system has been removed, + it is possible to add your own type of event system that is powered by the + middleware system. + - Removed the `Event` namespace. + - Removed the `Subscriber` namespace. + - Removed `Transaction` class + - Removed `RequestFsm` + - Removed `RingBridge` + - `GuzzleHttp\Subscriber\Cookie` is now provided by + `GuzzleHttp\Middleware::cookies` + - `GuzzleHttp\Subscriber\HttpError` is now provided by + `GuzzleHttp\Middleware::httpError` + - `GuzzleHttp\Subscriber\History` is now provided by + `GuzzleHttp\Middleware::history` + - `GuzzleHttp\Subscriber\Mock` is now provided by + `GuzzleHttp\Handler\MockHandler` + - `GuzzleHttp\Subscriber\Prepare` is now provided by + `GuzzleHttp\PrepareBodyMiddleware` + - `GuzzleHttp\Subscriber\Redirect` is now provided by + `GuzzleHttp\RedirectMiddleware` +- Guzzle now uses `Psr\Http\Message\UriInterface` (implements in + `GuzzleHttp\Psr7\Uri`) for URI support. `GuzzleHttp\Url` is now gone. +- Static functions in `GuzzleHttp\Utils` have been moved to namespaced + functions under the `GuzzleHttp` namespace. This requires either a Composer + based autoloader or you to include functions.php. +- `GuzzleHttp\ClientInterface::getDefaultOption` has been renamed to + `GuzzleHttp\ClientInterface::getConfig`. +- `GuzzleHttp\ClientInterface::setDefaultOption` has been removed. +- The `json` and `xml` methods of response objects has been removed. With the + migration to strictly adhering to PSR-7 as the interface for Guzzle messages, + adding methods to message interfaces would actually require Guzzle messages + to extend from PSR-7 messages rather then work with them directly. + +## Migrating to middleware + +The change to PSR-7 unfortunately required significant refactoring to Guzzle +due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event +system from plugins. The event system relied on mutability of HTTP messages and +side effects in order to work. With immutable messages, you have to change your +workflow to become more about either returning a value (e.g., functional +middlewares) or setting a value on an object. Guzzle v6 has chosen the +functional middleware approach. + +Instead of using the event system to listen for things like the `before` event, +you now create a stack based middleware function that intercepts a request on +the way in and the promise of the response on the way out. This is a much +simpler and more predictable approach than the event system and works nicely +with PSR-7 middleware. Due to the use of promises, the middleware system is +also asynchronous. + +v5: + +```php +use GuzzleHttp\Event\BeforeEvent; +$client = new GuzzleHttp\Client(); +// Get the emitter and listen to the before event. +$client->getEmitter()->on('before', function (BeforeEvent $e) { + // Guzzle v5 events relied on mutation + $e->getRequest()->setHeader('X-Foo', 'Bar'); +}); +``` + +v6: + +In v6, you can modify the request before it is sent using the `mapRequest` +middleware. The idiomatic way in v6 to modify the request/response lifecycle is +to setup a handler middleware stack up front and inject the handler into a +client. + +```php +use GuzzleHttp\Middleware; +// Create a handler stack that has all of the default middlewares attached +$handler = GuzzleHttp\HandlerStack::create(); +// Push the handler onto the handler stack +$handler->push(Middleware::mapRequest(function (RequestInterface $request) { + // Notice that we have to return a request object + return $request->withHeader('X-Foo', 'Bar'); +})); +// Inject the handler into the client +$client = new GuzzleHttp\Client(['handler' => $handler]); +``` + +## POST Requests + +This version added the [`form_params`](https://docs.guzzlephp.org/en/latest/request-options.html#form_params) +and `multipart` request options. `form_params` is an associative array of +strings or array of strings and is used to serialize an +`application/x-www-form-urlencoded` POST request. The +[`multipart`](https://docs.guzzlephp.org/en/latest/request-options.html#multipart) +option is now used to send a multipart/form-data POST request. + +`GuzzleHttp\Post\PostFile` has been removed. Use the `multipart` option to add +POST files to a multipart/form-data request. + +The `body` option no longer accepts an array to send POST requests. Please use +`multipart` or `form_params` instead. + +The `base_url` option has been renamed to `base_uri`. + +4.x to 5.0 +---------- + +## Rewritten Adapter Layer + +Guzzle now uses [RingPHP](https://ringphp.readthedocs.org/en/latest) to send +HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor +is still supported, but it has now been renamed to `handler`. Instead of +passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP +`callable` that follows the RingPHP specification. + +## Removed Fluent Interfaces + +[Fluent interfaces were removed](https://ocramius.github.io/blog/fluent-interfaces-are-evil/) +from the following classes: + +- `GuzzleHttp\Collection` +- `GuzzleHttp\Url` +- `GuzzleHttp\Query` +- `GuzzleHttp\Post\PostBody` +- `GuzzleHttp\Cookie\SetCookie` + +## Removed functions.php + +Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following +functions can be used as replacements. + +- `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode` +- `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath` +- `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path` +- `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however, + deprecated in favor of using `GuzzleHttp\Pool::batch()`. + +The "procedural" global client has been removed with no replacement (e.g., +`GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client` +object as a replacement. + +## `throwImmediately` has been removed + +The concept of "throwImmediately" has been removed from exceptions and error +events. This control mechanism was used to stop a transfer of concurrent +requests from completing. This can now be handled by throwing the exception or +by cancelling a pool of requests or each outstanding future request +individually. + +## headers event has been removed + +Removed the "headers" event. This event was only useful for changing the +body a response once the headers of the response were known. You can implement +a similar behavior in a number of ways. One example might be to use a +FnStream that has access to the transaction being sent. For example, when the +first byte is written, you could check if the response headers match your +expectations, and if so, change the actual stream body that is being +written to. + +## Updates to HTTP Messages + +Removed the `asArray` parameter from +`GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header +value as an array, then use the newly added `getHeaderAsArray()` method of +`MessageInterface`. This change makes the Guzzle interfaces compatible with +the PSR-7 interfaces. + +3.x to 4.0 +---------- + +## Overarching changes: + +- Now requires PHP 5.4 or greater. +- No longer requires cURL to send requests. +- Guzzle no longer wraps every exception it throws. Only exceptions that are + recoverable are now wrapped by Guzzle. +- Various namespaces have been removed or renamed. +- No longer requiring the Symfony EventDispatcher. A custom event dispatcher + based on the Symfony EventDispatcher is + now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant + speed and functionality improvements). + +Changes per Guzzle 3.x namespace are described below. + +## Batch + +The `Guzzle\Batch` namespace has been removed. This is best left to +third-parties to implement on top of Guzzle's core HTTP library. + +## Cache + +The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement +has been implemented yet, but hoping to utilize a PSR cache interface). + +## Common + +- Removed all of the wrapped exceptions. It's better to use the standard PHP + library for unrecoverable exceptions. +- `FromConfigInterface` has been removed. +- `Guzzle\Common\Version` has been removed. The VERSION constant can be found + at `GuzzleHttp\ClientInterface::VERSION`. + +### Collection + +- `getAll` has been removed. Use `toArray` to convert a collection to an array. +- `inject` has been removed. +- `keySearch` has been removed. +- `getPath` no longer supports wildcard expressions. Use something better like + JMESPath for this. +- `setPath` now supports appending to an existing array via the `[]` notation. + +### Events + +Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses +`GuzzleHttp\Event\Emitter`. + +- `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by + `GuzzleHttp\Event\EmitterInterface`. +- `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by + `GuzzleHttp\Event\Emitter`. +- `Symfony\Component\EventDispatcher\Event` is replaced by + `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in + `GuzzleHttp\Event\EventInterface`. +- `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and + `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the + event emitter of a request, client, etc. now uses the `getEmitter` method + rather than the `getDispatcher` method. + +#### Emitter + +- Use the `once()` method to add a listener that automatically removes itself + the first time it is invoked. +- Use the `listeners()` method to retrieve a list of event listeners rather than + the `getListeners()` method. +- Use `emit()` instead of `dispatch()` to emit an event from an emitter. +- Use `attach()` instead of `addSubscriber()` and `detach()` instead of + `removeSubscriber()`. + +```php +$mock = new Mock(); +// 3.x +$request->getEventDispatcher()->addSubscriber($mock); +$request->getEventDispatcher()->removeSubscriber($mock); +// 4.x +$request->getEmitter()->attach($mock); +$request->getEmitter()->detach($mock); +``` + +Use the `on()` method to add a listener rather than the `addListener()` method. + +```php +// 3.x +$request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } ); +// 4.x +$request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } ); +``` + +## Http + +### General changes + +- The cacert.pem certificate has been moved to `src/cacert.pem`. +- Added the concept of adapters that are used to transfer requests over the + wire. +- Simplified the event system. +- Sending requests in parallel is still possible, but batching is no longer a + concept of the HTTP layer. Instead, you must use the `complete` and `error` + events to asynchronously manage parallel request transfers. +- `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`. +- `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`. +- QueryAggregators have been rewritten so that they are simply callable + functions. +- `GuzzleHttp\StaticClient` has been removed. Use the functions provided in + `functions.php` for an easy to use static client instance. +- Exceptions in `GuzzleHttp\Exception` have been updated to all extend from + `GuzzleHttp\Exception\TransferException`. + +### Client + +Calling methods like `get()`, `post()`, `head()`, etc. no longer create and +return a request, but rather creates a request, sends the request, and returns +the response. + +```php +// 3.0 +$request = $client->get('/'); +$response = $request->send(); + +// 4.0 +$response = $client->get('/'); + +// or, to mirror the previous behavior +$request = $client->createRequest('GET', '/'); +$response = $client->send($request); +``` + +`GuzzleHttp\ClientInterface` has changed. + +- The `send` method no longer accepts more than one request. Use `sendAll` to + send multiple requests in parallel. +- `setUserAgent()` has been removed. Use a default request option instead. You + could, for example, do something like: + `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`. +- `setSslVerification()` has been removed. Use default request options instead, + like `$client->setConfig('defaults/verify', true)`. + +`GuzzleHttp\Client` has changed. + +- The constructor now accepts only an associative array. You can include a + `base_url` string or array to use a URI template as the base URL of a client. + You can also specify a `defaults` key that is an associative array of default + request options. You can pass an `adapter` to use a custom adapter, + `batch_adapter` to use a custom adapter for sending requests in parallel, or + a `message_factory` to change the factory used to create HTTP requests and + responses. +- The client no longer emits a `client.create_request` event. +- Creating requests with a client no longer automatically utilize a URI + template. You must pass an array into a creational method (e.g., + `createRequest`, `get`, `put`, etc.) in order to expand a URI template. + +### Messages + +Messages no longer have references to their counterparts (i.e., a request no +longer has a reference to it's response, and a response no loger has a +reference to its request). This association is now managed through a +`GuzzleHttp\Adapter\TransactionInterface` object. You can get references to +these transaction objects using request events that are emitted over the +lifecycle of a request. + +#### Requests with a body + +- `GuzzleHttp\Message\EntityEnclosingRequest` and + `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The + separation between requests that contain a body and requests that do not + contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface` + handles both use cases. +- Any method that previously accepts a `GuzzleHttp\Response` object now accept a + `GuzzleHttp\Message\ResponseInterface`. +- `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to + `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create + both requests and responses and is implemented in + `GuzzleHttp\Message\MessageFactory`. +- POST field and file methods have been removed from the request object. You + must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface` + to control the format of a POST body. Requests that are created using a + standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use + a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if + the method is POST and no body is provided. + +```php +$request = $client->createRequest('POST', '/'); +$request->getBody()->setField('foo', 'bar'); +$request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r'))); +``` + +#### Headers + +- `GuzzleHttp\Message\Header` has been removed. Header values are now simply + represented by an array of values or as a string. Header values are returned + as a string by default when retrieving a header value from a message. You can + pass an optional argument of `true` to retrieve a header value as an array + of strings instead of a single concatenated string. +- `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to + `GuzzleHttp\Post`. This interface has been simplified and now allows the + addition of arbitrary headers. +- Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most + of the custom headers are now handled separately in specific + subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has + been updated to properly handle headers that contain parameters (like the + `Link` header). + +#### Responses + +- `GuzzleHttp\Message\Response::getInfo()` and + `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event + system to retrieve this type of information. +- `GuzzleHttp\Message\Response::getRawHeaders()` has been removed. +- `GuzzleHttp\Message\Response::getMessage()` has been removed. +- `GuzzleHttp\Message\Response::calculateAge()` and other cache specific + methods have moved to the CacheSubscriber. +- Header specific helper functions like `getContentMd5()` have been removed. + Just use `getHeader('Content-MD5')` instead. +- `GuzzleHttp\Message\Response::setRequest()` and + `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event + system to work with request and response objects as a transaction. +- `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the + Redirect subscriber instead. +- `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have + been removed. Use `getStatusCode()` instead. + +#### Streaming responses + +Streaming requests can now be created by a client directly, returning a +`GuzzleHttp\Message\ResponseInterface` object that contains a body stream +referencing an open PHP HTTP stream. + +```php +// 3.0 +use Guzzle\Stream\PhpStreamRequestFactory; +$request = $client->get('/'); +$factory = new PhpStreamRequestFactory(); +$stream = $factory->fromRequest($request); +$data = $stream->read(1024); + +// 4.0 +$response = $client->get('/', ['stream' => true]); +// Read some data off of the stream in the response body +$data = $response->getBody()->read(1024); +``` + +#### Redirects + +The `configureRedirects()` method has been removed in favor of a +`allow_redirects` request option. + +```php +// Standard redirects with a default of a max of 5 redirects +$request = $client->createRequest('GET', '/', ['allow_redirects' => true]); + +// Strict redirects with a custom number of redirects +$request = $client->createRequest('GET', '/', [ + 'allow_redirects' => ['max' => 5, 'strict' => true] +]); +``` + +#### EntityBody + +EntityBody interfaces and classes have been removed or moved to +`GuzzleHttp\Stream`. All classes and interfaces that once required +`GuzzleHttp\EntityBodyInterface` now require +`GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no +longer uses `GuzzleHttp\EntityBody::factory` but now uses +`GuzzleHttp\Stream\Stream::factory` or even better: +`GuzzleHttp\Stream\create()`. + +- `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface` +- `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream` +- `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream` +- `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream` +- `Guzzle\Http\IoEmittyinEntityBody` has been removed. + +#### Request lifecycle events + +Requests previously submitted a large number of requests. The number of events +emitted over the lifecycle of a request has been significantly reduced to make +it easier to understand how to extend the behavior of a request. All events +emitted during the lifecycle of a request now emit a custom +`GuzzleHttp\Event\EventInterface` object that contains context providing +methods and a way in which to modify the transaction at that specific point in +time (e.g., intercept the request and set a response on the transaction). + +- `request.before_send` has been renamed to `before` and now emits a + `GuzzleHttp\Event\BeforeEvent` +- `request.complete` has been renamed to `complete` and now emits a + `GuzzleHttp\Event\CompleteEvent`. +- `request.sent` has been removed. Use `complete`. +- `request.success` has been removed. Use `complete`. +- `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`. +- `request.exception` has been removed. Use `error`. +- `request.receive.status_line` has been removed. +- `curl.callback.progress` has been removed. Use a custom `StreamInterface` to + maintain a status update. +- `curl.callback.write` has been removed. Use a custom `StreamInterface` to + intercept writes. +- `curl.callback.read` has been removed. Use a custom `StreamInterface` to + intercept reads. + +`headers` is a new event that is emitted after the response headers of a +request have been received before the body of the response is downloaded. This +event emits a `GuzzleHttp\Event\HeadersEvent`. + +You can intercept a request and inject a response using the `intercept()` event +of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and +`GuzzleHttp\Event\ErrorEvent` event. + +See: https://docs.guzzlephp.org/en/latest/events.html + +## Inflection + +The `Guzzle\Inflection` namespace has been removed. This is not a core concern +of Guzzle. + +## Iterator + +The `Guzzle\Iterator` namespace has been removed. + +- `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and + `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of + Guzzle itself. +- `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent + class is shipped with PHP 5.4. +- `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because + it's easier to just wrap an iterator in a generator that maps values. + +For a replacement of these iterators, see https://github.com/nikic/iter + +## Log + +The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The +`Guzzle\Log` namespace has been removed. Guzzle now relies on +`Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been +moved to `GuzzleHttp\Subscriber\Log\Formatter`. + +## Parser + +The `Guzzle\Parser` namespace has been removed. This was previously used to +make it possible to plug in custom parsers for cookies, messages, URI +templates, and URLs; however, this level of complexity is not needed in Guzzle +so it has been removed. + +- Cookie: Cookie parsing logic has been moved to + `GuzzleHttp\Cookie\SetCookie::fromString`. +- Message: Message parsing logic for both requests and responses has been moved + to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only + used in debugging or deserializing messages, so it doesn't make sense for + Guzzle as a library to add this level of complexity to parsing messages. +- UriTemplate: URI template parsing has been moved to + `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL + URI template library if it is installed. +- Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously + it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary, + then developers are free to subclass `GuzzleHttp\Url`. + +## Plugin + +The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`. +Several plugins are shipping with the core Guzzle library under this namespace. + +- `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar + code has moved to `GuzzleHttp\Cookie`. +- `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin. +- `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is + received. +- `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin. +- `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before + sending. This subscriber is attached to all requests by default. +- `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin. + +The following plugins have been removed (third-parties are free to re-implement +these if needed): + +- `GuzzleHttp\Plugin\Async` has been removed. +- `GuzzleHttp\Plugin\CurlAuth` has been removed. +- `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This + functionality should instead be implemented with event listeners that occur + after normal response parsing occurs in the guzzle/command package. + +The following plugins are not part of the core Guzzle package, but are provided +in separate repositories: + +- `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be much simpler + to build custom retry policies using simple functions rather than various + chained classes. See: https://github.com/guzzle/retry-subscriber +- `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to + https://github.com/guzzle/cache-subscriber +- `Guzzle\Http\Plugin\Log\LogPlugin` has moved to + https://github.com/guzzle/log-subscriber +- `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to + https://github.com/guzzle/message-integrity-subscriber +- `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to + `GuzzleHttp\Subscriber\MockSubscriber`. +- `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to + https://github.com/guzzle/oauth-subscriber + +## Service + +The service description layer of Guzzle has moved into two separate packages: + +- https://github.com/guzzle/command Provides a high level abstraction over web + services by representing web service operations using commands. +- https://github.com/guzzle/guzzle-services Provides an implementation of + guzzle/command that provides request serialization and response parsing using + Guzzle service descriptions. + +## Stream + +Stream have moved to a separate package available at +https://github.com/guzzle/streams. + +`Guzzle\Stream\StreamInterface` has been given a large update to cleanly take +on the responsibilities of `Guzzle\Http\EntityBody` and +`Guzzle\Http\EntityBodyInterface` now that they have been removed. The number +of methods implemented by the `StreamInterface` has been drastically reduced to +allow developers to more easily extend and decorate stream behavior. + +## Removed methods from StreamInterface + +- `getStream` and `setStream` have been removed to better encapsulate streams. +- `getMetadata` and `setMetadata` have been removed in favor of + `GuzzleHttp\Stream\MetadataStreamInterface`. +- `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been + removed. This data is accessible when + using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`. +- `rewind` has been removed. Use `seek(0)` for a similar behavior. + +## Renamed methods + +- `detachStream` has been renamed to `detach`. +- `feof` has been renamed to `eof`. +- `ftell` has been renamed to `tell`. +- `readLine` has moved from an instance method to a static class method of + `GuzzleHttp\Stream\Stream`. + +## Metadata streams + +`GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams +that contain additional metadata accessible via `getMetadata()`. +`GuzzleHttp\Stream\StreamInterface::getMetadata` and +`GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed. + +## StreamRequestFactory + +The entire concept of the StreamRequestFactory has been removed. The way this +was used in Guzzle 3 broke the actual interface of sending streaming requests +(instead of getting back a Response, you got a StreamInterface). Streaming +PHP requests are now implemented through the `GuzzleHttp\Adapter\StreamAdapter`. + +3.6 to 3.7 +---------- + +### Deprecations + +- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.: + +```php +\Guzzle\Common\Version::$emitWarnings = true; +``` + +The following APIs and options have been marked as deprecated: + +- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +- Marked `Guzzle\Common\Collection::inject()` as deprecated. +- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use + `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or + `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` + +3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational +request methods. When paired with a client's configuration settings, these options allow you to specify default settings +for various aspects of a request. Because these options make other previous configuration options redundant, several +configuration options and methods of a client and AbstractCommand have been deprecated. + +- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`. +- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`. +- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')` +- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0 + + $command = $client->getCommand('foo', array( + 'command.headers' => array('Test' => '123'), + 'command.response_body' => '/path/to/file' + )); + + // Should be changed to: + + $command = $client->getCommand('foo', array( + 'command.request_options' => array( + 'headers' => array('Test' => '123'), + 'save_as' => '/path/to/file' + ) + )); + +### Interface changes + +Additions and changes (you will need to update any implementations or subclasses you may have created): + +- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +- Added `Guzzle\Stream\StreamInterface::isRepeatable` +- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. + +The following methods were removed from interfaces. All of these methods are still available in the concrete classes +that implement them, but you should update your code to use alternative methods: + +- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or + `$client->setDefaultOption('headers/{header_name}', 'value')`. or + `$client->setDefaultOption('headers', array('header_name' => 'value'))`. +- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`. +- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail. +- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin. +- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin. +- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin. + +### Cache plugin breaking changes + +- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +- Always setting X-cache headers on cached responses +- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +- Added `CacheStorageInterface::purge($url)` +- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +3.5 to 3.6 +---------- + +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). + For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader(). + Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request. +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Moved getLinks() from Response to just be used on a Link header object. + +If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the +HeaderInterface (e.g. toArray(), getAll(), etc.). + +### Interface changes + +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() + +### Removed deprecated functions + +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). + +### Deprecations + +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. + +### Other changes + +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess + +3.3 to 3.4 +---------- + +Base URLs of a client now follow the rules of https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2 when merging URLs. + +3.2 to 3.3 +---------- + +### Response::getEtag() quote stripping removed + +`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header + +### Removed `Guzzle\Http\Utils` + +The `Guzzle\Http\Utils` class was removed. This class was only used for testing. + +### Stream wrapper and type + +`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase. + +### curl.emit_io became emit_io + +Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the +'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' + +3.1 to 3.2 +---------- + +### CurlMulti is no longer reused globally + +Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added +to a single client can pollute requests dispatched from other clients. + +If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the +ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is +created. + +```php +$multi = new Guzzle\Http\Curl\CurlMulti(); +$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json'); +$builder->addListener('service_builder.create_client', function ($event) use ($multi) { + $event['client']->setCurlMulti($multi); +} +}); +``` + +### No default path + +URLs no longer have a default path value of '/' if no path was specified. + +Before: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com/ +``` + +After: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com +``` + +### Less verbose BadResponseException + +The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and +response information. You can, however, get access to the request and response object by calling `getRequest()` or +`getResponse()` on the exception object. + +### Query parameter aggregation + +Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a +setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is +responsible for handling the aggregation of multi-valued query string variables into a flattened hash. + +2.8 to 3.x +---------- + +### Guzzle\Service\Inspector + +Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig` + +**Before** + +```php +use Guzzle\Service\Inspector; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Inspector::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +**After** + +```php +use Guzzle\Common\Collection; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Collection::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +### Convert XML Service Descriptions to JSON + +**Before** + +```xml + + + + + + Get a list of groups + + + Uses a search query to get a list of groups + + + + Create a group + + + + + Delete a group by ID + + + + + + + Update a group + + + + + + +``` + +**After** + +```json +{ + "name": "Zendesk REST API v2", + "apiVersion": "2012-12-31", + "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users", + "operations": { + "list_groups": { + "httpMethod":"GET", + "uri": "groups.json", + "summary": "Get a list of groups" + }, + "search_groups":{ + "httpMethod":"GET", + "uri": "search.json?query=\"{query} type:group\"", + "summary": "Uses a search query to get a list of groups", + "parameters":{ + "query":{ + "location": "uri", + "description":"Zendesk Search Query", + "type": "string", + "required": true + } + } + }, + "create_group": { + "httpMethod":"POST", + "uri": "groups.json", + "summary": "Create a group", + "parameters":{ + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + }, + "delete_group": { + "httpMethod":"DELETE", + "uri": "groups/{id}.json", + "summary": "Delete a group", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to delete by ID", + "type": "integer", + "required": true + } + } + }, + "get_group": { + "httpMethod":"GET", + "uri": "groups/{id}.json", + "summary": "Get a ticket", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to get by ID", + "type": "integer", + "required": true + } + } + }, + "update_group": { + "httpMethod":"PUT", + "uri": "groups/{id}.json", + "summary": "Update a group", + "parameters":{ + "id": { + "location": "uri", + "description":"Group to update by ID", + "type": "integer", + "required": true + }, + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + } +} +``` + +### Guzzle\Service\Description\ServiceDescription + +Commands are now called Operations + +**Before** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getCommands(); // @returns ApiCommandInterface[] +$sd->hasCommand($name); +$sd->getCommand($name); // @returns ApiCommandInterface|null +$sd->addCommand($command); // @param ApiCommandInterface $command +``` + +**After** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getOperations(); // @returns OperationInterface[] +$sd->hasOperation($name); +$sd->getOperation($name); // @returns OperationInterface|null +$sd->addOperation($operation); // @param OperationInterface $operation +``` + +### Guzzle\Common\Inflection\Inflector + +Namespace is now `Guzzle\Inflection\Inflector` + +### Guzzle\Http\Plugin + +Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below. + +### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log + +Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively. + +**Before** + +```php +use Guzzle\Common\Log\ClosureLogAdapter; +use Guzzle\Http\Plugin\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $verbosity is an integer indicating desired message verbosity level +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE); +``` + +**After** + +```php +use Guzzle\Log\ClosureLogAdapter; +use Guzzle\Log\MessageFormatter; +use Guzzle\Plugin\Log\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $format is a string indicating desired message format -- @see MessageFormatter +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT); +``` + +### Guzzle\Http\Plugin\CurlAuthPlugin + +Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`. + +### Guzzle\Http\Plugin\ExponentialBackoffPlugin + +Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes. + +**Before** + +```php +use Guzzle\Http\Plugin\ExponentialBackoffPlugin; + +$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge( + ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429) + )); + +$client->addSubscriber($backoffPlugin); +``` + +**After** + +```php +use Guzzle\Plugin\Backoff\BackoffPlugin; +use Guzzle\Plugin\Backoff\HttpBackoffStrategy; + +// Use convenient factory method instead -- see implementation for ideas of what +// you can do with chaining backoff strategies +$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge( + HttpBackoffStrategy::getDefaultFailureCodes(), array(429) + )); +$client->addSubscriber($backoffPlugin); +``` + +### Known Issues + +#### [BUG] Accept-Encoding header behavior changed unintentionally. + +(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e) + +In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to +properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen. +See issue #217 for a workaround, or use a version containing the fix. diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/composer.json b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/composer.json new file mode 100644 index 000000000..0db75a950 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/composer.json @@ -0,0 +1,131 @@ +{ + "name": "guzzlehttp/guzzle", + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "framework", + "http", + "rest", + "web service", + "curl", + "client", + "HTTP client", + "PSR-7", + "PSR-18" + ], + "license": "MIT", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "repositories": [ + { + "type": "package", + "package": { + "name": "guzzle/client-integration-tests", + "version": "v3.0.2", + "dist": { + "url": "https://codeload.github.com/guzzle/client-integration-tests/zip/2c025848417c1135031fdf9c728ee53d0a7ceaee", + "type": "zip" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.11", + "php-http/message": "^1.0 || ^2.0", + "guzzlehttp/psr7": "^1.7 || ^2.0", + "th3n3rd/cartesian-product": "^0.3" + }, + "autoload": { + "psr-4": { + "Http\\Client\\Tests\\": "src/" + } + }, + "bin": [ + "bin/http_test_server" + ] + } + } + ], + "require": { + "php": "^7.2.5 || ^8.0", + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "bamarni/composer-bin-plugin": "^1.8.2", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "config": { + "allow-plugins": { + "bamarni/composer-bin-plugin": true + }, + "preferred-install": "dist", + "sort-packages": true + }, + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "autoload-dev": { + "psr-4": { + "GuzzleHttp\\Tests\\": "tests/" + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/package-lock.json b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/package-lock.json new file mode 100644 index 000000000..0e14dc181 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "guzzle", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizer.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizer.php new file mode 100644 index 000000000..761506dd0 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizer.php @@ -0,0 +1,28 @@ +truncateAt = $truncateAt; + } + + /** + * Returns a summarized message body. + */ + public function summarize(MessageInterface $message): ?string + { + return $this->truncateAt === null + ? Psr7\Message::bodySummary($message) + : Psr7\Message::bodySummary($message, $this->truncateAt); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizerInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizerInterface.php new file mode 100644 index 000000000..3e02e036e --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/BodySummarizerInterface.php @@ -0,0 +1,13 @@ + 'http://www.foo.com/1.0/', + * 'timeout' => 0, + * 'allow_redirects' => false, + * 'proxy' => '192.168.16.1:10' + * ]); + * + * Client configuration settings include the following options: + * + * - handler: (callable) Function that transfers HTTP requests over the + * wire. The function is called with a Psr7\Http\Message\RequestInterface + * and array of transfer options, and must return a + * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a + * Psr7\Http\Message\ResponseInterface on success. + * If no handler is provided, a default handler will be created + * that enables all of the request options below by attaching all of the + * default middleware to the handler. + * - base_uri: (string|UriInterface) Base URI of the client that is merged + * into relative URIs. Can be a string or instance of UriInterface. + * - **: any request option + * + * @param array $config Client configuration settings. + * + * @see RequestOptions for a list of available request options. + */ + public function __construct(array $config = []) + { + if (!isset($config['handler'])) { + $config['handler'] = HandlerStack::create(); + } elseif (!\is_callable($config['handler'])) { + throw new InvalidArgumentException('handler must be a callable'); + } + + // Convert the base_uri to a UriInterface + if (isset($config['base_uri'])) { + $config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']); + } + + $this->configureDefaults($config); + } + + /** + * @param string $method + * @param array $args + * + * @return PromiseInterface|ResponseInterface + * + * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0. + */ + public function __call($method, $args) + { + if (\count($args) < 1) { + throw new InvalidArgumentException('Magic request methods require a URI and optional options array'); + } + + $uri = $args[0]; + $opts = $args[1] ?? []; + + return \substr($method, -5) === 'Async' + ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts) + : $this->request($method, $uri, $opts); + } + + /** + * Asynchronously send an HTTP request. + * + * @param array $options Request options to apply to the given + * request and to the transfer. See \GuzzleHttp\RequestOptions. + */ + public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface + { + // Merge the base URI into the request URI if needed. + $options = $this->prepareDefaults($options); + + return $this->transfer( + $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')), + $options + ); + } + + /** + * Send an HTTP request. + * + * @param array $options Request options to apply to the given + * request and to the transfer. See \GuzzleHttp\RequestOptions. + * + * @throws GuzzleException + */ + public function send(RequestInterface $request, array $options = []): ResponseInterface + { + $options[RequestOptions::SYNCHRONOUS] = true; + + return $this->sendAsync($request, $options)->wait(); + } + + /** + * The HttpClient PSR (PSR-18) specify this method. + * + * {@inheritDoc} + */ + public function sendRequest(RequestInterface $request): ResponseInterface + { + $options[RequestOptions::SYNCHRONOUS] = true; + $options[RequestOptions::ALLOW_REDIRECTS] = false; + $options[RequestOptions::HTTP_ERRORS] = false; + + return $this->sendAsync($request, $options)->wait(); + } + + /** + * Create and send an asynchronous HTTP request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string $method HTTP method + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions. + */ + public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface + { + $options = $this->prepareDefaults($options); + // Remove request modifying parameter because it can be done up-front. + $headers = $options['headers'] ?? []; + $body = $options['body'] ?? null; + $version = $options['version'] ?? '1.1'; + // Merge the URI into the base URI. + $uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options); + if (\is_array($body)) { + throw $this->invalidBody(); + } + $request = new Psr7\Request($method, $uri, $headers, $body, $version); + // Remove the option so that they are not doubly-applied. + unset($options['headers'], $options['body'], $options['version']); + + return $this->transfer($request, $options); + } + + /** + * Create and send an HTTP request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string $method HTTP method. + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions. + * + * @throws GuzzleException + */ + public function request(string $method, $uri = '', array $options = []): ResponseInterface + { + $options[RequestOptions::SYNCHRONOUS] = true; + + return $this->requestAsync($method, $uri, $options)->wait(); + } + + /** + * Get a client configuration option. + * + * These options include default request options of the client, a "handler" + * (if utilized by the concrete client), and a "base_uri" if utilized by + * the concrete client. + * + * @param string|null $option The config option to retrieve. + * + * @return mixed + * + * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0. + */ + public function getConfig(?string $option = null) + { + return $option === null + ? $this->config + : ($this->config[$option] ?? null); + } + + private function buildUri(UriInterface $uri, array $config): UriInterface + { + if (isset($config['base_uri'])) { + $uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri); + } + + if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) { + $idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion']; + $uri = Utils::idnUriConvert($uri, $idnOptions); + } + + return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri; + } + + /** + * Configures the default options for a client. + */ + private function configureDefaults(array $config): void + { + $defaults = [ + 'allow_redirects' => RedirectMiddleware::$defaultSettings, + 'http_errors' => true, + 'decode_content' => true, + 'verify' => true, + 'cookies' => false, + 'idn_conversion' => false, + ]; + + // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set. + + // We can only trust the HTTP_PROXY environment variable in a CLI + // process due to the fact that PHP has no reliable mechanism to + // get environment variables that start with "HTTP_". + if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) { + $defaults['proxy']['http'] = $proxy; + } + + if ($proxy = Utils::getenv('HTTPS_PROXY')) { + $defaults['proxy']['https'] = $proxy; + } + + if ($noProxy = Utils::getenv('NO_PROXY')) { + $cleanedNoProxy = \str_replace(' ', '', $noProxy); + $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy); + } + + $this->config = $config + $defaults; + + if (!empty($config['cookies']) && $config['cookies'] === true) { + $this->config['cookies'] = new CookieJar(); + } + + // Add the default user-agent header. + if (!isset($this->config['headers'])) { + $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()]; + } else { + // Add the User-Agent header if one was not already set. + foreach (\array_keys($this->config['headers']) as $name) { + if (\strtolower($name) === 'user-agent') { + return; + } + } + $this->config['headers']['User-Agent'] = Utils::defaultUserAgent(); + } + } + + /** + * Merges default options into the array. + * + * @param array $options Options to modify by reference + */ + private function prepareDefaults(array $options): array + { + $defaults = $this->config; + + if (!empty($defaults['headers'])) { + // Default headers are only added if they are not present. + $defaults['_conditional'] = $defaults['headers']; + unset($defaults['headers']); + } + + // Special handling for headers is required as they are added as + // conditional headers and as headers passed to a request ctor. + if (\array_key_exists('headers', $options)) { + // Allows default headers to be unset. + if ($options['headers'] === null) { + $defaults['_conditional'] = []; + unset($options['headers']); + } elseif (!\is_array($options['headers'])) { + throw new InvalidArgumentException('headers must be an array'); + } + } + + // Shallow merge defaults underneath options. + $result = $options + $defaults; + + // Remove null values. + foreach ($result as $k => $v) { + if ($v === null) { + unset($result[$k]); + } + } + + return $result; + } + + /** + * Transfers the given request and applies request options. + * + * The URI of the request is not modified and the request options are used + * as-is without merging in default options. + * + * @param array $options See \GuzzleHttp\RequestOptions. + */ + private function transfer(RequestInterface $request, array $options): PromiseInterface + { + $request = $this->applyOptions($request, $options); + /** @var HandlerStack $handler */ + $handler = $options['handler']; + + try { + return P\Create::promiseFor($handler($request, $options)); + } catch (\Exception $e) { + return P\Create::rejectionFor($e); + } + } + + /** + * Applies the array of request options to a request. + */ + private function applyOptions(RequestInterface $request, array &$options): RequestInterface + { + $modify = [ + 'set_headers' => [], + ]; + + if (isset($options['headers'])) { + if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) { + throw new InvalidArgumentException('The headers array must have header name as keys.'); + } + $modify['set_headers'] = $options['headers']; + unset($options['headers']); + } + + if (isset($options['form_params'])) { + if (isset($options['multipart'])) { + throw new InvalidArgumentException('You cannot use ' + .'form_params and multipart at the same time. Use the ' + .'form_params option if you want to send application/' + .'x-www-form-urlencoded requests, and the multipart ' + .'option to send multipart/form-data requests.'); + } + $options['body'] = \http_build_query($options['form_params'], '', '&'); + unset($options['form_params']); + // Ensure that we don't have the header in different case and set the new value. + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']); + $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded'; + } + + if (isset($options['multipart'])) { + $options['body'] = new Psr7\MultipartStream($options['multipart']); + unset($options['multipart']); + } + + if (isset($options['json'])) { + $options['body'] = Utils::jsonEncode($options['json']); + unset($options['json']); + // Ensure that we don't have the header in different case and set the new value. + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']); + $options['_conditional']['Content-Type'] = 'application/json'; + } + + if (!empty($options['decode_content']) + && $options['decode_content'] !== true + ) { + // Ensure that we don't have the header in different case and set the new value. + $options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']); + $modify['set_headers']['Accept-Encoding'] = $options['decode_content']; + } + + if (isset($options['body'])) { + if (\is_array($options['body'])) { + throw $this->invalidBody(); + } + $modify['body'] = Psr7\Utils::streamFor($options['body']); + unset($options['body']); + } + + if (!empty($options['auth']) && \is_array($options['auth'])) { + $value = $options['auth']; + $type = isset($value[2]) ? \strtolower($value[2]) : 'basic'; + switch ($type) { + case 'basic': + // Ensure that we don't have the header in different case and set the new value. + $modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']); + $modify['set_headers']['Authorization'] = 'Basic ' + .\base64_encode("$value[0]:$value[1]"); + break; + case 'digest': + // @todo: Do not rely on curl + $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST; + $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]"; + break; + case 'ntlm': + $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM; + $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]"; + break; + } + } + + if (isset($options['query'])) { + $value = $options['query']; + if (\is_array($value)) { + $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986); + } + if (!\is_string($value)) { + throw new InvalidArgumentException('query must be a string or array'); + } + $modify['query'] = $value; + unset($options['query']); + } + + // Ensure that sink is not an invalid value. + if (isset($options['sink'])) { + // TODO: Add more sink validation? + if (\is_bool($options['sink'])) { + throw new InvalidArgumentException('sink must not be a boolean'); + } + } + + if (isset($options['version'])) { + $modify['version'] = $options['version']; + } + + $request = Psr7\Utils::modifyRequest($request, $modify); + if ($request->getBody() instanceof Psr7\MultipartStream) { + // Use a multipart/form-data POST if a Content-Type is not set. + // Ensure that we don't have the header in different case and set the new value. + $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']); + $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary=' + .$request->getBody()->getBoundary(); + } + + // Merge in conditional headers if they are not present. + if (isset($options['_conditional'])) { + // Build up the changes so it's in a single clone of the message. + $modify = []; + foreach ($options['_conditional'] as $k => $v) { + if (!$request->hasHeader($k)) { + $modify['set_headers'][$k] = $v; + } + } + $request = Psr7\Utils::modifyRequest($request, $modify); + // Don't pass this internal value along to middleware/handlers. + unset($options['_conditional']); + } + + return $request; + } + + /** + * Return an InvalidArgumentException with pre-set message. + */ + private function invalidBody(): InvalidArgumentException + { + return new InvalidArgumentException('Passing in the "body" request ' + .'option as an array to send a request is not supported. ' + .'Please use the "form_params" request option to send a ' + .'application/x-www-form-urlencoded request, or the "multipart" ' + .'request option to send a multipart/form-data request.'); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/ClientInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/ClientInterface.php new file mode 100644 index 000000000..6aaee61af --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/ClientInterface.php @@ -0,0 +1,84 @@ +request('GET', $uri, $options); + } + + /** + * Create and send an HTTP HEAD request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + * + * @throws GuzzleException + */ + public function head($uri, array $options = []): ResponseInterface + { + return $this->request('HEAD', $uri, $options); + } + + /** + * Create and send an HTTP PUT request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + * + * @throws GuzzleException + */ + public function put($uri, array $options = []): ResponseInterface + { + return $this->request('PUT', $uri, $options); + } + + /** + * Create and send an HTTP POST request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + * + * @throws GuzzleException + */ + public function post($uri, array $options = []): ResponseInterface + { + return $this->request('POST', $uri, $options); + } + + /** + * Create and send an HTTP PATCH request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + * + * @throws GuzzleException + */ + public function patch($uri, array $options = []): ResponseInterface + { + return $this->request('PATCH', $uri, $options); + } + + /** + * Create and send an HTTP DELETE request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + * + * @throws GuzzleException + */ + public function delete($uri, array $options = []): ResponseInterface + { + return $this->request('DELETE', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string $method HTTP method + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + abstract public function requestAsync(string $method, $uri, array $options = []): PromiseInterface; + + /** + * Create and send an asynchronous HTTP GET request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function getAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('GET', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP HEAD request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function headAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('HEAD', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP PUT request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function putAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('PUT', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP POST request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function postAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('POST', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP PATCH request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function patchAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('PATCH', $uri, $options); + } + + /** + * Create and send an asynchronous HTTP DELETE request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. + */ + public function deleteAsync($uri, array $options = []): PromiseInterface + { + return $this->requestAsync('DELETE', $uri, $options); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJar.php new file mode 100644 index 000000000..b616cf2ed --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJar.php @@ -0,0 +1,307 @@ +strictMode = $strictMode; + + foreach ($cookieArray as $cookie) { + if (!($cookie instanceof SetCookie)) { + $cookie = new SetCookie($cookie); + } + $this->setCookie($cookie); + } + } + + /** + * Create a new Cookie jar from an associative array and domain. + * + * @param array $cookies Cookies to create the jar from + * @param string $domain Domain to set the cookies to + */ + public static function fromArray(array $cookies, string $domain): self + { + $cookieJar = new self(); + foreach ($cookies as $name => $value) { + $cookieJar->setCookie(new SetCookie([ + 'Domain' => $domain, + 'Name' => $name, + 'Value' => $value, + 'Discard' => true, + ])); + } + + return $cookieJar; + } + + /** + * Evaluate if this cookie should be persisted to storage + * that survives between requests. + * + * @param SetCookie $cookie Being evaluated. + * @param bool $allowSessionCookies If we should persist session cookies + */ + public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool + { + if ($cookie->getExpires() || $allowSessionCookies) { + if (!$cookie->getDiscard()) { + return true; + } + } + + return false; + } + + /** + * Finds and returns the cookie based on the name + * + * @param string $name cookie name to search for + * + * @return SetCookie|null cookie that was found or null if not found + */ + public function getCookieByName(string $name): ?SetCookie + { + foreach ($this->cookies as $cookie) { + if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) { + return $cookie; + } + } + + return null; + } + + public function toArray(): array + { + return \array_map(static function (SetCookie $cookie): array { + return $cookie->toArray(); + }, $this->getIterator()->getArrayCopy()); + } + + public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void + { + if (!$domain) { + $this->cookies = []; + + return; + } elseif (!$path) { + $this->cookies = \array_filter( + $this->cookies, + static function (SetCookie $cookie) use ($domain): bool { + return !$cookie->matchesDomain($domain); + } + ); + } elseif (!$name) { + $this->cookies = \array_filter( + $this->cookies, + static function (SetCookie $cookie) use ($path, $domain): bool { + return !($cookie->matchesPath($path) + && $cookie->matchesDomain($domain)); + } + ); + } else { + $this->cookies = \array_filter( + $this->cookies, + static function (SetCookie $cookie) use ($path, $domain, $name) { + return !($cookie->getName() == $name + && $cookie->matchesPath($path) + && $cookie->matchesDomain($domain)); + } + ); + } + } + + public function clearSessionCookies(): void + { + $this->cookies = \array_filter( + $this->cookies, + static function (SetCookie $cookie): bool { + return !$cookie->getDiscard() && $cookie->getExpires(); + } + ); + } + + public function setCookie(SetCookie $cookie): bool + { + // If the name string is empty (but not 0), ignore the set-cookie + // string entirely. + $name = $cookie->getName(); + if (!$name && $name !== '0') { + return false; + } + + // Only allow cookies with set and valid domain, name, value + $result = $cookie->validate(); + if ($result !== true) { + if ($this->strictMode) { + throw new \RuntimeException('Invalid cookie: '.$result); + } + $this->removeCookieIfEmpty($cookie); + + return false; + } + + // Resolve conflicts with previously set cookies + foreach ($this->cookies as $i => $c) { + // Two cookies are identical, when their path, and domain are + // identical. + if ($c->getPath() != $cookie->getPath() + || $c->getDomain() != $cookie->getDomain() + || $c->getName() != $cookie->getName() + ) { + continue; + } + + // The previously set cookie is a discard cookie and this one is + // not so allow the new cookie to be set + if (!$cookie->getDiscard() && $c->getDiscard()) { + unset($this->cookies[$i]); + continue; + } + + // If the new cookie's expiration is further into the future, then + // replace the old cookie + if ($cookie->getExpires() > $c->getExpires()) { + unset($this->cookies[$i]); + continue; + } + + // If the value has changed, we better change it + if ($cookie->getValue() !== $c->getValue()) { + unset($this->cookies[$i]); + continue; + } + + // The cookie exists, so no need to continue + return false; + } + + $this->cookies[] = $cookie; + + return true; + } + + public function count(): int + { + return \count($this->cookies); + } + + /** + * @return \ArrayIterator + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator(\array_values($this->cookies)); + } + + public function extractCookies(RequestInterface $request, ResponseInterface $response): void + { + if ($cookieHeader = $response->getHeader('Set-Cookie')) { + foreach ($cookieHeader as $cookie) { + $sc = SetCookie::fromString($cookie); + if (!$sc->getDomain()) { + $sc->setDomain($request->getUri()->getHost()); + } + if (0 !== \strpos($sc->getPath(), '/')) { + $sc->setPath($this->getCookiePathFromRequest($request)); + } + if (!$sc->matchesDomain($request->getUri()->getHost())) { + continue; + } + // Note: At this point `$sc->getDomain()` being a public suffix should + // be rejected, but we don't want to pull in the full PSL dependency. + $this->setCookie($sc); + } + } + } + + /** + * Computes cookie path following RFC 6265 section 5.1.4 + * + * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4 + */ + private function getCookiePathFromRequest(RequestInterface $request): string + { + $uriPath = $request->getUri()->getPath(); + if ('' === $uriPath) { + return '/'; + } + if (0 !== \strpos($uriPath, '/')) { + return '/'; + } + if ('/' === $uriPath) { + return '/'; + } + $lastSlashPos = \strrpos($uriPath, '/'); + if (0 === $lastSlashPos || false === $lastSlashPos) { + return '/'; + } + + return \substr($uriPath, 0, $lastSlashPos); + } + + public function withCookieHeader(RequestInterface $request): RequestInterface + { + $values = []; + $uri = $request->getUri(); + $scheme = $uri->getScheme(); + $host = $uri->getHost(); + $path = $uri->getPath() ?: '/'; + + foreach ($this->cookies as $cookie) { + if ($cookie->matchesPath($path) + && $cookie->matchesDomain($host) + && !$cookie->isExpired() + && (!$cookie->getSecure() || $scheme === 'https') + ) { + $values[] = $cookie->getName().'=' + .$cookie->getValue(); + } + } + + return $values + ? $request->withHeader('Cookie', \implode('; ', $values)) + : $request; + } + + /** + * If a cookie already exists and the server asks to set it again with a + * null value, the cookie must be deleted. + */ + private function removeCookieIfEmpty(SetCookie $cookie): void + { + $cookieValue = $cookie->getValue(); + if ($cookieValue === null || $cookieValue === '') { + $this->clear( + $cookie->getDomain(), + $cookie->getPath(), + $cookie->getName() + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php new file mode 100644 index 000000000..93ada58d2 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php @@ -0,0 +1,80 @@ + + */ +interface CookieJarInterface extends \Countable, \IteratorAggregate +{ + /** + * Create a request with added cookie headers. + * + * If no matching cookies are found in the cookie jar, then no Cookie + * header is added to the request and the same request is returned. + * + * @param RequestInterface $request Request object to modify. + * + * @return RequestInterface returns the modified request. + */ + public function withCookieHeader(RequestInterface $request): RequestInterface; + + /** + * Extract cookies from an HTTP response and store them in the CookieJar. + * + * @param RequestInterface $request Request that was sent + * @param ResponseInterface $response Response that was received + */ + public function extractCookies(RequestInterface $request, ResponseInterface $response): void; + + /** + * Sets a cookie in the cookie jar. + * + * @param SetCookie $cookie Cookie to set. + * + * @return bool Returns true on success or false on failure + */ + public function setCookie(SetCookie $cookie): bool; + + /** + * Remove cookies currently held in the cookie jar. + * + * Invoking this method without arguments will empty the whole cookie jar. + * If given a $domain argument only cookies belonging to that domain will + * be removed. If given a $domain and $path argument, cookies belonging to + * the specified path within that domain are removed. If given all three + * arguments, then the cookie with the specified name, path and domain is + * removed. + * + * @param string|null $domain Clears cookies matching a domain + * @param string|null $path Clears cookies matching a domain and path + * @param string|null $name Clears cookies matching a domain, path, and name + */ + public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void; + + /** + * Discard all sessions cookies. + * + * Removes cookies that don't have an expire field or a have a discard + * field set to true. To be called when the user agent shuts down according + * to RFC 2965. + */ + public function clearSessionCookies(): void; + + /** + * Converts the cookie jar to an array. + */ + public function toArray(): array; +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php new file mode 100644 index 000000000..290236d54 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php @@ -0,0 +1,101 @@ +filename = $cookieFile; + $this->storeSessionCookies = $storeSessionCookies; + + if (\file_exists($cookieFile)) { + $this->load($cookieFile); + } + } + + /** + * Saves the file when shutting down + */ + public function __destruct() + { + $this->save($this->filename); + } + + /** + * Saves the cookies to a file. + * + * @param string $filename File to save + * + * @throws \RuntimeException if the file cannot be found or created + */ + public function save(string $filename): void + { + $json = []; + /** @var SetCookie $cookie */ + foreach ($this as $cookie) { + if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) { + $json[] = $cookie->toArray(); + } + } + + $jsonStr = Utils::jsonEncode($json); + if (false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) { + throw new \RuntimeException("Unable to save file {$filename}"); + } + } + + /** + * Load cookies from a JSON formatted file. + * + * Old cookies are kept unless overwritten by newly loaded ones. + * + * @param string $filename Cookie file to load. + * + * @throws \RuntimeException if the file cannot be loaded. + */ + public function load(string $filename): void + { + $json = \file_get_contents($filename); + if (false === $json) { + throw new \RuntimeException("Unable to load file {$filename}"); + } + if ($json === '') { + return; + } + + $data = Utils::jsonDecode($json, true); + if (\is_array($data)) { + foreach ($data as $cookie) { + $this->setCookie(new SetCookie($cookie)); + } + } elseif (\is_scalar($data) && !empty($data)) { + throw new \RuntimeException("Invalid cookie file: {$filename}"); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php new file mode 100644 index 000000000..cb3e67c6a --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php @@ -0,0 +1,77 @@ +sessionKey = $sessionKey; + $this->storeSessionCookies = $storeSessionCookies; + $this->load(); + } + + /** + * Saves cookies to session when shutting down + */ + public function __destruct() + { + $this->save(); + } + + /** + * Save cookies to the client session + */ + public function save(): void + { + $json = []; + /** @var SetCookie $cookie */ + foreach ($this as $cookie) { + if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) { + $json[] = $cookie->toArray(); + } + } + + $_SESSION[$this->sessionKey] = \json_encode($json); + } + + /** + * Load the contents of the client session into the data array + */ + protected function load(): void + { + if (!isset($_SESSION[$this->sessionKey])) { + return; + } + $data = \json_decode($_SESSION[$this->sessionKey], true); + if (\is_array($data)) { + foreach ($data as $cookie) { + $this->setCookie(new SetCookie($cookie)); + } + } elseif (\strlen($data)) { + throw new \RuntimeException('Invalid cookie data'); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SetCookie.php new file mode 100644 index 000000000..47c4d10ae --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -0,0 +1,492 @@ + null, + 'Value' => null, + 'Domain' => null, + 'Path' => '/', + 'Max-Age' => null, + 'Expires' => null, + 'Secure' => false, + 'Discard' => false, + 'HttpOnly' => false, + ]; + + /** + * @var array Cookie data + */ + private $data; + + /** + * Create a new SetCookie object from a string. + * + * @param string $cookie Set-Cookie header string + */ + public static function fromString(string $cookie): self + { + // Create the default return array + $data = self::$defaults; + // Explode the cookie string using a series of semicolons + $pieces = \array_filter(\array_map('trim', \explode(';', $cookie))); + // The name of the cookie (first kvp) must exist and include an equal sign. + if (!isset($pieces[0]) || \strpos($pieces[0], '=') === false) { + return new self($data); + } + + // Add the cookie pieces into the parsed data array + foreach ($pieces as $part) { + $cookieParts = \explode('=', $part, 2); + $key = \trim($cookieParts[0]); + $value = isset($cookieParts[1]) + ? \trim($cookieParts[1], " \n\r\t\0\x0B") + : true; + + // Only check for non-cookies when cookies have been found + if (!isset($data['Name'])) { + $data['Name'] = $key; + $data['Value'] = $value; + } else { + foreach (\array_keys(self::$defaults) as $search) { + if (!\strcasecmp($search, $key)) { + if ($search === 'Max-Age') { + if (is_numeric($value)) { + $data[$search] = (int) $value; + } + } elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') { + if ($value) { + $data[$search] = true; + } + } else { + $data[$search] = $value; + } + continue 2; + } + } + $data[$key] = $value; + } + } + + return new self($data); + } + + /** + * @param array $data Array of cookie data provided by a Cookie parser + */ + public function __construct(array $data = []) + { + $this->data = self::$defaults; + + if (isset($data['Name'])) { + $this->setName($data['Name']); + } + + if (isset($data['Value'])) { + $this->setValue($data['Value']); + } + + if (isset($data['Domain'])) { + $this->setDomain($data['Domain']); + } + + if (isset($data['Path'])) { + $this->setPath($data['Path']); + } + + if (isset($data['Max-Age'])) { + $this->setMaxAge($data['Max-Age']); + } + + if (isset($data['Expires'])) { + $this->setExpires($data['Expires']); + } + + if (isset($data['Secure'])) { + $this->setSecure($data['Secure']); + } + + if (isset($data['Discard'])) { + $this->setDiscard($data['Discard']); + } + + if (isset($data['HttpOnly'])) { + $this->setHttpOnly($data['HttpOnly']); + } + + // Set the remaining values that don't have extra validation logic + foreach (array_diff(array_keys($data), array_keys(self::$defaults)) as $key) { + $this->data[$key] = $data[$key]; + } + + // Extract the Expires value and turn it into a UNIX timestamp if needed + if (!$this->getExpires() && $this->getMaxAge()) { + // Calculate the Expires date + $this->setExpires(\time() + $this->getMaxAge()); + } elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) { + $this->setExpires($expires); + } + } + + public function __toString() + { + $str = $this->data['Name'].'='.($this->data['Value'] ?? '').'; '; + foreach ($this->data as $k => $v) { + if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) { + if ($k === 'Expires') { + $str .= 'Expires='.\gmdate('D, d M Y H:i:s \G\M\T', $v).'; '; + } else { + $str .= ($v === true ? $k : "{$k}={$v}").'; '; + } + } + } + + return \rtrim($str, '; '); + } + + public function toArray(): array + { + return $this->data; + } + + /** + * Get the cookie name. + * + * @return string + */ + public function getName() + { + return $this->data['Name']; + } + + /** + * Set the cookie name. + * + * @param string $name Cookie name + */ + public function setName($name): void + { + if (!is_string($name)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Name'] = (string) $name; + } + + /** + * Get the cookie value. + * + * @return string|null + */ + public function getValue() + { + return $this->data['Value']; + } + + /** + * Set the cookie value. + * + * @param string $value Cookie value + */ + public function setValue($value): void + { + if (!is_string($value)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Value'] = (string) $value; + } + + /** + * Get the domain. + * + * @return string|null + */ + public function getDomain() + { + return $this->data['Domain']; + } + + /** + * Set the domain of the cookie. + * + * @param string|null $domain + */ + public function setDomain($domain): void + { + if (!is_string($domain) && null !== $domain) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Domain'] = null === $domain ? null : (string) $domain; + } + + /** + * Get the path. + * + * @return string + */ + public function getPath() + { + return $this->data['Path']; + } + + /** + * Set the path of the cookie. + * + * @param string $path Path of the cookie + */ + public function setPath($path): void + { + if (!is_string($path)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Path'] = (string) $path; + } + + /** + * Maximum lifetime of the cookie in seconds. + * + * @return int|null + */ + public function getMaxAge() + { + return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age']; + } + + /** + * Set the max-age of the cookie. + * + * @param int|null $maxAge Max age of the cookie in seconds + */ + public function setMaxAge($maxAge): void + { + if (!is_int($maxAge) && null !== $maxAge) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge; + } + + /** + * The UNIX timestamp when the cookie Expires. + * + * @return string|int|null + */ + public function getExpires() + { + return $this->data['Expires']; + } + + /** + * Set the unix timestamp for which the cookie will expire. + * + * @param int|string|null $timestamp Unix timestamp or any English textual datetime description. + */ + public function setExpires($timestamp): void + { + if (!is_int($timestamp) && !is_string($timestamp) && null !== $timestamp) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp)); + } + + /** + * Get whether or not this is a secure cookie. + * + * @return bool + */ + public function getSecure() + { + return $this->data['Secure']; + } + + /** + * Set whether or not the cookie is secure. + * + * @param bool $secure Set to true or false if secure + */ + public function setSecure($secure): void + { + if (!is_bool($secure)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Secure'] = (bool) $secure; + } + + /** + * Get whether or not this is a session cookie. + * + * @return bool|null + */ + public function getDiscard() + { + return $this->data['Discard']; + } + + /** + * Set whether or not this is a session cookie. + * + * @param bool $discard Set to true or false if this is a session cookie + */ + public function setDiscard($discard): void + { + if (!is_bool($discard)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['Discard'] = (bool) $discard; + } + + /** + * Get whether or not this is an HTTP only cookie. + * + * @return bool + */ + public function getHttpOnly() + { + return $this->data['HttpOnly']; + } + + /** + * Set whether or not this is an HTTP only cookie. + * + * @param bool $httpOnly Set to true or false if this is HTTP only + */ + public function setHttpOnly($httpOnly): void + { + if (!is_bool($httpOnly)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->data['HttpOnly'] = (bool) $httpOnly; + } + + /** + * Check if the cookie matches a path value. + * + * A request-path path-matches a given cookie-path if at least one of + * the following conditions holds: + * + * - The cookie-path and the request-path are identical. + * - The cookie-path is a prefix of the request-path, and the last + * character of the cookie-path is %x2F ("/"). + * - The cookie-path is a prefix of the request-path, and the first + * character of the request-path that is not included in the cookie- + * path is a %x2F ("/") character. + * + * @param string $requestPath Path to check against + */ + public function matchesPath(string $requestPath): bool + { + $cookiePath = $this->getPath(); + + // Match on exact matches or when path is the default empty "/" + if ($cookiePath === '/' || $cookiePath == $requestPath) { + return true; + } + + // Ensure that the cookie-path is a prefix of the request path. + if (0 !== \strpos($requestPath, $cookiePath)) { + return false; + } + + // Match if the last character of the cookie-path is "/" + if (\substr($cookiePath, -1, 1) === '/') { + return true; + } + + // Match if the first character not included in cookie path is "/" + return \substr($requestPath, \strlen($cookiePath), 1) === '/'; + } + + /** + * Check if the cookie matches a domain value. + * + * @param string $domain Domain to check against + */ + public function matchesDomain(string $domain): bool + { + $cookieDomain = $this->getDomain(); + if (null === $cookieDomain) { + return true; + } + + // Remove the leading '.' as per spec in RFC 6265. + // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3 + $cookieDomain = \ltrim(\strtolower($cookieDomain), '.'); + + $domain = \strtolower($domain); + + // Domain not set or exact match. + if ('' === $cookieDomain || $domain === $cookieDomain) { + return true; + } + + // Matching the subdomain according to RFC 6265. + // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3 + if (\filter_var($domain, \FILTER_VALIDATE_IP)) { + return false; + } + + return (bool) \preg_match('/\.'.\preg_quote($cookieDomain, '/').'$/', $domain); + } + + /** + * Check if the cookie is expired. + */ + public function isExpired(): bool + { + return $this->getExpires() !== null && \time() > $this->getExpires(); + } + + /** + * Check if the cookie is valid according to RFC 6265. + * + * @return bool|string Returns true if valid or an error message if invalid + */ + public function validate() + { + $name = $this->getName(); + if ($name === '') { + return 'The cookie name must not be empty'; + } + + // Check if any of the invalid characters are present in the cookie name + if (\preg_match( + '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/', + $name + )) { + return 'Cookie name must not contain invalid characters: ASCII ' + .'Control characters (0-31;127), space, tab and the ' + .'following characters: ()<>@,;:\"/?={}'; + } + + // Value must not be null. 0 and empty string are valid. Empty strings + // are technically against RFC 6265, but known to happen in the wild. + $value = $this->getValue(); + if ($value === null) { + return 'The cookie value must not be empty'; + } + + // Domains must not be empty, but can be 0. "0" is not a valid internet + // domain, but may be used as server name in a private network. + $domain = $this->getDomain(); + if ($domain === null || $domain === '') { + return 'The cookie domain must not be empty'; + } + + return true; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/BadResponseException.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/BadResponseException.php new file mode 100644 index 000000000..ba67ad498 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/BadResponseException.php @@ -0,0 +1,39 @@ +request = $request; + $this->handlerContext = $handlerContext; + } + + /** + * Get the request that caused the exception + */ + public function getRequest(): RequestInterface + { + return $this->request; + } + + /** + * Get contextual information about the error from the underlying handler. + * + * The contents of this array will vary depending on which handler you are + * using. It may also be just an empty array. Relying on this data will + * couple you to a specific handler, but can give more debug information + * when needed. + */ + public function getHandlerContext(): array + { + return $this->handlerContext; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/GuzzleException.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/GuzzleException.php new file mode 100644 index 000000000..fa3ed6998 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/GuzzleException.php @@ -0,0 +1,9 @@ +getStatusCode() : 0; + parent::__construct($message, $code, $previous); + $this->request = $request; + $this->response = $response; + $this->handlerContext = $handlerContext; + } + + /** + * Wrap non-RequestExceptions with a RequestException + */ + public static function wrapException(RequestInterface $request, \Throwable $e): RequestException + { + return $e instanceof RequestException ? $e : new RequestException($e->getMessage(), $request, null, $e); + } + + /** + * Factory method to create a new exception with a normalized error message + * + * @param RequestInterface $request Request sent + * @param ResponseInterface $response Response received + * @param \Throwable|null $previous Previous exception + * @param array $handlerContext Optional handler context + * @param BodySummarizerInterface|null $bodySummarizer Optional body summarizer + */ + public static function create( + RequestInterface $request, + ?ResponseInterface $response = null, + ?\Throwable $previous = null, + array $handlerContext = [], + ?BodySummarizerInterface $bodySummarizer = null + ): self { + if (!$response) { + return new self( + 'Error completing request', + $request, + null, + $previous, + $handlerContext + ); + } + + $level = (int) \floor($response->getStatusCode() / 100); + if ($level === 4) { + $label = 'Client error'; + $className = ClientException::class; + } elseif ($level === 5) { + $label = 'Server error'; + $className = ServerException::class; + } else { + $label = 'Unsuccessful request'; + $className = __CLASS__; + } + + $uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri()); + + // Client Error: `GET /` resulted in a `404 Not Found` response: + // ... (truncated) + $message = \sprintf( + '%s: `%s %s` resulted in a `%s %s` response', + $label, + $request->getMethod(), + $uri->__toString(), + $response->getStatusCode(), + $response->getReasonPhrase() + ); + + $summary = ($bodySummarizer ?? new BodySummarizer())->summarize($response); + + if ($summary !== null) { + $message .= ":\n{$summary}\n"; + } + + return new $className($message, $request, $response, $previous, $handlerContext); + } + + /** + * Get the request that caused the exception + */ + public function getRequest(): RequestInterface + { + return $this->request; + } + + /** + * Get the associated response + */ + public function getResponse(): ?ResponseInterface + { + return $this->response; + } + + /** + * Check if a response was received + */ + public function hasResponse(): bool + { + return $this->response !== null; + } + + /** + * Get contextual information about the error from the underlying handler. + * + * The contents of this array will vary depending on which handler you are + * using. It may also be just an empty array. Relying on this data will + * couple you to a specific handler, but can give more debug information + * when needed. + */ + public function getHandlerContext(): array + { + return $this->handlerContext; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/ServerException.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/ServerException.php new file mode 100644 index 000000000..8055e067c --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Exception/ServerException.php @@ -0,0 +1,10 @@ +maxHandles = $maxHandles; + } + + public function create(RequestInterface $request, array $options): EasyHandle + { + $protocolVersion = $request->getProtocolVersion(); + + if ('2' === $protocolVersion || '2.0' === $protocolVersion) { + if (!self::supportsHttp2()) { + throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request); + } + } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) { + throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request); + } + + if (isset($options['curl']['body_as_string'])) { + $options['_body_as_string'] = $options['curl']['body_as_string']; + unset($options['curl']['body_as_string']); + } + + $easy = new EasyHandle(); + $easy->request = $request; + $easy->options = $options; + $conf = $this->getDefaultConf($easy); + $this->applyMethod($easy, $conf); + $this->applyHandlerOptions($easy, $conf); + $this->applyHeaders($easy, $conf); + unset($conf['_headers']); + + // Add handler options from the request configuration options + if (isset($options['curl'])) { + $conf = \array_replace($conf, $options['curl']); + } + + $conf[\CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy); + $easy->handle = $this->handles ? \array_pop($this->handles) : \curl_init(); + curl_setopt_array($easy->handle, $conf); + + return $easy; + } + + private static function supportsHttp2(): bool + { + static $supportsHttp2 = null; + + if (null === $supportsHttp2) { + $supportsHttp2 = self::supportsTls12() + && defined('CURL_VERSION_HTTP2') + && (\CURL_VERSION_HTTP2 & \curl_version()['features']); + } + + return $supportsHttp2; + } + + private static function supportsTls12(): bool + { + static $supportsTls12 = null; + + if (null === $supportsTls12) { + $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features']; + } + + return $supportsTls12; + } + + private static function supportsTls13(): bool + { + static $supportsTls13 = null; + + if (null === $supportsTls13) { + $supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3') + && (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']); + } + + return $supportsTls13; + } + + public function release(EasyHandle $easy): void + { + $resource = $easy->handle; + unset($easy->handle); + + if (\count($this->handles) >= $this->maxHandles) { + if (PHP_VERSION_ID < 80000) { + \curl_close($resource); + } + } else { + // Remove all callback functions as they can hold onto references + // and are not cleaned up by curl_reset. Using curl_setopt_array + // does not work for some reason, so removing each one + // individually. + \curl_setopt($resource, \CURLOPT_HEADERFUNCTION, null); + \curl_setopt($resource, \CURLOPT_READFUNCTION, null); + \curl_setopt($resource, \CURLOPT_WRITEFUNCTION, null); + \curl_setopt($resource, \CURLOPT_PROGRESSFUNCTION, null); + \curl_reset($resource); + $this->handles[] = $resource; + } + } + + /** + * Completes a cURL transaction, either returning a response promise or a + * rejected promise. + * + * @param callable(RequestInterface, array): PromiseInterface $handler + * @param CurlFactoryInterface $factory Dictates how the handle is released + */ + public static function finish(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface + { + if (isset($easy->options['on_stats'])) { + self::invokeStats($easy); + } + + if (!$easy->response || $easy->errno) { + return self::finishError($handler, $easy, $factory); + } + + // Return the response if it is present and there is no error. + $factory->release($easy); + + // Rewind the body of the response if possible. + $body = $easy->response->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } + + return new FulfilledPromise($easy->response); + } + + private static function invokeStats(EasyHandle $easy): void + { + $curlStats = \curl_getinfo($easy->handle); + $curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME); + $stats = new TransferStats( + $easy->request, + $easy->response, + $curlStats['total_time'], + $easy->errno, + $curlStats + ); + ($easy->options['on_stats'])($stats); + } + + /** + * @param callable(RequestInterface, array): PromiseInterface $handler + */ + private static function finishError(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface + { + // Get error information and release the handle to the factory. + $ctx = [ + 'errno' => $easy->errno, + 'error' => \curl_error($easy->handle), + 'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME), + ] + \curl_getinfo($easy->handle); + $ctx[self::CURL_VERSION_STR] = self::getCurlVersion(); + $factory->release($easy); + + // Retry when nothing is present or when curl failed to rewind. + if (empty($easy->options['_err_message']) && (!$easy->errno || $easy->errno == 65)) { + return self::retryFailedRewind($handler, $easy, $ctx); + } + + return self::createRejection($easy, $ctx); + } + + private static function getCurlVersion(): string + { + static $curlVersion = null; + + if (null === $curlVersion) { + $curlVersion = \curl_version()['version']; + } + + return $curlVersion; + } + + private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface + { + static $connectionErrors = [ + \CURLE_OPERATION_TIMEOUTED => true, + \CURLE_COULDNT_RESOLVE_HOST => true, + \CURLE_COULDNT_CONNECT => true, + \CURLE_SSL_CONNECT_ERROR => true, + \CURLE_GOT_NOTHING => true, + ]; + + if ($easy->createResponseException) { + return P\Create::rejectionFor( + new RequestException( + 'An error was encountered while creating the response', + $easy->request, + $easy->response, + $easy->createResponseException, + $ctx + ) + ); + } + + // If an exception was encountered during the onHeaders event, then + // return a rejected promise that wraps that exception. + if ($easy->onHeadersException) { + return P\Create::rejectionFor( + new RequestException( + 'An error was encountered during the on_headers event', + $easy->request, + $easy->response, + $easy->onHeadersException, + $ctx + ) + ); + } + + $uri = $easy->request->getUri(); + + $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri); + + $message = \sprintf( + 'cURL error %s: %s (%s)', + $ctx['errno'], + $sanitizedError, + 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html' + ); + + if ('' !== $sanitizedError) { + $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString(); + if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) { + $message .= \sprintf(' for %s', $redactedUriString); + } + } + + // Create a connection exception if it was a specific error code. + $error = isset($connectionErrors[$easy->errno]) + ? new ConnectException($message, $easy->request, null, $ctx) + : new RequestException($message, $easy->request, $easy->response, null, $ctx); + + return P\Create::rejectionFor($error); + } + + private static function sanitizeCurlError(string $error, UriInterface $uri): string + { + if ('' === $error) { + return $error; + } + + $baseUri = $uri->withQuery('')->withFragment(''); + $baseUriString = $baseUri->__toString(); + + if ('' === $baseUriString) { + return $error; + } + + $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString(); + + return str_replace($baseUriString, $redactedUriString, $error); + } + + /** + * @return array + */ + private function getDefaultConf(EasyHandle $easy): array + { + $conf = [ + '_headers' => $easy->request->getHeaders(), + \CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(), + \CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''), + \CURLOPT_RETURNTRANSFER => false, + \CURLOPT_HEADER => false, + \CURLOPT_CONNECTTIMEOUT => 300, + ]; + + if (\defined('CURLOPT_PROTOCOLS')) { + $conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS; + } + + $version = $easy->request->getProtocolVersion(); + + if ('2' === $version || '2.0' === $version) { + $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0; + } elseif ('1.1' === $version) { + $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; + } else { + $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0; + } + + return $conf; + } + + private function applyMethod(EasyHandle $easy, array &$conf): void + { + $body = $easy->request->getBody(); + $size = $body->getSize(); + + if ($size === null || $size > 0) { + $this->applyBody($easy->request, $easy->options, $conf); + + return; + } + + $method = $easy->request->getMethod(); + if ($method === 'PUT' || $method === 'POST') { + // See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 + if (!$easy->request->hasHeader('Content-Length')) { + $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0'; + } + } elseif ($method === 'HEAD') { + $conf[\CURLOPT_NOBODY] = true; + unset( + $conf[\CURLOPT_WRITEFUNCTION], + $conf[\CURLOPT_READFUNCTION], + $conf[\CURLOPT_FILE], + $conf[\CURLOPT_INFILE] + ); + } + } + + private function applyBody(RequestInterface $request, array $options, array &$conf): void + { + $size = $request->hasHeader('Content-Length') + ? (int) $request->getHeaderLine('Content-Length') + : null; + + // Send the body as a string if the size is less than 1MB OR if the + // [curl][body_as_string] request value is set. + if (($size !== null && $size < 1000000) || !empty($options['_body_as_string'])) { + $conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody(); + // Don't duplicate the Content-Length header + $this->removeHeader('Content-Length', $conf); + $this->removeHeader('Transfer-Encoding', $conf); + } else { + $conf[\CURLOPT_UPLOAD] = true; + if ($size !== null) { + $conf[\CURLOPT_INFILESIZE] = $size; + $this->removeHeader('Content-Length', $conf); + } + $body = $request->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } + $conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) { + return $body->read($length); + }; + } + + // If the Expect header is not present, prevent curl from adding it + if (!$request->hasHeader('Expect')) { + $conf[\CURLOPT_HTTPHEADER][] = 'Expect:'; + } + + // cURL sometimes adds a content-type by default. Prevent this. + if (!$request->hasHeader('Content-Type')) { + $conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:'; + } + } + + private function applyHeaders(EasyHandle $easy, array &$conf): void + { + foreach ($conf['_headers'] as $name => $values) { + foreach ($values as $value) { + $value = (string) $value; + if ($value === '') { + // cURL requires a special format for empty headers. + // See https://github.com/guzzle/guzzle/issues/1882 for more details. + $conf[\CURLOPT_HTTPHEADER][] = "$name;"; + } else { + $conf[\CURLOPT_HTTPHEADER][] = "$name: $value"; + } + } + } + + // Remove the Accept header if one was not set + if (!$easy->request->hasHeader('Accept')) { + $conf[\CURLOPT_HTTPHEADER][] = 'Accept:'; + } + } + + /** + * Remove a header from the options array. + * + * @param string $name Case-insensitive header to remove + * @param array $options Array of options to modify + */ + private function removeHeader(string $name, array &$options): void + { + foreach (\array_keys($options['_headers']) as $key) { + if (!\strcasecmp($key, $name)) { + unset($options['_headers'][$key]); + + return; + } + } + } + + private function applyHandlerOptions(EasyHandle $easy, array &$conf): void + { + $options = $easy->options; + if (isset($options['verify'])) { + if ($options['verify'] === false) { + unset($conf[\CURLOPT_CAINFO]); + $conf[\CURLOPT_SSL_VERIFYHOST] = 0; + $conf[\CURLOPT_SSL_VERIFYPEER] = false; + } else { + $conf[\CURLOPT_SSL_VERIFYHOST] = 2; + $conf[\CURLOPT_SSL_VERIFYPEER] = true; + if (\is_string($options['verify'])) { + // Throw an error if the file/folder/link path is not valid or doesn't exist. + if (!\file_exists($options['verify'])) { + throw new \InvalidArgumentException("SSL CA bundle not found: {$options['verify']}"); + } + // If it's a directory or a link to a directory use CURLOPT_CAPATH. + // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO. + if ( + \is_dir($options['verify']) + || ( + \is_link($options['verify']) === true + && ($verifyLink = \readlink($options['verify'])) !== false + && \is_dir($verifyLink) + ) + ) { + $conf[\CURLOPT_CAPATH] = $options['verify']; + } else { + $conf[\CURLOPT_CAINFO] = $options['verify']; + } + } + } + } + + if (!isset($options['curl'][\CURLOPT_ENCODING]) && !empty($options['decode_content'])) { + $accept = $easy->request->getHeaderLine('Accept-Encoding'); + if ($accept) { + $conf[\CURLOPT_ENCODING] = $accept; + } else { + // The empty string enables all available decoders and implicitly + // sets a matching 'Accept-Encoding' header. + $conf[\CURLOPT_ENCODING] = ''; + // But as the user did not specify any encoding preference, + // let's leave it up to server by preventing curl from sending + // the header, which will be interpreted as 'Accept-Encoding: *'. + // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding + $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:'; + } + } + + if (!isset($options['sink'])) { + // Use a default temp stream if no sink was set. + $options['sink'] = \GuzzleHttp\Psr7\Utils::tryFopen('php://temp', 'w+'); + } + $sink = $options['sink']; + if (!\is_string($sink)) { + $sink = \GuzzleHttp\Psr7\Utils::streamFor($sink); + } elseif (!\is_dir(\dirname($sink))) { + // Ensure that the directory exists before failing in curl. + throw new \RuntimeException(\sprintf('Directory %s does not exist for sink value of %s', \dirname($sink), $sink)); + } else { + $sink = new LazyOpenStream($sink, 'w+'); + } + $easy->sink = $sink; + $conf[\CURLOPT_WRITEFUNCTION] = static function ($ch, $write) use ($sink): int { + return $sink->write($write); + }; + + $timeoutRequiresNoSignal = false; + if (isset($options['timeout'])) { + $timeoutRequiresNoSignal |= $options['timeout'] < 1; + $conf[\CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000; + } + + // CURL default value is CURL_IPRESOLVE_WHATEVER + if (isset($options['force_ip_resolve'])) { + if ('v4' === $options['force_ip_resolve']) { + $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4; + } elseif ('v6' === $options['force_ip_resolve']) { + $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V6; + } + } + + if (isset($options['connect_timeout'])) { + $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1; + $conf[\CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000; + } + + if ($timeoutRequiresNoSignal && \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN') { + $conf[\CURLOPT_NOSIGNAL] = true; + } + + if (isset($options['proxy'])) { + if (!\is_array($options['proxy'])) { + $conf[\CURLOPT_PROXY] = $options['proxy']; + } else { + $scheme = $easy->request->getUri()->getScheme(); + if (isset($options['proxy'][$scheme])) { + $host = $easy->request->getUri()->getHost(); + if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) { + unset($conf[\CURLOPT_PROXY]); + } else { + $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme]; + } + } + } + } + + if (isset($options['crypto_method'])) { + $protocolVersion = $easy->request->getProtocolVersion(); + + // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2 + if ('2' === $protocolVersion || '2.0' === $protocolVersion) { + if ( + \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method'] + || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method'] + || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method'] + ) { + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2; + } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) { + if (!self::supportsTls13()) { + throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL'); + } + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3; + } else { + throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided'); + } + } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) { + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0; + } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) { + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1; + } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) { + if (!self::supportsTls12()) { + throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL'); + } + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2; + } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) { + if (!self::supportsTls13()) { + throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL'); + } + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3; + } else { + throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided'); + } + } + + if (isset($options['cert'])) { + $cert = $options['cert']; + if (\is_array($cert)) { + $conf[\CURLOPT_SSLCERTPASSWD] = $cert[1]; + $cert = $cert[0]; + } + if (!\file_exists($cert)) { + throw new \InvalidArgumentException("SSL certificate not found: {$cert}"); + } + // OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files. + // see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html + $ext = pathinfo($cert, \PATHINFO_EXTENSION); + if (preg_match('#^(der|p12)$#i', $ext)) { + $conf[\CURLOPT_SSLCERTTYPE] = strtoupper($ext); + } + $conf[\CURLOPT_SSLCERT] = $cert; + } + + if (isset($options['ssl_key'])) { + if (\is_array($options['ssl_key'])) { + if (\count($options['ssl_key']) === 2) { + [$sslKey, $conf[\CURLOPT_SSLKEYPASSWD]] = $options['ssl_key']; + } else { + [$sslKey] = $options['ssl_key']; + } + } + + $sslKey = $sslKey ?? $options['ssl_key']; + + if (!\file_exists($sslKey)) { + throw new \InvalidArgumentException("SSL private key not found: {$sslKey}"); + } + $conf[\CURLOPT_SSLKEY] = $sslKey; + } + + if (isset($options['progress'])) { + $progress = $options['progress']; + if (!\is_callable($progress)) { + throw new \InvalidArgumentException('progress client option must be callable'); + } + $conf[\CURLOPT_NOPROGRESS] = false; + $conf[\CURLOPT_PROGRESSFUNCTION] = static function ($resource, int $downloadSize, int $downloaded, int $uploadSize, int $uploaded) use ($progress) { + $progress($downloadSize, $downloaded, $uploadSize, $uploaded); + }; + } + + if (!empty($options['debug'])) { + $conf[\CURLOPT_STDERR] = Utils::debugResource($options['debug']); + $conf[\CURLOPT_VERBOSE] = true; + } + } + + /** + * This function ensures that a response was set on a transaction. If one + * was not set, then the request is retried if possible. This error + * typically means you are sending a payload, curl encountered a + * "Connection died, retrying a fresh connect" error, tried to rewind the + * stream, and then encountered a "necessary data rewind wasn't possible" + * error, causing the request to be sent through curl_multi_info_read() + * without an error status. + * + * @param callable(RequestInterface, array): PromiseInterface $handler + */ + private static function retryFailedRewind(callable $handler, EasyHandle $easy, array $ctx): PromiseInterface + { + try { + // Only rewind if the body has been read from. + $body = $easy->request->getBody(); + if ($body->tell() > 0) { + $body->rewind(); + } + } catch (\RuntimeException $e) { + $ctx['error'] = 'The connection unexpectedly failed without ' + .'providing an error. The request would have been retried, ' + .'but attempting to rewind the request body failed. ' + .'Exception: '.$e; + + return self::createRejection($easy, $ctx); + } + + // Retry no more than 3 times before giving up. + if (!isset($easy->options['_curl_retries'])) { + $easy->options['_curl_retries'] = 1; + } elseif ($easy->options['_curl_retries'] == 2) { + $ctx['error'] = 'The cURL request was retried 3 times ' + .'and did not succeed. The most likely reason for the failure ' + .'is that cURL was unable to rewind the body of the request ' + .'and subsequent retries resulted in the same error. Turn on ' + .'the debug option to see what went wrong. See ' + .'https://bugs.php.net/bug.php?id=47204 for more information.'; + + return self::createRejection($easy, $ctx); + } else { + ++$easy->options['_curl_retries']; + } + + return $handler($easy->request, $easy->options); + } + + private function createHeaderFn(EasyHandle $easy): callable + { + if (isset($easy->options['on_headers'])) { + $onHeaders = $easy->options['on_headers']; + + if (!\is_callable($onHeaders)) { + throw new \InvalidArgumentException('on_headers must be callable'); + } + } else { + $onHeaders = null; + } + + return static function ($ch, $h) use ( + $onHeaders, + $easy, + &$startingResponse + ) { + $value = \trim($h); + if ($value === '') { + $startingResponse = true; + try { + $easy->createResponse(); + } catch (\Exception $e) { + $easy->createResponseException = $e; + + return -1; + } + if ($onHeaders !== null) { + try { + $onHeaders($easy->response); + } catch (\Exception $e) { + // Associate the exception with the handle and trigger + // a curl header write error by returning 0. + $easy->onHeadersException = $e; + + return -1; + } + } + } elseif ($startingResponse) { + $startingResponse = false; + $easy->headers = [$value]; + } else { + $easy->headers[] = $value; + } + + return \strlen($h); + }; + } + + public function __destruct() + { + foreach ($this->handles as $id => $handle) { + if (PHP_VERSION_ID < 80000) { + \curl_close($handle); + } + + unset($this->handles[$id]); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php new file mode 100644 index 000000000..fe57ed5d5 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php @@ -0,0 +1,25 @@ +factory = $options['handle_factory'] + ?? new CurlFactory(3); + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + if (isset($options['delay'])) { + \usleep($options['delay'] * 1000); + } + + $easy = $this->factory->create($request, $options); + \curl_exec($easy->handle); + $easy->errno = \curl_errno($easy->handle); + + return CurlFactory::finish($this, $easy, $this->factory); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php new file mode 100644 index 000000000..21abbedf3 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php @@ -0,0 +1,287 @@ + An array of delay times, indexed by handle id in `addRequest`. + * + * @see CurlMultiHandler::addRequest + */ + private $delays = []; + + /** + * @var array An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt() + */ + private $options = []; + + /** @var resource|\CurlMultiHandle */ + private $_mh; + + /** + * This handler accepts the following options: + * + * - handle_factory: An optional factory used to create curl handles + * - select_timeout: Optional timeout (in seconds) to block before timing + * out while selecting curl handles. Defaults to 1 second. + * - options: An associative array of CURLMOPT_* options and + * corresponding values for curl_multi_setopt() + */ + public function __construct(array $options = []) + { + $this->factory = $options['handle_factory'] ?? new CurlFactory(50); + + if (isset($options['select_timeout'])) { + $this->selectTimeout = $options['select_timeout']; + } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) { + @trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED); + $this->selectTimeout = (int) $selectTimeout; + } else { + $this->selectTimeout = 1; + } + + $this->options = $options['options'] ?? []; + + // unsetting the property forces the first access to go through + // __get(). + unset($this->_mh); + } + + /** + * @param string $name + * + * @return resource|\CurlMultiHandle + * + * @throws \BadMethodCallException when another field as `_mh` will be gotten + * @throws \RuntimeException when curl can not initialize a multi handle + */ + public function __get($name) + { + if ($name !== '_mh') { + throw new \BadMethodCallException("Can not get other property as '_mh'."); + } + + $multiHandle = \curl_multi_init(); + + if (false === $multiHandle) { + throw new \RuntimeException('Can not initialize curl multi handle.'); + } + + $this->_mh = $multiHandle; + + foreach ($this->options as $option => $value) { + // A warning is raised in case of a wrong option. + curl_multi_setopt($this->_mh, $option, $value); + } + + return $this->_mh; + } + + public function __destruct() + { + if (isset($this->_mh)) { + \curl_multi_close($this->_mh); + unset($this->_mh); + } + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + $easy = $this->factory->create($request, $options); + $id = (int) $easy->handle; + + $promise = new Promise( + [$this, 'execute'], + function () use ($id) { + return $this->cancel($id); + } + ); + + $this->addRequest(['easy' => $easy, 'deferred' => $promise]); + + return $promise; + } + + /** + * Ticks the curl event loop. + */ + public function tick(): void + { + // Add any delayed handles if needed. + if ($this->delays) { + $currentTime = Utils::currentTime(); + foreach ($this->delays as $id => $delay) { + if ($currentTime >= $delay) { + unset($this->delays[$id]); + \curl_multi_add_handle( + $this->_mh, + $this->handles[$id]['easy']->handle + ); + } + } + } + + // Run curl_multi_exec in the queue to enable other async tasks to run + P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue'])); + + // Step through the task queue which may add additional requests. + P\Utils::queue()->run(); + + if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) { + // Perform a usleep if a select returns -1. + // See: https://bugs.php.net/bug.php?id=61141 + \usleep(250); + } + + while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) { + // Prevent busy looping for slow HTTP requests. + \curl_multi_select($this->_mh, $this->selectTimeout); + } + + $this->processMessages(); + } + + /** + * Runs \curl_multi_exec() inside the event loop, to prevent busy looping + */ + private function tickInQueue(): void + { + if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) { + \curl_multi_select($this->_mh, 0); + P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue'])); + } + } + + /** + * Runs until all outstanding connections have completed. + */ + public function execute(): void + { + $queue = P\Utils::queue(); + + while ($this->handles || !$queue->isEmpty()) { + // If there are no transfers, then sleep for the next delay + if (!$this->active && $this->delays) { + \usleep($this->timeToNext()); + } + $this->tick(); + } + } + + private function addRequest(array $entry): void + { + $easy = $entry['easy']; + $id = (int) $easy->handle; + $this->handles[$id] = $entry; + if (empty($easy->options['delay'])) { + \curl_multi_add_handle($this->_mh, $easy->handle); + } else { + $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000); + } + } + + /** + * Cancels a handle from sending and removes references to it. + * + * @param int $id Handle ID to cancel and remove. + * + * @return bool True on success, false on failure. + */ + private function cancel($id): bool + { + if (!is_int($id)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + // Cannot cancel if it has been processed. + if (!isset($this->handles[$id])) { + return false; + } + + $handle = $this->handles[$id]['easy']->handle; + unset($this->delays[$id], $this->handles[$id]); + \curl_multi_remove_handle($this->_mh, $handle); + + if (PHP_VERSION_ID < 80000) { + \curl_close($handle); + } + + return true; + } + + private function processMessages(): void + { + while ($done = \curl_multi_info_read($this->_mh)) { + if ($done['msg'] !== \CURLMSG_DONE) { + // if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216 + continue; + } + $id = (int) $done['handle']; + \curl_multi_remove_handle($this->_mh, $done['handle']); + + if (!isset($this->handles[$id])) { + // Probably was cancelled. + continue; + } + + $entry = $this->handles[$id]; + unset($this->handles[$id], $this->delays[$id]); + $entry['easy']->errno = $done['result']; + $entry['deferred']->resolve( + CurlFactory::finish($this, $entry['easy'], $this->factory) + ); + } + } + + private function timeToNext(): int + { + $currentTime = Utils::currentTime(); + $nextTime = \PHP_INT_MAX; + foreach ($this->delays as $time) { + if ($time < $nextTime) { + $nextTime = $time; + } + } + + return ((int) \max(0, $nextTime - $currentTime)) * 1000000; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/EasyHandle.php new file mode 100644 index 000000000..1bc39f4b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/EasyHandle.php @@ -0,0 +1,112 @@ +headers); + + $normalizedKeys = Utils::normalizeHeaderKeys($headers); + + if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) { + $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']]; + unset($headers[$normalizedKeys['content-encoding']]); + if (isset($normalizedKeys['content-length'])) { + $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']]; + + $bodyLength = (int) $this->sink->getSize(); + if ($bodyLength) { + $headers[$normalizedKeys['content-length']] = $bodyLength; + } else { + unset($headers[$normalizedKeys['content-length']]); + } + } + } + + // Attach a response to the easy handle with the parsed headers. + $this->response = new Response( + $status, + $headers, + $this->sink, + $ver, + $reason + ); + } + + /** + * @param string $name + * + * @return void + * + * @throws \BadMethodCallException + */ + public function __get($name) + { + $msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: '.$name; + throw new \BadMethodCallException($msg); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php new file mode 100644 index 000000000..5554b8fa9 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php @@ -0,0 +1,42 @@ +|null $queue The parameters to be passed to the append function, as an indexed array. + * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled. + * @param callable|null $onRejected Callback to invoke when the return value is rejected. + */ + public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null) + { + $this->onFulfilled = $onFulfilled; + $this->onRejected = $onRejected; + + if ($queue) { + // array_values included for BC + $this->append(...array_values($queue)); + } + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + if (!$this->queue) { + throw new \OutOfBoundsException('Mock queue is empty'); + } + + if (isset($options['delay']) && \is_numeric($options['delay'])) { + \usleep((int) $options['delay'] * 1000); + } + + $this->lastRequest = $request; + $this->lastOptions = $options; + $response = \array_shift($this->queue); + + if (isset($options['on_headers'])) { + if (!\is_callable($options['on_headers'])) { + throw new \InvalidArgumentException('on_headers must be callable'); + } + try { + $options['on_headers']($response); + } catch (\Exception $e) { + $msg = 'An error was encountered during the on_headers event'; + $response = new RequestException($msg, $request, $response, $e); + } + } + + if (\is_callable($response)) { + $response = $response($request, $options); + } + + $response = $response instanceof \Throwable + ? P\Create::rejectionFor($response) + : P\Create::promiseFor($response); + + return $response->then( + function (?ResponseInterface $value) use ($request, $options) { + $this->invokeStats($request, $options, $value); + if ($this->onFulfilled) { + ($this->onFulfilled)($value); + } + + if ($value !== null && isset($options['sink'])) { + $contents = (string) $value->getBody(); + $sink = $options['sink']; + + if (\is_resource($sink)) { + \fwrite($sink, $contents); + } elseif (\is_string($sink)) { + \file_put_contents($sink, $contents); + } elseif ($sink instanceof StreamInterface) { + $sink->write($contents); + } + } + + return $value; + }, + function ($reason) use ($request, $options) { + $this->invokeStats($request, $options, null, $reason); + if ($this->onRejected) { + ($this->onRejected)($reason); + } + + return P\Create::rejectionFor($reason); + } + ); + } + + /** + * Adds one or more variadic requests, exceptions, callables, or promises + * to the queue. + * + * @param mixed ...$values + */ + public function append(...$values): void + { + foreach ($values as $value) { + if ($value instanceof ResponseInterface + || $value instanceof \Throwable + || $value instanceof PromiseInterface + || \is_callable($value) + ) { + $this->queue[] = $value; + } else { + throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found '.Utils::describeType($value)); + } + } + } + + /** + * Get the last received request. + */ + public function getLastRequest(): ?RequestInterface + { + return $this->lastRequest; + } + + /** + * Get the last received request options. + */ + public function getLastOptions(): array + { + return $this->lastOptions; + } + + /** + * Returns the number of remaining items in the queue. + */ + public function count(): int + { + return \count($this->queue); + } + + public function reset(): void + { + $this->queue = []; + } + + /** + * @param mixed $reason Promise or reason. + */ + private function invokeStats( + RequestInterface $request, + array $options, + ?ResponseInterface $response = null, + $reason = null + ): void { + if (isset($options['on_stats'])) { + $transferTime = $options['transfer_time'] ?? 0; + $stats = new TransferStats($request, $response, $transferTime, $reason); + ($options['on_stats'])($stats); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/Proxy.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/Proxy.php new file mode 100644 index 000000000..9df70cf23 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Handler/Proxy.php @@ -0,0 +1,51 @@ +getProtocolVersion(); + + if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) { + throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request); + } + + $startTime = isset($options['on_stats']) ? Utils::currentTime() : null; + + try { + // Does not support the expect header. + $request = $request->withoutHeader('Expect'); + + // Append a content-length header if body size is zero to match + // the behavior of `CurlHandler` + if ( + ( + 0 === \strcasecmp('PUT', $request->getMethod()) + || 0 === \strcasecmp('POST', $request->getMethod()) + ) + && 0 === $request->getBody()->getSize() + ) { + $request = $request->withHeader('Content-Length', '0'); + } + + return $this->createResponse( + $request, + $options, + $this->createStream($request, $options), + $startTime + ); + } catch (\InvalidArgumentException $e) { + throw $e; + } catch (\Exception $e) { + // Determine if the error was a networking error. + $message = $e->getMessage(); + // This list can probably get more comprehensive. + if (false !== \strpos($message, 'getaddrinfo') // DNS lookup failed + || false !== \strpos($message, 'Connection refused') + || false !== \strpos($message, "couldn't connect to host") // error on HHVM + || false !== \strpos($message, 'connection attempt failed') + ) { + $e = new ConnectException($e->getMessage(), $request, $e); + } else { + $e = RequestException::wrapException($request, $e); + } + $this->invokeStats($options, $request, $startTime, null, $e); + + return P\Create::rejectionFor($e); + } + } + + private function invokeStats( + array $options, + RequestInterface $request, + ?float $startTime, + ?ResponseInterface $response = null, + ?\Throwable $error = null + ): void { + if (isset($options['on_stats'])) { + $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []); + ($options['on_stats'])($stats); + } + } + + /** + * @param resource $stream + */ + private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime): PromiseInterface + { + $hdrs = $this->lastHeaders; + $this->lastHeaders = []; + + try { + [$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs); + } catch (\Exception $e) { + return P\Create::rejectionFor( + new RequestException('An error was encountered while creating the response', $request, null, $e) + ); + } + + [$stream, $headers] = $this->checkDecode($options, $headers, $stream); + $stream = Psr7\Utils::streamFor($stream); + $sink = $stream; + + if (\strcasecmp('HEAD', $request->getMethod())) { + $sink = $this->createSink($stream, $options); + } + + try { + $response = new Psr7\Response($status, $headers, $sink, $ver, $reason); + } catch (\Exception $e) { + return P\Create::rejectionFor( + new RequestException('An error was encountered while creating the response', $request, null, $e) + ); + } + + if (isset($options['on_headers'])) { + try { + $options['on_headers']($response); + } catch (\Exception $e) { + return P\Create::rejectionFor( + new RequestException('An error was encountered during the on_headers event', $request, $response, $e) + ); + } + } + + // Do not drain when the request is a HEAD request because they have + // no body. + if ($sink !== $stream) { + $this->drain($stream, $sink, $response->getHeaderLine('Content-Length')); + } + + $this->invokeStats($options, $request, $startTime, $response, null); + + return new FulfilledPromise($response); + } + + private function createSink(StreamInterface $stream, array $options): StreamInterface + { + if (!empty($options['stream'])) { + return $stream; + } + + $sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+'); + + return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink); + } + + /** + * @param resource $stream + */ + private function checkDecode(array $options, array $headers, $stream): array + { + // Automatically decode responses when instructed. + if (!empty($options['decode_content'])) { + $normalizedKeys = Utils::normalizeHeaderKeys($headers); + if (isset($normalizedKeys['content-encoding'])) { + $encoding = $headers[$normalizedKeys['content-encoding']]; + if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') { + $stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream)); + $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']]; + + // Remove content-encoding header + unset($headers[$normalizedKeys['content-encoding']]); + + // Fix content-length header + if (isset($normalizedKeys['content-length'])) { + $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']]; + $length = (int) $stream->getSize(); + if ($length === 0) { + unset($headers[$normalizedKeys['content-length']]); + } else { + $headers[$normalizedKeys['content-length']] = [$length]; + } + } + } + } + } + + return [$stream, $headers]; + } + + /** + * Drains the source stream into the "sink" client option. + * + * @param string $contentLength Header specifying the amount of + * data to read. + * + * @throws \RuntimeException when the sink option is invalid. + */ + private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength): StreamInterface + { + // If a content-length header is provided, then stop reading once + // that number of bytes has been read. This can prevent infinitely + // reading from a stream when dealing with servers that do not honor + // Connection: Close headers. + Psr7\Utils::copyToStream( + $source, + $sink, + (\strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1 + ); + + $sink->seek(0); + $source->close(); + + return $sink; + } + + /** + * Create a resource and check to ensure it was created successfully + * + * @param callable $callback Callable that returns stream resource + * + * @return resource + * + * @throws \RuntimeException on error + */ + private function createResource(callable $callback) + { + $errors = []; + \set_error_handler(static function ($_, $msg, $file, $line) use (&$errors): bool { + $errors[] = [ + 'message' => $msg, + 'file' => $file, + 'line' => $line, + ]; + + return true; + }); + + try { + $resource = $callback(); + } finally { + \restore_error_handler(); + } + + if (!$resource) { + $message = 'Error creating resource: '; + foreach ($errors as $err) { + foreach ($err as $key => $value) { + $message .= "[$key] $value".\PHP_EOL; + } + } + throw new \RuntimeException(\trim($message)); + } + + return $resource; + } + + /** + * @return resource + */ + private function createStream(RequestInterface $request, array $options) + { + static $methods; + if (!$methods) { + $methods = \array_flip(\get_class_methods(__CLASS__)); + } + + if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) { + throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request); + } + + // HTTP/1.1 streams using the PHP stream wrapper require a + // Connection: close header + if ($request->getProtocolVersion() === '1.1' + && !$request->hasHeader('Connection') + ) { + $request = $request->withHeader('Connection', 'close'); + } + + // Ensure SSL is verified by default + if (!isset($options['verify'])) { + $options['verify'] = true; + } + + $params = []; + $context = $this->getDefaultContext($request); + + if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) { + throw new \InvalidArgumentException('on_headers must be callable'); + } + + if (!empty($options)) { + foreach ($options as $key => $value) { + $method = "add_{$key}"; + if (isset($methods[$method])) { + $this->{$method}($request, $context, $value, $params); + } + } + } + + if (isset($options['stream_context'])) { + if (!\is_array($options['stream_context'])) { + throw new \InvalidArgumentException('stream_context must be an array'); + } + $context = \array_replace_recursive($context, $options['stream_context']); + } + + // Microsoft NTLM authentication only supported with curl handler + if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) { + throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler'); + } + + $uri = $this->resolveHost($request, $options); + + $contextResource = $this->createResource( + static function () use ($context, $params) { + return \stream_context_create($context, $params); + } + ); + + return $this->createResource( + function () use ($uri, $contextResource, $context, $options, $request) { + $resource = @\fopen((string) $uri, 'r', false, $contextResource); + + // See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable + if (function_exists('http_get_last_response_headers')) { + /** @var array|null */ + $http_response_header = \http_get_last_response_headers(); + } + + $this->lastHeaders = $http_response_header ?? []; + + if (false === $resource) { + throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context); + } + + if (isset($options['read_timeout'])) { + $readTimeout = $options['read_timeout']; + $sec = (int) $readTimeout; + $usec = ($readTimeout - $sec) * 100000; + \stream_set_timeout($resource, $sec, $usec); + } + + return $resource; + } + ); + } + + private function resolveHost(RequestInterface $request, array $options): UriInterface + { + $uri = $request->getUri(); + + if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) { + if ('v4' === $options['force_ip_resolve']) { + $records = \dns_get_record($uri->getHost(), \DNS_A); + if (false === $records || !isset($records[0]['ip'])) { + throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request); + } + + return $uri->withHost($records[0]['ip']); + } + if ('v6' === $options['force_ip_resolve']) { + $records = \dns_get_record($uri->getHost(), \DNS_AAAA); + if (false === $records || !isset($records[0]['ipv6'])) { + throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request); + } + + return $uri->withHost('['.$records[0]['ipv6'].']'); + } + } + + return $uri; + } + + private function getDefaultContext(RequestInterface $request): array + { + $headers = ''; + foreach ($request->getHeaders() as $name => $value) { + foreach ($value as $val) { + $headers .= "$name: $val\r\n"; + } + } + + $context = [ + 'http' => [ + 'method' => $request->getMethod(), + 'header' => $headers, + 'protocol_version' => $request->getProtocolVersion(), + 'ignore_errors' => true, + 'follow_location' => 0, + ], + 'ssl' => [ + 'peer_name' => $request->getUri()->getHost(), + ], + ]; + + $body = (string) $request->getBody(); + + if ('' !== $body) { + $context['http']['content'] = $body; + // Prevent the HTTP handler from adding a Content-Type header. + if (!$request->hasHeader('Content-Type')) { + $context['http']['header'] .= "Content-Type:\r\n"; + } + } + + $context['http']['header'] = \rtrim($context['http']['header']); + + return $context; + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_proxy(RequestInterface $request, array &$options, $value, array &$params): void + { + $uri = null; + + if (!\is_array($value)) { + $uri = $value; + } else { + $scheme = $request->getUri()->getScheme(); + if (isset($value[$scheme])) { + if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) { + $uri = $value[$scheme]; + } + } + } + + if (!$uri) { + return; + } + + $parsed = $this->parse_proxy($uri); + $options['http']['proxy'] = $parsed['proxy']; + + if ($parsed['auth']) { + if (!isset($options['http']['header'])) { + $options['http']['header'] = []; + } + $options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}"; + } + } + + /** + * Parses the given proxy URL to make it compatible with the format PHP's stream context expects. + */ + private function parse_proxy(string $url): array + { + $parsed = \parse_url($url); + + if ($parsed !== false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') { + if (isset($parsed['host']) && isset($parsed['port'])) { + $auth = null; + if (isset($parsed['user']) && isset($parsed['pass'])) { + $auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}"); + } + + return [ + 'proxy' => "tcp://{$parsed['host']}:{$parsed['port']}", + 'auth' => $auth ? "Basic {$auth}" : null, + ]; + } + } + + // Return proxy as-is. + return [ + 'proxy' => $url, + 'auth' => null, + ]; + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_timeout(RequestInterface $request, array &$options, $value, array &$params): void + { + if ($value > 0) { + $options['http']['timeout'] = $value; + } + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params): void + { + if ( + $value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT + || $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT + || $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT + || (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT) + ) { + $options['http']['crypto_method'] = $value; + + return; + } + + throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided'); + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_verify(RequestInterface $request, array &$options, $value, array &$params): void + { + if ($value === false) { + $options['ssl']['verify_peer'] = false; + $options['ssl']['verify_peer_name'] = false; + + return; + } + + if (\is_string($value)) { + $options['ssl']['cafile'] = $value; + if (!\file_exists($value)) { + throw new \RuntimeException("SSL CA bundle not found: $value"); + } + } elseif ($value !== true) { + throw new \InvalidArgumentException('Invalid verify request option'); + } + + $options['ssl']['verify_peer'] = true; + $options['ssl']['verify_peer_name'] = true; + $options['ssl']['allow_self_signed'] = false; + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_cert(RequestInterface $request, array &$options, $value, array &$params): void + { + if (\is_array($value)) { + $options['ssl']['passphrase'] = $value[1]; + $value = $value[0]; + } + + if (!\file_exists($value)) { + throw new \RuntimeException("SSL certificate not found: {$value}"); + } + + $options['ssl']['local_cert'] = $value; + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_progress(RequestInterface $request, array &$options, $value, array &$params): void + { + self::addNotification( + $params, + static function ($code, $a, $b, $c, $transferred, $total) use ($value) { + if ($code == \STREAM_NOTIFY_PROGRESS) { + // The upload progress cannot be determined. Use 0 for cURL compatibility: + // https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html + $value($total, $transferred, 0, 0); + } + } + ); + } + + /** + * @param mixed $value as passed via Request transfer options. + */ + private function add_debug(RequestInterface $request, array &$options, $value, array &$params): void + { + if ($value === false) { + return; + } + + static $map = [ + \STREAM_NOTIFY_CONNECT => 'CONNECT', + \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', + \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', + \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', + \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', + \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', + \STREAM_NOTIFY_PROGRESS => 'PROGRESS', + \STREAM_NOTIFY_FAILURE => 'FAILURE', + \STREAM_NOTIFY_COMPLETED => 'COMPLETED', + \STREAM_NOTIFY_RESOLVE => 'RESOLVE', + ]; + static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max']; + + $value = Utils::debugResource($value); + $ident = $request->getMethod().' '.$request->getUri()->withFragment(''); + self::addNotification( + $params, + static function (int $code, ...$passed) use ($ident, $value, $map, $args): void { + \fprintf($value, '<%s> [%s] ', $ident, $map[$code]); + foreach (\array_filter($passed) as $i => $v) { + \fwrite($value, $args[$i].': "'.$v.'" '); + } + \fwrite($value, "\n"); + } + ); + } + + private static function addNotification(array &$params, callable $notify): void + { + // Wrap the existing function if needed. + if (!isset($params['notification'])) { + $params['notification'] = $notify; + } else { + $params['notification'] = self::callArray([ + $params['notification'], + $notify, + ]); + } + } + + private static function callArray(array $functions): callable + { + return static function (...$args) use ($functions) { + foreach ($functions as $fn) { + $fn(...$args); + } + }; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/HandlerStack.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/HandlerStack.php new file mode 100644 index 000000000..03f9a18ff --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/HandlerStack.php @@ -0,0 +1,275 @@ +push(Middleware::httpErrors(), 'http_errors'); + $stack->push(Middleware::redirect(), 'allow_redirects'); + $stack->push(Middleware::cookies(), 'cookies'); + $stack->push(Middleware::prepareBody(), 'prepare_body'); + + return $stack; + } + + /** + * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler. + */ + public function __construct(?callable $handler = null) + { + $this->handler = $handler; + } + + /** + * Invokes the handler stack as a composed handler + * + * @return ResponseInterface|PromiseInterface + */ + public function __invoke(RequestInterface $request, array $options) + { + $handler = $this->resolve(); + + return $handler($request, $options); + } + + /** + * Dumps a string representation of the stack. + * + * @return string + */ + public function __toString() + { + $depth = 0; + $stack = []; + + if ($this->handler !== null) { + $stack[] = '0) Handler: '.$this->debugCallable($this->handler); + } + + $result = ''; + foreach (\array_reverse($this->stack) as $tuple) { + ++$depth; + $str = "{$depth}) Name: '{$tuple[1]}', "; + $str .= 'Function: '.$this->debugCallable($tuple[0]); + $result = "> {$str}\n{$result}"; + $stack[] = $str; + } + + foreach (\array_keys($stack) as $k) { + $result .= "< {$stack[$k]}\n"; + } + + return $result; + } + + /** + * Set the HTTP handler that actually returns a promise. + * + * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and + * returns a Promise. + */ + public function setHandler(callable $handler): void + { + $this->handler = $handler; + $this->cached = null; + } + + /** + * Returns true if the builder has a handler. + */ + public function hasHandler(): bool + { + return $this->handler !== null; + } + + /** + * Unshift a middleware to the bottom of the stack. + * + * @param callable(callable): callable $middleware Middleware function + * @param string $name Name to register for this middleware. + */ + public function unshift(callable $middleware, ?string $name = null): void + { + \array_unshift($this->stack, [$middleware, $name]); + $this->cached = null; + } + + /** + * Push a middleware to the top of the stack. + * + * @param callable(callable): callable $middleware Middleware function + * @param string $name Name to register for this middleware. + */ + public function push(callable $middleware, string $name = ''): void + { + $this->stack[] = [$middleware, $name]; + $this->cached = null; + } + + /** + * Add a middleware before another middleware by name. + * + * @param string $findName Middleware to find + * @param callable(callable): callable $middleware Middleware function + * @param string $withName Name to register for this middleware. + */ + public function before(string $findName, callable $middleware, string $withName = ''): void + { + $this->splice($findName, $withName, $middleware, true); + } + + /** + * Add a middleware after another middleware by name. + * + * @param string $findName Middleware to find + * @param callable(callable): callable $middleware Middleware function + * @param string $withName Name to register for this middleware. + */ + public function after(string $findName, callable $middleware, string $withName = ''): void + { + $this->splice($findName, $withName, $middleware, false); + } + + /** + * Remove a middleware by instance or name from the stack. + * + * @param callable|string $remove Middleware to remove by instance or name. + */ + public function remove($remove): void + { + if (!is_string($remove) && !is_callable($remove)) { + trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__); + } + + $this->cached = null; + $idx = \is_callable($remove) ? 0 : 1; + $this->stack = \array_values(\array_filter( + $this->stack, + static function ($tuple) use ($idx, $remove) { + return $tuple[$idx] !== $remove; + } + )); + } + + /** + * Compose the middleware and handler into a single callable function. + * + * @return callable(RequestInterface, array): PromiseInterface + */ + public function resolve(): callable + { + if ($this->cached === null) { + if (($prev = $this->handler) === null) { + throw new \LogicException('No handler has been specified'); + } + + foreach (\array_reverse($this->stack) as $fn) { + /** @var callable(RequestInterface, array): PromiseInterface $prev */ + $prev = $fn[0]($prev); + } + + $this->cached = $prev; + } + + return $this->cached; + } + + private function findByName(string $name): int + { + foreach ($this->stack as $k => $v) { + if ($v[1] === $name) { + return $k; + } + } + + throw new \InvalidArgumentException("Middleware not found: $name"); + } + + /** + * Splices a function into the middleware list at a specific position. + */ + private function splice(string $findName, string $withName, callable $middleware, bool $before): void + { + $this->cached = null; + $idx = $this->findByName($findName); + $tuple = [$middleware, $withName]; + + if ($before) { + if ($idx === 0) { + \array_unshift($this->stack, $tuple); + } else { + $replacement = [$tuple, $this->stack[$idx]]; + \array_splice($this->stack, $idx, 1, $replacement); + } + } elseif ($idx === \count($this->stack) - 1) { + $this->stack[] = $tuple; + } else { + $replacement = [$this->stack[$idx], $tuple]; + \array_splice($this->stack, $idx, 1, $replacement); + } + } + + /** + * Provides a debug string for a given callable. + * + * @param callable|string $fn Function to write as a string. + */ + private function debugCallable($fn): string + { + if (\is_string($fn)) { + return "callable({$fn})"; + } + + if (\is_array($fn)) { + return \is_string($fn[0]) + ? "callable({$fn[0]}::{$fn[1]})" + : "callable(['".\get_class($fn[0])."', '{$fn[1]}'])"; + } + + /** @var object $fn */ + return 'callable('.\spl_object_hash($fn).')'; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatter.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatter.php new file mode 100644 index 000000000..9b77eee83 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatter.php @@ -0,0 +1,199 @@ +>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}"; + public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}'; + + /** + * @var string Template used to format log messages + */ + private $template; + + /** + * @param string $template Log message template + */ + public function __construct(?string $template = self::CLF) + { + $this->template = $template ?: self::CLF; + } + + /** + * Returns a formatted message string. + * + * @param RequestInterface $request Request that was sent + * @param ResponseInterface|null $response Response that was received + * @param \Throwable|null $error Exception that was received + */ + public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string + { + $cache = []; + + /** @var string */ + return \preg_replace_callback( + '/{\s*([A-Za-z_\-\.0-9]+)\s*}/', + function (array $matches) use ($request, $response, $error, &$cache) { + if (isset($cache[$matches[1]])) { + return $cache[$matches[1]]; + } + + $result = ''; + switch ($matches[1]) { + case 'request': + $result = Psr7\Message::toString($request); + break; + case 'response': + $result = $response ? Psr7\Message::toString($response) : ''; + break; + case 'req_headers': + $result = \trim($request->getMethod() + .' '.$request->getRequestTarget()) + .' HTTP/'.$request->getProtocolVersion()."\r\n" + .$this->headers($request); + break; + case 'res_headers': + $result = $response ? + \sprintf( + 'HTTP/%s %d %s', + $response->getProtocolVersion(), + $response->getStatusCode(), + $response->getReasonPhrase() + )."\r\n".$this->headers($response) + : 'NULL'; + break; + case 'req_body': + $result = $request->getBody()->__toString(); + break; + case 'res_body': + if (!$response instanceof ResponseInterface) { + $result = 'NULL'; + break; + } + + $body = $response->getBody(); + + if (!$body->isSeekable()) { + $result = 'RESPONSE_NOT_LOGGEABLE'; + break; + } + + $result = $response->getBody()->__toString(); + break; + case 'ts': + case 'date_iso_8601': + $result = \gmdate('c'); + break; + case 'date_common_log': + $result = \date('d/M/Y:H:i:s O'); + break; + case 'method': + $result = $request->getMethod(); + break; + case 'version': + $result = $request->getProtocolVersion(); + break; + case 'uri': + case 'url': + $result = $request->getUri()->__toString(); + break; + case 'target': + $result = $request->getRequestTarget(); + break; + case 'req_version': + $result = $request->getProtocolVersion(); + break; + case 'res_version': + $result = $response + ? $response->getProtocolVersion() + : 'NULL'; + break; + case 'host': + $result = $request->getHeaderLine('Host'); + break; + case 'hostname': + $result = \gethostname(); + break; + case 'code': + $result = $response ? $response->getStatusCode() : 'NULL'; + break; + case 'phrase': + $result = $response ? $response->getReasonPhrase() : 'NULL'; + break; + case 'error': + $result = $error ? $error->getMessage() : 'NULL'; + break; + default: + // handle prefixed dynamic headers + if (\strpos($matches[1], 'req_header_') === 0) { + $result = $request->getHeaderLine(\substr($matches[1], 11)); + } elseif (\strpos($matches[1], 'res_header_') === 0) { + $result = $response + ? $response->getHeaderLine(\substr($matches[1], 11)) + : 'NULL'; + } + } + + $cache[$matches[1]] = $result; + + return $result; + }, + $this->template + ); + } + + /** + * Get headers from message as string + */ + private function headers(MessageInterface $message): string + { + $result = ''; + foreach ($message->getHeaders() as $name => $values) { + $result .= $name.': '.\implode(', ', $values)."\r\n"; + } + + return \trim($result); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatterInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatterInterface.php new file mode 100644 index 000000000..a39ac248e --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/MessageFormatterInterface.php @@ -0,0 +1,18 @@ +withCookieHeader($request); + + return $handler($request, $options) + ->then( + static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface { + $cookieJar->extractCookies($request, $response); + + return $response; + } + ); + }; + }; + } + + /** + * Middleware that throws exceptions for 4xx or 5xx responses when the + * "http_errors" request option is set to true. + * + * @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages. + * + * @return callable(callable): callable Returns a function that accepts the next handler. + */ + public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable + { + return static function (callable $handler) use ($bodySummarizer): callable { + return static function ($request, array $options) use ($handler, $bodySummarizer) { + if (empty($options['http_errors'])) { + return $handler($request, $options); + } + + return $handler($request, $options)->then( + static function (ResponseInterface $response) use ($request, $bodySummarizer) { + $code = $response->getStatusCode(); + if ($code < 400) { + return $response; + } + throw RequestException::create($request, $response, null, [], $bodySummarizer); + } + ); + }; + }; + } + + /** + * Middleware that pushes history data to an ArrayAccess container. + * + * @param array|\ArrayAccess $container Container to hold the history (by reference). + * + * @return callable(callable): callable Returns a function that accepts the next handler. + * + * @throws \InvalidArgumentException if container is not an array or ArrayAccess. + */ + public static function history(&$container): callable + { + if (!\is_array($container) && !$container instanceof \ArrayAccess) { + throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); + } + + return static function (callable $handler) use (&$container): callable { + return static function (RequestInterface $request, array $options) use ($handler, &$container) { + return $handler($request, $options)->then( + static function ($value) use ($request, &$container, $options) { + $container[] = [ + 'request' => $request, + 'response' => $value, + 'error' => null, + 'options' => $options, + ]; + + return $value; + }, + static function ($reason) use ($request, &$container, $options) { + $container[] = [ + 'request' => $request, + 'response' => null, + 'error' => $reason, + 'options' => $options, + ]; + + return P\Create::rejectionFor($reason); + } + ); + }; + }; + } + + /** + * Middleware that invokes a callback before and after sending a request. + * + * The provided listener cannot modify or alter the response. It simply + * "taps" into the chain to be notified before returning the promise. The + * before listener accepts a request and options array, and the after + * listener accepts a request, options array, and response promise. + * + * @param callable $before Function to invoke before forwarding the request. + * @param callable $after Function invoked after forwarding. + * + * @return callable Returns a function that accepts the next handler. + */ + public static function tap(?callable $before = null, ?callable $after = null): callable + { + return static function (callable $handler) use ($before, $after): callable { + return static function (RequestInterface $request, array $options) use ($handler, $before, $after) { + if ($before) { + $before($request, $options); + } + $response = $handler($request, $options); + if ($after) { + $after($request, $options, $response); + } + + return $response; + }; + }; + } + + /** + * Middleware that handles request redirects. + * + * @return callable Returns a function that accepts the next handler. + */ + public static function redirect(): callable + { + return static function (callable $handler): RedirectMiddleware { + return new RedirectMiddleware($handler); + }; + } + + /** + * Middleware that retries requests based on the boolean result of + * invoking the provided "decider" function. + * + * If no delay function is provided, a simple implementation of exponential + * backoff will be utilized. + * + * @param callable $decider Function that accepts the number of retries, + * a request, [response], and [exception] and + * returns true if the request is to be retried. + * @param callable $delay Function that accepts the number of retries and + * returns the number of milliseconds to delay. + * + * @return callable Returns a function that accepts the next handler. + */ + public static function retry(callable $decider, ?callable $delay = null): callable + { + return static function (callable $handler) use ($decider, $delay): RetryMiddleware { + return new RetryMiddleware($decider, $handler, $delay); + }; + } + + /** + * Middleware that logs requests, responses, and errors using a message + * formatter. + * + * @param LoggerInterface $logger Logs messages. + * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. + * @param string $logLevel Level at which to log requests. + * + * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. + * + * @return callable Returns a function that accepts the next handler. + */ + public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable + { + // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter + if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) { + throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class)); + } + + return static function (callable $handler) use ($logger, $formatter, $logLevel): callable { + return static function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) { + return $handler($request, $options)->then( + static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface { + $message = $formatter->format($request, $response); + $logger->log($logLevel, $message); + + return $response; + }, + static function ($reason) use ($logger, $request, $formatter): PromiseInterface { + $response = $reason instanceof RequestException ? $reason->getResponse() : null; + $message = $formatter->format($request, $response, P\Create::exceptionFor($reason)); + $logger->error($message); + + return P\Create::rejectionFor($reason); + } + ); + }; + }; + } + + /** + * This middleware adds a default content-type if possible, a default + * content-length or transfer-encoding header, and the expect header. + */ + public static function prepareBody(): callable + { + return static function (callable $handler): PrepareBodyMiddleware { + return new PrepareBodyMiddleware($handler); + }; + } + + /** + * Middleware that applies a map function to the request before passing to + * the next handler. + * + * @param callable $fn Function that accepts a RequestInterface and returns + * a RequestInterface. + */ + public static function mapRequest(callable $fn): callable + { + return static function (callable $handler) use ($fn): callable { + return static function (RequestInterface $request, array $options) use ($handler, $fn) { + return $handler($fn($request), $options); + }; + }; + } + + /** + * Middleware that applies a map function to the resolved promise's + * response. + * + * @param callable $fn Function that accepts a ResponseInterface and + * returns a ResponseInterface. + */ + public static function mapResponse(callable $fn): callable + { + return static function (callable $handler) use ($fn): callable { + return static function (RequestInterface $request, array $options) use ($handler, $fn) { + return $handler($request, $options)->then($fn); + }; + }; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Pool.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Pool.php new file mode 100644 index 000000000..ddc304bb1 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Pool.php @@ -0,0 +1,125 @@ + $rfn) { + if ($rfn instanceof RequestInterface) { + yield $key => $client->sendAsync($rfn, $opts); + } elseif (\is_callable($rfn)) { + yield $key => $rfn($opts); + } else { + throw new \InvalidArgumentException('Each value yielded by the iterator must be a Psr7\Http\Message\RequestInterface or a callable that returns a promise that fulfills with a Psr7\Message\Http\ResponseInterface object.'); + } + } + }; + + $this->each = new EachPromise($requests(), $config); + } + + /** + * Get promise + */ + public function promise(): PromiseInterface + { + return $this->each->promise(); + } + + /** + * Sends multiple requests concurrently and returns an array of responses + * and exceptions that uses the same ordering as the provided requests. + * + * IMPORTANT: This method keeps every request and response in memory, and + * as such, is NOT recommended when sending a large number or an + * indeterminate number of requests concurrently. + * + * @param ClientInterface $client Client used to send the requests + * @param array|\Iterator $requests Requests to send concurrently. + * @param array $options Passes through the options available in + * {@see Pool::__construct} + * + * @return array Returns an array containing the response or an exception + * in the same order that the requests were sent. + * + * @throws \InvalidArgumentException if the event format is incorrect. + */ + public static function batch(ClientInterface $client, $requests, array $options = []): array + { + $res = []; + self::cmpCallback($options, 'fulfilled', $res); + self::cmpCallback($options, 'rejected', $res); + $pool = new static($client, $requests, $options); + $pool->promise()->wait(); + \ksort($res); + + return $res; + } + + /** + * Execute callback(s) + */ + private static function cmpCallback(array &$options, string $name, array &$results): void + { + if (!isset($options[$name])) { + $options[$name] = static function ($v, $k) use (&$results) { + $results[$k] = $v; + }; + } else { + $currentFn = $options[$name]; + $options[$name] = static function ($v, $k) use (&$results, $currentFn) { + $currentFn($v, $k); + $results[$k] = $v; + }; + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php new file mode 100644 index 000000000..7dde6c5f4 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php @@ -0,0 +1,105 @@ +nextHandler = $nextHandler; + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + $fn = $this->nextHandler; + + // Don't do anything if the request has no body. + if ($request->getBody()->getSize() === 0) { + return $fn($request, $options); + } + + $modify = []; + + // Add a default content-type if possible. + if (!$request->hasHeader('Content-Type')) { + if ($uri = $request->getBody()->getMetadata('uri')) { + if (is_string($uri) && $type = Psr7\MimeType::fromFilename($uri)) { + $modify['set_headers']['Content-Type'] = $type; + } + } + } + + // Add a default content-length or transfer-encoding header. + if (!$request->hasHeader('Content-Length') + && !$request->hasHeader('Transfer-Encoding') + ) { + $size = $request->getBody()->getSize(); + if ($size !== null) { + $modify['set_headers']['Content-Length'] = $size; + } else { + $modify['set_headers']['Transfer-Encoding'] = 'chunked'; + } + } + + // Add the expect header if needed. + $this->addExpectHeader($request, $options, $modify); + + return $fn(Psr7\Utils::modifyRequest($request, $modify), $options); + } + + /** + * Add expect header + */ + private function addExpectHeader(RequestInterface $request, array $options, array &$modify): void + { + // Determine if the Expect header should be used + if ($request->hasHeader('Expect')) { + return; + } + + $expect = $options['expect'] ?? null; + + // Return if disabled or using HTTP/1.0 + if ($expect === false || $request->getProtocolVersion() === '1.0') { + return; + } + + // The expect header is unconditionally enabled + if ($expect === true) { + $modify['set_headers']['Expect'] = '100-Continue'; + + return; + } + + // By default, send the expect header when the payload is > 1mb + if ($expect === null) { + $expect = 1048576; + } + + // Always add if the body cannot be rewound, the size cannot be + // determined, or the size is greater than the cutoff threshold + $body = $request->getBody(); + $size = $body->getSize(); + + if ($size === null || $size >= (int) $expect || !$body->isSeekable()) { + $modify['set_headers']['Expect'] = '100-Continue'; + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RedirectMiddleware.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RedirectMiddleware.php new file mode 100644 index 000000000..7aa21a623 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RedirectMiddleware.php @@ -0,0 +1,228 @@ + 5, + 'protocols' => ['http', 'https'], + 'strict' => false, + 'referer' => false, + 'track_redirects' => false, + ]; + + /** + * @var callable(RequestInterface, array): PromiseInterface + */ + private $nextHandler; + + /** + * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke. + */ + public function __construct(callable $nextHandler) + { + $this->nextHandler = $nextHandler; + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + $fn = $this->nextHandler; + + if (empty($options['allow_redirects'])) { + return $fn($request, $options); + } + + if ($options['allow_redirects'] === true) { + $options['allow_redirects'] = self::$defaultSettings; + } elseif (!\is_array($options['allow_redirects'])) { + throw new \InvalidArgumentException('allow_redirects must be true, false, or array'); + } else { + // Merge the default settings with the provided settings + $options['allow_redirects'] += self::$defaultSettings; + } + + if (empty($options['allow_redirects']['max'])) { + return $fn($request, $options); + } + + return $fn($request, $options) + ->then(function (ResponseInterface $response) use ($request, $options) { + return $this->checkRedirect($request, $options, $response); + }); + } + + /** + * @return ResponseInterface|PromiseInterface + */ + public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) + { + if (\strpos((string) $response->getStatusCode(), '3') !== 0 + || !$response->hasHeader('Location') + ) { + return $response; + } + + $this->guardMax($request, $response, $options); + $nextRequest = $this->modifyRequest($request, $options, $response); + + // If authorization is handled by curl, unset it if URI is cross-origin. + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\CURLOPT_HTTPAUTH')) { + unset( + $options['curl'][\CURLOPT_HTTPAUTH], + $options['curl'][\CURLOPT_USERPWD] + ); + } + + if (isset($options['allow_redirects']['on_redirect'])) { + ($options['allow_redirects']['on_redirect'])( + $request, + $response, + $nextRequest->getUri() + ); + } + + $promise = $this($nextRequest, $options); + + // Add headers to be able to track history of redirects. + if (!empty($options['allow_redirects']['track_redirects'])) { + return $this->withTracking( + $promise, + (string) $nextRequest->getUri(), + $response->getStatusCode() + ); + } + + return $promise; + } + + /** + * Enable tracking on promise. + */ + private function withTracking(PromiseInterface $promise, string $uri, int $statusCode): PromiseInterface + { + return $promise->then( + static function (ResponseInterface $response) use ($uri, $statusCode) { + // Note that we are pushing to the front of the list as this + // would be an earlier response than what is currently present + // in the history header. + $historyHeader = $response->getHeader(self::HISTORY_HEADER); + $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER); + \array_unshift($historyHeader, $uri); + \array_unshift($statusHeader, (string) $statusCode); + + return $response->withHeader(self::HISTORY_HEADER, $historyHeader) + ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader); + } + ); + } + + /** + * Check for too many redirects. + * + * @throws TooManyRedirectsException Too many redirects. + */ + private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options): void + { + $current = $options['__redirect_count'] + ?? 0; + $options['__redirect_count'] = $current + 1; + $max = $options['allow_redirects']['max']; + + if ($options['__redirect_count'] > $max) { + throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response); + } + } + + public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response): RequestInterface + { + // Request modifications to apply. + $modify = []; + $protocols = $options['allow_redirects']['protocols']; + + // Use a GET request if this is an entity enclosing request and we are + // not forcing RFC compliance, but rather emulating what all browsers + // would do. + $statusCode = $response->getStatusCode(); + if ($statusCode == 303 + || ($statusCode <= 302 && !$options['allow_redirects']['strict']) + ) { + $safeMethods = ['GET', 'HEAD', 'OPTIONS']; + $requestMethod = $request->getMethod(); + + $modify['method'] = in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET'; + $modify['body'] = ''; + } + + $uri = self::redirectUri($request, $response, $protocols); + if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) { + $idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion']; + $uri = Utils::idnUriConvert($uri, $idnOptions); + } + + $modify['uri'] = $uri; + Psr7\Message::rewindBody($request); + + // Add the Referer header if it is told to do so and only + // add the header if we are not redirecting from https to http. + if ($options['allow_redirects']['referer'] + && $modify['uri']->getScheme() === $request->getUri()->getScheme() + ) { + $uri = $request->getUri()->withUserInfo(''); + $modify['set_headers']['Referer'] = (string) $uri; + } else { + $modify['remove_headers'][] = 'Referer'; + } + + // Remove Authorization and Cookie headers if URI is cross-origin. + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) { + $modify['remove_headers'][] = 'Authorization'; + $modify['remove_headers'][] = 'Cookie'; + } + + return Psr7\Utils::modifyRequest($request, $modify); + } + + /** + * Set the appropriate URL on the request based on the location header. + */ + private static function redirectUri( + RequestInterface $request, + ResponseInterface $response, + array $protocols + ): UriInterface { + $location = Psr7\UriResolver::resolve( + $request->getUri(), + new Psr7\Uri($response->getHeaderLine('Location')) + ); + + // Ensure that the redirect URI is allowed based on the protocols. + if (!\in_array($location->getScheme(), $protocols)) { + throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response); + } + + return $location; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RequestOptions.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RequestOptions.php new file mode 100644 index 000000000..84a3500e4 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/RequestOptions.php @@ -0,0 +1,274 @@ +decider = $decider; + $this->nextHandler = $nextHandler; + $this->delay = $delay ?: __CLASS__.'::exponentialDelay'; + } + + /** + * Default exponential backoff delay function. + * + * @return int milliseconds. + */ + public static function exponentialDelay(int $retries): int + { + return (int) 2 ** ($retries - 1) * 1000; + } + + public function __invoke(RequestInterface $request, array $options): PromiseInterface + { + if (!isset($options['retries'])) { + $options['retries'] = 0; + } + + $fn = $this->nextHandler; + + return $fn($request, $options) + ->then( + $this->onFulfilled($request, $options), + $this->onRejected($request, $options) + ); + } + + /** + * Execute fulfilled closure + */ + private function onFulfilled(RequestInterface $request, array $options): callable + { + return function ($value) use ($request, $options) { + if (!($this->decider)( + $options['retries'], + $request, + $value, + null + )) { + return $value; + } + + return $this->doRetry($request, $options, $value); + }; + } + + /** + * Execute rejected closure + */ + private function onRejected(RequestInterface $req, array $options): callable + { + return function ($reason) use ($req, $options) { + if (!($this->decider)( + $options['retries'], + $req, + null, + $reason + )) { + return P\Create::rejectionFor($reason); + } + + return $this->doRetry($req, $options); + }; + } + + private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface + { + $options['delay'] = ($this->delay)(++$options['retries'], $response, $request); + + return $this($request, $options); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/TransferStats.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/TransferStats.php new file mode 100644 index 000000000..93fa334c8 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/TransferStats.php @@ -0,0 +1,133 @@ +request = $request; + $this->response = $response; + $this->transferTime = $transferTime; + $this->handlerErrorData = $handlerErrorData; + $this->handlerStats = $handlerStats; + } + + public function getRequest(): RequestInterface + { + return $this->request; + } + + /** + * Returns the response that was received (if any). + */ + public function getResponse(): ?ResponseInterface + { + return $this->response; + } + + /** + * Returns true if a response was received. + */ + public function hasResponse(): bool + { + return $this->response !== null; + } + + /** + * Gets handler specific error data. + * + * This might be an exception, a integer representing an error code, or + * anything else. Relying on this value assumes that you know what handler + * you are using. + * + * @return mixed + */ + public function getHandlerErrorData() + { + return $this->handlerErrorData; + } + + /** + * Get the effective URI the request was sent to. + */ + public function getEffectiveUri(): UriInterface + { + return $this->request->getUri(); + } + + /** + * Get the estimated time the request was being transferred by the handler. + * + * @return float|null Time in seconds. + */ + public function getTransferTime(): ?float + { + return $this->transferTime; + } + + /** + * Gets an array of all of the handler specific transfer data. + */ + public function getHandlerStats(): array + { + return $this->handlerStats; + } + + /** + * Get a specific handler statistic from the handler by name. + * + * @param string $stat Handler specific transfer stat to retrieve. + * + * @return mixed|null + */ + public function getHandlerStat(string $stat) + { + return $this->handlerStats[$stat] ?? null; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Utils.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Utils.php new file mode 100644 index 000000000..c6a5893dd --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/Utils.php @@ -0,0 +1,384 @@ += 0) { + if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) { + $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler()); + } elseif (\function_exists('curl_exec')) { + $handler = new CurlHandler(); + } elseif (\function_exists('curl_multi_exec')) { + $handler = new CurlMultiHandler(); + } + } + + if (\ini_get('allow_url_fopen')) { + $handler = $handler + ? Proxy::wrapStreaming($handler, new StreamHandler()) + : new StreamHandler(); + } elseif (!$handler) { + throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.'); + } + + return $handler; + } + + /** + * Get the default User-Agent string to use with Guzzle. + */ + public static function defaultUserAgent(): string + { + return sprintf('GuzzleHttp/%d', ClientInterface::MAJOR_VERSION); + } + + /** + * Returns the default cacert bundle for the current system. + * + * First, the openssl.cafile and curl.cainfo php.ini settings are checked. + * If those settings are not configured, then the common locations for + * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X + * and Windows are checked. If any of these file locations are found on + * disk, they will be utilized. + * + * Note: the result of this function is cached for subsequent calls. + * + * @throws \RuntimeException if no bundle can be found. + * + * @deprecated Utils::defaultCaBundle will be removed in guzzlehttp/guzzle:8.0. This method is not needed in PHP 5.6+. + */ + public static function defaultCaBundle(): string + { + static $cached = null; + static $cafiles = [ + // Red Hat, CentOS, Fedora (provided by the ca-certificates package) + '/etc/pki/tls/certs/ca-bundle.crt', + // Ubuntu, Debian (provided by the ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', + // FreeBSD (provided by the ca_root_nss package) + '/usr/local/share/certs/ca-root-nss.crt', + // SLES 12 (provided by the ca-certificates package) + '/var/lib/ca-certificates/ca-bundle.pem', + // OS X provided by homebrew (using the default path) + '/usr/local/etc/openssl/cert.pem', + // Google app engine + '/etc/ca-certificates.crt', + // Windows? + 'C:\\windows\\system32\\curl-ca-bundle.crt', + 'C:\\windows\\curl-ca-bundle.crt', + ]; + + if ($cached) { + return $cached; + } + + if ($ca = \ini_get('openssl.cafile')) { + return $cached = $ca; + } + + if ($ca = \ini_get('curl.cainfo')) { + return $cached = $ca; + } + + foreach ($cafiles as $filename) { + if (\file_exists($filename)) { + return $cached = $filename; + } + } + + throw new \RuntimeException( + <<< EOT +No system CA bundle could be found in any of the the common system locations. +PHP versions earlier than 5.6 are not properly configured to use the system's +CA bundle by default. In order to verify peer certificates, you will need to +supply the path on disk to a certificate bundle to the 'verify' request +option: https://docs.guzzlephp.org/en/latest/request-options.html#verify. If +you do not need a specific certificate bundle, then Mozilla provides a commonly +used CA bundle which can be downloaded here (provided by the maintainer of +cURL): https://curl.haxx.se/ca/cacert.pem. Once you have a CA bundle available +on disk, you can set the 'openssl.cafile' PHP ini setting to point to the path +to the file, allowing you to omit the 'verify' request option. See +https://curl.haxx.se/docs/sslcerts.html for more information. +EOT + ); + } + + /** + * Creates an associative array of lowercase header names to the actual + * header casing. + */ + public static function normalizeHeaderKeys(array $headers): array + { + $result = []; + foreach (\array_keys($headers) as $key) { + $result[\strtolower($key)] = $key; + } + + return $result; + } + + /** + * Returns true if the provided host matches any of the no proxy areas. + * + * This method will strip a port from the host if it is present. Each pattern + * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a + * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" == + * "baz.foo.com", but ".foo.com" != "foo.com"). + * + * Areas are matched in the following cases: + * 1. "*" (without quotes) always matches any hosts. + * 2. An exact match. + * 3. The area starts with "." and the area is the last part of the host. e.g. + * '.mit.edu' will match any host that ends with '.mit.edu'. + * + * @param string $host Host to check against the patterns. + * @param string[] $noProxyArray An array of host patterns. + * + * @throws InvalidArgumentException + */ + public static function isHostInNoProxy(string $host, array $noProxyArray): bool + { + if (\strlen($host) === 0) { + throw new InvalidArgumentException('Empty host provided'); + } + + // Strip port if present. + [$host] = \explode(':', $host, 2); + + foreach ($noProxyArray as $area) { + // Always match on wildcards. + if ($area === '*') { + return true; + } + + if (empty($area)) { + // Don't match on empty values. + continue; + } + + if ($area === $host) { + // Exact matches. + return true; + } + // Special match if the area when prefixed with ".". Remove any + // existing leading "." and add a new leading ".". + $area = '.'.\ltrim($area, '.'); + if (\substr($host, -\strlen($area)) === $area) { + return true; + } + } + + return false; + } + + /** + * Wrapper for json_decode that throws when an error occurs. + * + * @param string $json JSON data to parse + * @param bool $assoc When true, returned objects will be converted + * into associative arrays. + * @param int $depth User specified recursion depth. + * @param int $options Bitmask of JSON decode options. + * + * @return object|array|string|int|float|bool|null + * + * @throws InvalidArgumentException if the JSON cannot be decoded. + * + * @see https://www.php.net/manual/en/function.json-decode.php + */ + public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0) + { + $data = \json_decode($json, $assoc, $depth, $options); + if (\JSON_ERROR_NONE !== \json_last_error()) { + throw new InvalidArgumentException('json_decode error: '.\json_last_error_msg()); + } + + return $data; + } + + /** + * Wrapper for JSON encoding that throws when an error occurs. + * + * @param mixed $value The value being encoded + * @param int $options JSON encode option bitmask + * @param int $depth Set the maximum depth. Must be greater than zero. + * + * @throws InvalidArgumentException if the JSON cannot be encoded. + * + * @see https://www.php.net/manual/en/function.json-encode.php + */ + public static function jsonEncode($value, int $options = 0, int $depth = 512): string + { + $json = \json_encode($value, $options, $depth); + if (\JSON_ERROR_NONE !== \json_last_error()) { + throw new InvalidArgumentException('json_encode error: '.\json_last_error_msg()); + } + + /** @var string */ + return $json; + } + + /** + * Wrapper for the hrtime() or microtime() functions + * (depending on the PHP version, one of the two is used) + * + * @return float UNIX timestamp + * + * @internal + */ + public static function currentTime(): float + { + return (float) \function_exists('hrtime') ? \hrtime(true) / 1e9 : \microtime(true); + } + + /** + * @throws InvalidArgumentException + * + * @internal + */ + public static function idnUriConvert(UriInterface $uri, int $options = 0): UriInterface + { + if ($uri->getHost()) { + $asciiHost = self::idnToAsci($uri->getHost(), $options, $info); + if ($asciiHost === false) { + $errorBitSet = $info['errors'] ?? 0; + + $errorConstants = array_filter(array_keys(get_defined_constants()), static function (string $name): bool { + return substr($name, 0, 11) === 'IDNA_ERROR_'; + }); + + $errors = []; + foreach ($errorConstants as $errorConstant) { + if ($errorBitSet & constant($errorConstant)) { + $errors[] = $errorConstant; + } + } + + $errorMessage = 'IDN conversion failed'; + if ($errors) { + $errorMessage .= ' (errors: '.implode(', ', $errors).')'; + } + + throw new InvalidArgumentException($errorMessage); + } + if ($uri->getHost() !== $asciiHost) { + // Replace URI only if the ASCII version is different + $uri = $uri->withHost($asciiHost); + } + } + + return $uri; + } + + /** + * @internal + */ + public static function getenv(string $name): ?string + { + if (isset($_SERVER[$name])) { + return (string) $_SERVER[$name]; + } + + if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== false && $value !== null) { + return (string) $value; + } + + return null; + } + + /** + * @return string|false + */ + private static function idnToAsci(string $domain, int $options, ?array &$info = []) + { + if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) { + return \idn_to_ascii($domain, $options, \INTL_IDNA_VARIANT_UTS46, $info); + } + + throw new \Error('ext-idn or symfony/polyfill-intl-idn not loaded or too old'); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/functions.php b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/functions.php new file mode 100644 index 000000000..9ab4b9649 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/guzzle/src/functions.php @@ -0,0 +1,167 @@ + +Copyright (c) 2015 Graham Campbell +Copyright (c) 2017 Tobias Schultze +Copyright (c) 2020 Tobias Nyholm + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/README.md b/lam/lib/3rdParty/composer/guzzlehttp/promises/README.md new file mode 100644 index 000000000..493a9315b --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/README.md @@ -0,0 +1,559 @@ +# Guzzle Promises + +[Promises/A+](https://promisesaplus.com/) implementation that handles promise +chaining and resolution iteratively, allowing for "infinite" promise chaining +while keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/) +for a general introduction to promises. + +- [Features](#features) +- [Quick start](#quick-start) +- [Synchronous wait](#synchronous-wait) +- [Cancellation](#cancellation) +- [API](#api) + - [Promise](#promise) + - [FulfilledPromise](#fulfilledpromise) + - [RejectedPromise](#rejectedpromise) +- [Promise interop](#promise-interop) +- [Implementation notes](#implementation-notes) + + +## Features + +- [Promises/A+](https://promisesaplus.com/) implementation. +- Promise resolution and chaining is handled iteratively, allowing for + "infinite" promise chaining. +- Promises have a synchronous `wait` method. +- Promises can be cancelled. +- Works with any object that has a `then` function. +- C# style async/await coroutine promises using + `GuzzleHttp\Promise\Coroutine::of()`. + + +## Installation + +```shell +composer require guzzlehttp/promises +``` + + +## Version Guidance + +| Version | Status | PHP Version | +|---------|---------------------|--------------| +| 1.x | Security fixes only | >=5.5,<8.3 | +| 2.x | Latest | >=7.2.5,<8.6 | + + +## Quick Start + +A *promise* represents the eventual result of an asynchronous operation. The +primary way of interacting with a promise is through its `then` method, which +registers callbacks to receive either a promise's eventual value or the reason +why the promise cannot be fulfilled. + +### Callbacks + +Callbacks are registered with the `then` method by providing an optional +`$onFulfilled` followed by an optional `$onRejected` function. + + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$promise->then( + // $onFulfilled + function ($value) { + echo 'The promise was fulfilled.'; + }, + // $onRejected + function ($reason) { + echo 'The promise was rejected.'; + } +); +``` + +*Resolving* a promise means that you either fulfill a promise with a *value* or +reject a promise with a *reason*. Resolving a promise triggers callbacks +registered with the promise's `then` method. These callbacks are triggered +only once and in the order in which they were added. + +### Resolving a Promise + +Promises are fulfilled using the `resolve($value)` method. Resolving a promise +with any value other than a `GuzzleHttp\Promise\RejectedPromise` will trigger +all of the onFulfilled callbacks (resolving a promise with a rejected promise +will reject the promise and trigger the `$onRejected` callbacks). + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$promise + ->then(function ($value) { + // Return a value and don't break the chain + return "Hello, " . $value; + }) + // This then is executed after the first then and receives the value + // returned from the first then. + ->then(function ($value) { + echo $value; + }); + +// Resolving the promise triggers the $onFulfilled callbacks and outputs +// "Hello, reader." +$promise->resolve('reader.'); +``` + +### Promise Forwarding + +Promises can be chained one after the other. Each then in the chain is a new +promise. The return value of a promise is what's forwarded to the next +promise in the chain. Returning a promise in a `then` callback will cause the +subsequent promises in the chain to only be fulfilled when the returned promise +has been fulfilled. The next promise in the chain will be invoked with the +resolved value of the promise. + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$nextPromise = new Promise(); + +$promise + ->then(function ($value) use ($nextPromise) { + echo $value; + return $nextPromise; + }) + ->then(function ($value) { + echo $value; + }); + +// Triggers the first callback and outputs "A" +$promise->resolve('A'); +// Triggers the second callback and outputs "B" +$nextPromise->resolve('B'); +``` + +### Promise Rejection + +When a promise is rejected, the `$onRejected` callbacks are invoked with the +rejection reason. + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$promise->then(null, function ($reason) { + echo $reason; +}); + +$promise->reject('Error!'); +// Outputs "Error!" +``` + +### Rejection Forwarding + +If an exception is thrown in an `$onRejected` callback, subsequent +`$onRejected` callbacks are invoked with the thrown exception as the reason. + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$promise->then(null, function ($reason) { + throw new Exception($reason); +})->then(null, function ($reason) { + assert($reason->getMessage() === 'Error!'); +}); + +$promise->reject('Error!'); +``` + +You can also forward a rejection down the promise chain by returning a +`GuzzleHttp\Promise\RejectedPromise` in either an `$onFulfilled` or +`$onRejected` callback. + +```php +use GuzzleHttp\Promise\Promise; +use GuzzleHttp\Promise\RejectedPromise; + +$promise = new Promise(); +$promise->then(null, function ($reason) { + return new RejectedPromise($reason); +})->then(null, function ($reason) { + assert($reason === 'Error!'); +}); + +$promise->reject('Error!'); +``` + +If an exception is not thrown in a `$onRejected` callback and the callback +does not return a rejected promise, downstream `$onFulfilled` callbacks are +invoked using the value returned from the `$onRejected` callback. + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise(); +$promise + ->then(null, function ($reason) { + return "It's ok"; + }) + ->then(function ($value) { + assert($value === "It's ok"); + }); + +$promise->reject('Error!'); +``` + + +## Synchronous Wait + +You can synchronously force promises to complete using a promise's `wait` +method. When creating a promise, you can provide a wait function that is used +to synchronously force a promise to complete. When a wait function is invoked +it is expected to deliver a value to the promise or reject the promise. If the +wait function does not deliver a value, then an exception is thrown. The wait +function provided to a promise constructor is invoked when the `wait` function +of the promise is called. + +```php +$promise = new Promise(function () use (&$promise) { + $promise->resolve('foo'); +}); + +// Calling wait will return the value of the promise. +echo $promise->wait(); // outputs "foo" +``` + +If an exception is encountered while invoking the wait function of a promise, +the promise is rejected with the exception and the exception is thrown. + +```php +$promise = new Promise(function () use (&$promise) { + throw new Exception('foo'); +}); + +$promise->wait(); // throws the exception. +``` + +Calling `wait` on a promise that has been fulfilled will not trigger the wait +function. It will simply return the previously resolved value. + +```php +$promise = new Promise(function () { die('this is not called!'); }); +$promise->resolve('foo'); +echo $promise->wait(); // outputs "foo" +``` + +Calling `wait` on a promise that has been rejected will throw an exception. If +the rejection reason is an instance of `\Exception` the reason is thrown. +Otherwise, a `GuzzleHttp\Promise\RejectionException` is thrown and the reason +can be obtained by calling the `getReason` method of the exception. + +```php +$promise = new Promise(); +$promise->reject('foo'); +$promise->wait(); +``` + +> PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo' + +### Unwrapping a Promise + +When synchronously waiting on a promise, you are joining the state of the +promise into the current state of execution (i.e., return the value of the +promise if it was fulfilled or throw an exception if it was rejected). This is +called "unwrapping" the promise. Waiting on a promise will by default unwrap +the promise state. + +You can force a promise to resolve and *not* unwrap the state of the promise +by passing `false` to the first argument of the `wait` function: + +```php +$promise = new Promise(); +$promise->reject('foo'); +// This will not throw an exception. It simply ensures the promise has +// been resolved. +$promise->wait(false); +``` + +When unwrapping a promise, the resolved value of the promise will be waited +upon until the unwrapped value is not a promise. This means that if you resolve +promise A with a promise B and unwrap promise A, the value returned by the +wait function will be the value delivered to promise B. + +**Note**: when you do not unwrap the promise, no value is returned. + + +## Cancellation + +You can cancel a promise that has not yet been fulfilled using the `cancel()` +method of a promise. When creating a promise you can provide an optional +cancel function that when invoked cancels the action of computing a resolution +of the promise. + + +## API + +### Promise + +When creating a promise object, you can provide an optional `$waitFn` and +`$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is +expected to resolve the promise. `$cancelFn` is a function with no arguments +that is expected to cancel the computation of a promise. It is invoked when the +`cancel()` method of a promise is called. + +```php +use GuzzleHttp\Promise\Promise; + +$promise = new Promise( + function () use (&$promise) { + $promise->resolve('waited'); + }, + function () { + // do something that will cancel the promise computation (e.g., close + // a socket, cancel a database query, etc...) + } +); + +assert('waited' === $promise->wait()); +``` + +A promise has the following methods: + +- `then(callable $onFulfilled, callable $onRejected) : PromiseInterface` + + Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler. + +- `otherwise(callable $onRejected) : PromiseInterface` + + Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled. + +- `wait($unwrap = true) : mixed` + + Synchronously waits on the promise to complete. + + `$unwrap` controls whether or not the value of the promise is returned for a + fulfilled promise or if an exception is thrown if the promise is rejected. + This is set to `true` by default. + +- `cancel()` + + Attempts to cancel the promise if possible. The promise being cancelled and + the parent most ancestor that has not yet been resolved will also be + cancelled. Any promises waiting on the cancelled promise to resolve will also + be cancelled. + +- `getState() : string` + + Returns the state of the promise. One of `pending`, `fulfilled`, or + `rejected`. + +- `resolve($value)` + + Fulfills the promise with the given `$value`. + +- `reject($reason)` + + Rejects the promise with the given `$reason`. + + +### FulfilledPromise + +A fulfilled promise can be created to represent a promise that has been +fulfilled. + +```php +use GuzzleHttp\Promise\FulfilledPromise; + +$promise = new FulfilledPromise('value'); + +// Fulfilled callbacks are immediately invoked. +$promise->then(function ($value) { + echo $value; +}); +``` + + +### RejectedPromise + +A rejected promise can be created to represent a promise that has been +rejected. + +```php +use GuzzleHttp\Promise\RejectedPromise; + +$promise = new RejectedPromise('Error'); + +// Rejected callbacks are immediately invoked. +$promise->then(null, function ($reason) { + echo $reason; +}); +``` + + +## Promise Interoperability + +This library works with foreign promises that have a `then` method. This means +you can use Guzzle promises with [React promises](https://github.com/reactphp/promise) +for example. When a foreign promise is returned inside of a then method +callback, promise resolution will occur recursively. + +```php +// Create a React promise +$deferred = new React\Promise\Deferred(); +$reactPromise = $deferred->promise(); + +// Create a Guzzle promise that is fulfilled with a React promise. +$guzzlePromise = new GuzzleHttp\Promise\Promise(); +$guzzlePromise->then(function ($value) use ($reactPromise) { + // Do something something with the value... + // Return the React promise + return $reactPromise; +}); +``` + +Please note that wait and cancel chaining is no longer possible when forwarding +a foreign promise. You will need to wrap a third-party promise with a Guzzle +promise in order to utilize wait and cancel functions with foreign promises. + + +### Event Loop Integration + +In order to keep the stack size constant, Guzzle promises are resolved +asynchronously using a task queue. When waiting on promises synchronously, the +task queue will be automatically run to ensure that the blocking promise and +any forwarded promises are resolved. When using promises asynchronously in an +event loop, you will need to run the task queue on each tick of the loop. If +you do not run the task queue, then promises will not be resolved. + +You can run the task queue using the `run()` method of the global task queue +instance. + +```php +// Get the global task queue +$queue = GuzzleHttp\Promise\Utils::queue(); +$queue->run(); +``` + +For example, you could use Guzzle promises with React using a periodic timer: + +```php +$loop = React\EventLoop\Factory::create(); +$loop->addPeriodicTimer(0, [$queue, 'run']); +``` + + +## Implementation Notes + +### Promise Resolution and Chaining is Handled Iteratively + +By shuffling pending handlers from one owner to another, promises are +resolved iteratively, allowing for "infinite" then chaining. + +```php +then(function ($v) { + // The stack size remains constant (a good thing) + echo xdebug_get_stack_depth() . ', '; + return $v + 1; + }); +} + +$parent->resolve(0); +var_dump($p->wait()); // int(1000) + +``` + +When a promise is fulfilled or rejected with a non-promise value, the promise +then takes ownership of the handlers of each child promise and delivers values +down the chain without using recursion. + +When a promise is resolved with another promise, the original promise transfers +all of its pending handlers to the new promise. When the new promise is +eventually resolved, all of the pending handlers are delivered the forwarded +value. + +### A Promise is the Deferred + +Some promise libraries implement promises using a deferred object to represent +a computation and a promise object to represent the delivery of the result of +the computation. This is a nice separation of computation and delivery because +consumers of the promise cannot modify the value that will be eventually +delivered. + +One side effect of being able to implement promise resolution and chaining +iteratively is that you need to be able for one promise to reach into the state +of another promise to shuffle around ownership of handlers. In order to achieve +this without making the handlers of a promise publicly mutable, a promise is +also the deferred value, allowing promises of the same parent class to reach +into and modify the private properties of promises of the same type. While this +does allow consumers of the value to modify the resolution or rejection of the +deferred, it is a small price to pay for keeping the stack size constant. + +```php +$promise = new Promise(); +$promise->then(function ($value) { echo $value; }); +// The promise is the deferred value, so you can deliver a value to it. +$promise->resolve('foo'); +// prints "foo" +``` + + +## Upgrading from Function API + +A static API was first introduced in 1.4.0, in order to mitigate problems with +functions conflicting between global and local copies of the package. The +function API was removed in 2.0.0. A migration table has been provided here for +your convenience: + +| Original Function | Replacement Method | +|----------------|----------------| +| `queue` | `Utils::queue` | +| `task` | `Utils::task` | +| `promise_for` | `Create::promiseFor` | +| `rejection_for` | `Create::rejectionFor` | +| `exception_for` | `Create::exceptionFor` | +| `iter_for` | `Create::iterFor` | +| `inspect` | `Utils::inspect` | +| `inspect_all` | `Utils::inspectAll` | +| `unwrap` | `Utils::unwrap` | +| `all` | `Utils::all` | +| `some` | `Utils::some` | +| `any` | `Utils::any` | +| `settle` | `Utils::settle` | +| `each` | `Each::of` | +| `each_limit` | `Each::ofLimit` | +| `each_limit_all` | `Each::ofLimitAll` | +| `!is_fulfilled` | `Is::pending` | +| `is_fulfilled` | `Is::fulfilled` | +| `is_rejected` | `Is::rejected` | +| `is_settled` | `Is::settled` | +| `coroutine` | `Coroutine::of` | + + +## Security + +If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/promises/security/policy) for more information. + + +## License + +Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information. + + +## For Enterprise + +Available as part of the Tidelift Subscription + +The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-promises?utm_source=packagist-guzzlehttp-promises&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/composer.json b/lam/lib/3rdParty/composer/guzzlehttp/promises/composer.json new file mode 100644 index 000000000..9d6e85678 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/composer.json @@ -0,0 +1,58 @@ +{ + "name": "guzzlehttp/promises", + "description": "Guzzle promises library", + "keywords": ["promise"], + "license": "MIT", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "GuzzleHttp\\Promise\\Tests\\": "tests/" + } + }, + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "config": { + "allow-plugins": { + "bamarni/composer-bin-plugin": true + }, + "preferred-install": "dist", + "sort-packages": true + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/AggregateException.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/AggregateException.php new file mode 100644 index 000000000..40ffdbcf1 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/AggregateException.php @@ -0,0 +1,19 @@ +then(function ($v) { echo $v; }); + * + * @param callable $generatorFn Generator function to wrap into a promise. + * + * @return Promise + * + * @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration + */ +final class Coroutine implements PromiseInterface +{ + /** + * @var PromiseInterface|null + */ + private $currentPromise; + + /** + * @var Generator + */ + private $generator; + + /** + * @var Promise + */ + private $result; + + public function __construct(callable $generatorFn) + { + $this->generator = $generatorFn(); + $this->result = new Promise(function (): void { + while (isset($this->currentPromise)) { + $this->currentPromise->wait(); + } + }); + try { + $this->nextCoroutine($this->generator->current()); + } catch (Throwable $throwable) { + $this->result->reject($throwable); + } + } + + /** + * Create a new coroutine. + */ + public static function of(callable $generatorFn): self + { + return new self($generatorFn); + } + + public function then( + ?callable $onFulfilled = null, + ?callable $onRejected = null + ): PromiseInterface { + return $this->result->then($onFulfilled, $onRejected); + } + + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->result->otherwise($onRejected); + } + + public function wait(bool $unwrap = true) + { + return $this->result->wait($unwrap); + } + + public function getState(): string + { + return $this->result->getState(); + } + + public function resolve($value): void + { + $this->result->resolve($value); + } + + public function reject($reason): void + { + $this->result->reject($reason); + } + + public function cancel(): void + { + $this->currentPromise->cancel(); + $this->result->cancel(); + } + + private function nextCoroutine($yielded): void + { + $this->currentPromise = Create::promiseFor($yielded) + ->then([$this, '_handleSuccess'], [$this, '_handleFailure']); + } + + /** + * @internal + */ + public function _handleSuccess($value): void + { + unset($this->currentPromise); + try { + $next = $this->generator->send($value); + if ($this->generator->valid()) { + $this->nextCoroutine($next); + } else { + $this->result->resolve($value); + } + } catch (Throwable $throwable) { + $this->result->reject($throwable); + } + } + + /** + * @internal + */ + public function _handleFailure($reason): void + { + unset($this->currentPromise); + try { + $nextYield = $this->generator->throw(Create::exceptionFor($reason)); + // The throw was caught, so keep iterating on the coroutine + $this->nextCoroutine($nextYield); + } catch (Throwable $throwable) { + $this->result->reject($throwable); + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Create.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Create.php new file mode 100644 index 000000000..9d3fc4a1e --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Create.php @@ -0,0 +1,79 @@ +then([$promise, 'resolve'], [$promise, 'reject']); + + return $promise; + } + + return new FulfilledPromise($value); + } + + /** + * Creates a rejected promise for a reason if the reason is not a promise. + * If the provided reason is a promise, then it is returned as-is. + * + * @param mixed $reason Promise or reason. + */ + public static function rejectionFor($reason): PromiseInterface + { + if ($reason instanceof PromiseInterface) { + return $reason; + } + + return new RejectedPromise($reason); + } + + /** + * Create an exception for a rejected promise value. + * + * @param mixed $reason + */ + public static function exceptionFor($reason): \Throwable + { + if ($reason instanceof \Throwable) { + return $reason; + } + + return new RejectionException($reason); + } + + /** + * Returns an iterator for the given value. + * + * @param mixed $value + */ + public static function iterFor($value): \Iterator + { + if ($value instanceof \Iterator) { + return $value; + } + + if (is_array($value)) { + return new \ArrayIterator($value); + } + + return new \ArrayIterator([$value]); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Each.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Each.php new file mode 100644 index 000000000..dd72c8310 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Each.php @@ -0,0 +1,81 @@ + $onFulfilled, + 'rejected' => $onRejected, + ]))->promise(); + } + + /** + * Like of, but only allows a certain number of outstanding promises at any + * given time. + * + * $concurrency may be an integer or a function that accepts the number of + * pending promises and returns a numeric concurrency limit value to allow + * for dynamic a concurrency size. + * + * @param mixed $iterable + * @param int|callable $concurrency + */ + public static function ofLimit( + $iterable, + $concurrency, + ?callable $onFulfilled = null, + ?callable $onRejected = null + ): PromiseInterface { + return (new EachPromise($iterable, [ + 'fulfilled' => $onFulfilled, + 'rejected' => $onRejected, + 'concurrency' => $concurrency, + ]))->promise(); + } + + /** + * Like limit, but ensures that no promise in the given $iterable argument + * is rejected. If any promise is rejected, then the aggregate promise is + * rejected with the encountered rejection. + * + * @param mixed $iterable + * @param int|callable $concurrency + */ + public static function ofLimitAll( + $iterable, + $concurrency, + ?callable $onFulfilled = null + ): PromiseInterface { + return self::ofLimit( + $iterable, + $concurrency, + $onFulfilled, + function ($reason, $idx, PromiseInterface $aggregate): void { + $aggregate->reject($reason); + } + ); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/EachPromise.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/EachPromise.php new file mode 100644 index 000000000..e12389818 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/EachPromise.php @@ -0,0 +1,248 @@ +iterable = Create::iterFor($iterable); + + if (isset($config['concurrency'])) { + $this->concurrency = $config['concurrency']; + } + + if (isset($config['fulfilled'])) { + $this->onFulfilled = $config['fulfilled']; + } + + if (isset($config['rejected'])) { + $this->onRejected = $config['rejected']; + } + } + + /** @psalm-suppress InvalidNullableReturnType */ + public function promise(): PromiseInterface + { + if ($this->aggregate) { + return $this->aggregate; + } + + try { + $this->createPromise(); + /** @psalm-assert Promise $this->aggregate */ + $this->iterable->rewind(); + $this->refillPending(); + } catch (\Throwable $e) { + $this->aggregate->reject($e); + } + + /** + * @psalm-suppress NullableReturnStatement + */ + return $this->aggregate; + } + + private function createPromise(): void + { + $this->mutex = false; + $this->aggregate = new Promise(function (): void { + if ($this->checkIfFinished()) { + return; + } + reset($this->pending); + // Consume a potentially fluctuating list of promises while + // ensuring that indexes are maintained (precluding array_shift). + while ($promise = current($this->pending)) { + next($this->pending); + $promise->wait(); + if (Is::settled($this->aggregate)) { + return; + } + } + }); + + // Clear the references when the promise is resolved. + $clearFn = function (): void { + $this->iterable = $this->concurrency = $this->pending = null; + $this->onFulfilled = $this->onRejected = null; + $this->nextPendingIndex = 0; + }; + + $this->aggregate->then($clearFn, $clearFn); + } + + private function refillPending(): void + { + if (!$this->concurrency) { + // Add all pending promises. + while ($this->addPending() && $this->advanceIterator()) { + } + + return; + } + + // Add only up to N pending promises. + $concurrency = is_callable($this->concurrency) + ? ($this->concurrency)(count($this->pending)) + : $this->concurrency; + $concurrency = max($concurrency - count($this->pending), 0); + // Concurrency may be set to 0 to disallow new promises. + if (!$concurrency) { + return; + } + // Add the first pending promise. + $this->addPending(); + // Note this is special handling for concurrency=1 so that we do + // not advance the iterator after adding the first promise. This + // helps work around issues with generators that might not have the + // next value to yield until promise callbacks are called. + while (--$concurrency + && $this->advanceIterator() + && $this->addPending()) { + } + } + + private function addPending(): bool + { + if (!$this->iterable || !$this->iterable->valid()) { + return false; + } + + $promise = Create::promiseFor($this->iterable->current()); + $key = $this->iterable->key(); + + // Iterable keys may not be unique, so we use a counter to + // guarantee uniqueness + $idx = $this->nextPendingIndex++; + + $this->pending[$idx] = $promise->then( + function ($value) use ($idx, $key): void { + if ($this->onFulfilled) { + ($this->onFulfilled)( + $value, + $key, + $this->aggregate + ); + } + $this->step($idx); + }, + function ($reason) use ($idx, $key): void { + if ($this->onRejected) { + ($this->onRejected)( + $reason, + $key, + $this->aggregate + ); + } + $this->step($idx); + } + ); + + return true; + } + + private function advanceIterator(): bool + { + // Place a lock on the iterator so that we ensure to not recurse, + // preventing fatal generator errors. + if ($this->mutex) { + return false; + } + + $this->mutex = true; + + try { + $this->iterable->next(); + $this->mutex = false; + + return true; + } catch (\Throwable $e) { + $this->aggregate->reject($e); + $this->mutex = false; + + return false; + } + } + + private function step(int $idx): void + { + // If the promise was already resolved, then ignore this step. + if (Is::settled($this->aggregate)) { + return; + } + + unset($this->pending[$idx]); + + // Only refill pending promises if we are not locked, preventing the + // EachPromise to recursively invoke the provided iterator, which + // cause a fatal error: "Cannot resume an already running generator" + if ($this->advanceIterator() && !$this->checkIfFinished()) { + // Add more pending promises if possible. + $this->refillPending(); + } + } + + private function checkIfFinished(): bool + { + if (!$this->pending && !$this->iterable->valid()) { + // Resolve the promise if there's nothing left to do. + $this->aggregate->resolve(null); + + return true; + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/FulfilledPromise.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/FulfilledPromise.php new file mode 100644 index 000000000..727ec315c --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/FulfilledPromise.php @@ -0,0 +1,89 @@ +value = $value; + } + + public function then( + ?callable $onFulfilled = null, + ?callable $onRejected = null + ): PromiseInterface { + // Return itself if there is no onFulfilled function. + if (!$onFulfilled) { + return $this; + } + + $queue = Utils::queue(); + $p = new Promise([$queue, 'run']); + $value = $this->value; + $queue->add(static function () use ($p, $value, $onFulfilled): void { + if (Is::pending($p)) { + try { + $p->resolve($onFulfilled($value)); + } catch (\Throwable $e) { + $p->reject($e); + } + } + }); + + return $p; + } + + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->then(null, $onRejected); + } + + public function wait(bool $unwrap = true) + { + return $unwrap ? $this->value : null; + } + + public function getState(): string + { + return self::FULFILLED; + } + + public function resolve($value): void + { + if ($value !== $this->value) { + throw new \LogicException('Cannot resolve a fulfilled promise'); + } + } + + public function reject($reason): void + { + throw new \LogicException('Cannot reject a fulfilled promise'); + } + + public function cancel(): void + { + // pass + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Is.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Is.php new file mode 100644 index 000000000..f3f050384 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Is.php @@ -0,0 +1,40 @@ +getState() === PromiseInterface::PENDING; + } + + /** + * Returns true if a promise is fulfilled or rejected. + */ + public static function settled(PromiseInterface $promise): bool + { + return $promise->getState() !== PromiseInterface::PENDING; + } + + /** + * Returns true if a promise is fulfilled. + */ + public static function fulfilled(PromiseInterface $promise): bool + { + return $promise->getState() === PromiseInterface::FULFILLED; + } + + /** + * Returns true if a promise is rejected. + */ + public static function rejected(PromiseInterface $promise): bool + { + return $promise->getState() === PromiseInterface::REJECTED; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Promise.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Promise.php new file mode 100644 index 000000000..c0c5be2c0 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/Promise.php @@ -0,0 +1,281 @@ +waitFn = $waitFn; + $this->cancelFn = $cancelFn; + } + + public function then( + ?callable $onFulfilled = null, + ?callable $onRejected = null + ): PromiseInterface { + if ($this->state === self::PENDING) { + $p = new Promise(null, [$this, 'cancel']); + $this->handlers[] = [$p, $onFulfilled, $onRejected]; + $p->waitList = $this->waitList; + $p->waitList[] = $this; + + return $p; + } + + // Return a fulfilled promise and immediately invoke any callbacks. + if ($this->state === self::FULFILLED) { + $promise = Create::promiseFor($this->result); + + return $onFulfilled ? $promise->then($onFulfilled) : $promise; + } + + // It's either cancelled or rejected, so return a rejected promise + // and immediately invoke any callbacks. + $rejection = Create::rejectionFor($this->result); + + return $onRejected ? $rejection->then(null, $onRejected) : $rejection; + } + + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->then(null, $onRejected); + } + + public function wait(bool $unwrap = true) + { + $this->waitIfPending(); + + if ($this->result instanceof PromiseInterface) { + return $this->result->wait($unwrap); + } + if ($unwrap) { + if ($this->state === self::FULFILLED) { + return $this->result; + } + // It's rejected so "unwrap" and throw an exception. + throw Create::exceptionFor($this->result); + } + } + + public function getState(): string + { + return $this->state; + } + + public function cancel(): void + { + if ($this->state !== self::PENDING) { + return; + } + + $this->waitFn = $this->waitList = null; + + if ($this->cancelFn) { + $fn = $this->cancelFn; + $this->cancelFn = null; + try { + $fn(); + } catch (\Throwable $e) { + $this->reject($e); + } + } + + // Reject the promise only if it wasn't rejected in a then callback. + /** @psalm-suppress RedundantCondition */ + if ($this->state === self::PENDING) { + $this->reject(new CancellationException('Promise has been cancelled')); + } + } + + public function resolve($value): void + { + $this->settle(self::FULFILLED, $value); + } + + public function reject($reason): void + { + $this->settle(self::REJECTED, $reason); + } + + private function settle(string $state, $value): void + { + if ($this->state !== self::PENDING) { + // Ignore calls with the same resolution. + if ($state === $this->state && $value === $this->result) { + return; + } + throw $this->state === $state + ? new \LogicException("The promise is already {$state}.") + : new \LogicException("Cannot change a {$this->state} promise to {$state}"); + } + + if ($value === $this) { + throw new \LogicException('Cannot fulfill or reject a promise with itself'); + } + + // Clear out the state of the promise but stash the handlers. + $this->state = $state; + $this->result = $value; + $handlers = $this->handlers; + $this->handlers = null; + $this->waitList = $this->waitFn = null; + $this->cancelFn = null; + + if (!$handlers) { + return; + } + + // If the value was not a settled promise or a thenable, then resolve + // it in the task queue using the correct ID. + if (!is_object($value) || !method_exists($value, 'then')) { + $id = $state === self::FULFILLED ? 1 : 2; + // It's a success, so resolve the handlers in the queue. + Utils::queue()->add(static function () use ($id, $value, $handlers): void { + foreach ($handlers as $handler) { + self::callHandler($id, $value, $handler); + } + }); + } elseif ($value instanceof Promise && Is::pending($value)) { + // We can just merge our handlers onto the next promise. + $value->handlers = array_merge($value->handlers, $handlers); + } else { + // Resolve the handlers when the forwarded promise is resolved. + $value->then( + static function ($value) use ($handlers): void { + foreach ($handlers as $handler) { + self::callHandler(1, $value, $handler); + } + }, + static function ($reason) use ($handlers): void { + foreach ($handlers as $handler) { + self::callHandler(2, $reason, $handler); + } + } + ); + } + } + + /** + * Call a stack of handlers using a specific callback index and value. + * + * @param int $index 1 (resolve) or 2 (reject). + * @param mixed $value Value to pass to the callback. + * @param array $handler Array of handler data (promise and callbacks). + */ + private static function callHandler(int $index, $value, array $handler): void + { + /** @var PromiseInterface $promise */ + $promise = $handler[0]; + + // The promise may have been cancelled or resolved before placing + // this thunk in the queue. + if (Is::settled($promise)) { + return; + } + + try { + if (isset($handler[$index])) { + /* + * If $f throws an exception, then $handler will be in the exception + * stack trace. Since $handler contains a reference to the callable + * itself we get a circular reference. We clear the $handler + * here to avoid that memory leak. + */ + $f = $handler[$index]; + unset($handler); + $promise->resolve($f($value)); + } elseif ($index === 1) { + // Forward resolution values as-is. + $promise->resolve($value); + } else { + // Forward rejections down the chain. + $promise->reject($value); + } + } catch (\Throwable $reason) { + $promise->reject($reason); + } + } + + private function waitIfPending(): void + { + if ($this->state !== self::PENDING) { + return; + } elseif ($this->waitFn) { + $this->invokeWaitFn(); + } elseif ($this->waitList) { + $this->invokeWaitList(); + } else { + // If there's no wait function, then reject the promise. + $this->reject('Cannot wait on a promise that has ' + .'no internal wait function. You must provide a wait ' + .'function when constructing the promise to be able to ' + .'wait on a promise.'); + } + + Utils::queue()->run(); + + /** @psalm-suppress RedundantCondition */ + if ($this->state === self::PENDING) { + $this->reject('Invoking the wait callback did not resolve the promise'); + } + } + + private function invokeWaitFn(): void + { + try { + $wfn = $this->waitFn; + $this->waitFn = null; + $wfn(true); + } catch (\Throwable $reason) { + if ($this->state === self::PENDING) { + // The promise has not been resolved yet, so reject the promise + // with the exception. + $this->reject($reason); + } else { + // The promise was already resolved, so there's a problem in + // the application. + throw $reason; + } + } + } + + private function invokeWaitList(): void + { + $waitList = $this->waitList; + $this->waitList = null; + + foreach ($waitList as $result) { + do { + $result->waitIfPending(); + $result = $result->result; + } while ($result instanceof Promise); + + if ($result instanceof PromiseInterface) { + $result->wait(false); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/PromiseInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/PromiseInterface.php new file mode 100644 index 000000000..c11721e4d --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/PromiseInterface.php @@ -0,0 +1,91 @@ +reason = $reason; + } + + public function then( + ?callable $onFulfilled = null, + ?callable $onRejected = null + ): PromiseInterface { + // If there's no onRejected callback then just return self. + if (!$onRejected) { + return $this; + } + + $queue = Utils::queue(); + $reason = $this->reason; + $p = new Promise([$queue, 'run']); + $queue->add(static function () use ($p, $reason, $onRejected): void { + if (Is::pending($p)) { + try { + // Return a resolved promise if onRejected does not throw. + $p->resolve($onRejected($reason)); + } catch (\Throwable $e) { + // onRejected threw, so return a rejected promise. + $p->reject($e); + } + } + }); + + return $p; + } + + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->then(null, $onRejected); + } + + public function wait(bool $unwrap = true) + { + if ($unwrap) { + throw Create::exceptionFor($this->reason); + } + + return null; + } + + public function getState(): string + { + return self::REJECTED; + } + + public function resolve($value): void + { + throw new \LogicException('Cannot resolve a rejected promise'); + } + + public function reject($reason): void + { + if ($reason !== $this->reason) { + throw new \LogicException('Cannot reject a rejected promise'); + } + } + + public function cancel(): void + { + // pass + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/RejectionException.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/RejectionException.php new file mode 100644 index 000000000..47dca8624 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/RejectionException.php @@ -0,0 +1,49 @@ +reason = $reason; + + $message = 'The promise was rejected'; + + if ($description) { + $message .= ' with reason: '.$description; + } elseif (is_string($reason) + || (is_object($reason) && method_exists($reason, '__toString')) + ) { + $message .= ' with reason: '.$this->reason; + } elseif ($reason instanceof \JsonSerializable) { + $message .= ' with reason: '.json_encode($this->reason, JSON_PRETTY_PRINT); + } + + parent::__construct($message); + } + + /** + * Returns the rejection reason. + * + * @return mixed + */ + public function getReason() + { + return $this->reason; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueue.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueue.php new file mode 100644 index 000000000..503e0b2da --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueue.php @@ -0,0 +1,71 @@ +run(); + * + * @final + */ +class TaskQueue implements TaskQueueInterface +{ + private $enableShutdown = true; + private $queue = []; + + public function __construct(bool $withShutdown = true) + { + if ($withShutdown) { + register_shutdown_function(function (): void { + if ($this->enableShutdown) { + // Only run the tasks if an E_ERROR didn't occur. + $err = error_get_last(); + if (!$err || ($err['type'] ^ E_ERROR)) { + $this->run(); + } + } + }); + } + } + + public function isEmpty(): bool + { + return !$this->queue; + } + + public function add(callable $task): void + { + $this->queue[] = $task; + } + + public function run(): void + { + while ($task = array_shift($this->queue)) { + /** @var callable $task */ + $task(); + } + } + + /** + * The task queue will be run and exhausted by default when the process + * exits IFF the exit is not the result of a PHP E_ERROR error. + * + * You can disable running the automatic shutdown of the queue by calling + * this function. If you disable the task queue shutdown process, then you + * MUST either run the task queue (as a result of running your event loop + * or manually using the run() method) or wait on each outstanding promise. + * + * Note: This shutdown will occur before any destructors are triggered. + */ + public function disableShutdown(): void + { + $this->enableShutdown = false; + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueueInterface.php b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueueInterface.php new file mode 100644 index 000000000..34c561a48 --- /dev/null +++ b/lam/lib/3rdParty/composer/guzzlehttp/promises/src/TaskQueueInterface.php @@ -0,0 +1,24 @@ + + * while ($eventLoop->isRunning()) { + * GuzzleHttp\Promise\Utils::queue()->run(); + * } + * + * + * @param TaskQueueInterface|null $assign Optionally specify a new queue instance. + */ + public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface + { + static $queue; + + if ($assign) { + $queue = $assign; + } elseif (!$queue) { + $queue = new TaskQueue(); + } + + return $queue; + } + + /** + * Adds a function to run in the task queue when it is next `run()` and + * returns a promise that is fulfilled or rejected with the result. + * + * @param callable $task Task function to run. + */ + public static function task(callable $task): PromiseInterface + { + $queue = self::queue(); + $promise = new Promise([$queue, 'run']); + $queue->add(function () use ($task, $promise): void { + try { + if (Is::pending($promise)) { + $promise->resolve($task()); + } + } catch (\Throwable $e) { + $promise->reject($e); + } + }); + + return $promise; + } + + /** + * Synchronously waits on a promise to resolve and returns an inspection + * state array. + * + * Returns a state associative array containing a "state" key mapping to a + * valid promise state. If the state of the promise is "fulfilled", the + * array will contain a "value" key mapping to the fulfilled value of the + * promise. If the promise is rejected, the array will contain a "reason" + * key mapping to the rejection reason of the promise. + * + * @param PromiseInterface $promise Promise or value. + */ + public static function inspect(PromiseInterface $promise): array + { + try { + return [ + 'state' => PromiseInterface::FULFILLED, + 'value' => $promise->wait(), + ]; + } catch (RejectionException $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()]; + } catch (\Throwable $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; + } + } + + /** + * Waits on all of the provided promises, but does not unwrap rejected + * promises as thrown exception. + * + * Returns an array of inspection state arrays. + * + * @see inspect for the inspection state array format. + * + * @param PromiseInterface[] $promises Traversable of promises to wait upon. + */ + public static function inspectAll($promises): array + { + $results = []; + foreach ($promises as $key => $promise) { + $results[$key] = self::inspect($promise); + } + + return $results; + } + + /** + * Waits on all of the provided promises and returns the fulfilled values. + * + * Returns an array that contains the value of each promise (in the same + * order the promises were provided). An exception is thrown if any of the + * promises are rejected. + * + * @param iterable $promises Iterable of PromiseInterface objects to wait on. + * + * @throws \Throwable on error + */ + public static function unwrap($promises): array + { + $results = []; + foreach ($promises as $key => $promise) { + $results[$key] = $promise->wait(); + } + + return $results; + } + + /** + * Given an array of promises, return a promise that is fulfilled when all + * the items in the array are fulfilled. + * + * The promise's fulfillment value is an array with fulfillment values at + * respective positions to the original array. If any promise in the array + * rejects, the returned promise is rejected with the rejection reason. + * + * @param mixed $promises Promises or values. + * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution. + */ + public static function all($promises, bool $recursive = false): PromiseInterface + { + $results = []; + $promise = Each::of( + $promises, + function ($value, $idx) use (&$results): void { + $results[$idx] = $value; + }, + function ($reason, $idx, Promise $aggregate): void { + if (Is::pending($aggregate)) { + $aggregate->reject($reason); + } + } + )->then(function () use (&$results) { + ksort($results); + + return $results; + }); + + if (true === $recursive) { + $promise = $promise->then(function ($results) use ($recursive, &$promises) { + foreach ($promises as $promise) { + if (Is::pending($promise)) { + return self::all($promises, $recursive); + } + } + + return $results; + }); + } + + return $promise; + } + + /** + * Initiate a competitive race between multiple promises or values (values + * will become immediately fulfilled promises). + * + * When count amount of promises have been fulfilled, the returned promise + * is fulfilled with an array that contains the fulfillment values of the + * winners in order of resolution. + * + * This promise is rejected with a {@see AggregateException} if the number + * of fulfilled promises is less than the desired $count. + * + * @param int $count Total number of promises. + * @param mixed $promises Promises or values. + */ + public static function some(int $count, $promises): PromiseInterface + { + $results = []; + $rejections = []; + + return Each::of( + $promises, + function ($value, $idx, PromiseInterface $p) use (&$results, $count): void { + if (Is::settled($p)) { + return; + } + $results[$idx] = $value; + if (count($results) >= $count) { + $p->resolve(null); + } + }, + function ($reason) use (&$rejections): void { + $rejections[] = $reason; + } + )->then( + function () use (&$results, &$rejections, $count) { + if (count($results) !== $count) { + throw new AggregateException( + 'Not enough promises to fulfill count', + $rejections + ); + } + ksort($results); + + return array_values($results); + } + ); + } + + /** + * Like some(), with 1 as count. However, if the promise fulfills, the + * fulfillment value is not an array of 1 but the value directly. + * + * @param mixed $promises Promises or values. + */ + public static function any($promises): PromiseInterface + { + return self::some(1, $promises)->then(function ($values) { + return $values[0]; + }); + } + + /** + * Returns a promise that is fulfilled when all of the provided promises have + * been fulfilled or rejected. + * + * The returned promise is fulfilled with an array of inspection state arrays. + * + * @see inspect for the inspection state array format. + * + * @param mixed $promises Promises or values. + */ + public static function settle($promises): PromiseInterface + { + $results = []; + + return Each::of( + $promises, + function ($value, $idx) use (&$results): void { + $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value]; + }, + function ($reason, $idx) use (&$results): void { + $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason]; + } + )->then(function () use (&$results) { + ksort($results); + + return $results; + }); + } +} diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/CHANGELOG.md b/lam/lib/3rdParty/composer/guzzlehttp/psr7/CHANGELOG.md index 75aabfb93..4a2a12194 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/CHANGELOG.md +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 2.8.0 - 2025-08-23 + +### Added + +- Allow empty lists as header values + +### Changed + +- PHP 8.5 support + +## 2.7.1 - 2025-03-27 + +### Fixed + +- Fixed uppercase IPv6 addresses in URI + +### Changed + +- Improve uploaded file error message + ## 2.7.0 - 2024-07-18 ### Added diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/README.md b/lam/lib/3rdParty/composer/guzzlehttp/psr7/README.md index 2e9bb0b9b..24aad8605 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/README.md +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/README.md @@ -25,7 +25,7 @@ composer require guzzlehttp/psr7 | Version | Status | PHP Version | |---------|---------------------|--------------| | 1.x | EOL (2024-06-30) | >=5.4,<8.2 | -| 2.x | Latest | >=7.2.5,<8.5 | +| 2.x | Latest | >=7.2.5,<8.6 | ## AppendStream diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/composer.json b/lam/lib/3rdParty/composer/guzzlehttp/psr7/composer.json index 28d15f571..96098f536 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/composer.json +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/composer.json @@ -62,7 +62,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/MessageTrait.php b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/MessageTrait.php index 65dbc4ba0..c15ee63fc 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/MessageTrait.php +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/MessageTrait.php @@ -174,10 +174,6 @@ trait MessageTrait return $this->trimAndValidateHeaderValues([$value]); } - if (count($value) === 0) { - throw new \InvalidArgumentException('Header value can not be an empty array.'); - } - return $this->trimAndValidateHeaderValues($value); } diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/UploadedFile.php b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/UploadedFile.php index 9c9ea49fb..d9b779f13 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/UploadedFile.php +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/UploadedFile.php @@ -11,15 +11,15 @@ use RuntimeException; class UploadedFile implements UploadedFileInterface { - private const ERRORS = [ - UPLOAD_ERR_OK, - UPLOAD_ERR_INI_SIZE, - UPLOAD_ERR_FORM_SIZE, - UPLOAD_ERR_PARTIAL, - UPLOAD_ERR_NO_FILE, - UPLOAD_ERR_NO_TMP_DIR, - UPLOAD_ERR_CANT_WRITE, - UPLOAD_ERR_EXTENSION, + private const ERROR_MAP = [ + UPLOAD_ERR_OK => 'UPLOAD_ERR_OK', + UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE', + UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE', + UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL', + UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE', + UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR', + UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE', + UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION', ]; /** @@ -104,7 +104,7 @@ class UploadedFile implements UploadedFileInterface */ private function setError(int $error): void { - if (false === in_array($error, UploadedFile::ERRORS, true)) { + if (!isset(UploadedFile::ERROR_MAP[$error])) { throw new InvalidArgumentException( 'Invalid error status for UploadedFile' ); @@ -137,7 +137,7 @@ class UploadedFile implements UploadedFileInterface private function validateActive(): void { if (false === $this->isOk()) { - throw new RuntimeException('Cannot retrieve stream due to upload error'); + throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error])); } if ($this->isMoved()) { diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Uri.php b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Uri.php index 481dfca94..a7cdfb003 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Uri.php +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Uri.php @@ -107,7 +107,7 @@ class Uri implements UriInterface, \JsonSerializable { // If IPv6 $prefix = ''; - if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) { + if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) { /** @var array{0:string, 1:string, 2:string} $matches */ $prefix = $matches[1]; $url = $matches[2]; diff --git a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Utils.php b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Utils.php index 7682d2cdc..5451e3dcd 100644 --- a/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Utils.php +++ b/lam/lib/3rdParty/composer/guzzlehttp/psr7/src/Utils.php @@ -397,7 +397,7 @@ final class Utils restore_error_handler(); if ($ex) { - /** @var $ex \RuntimeException */ + /** @var \RuntimeException $ex */ throw $ex; } @@ -444,7 +444,7 @@ final class Utils restore_error_handler(); if ($ex) { - /** @var $ex \RuntimeException */ + /** @var \RuntimeException $ex */ throw $ex; } diff --git a/lam/lib/3rdParty/composer/illuminate/collections/Arr.php b/lam/lib/3rdParty/composer/illuminate/collections/Arr.php deleted file mode 100644 index d83cf5f73..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/Arr.php +++ /dev/null @@ -1,939 +0,0 @@ -all(); - } elseif (! is_array($values)) { - continue; - } - - $results[] = $values; - } - - return array_merge([], ...$results); - } - - /** - * Cross join the given arrays, returning all possible permutations. - * - * @param iterable ...$arrays - * @return array - */ - public static function crossJoin(...$arrays) - { - $results = [[]]; - - foreach ($arrays as $index => $array) { - $append = []; - - foreach ($results as $product) { - foreach ($array as $item) { - $product[$index] = $item; - - $append[] = $product; - } - } - - $results = $append; - } - - return $results; - } - - /** - * Divide an array into two arrays. One with keys and the other with values. - * - * @param array $array - * @return array - */ - public static function divide($array) - { - return [array_keys($array), array_values($array)]; - } - - /** - * Flatten a multi-dimensional associative array with dots. - * - * @param iterable $array - * @param string $prepend - * @return array - */ - public static function dot($array, $prepend = '') - { - $results = []; - - foreach ($array as $key => $value) { - if (is_array($value) && ! empty($value)) { - $results = array_merge($results, static::dot($value, $prepend.$key.'.')); - } else { - $results[$prepend.$key] = $value; - } - } - - return $results; - } - - /** - * Convert a flatten "dot" notation array into an expanded array. - * - * @param iterable $array - * @return array - */ - public static function undot($array) - { - $results = []; - - foreach ($array as $key => $value) { - static::set($results, $key, $value); - } - - return $results; - } - - /** - * Get all of the given array except for a specified array of keys. - * - * @param array $array - * @param array|string|int|float $keys - * @return array - */ - public static function except($array, $keys) - { - static::forget($array, $keys); - - return $array; - } - - /** - * Determine if the given key exists in the provided array. - * - * @param \ArrayAccess|array $array - * @param string|int $key - * @return bool - */ - public static function exists($array, $key) - { - if ($array instanceof Enumerable) { - return $array->has($key); - } - - if ($array instanceof ArrayAccess) { - return $array->offsetExists($key); - } - - if (is_float($key)) { - $key = (string) $key; - } - - return array_key_exists($key, $array); - } - - /** - * Return the first element in an array passing a given truth test. - * - * @param iterable $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public static function first($array, ?callable $callback = null, $default = null) - { - if (is_null($callback)) { - if (empty($array)) { - return value($default); - } - - foreach ($array as $item) { - return $item; - } - - return value($default); - } - - foreach ($array as $key => $value) { - if ($callback($value, $key)) { - return $value; - } - } - - return value($default); - } - - /** - * Return the last element in an array passing a given truth test. - * - * @param array $array - * @param callable|null $callback - * @param mixed $default - * @return mixed - */ - public static function last($array, ?callable $callback = null, $default = null) - { - if (is_null($callback)) { - return empty($array) ? value($default) : end($array); - } - - return static::first(array_reverse($array, true), $callback, $default); - } - - /** - * Take the first or last {$limit} items from an array. - * - * @param array $array - * @param int $limit - * @return array - */ - public static function take($array, $limit) - { - if ($limit < 0) { - return array_slice($array, $limit, abs($limit)); - } - - return array_slice($array, 0, $limit); - } - - /** - * Flatten a multi-dimensional array into a single level. - * - * @param iterable $array - * @param int $depth - * @return array - */ - public static function flatten($array, $depth = INF) - { - $result = []; - - foreach ($array as $item) { - $item = $item instanceof Collection ? $item->all() : $item; - - if (! is_array($item)) { - $result[] = $item; - } else { - $values = $depth === 1 - ? array_values($item) - : static::flatten($item, $depth - 1); - - foreach ($values as $value) { - $result[] = $value; - } - } - } - - return $result; - } - - /** - * Remove one or many array items from a given array using "dot" notation. - * - * @param array $array - * @param array|string|int|float $keys - * @return void - */ - public static function forget(&$array, $keys) - { - $original = &$array; - - $keys = (array) $keys; - - if (count($keys) === 0) { - return; - } - - foreach ($keys as $key) { - // if the exact key exists in the top-level, remove it - if (static::exists($array, $key)) { - unset($array[$key]); - - continue; - } - - $parts = explode('.', $key); - - // clean up before each pass - $array = &$original; - - while (count($parts) > 1) { - $part = array_shift($parts); - - if (isset($array[$part]) && static::accessible($array[$part])) { - $array = &$array[$part]; - } else { - continue 2; - } - } - - unset($array[array_shift($parts)]); - } - } - - /** - * Get an item from an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|int|null $key - * @param mixed $default - * @return mixed - */ - public static function get($array, $key, $default = null) - { - if (! static::accessible($array)) { - return value($default); - } - - if (is_null($key)) { - return $array; - } - - if (static::exists($array, $key)) { - return $array[$key]; - } - - if (! str_contains($key, '.')) { - return $array[$key] ?? value($default); - } - - foreach (explode('.', $key) as $segment) { - if (static::accessible($array) && static::exists($array, $segment)) { - $array = $array[$segment]; - } else { - return value($default); - } - } - - return $array; - } - - /** - * Check if an item or items exist in an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|array $keys - * @return bool - */ - public static function has($array, $keys) - { - $keys = (array) $keys; - - if (! $array || $keys === []) { - return false; - } - - foreach ($keys as $key) { - $subKeyArray = $array; - - if (static::exists($array, $key)) { - continue; - } - - foreach (explode('.', $key) as $segment) { - if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { - $subKeyArray = $subKeyArray[$segment]; - } else { - return false; - } - } - } - - return true; - } - - /** - * Determine if any of the keys exist in an array using "dot" notation. - * - * @param \ArrayAccess|array $array - * @param string|array $keys - * @return bool - */ - public static function hasAny($array, $keys) - { - if (is_null($keys)) { - return false; - } - - $keys = (array) $keys; - - if (! $array) { - return false; - } - - if ($keys === []) { - return false; - } - - foreach ($keys as $key) { - if (static::has($array, $key)) { - return true; - } - } - - return false; - } - - /** - * Determines if an array is associative. - * - * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. - * - * @param array $array - * @return bool - */ - public static function isAssoc(array $array) - { - return ! array_is_list($array); - } - - /** - * Determines if an array is a list. - * - * An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between. - * - * @param array $array - * @return bool - */ - public static function isList($array) - { - return array_is_list($array); - } - - /** - * Join all items using a string. The final items can use a separate glue string. - * - * @param array $array - * @param string $glue - * @param string $finalGlue - * @return string - */ - public static function join($array, $glue, $finalGlue = '') - { - if ($finalGlue === '') { - return implode($glue, $array); - } - - if (count($array) === 0) { - return ''; - } - - if (count($array) === 1) { - return end($array); - } - - $finalItem = array_pop($array); - - return implode($glue, $array).$finalGlue.$finalItem; - } - - /** - * Key an associative array by a field or using a callback. - * - * @param array $array - * @param callable|array|string $keyBy - * @return array - */ - public static function keyBy($array, $keyBy) - { - return Collection::make($array)->keyBy($keyBy)->all(); - } - - /** - * Prepend the key names of an associative array. - * - * @param array $array - * @param string $prependWith - * @return array - */ - public static function prependKeysWith($array, $prependWith) - { - return static::mapWithKeys($array, fn ($item, $key) => [$prependWith.$key => $item]); - } - - /** - * Get a subset of the items from the given array. - * - * @param array $array - * @param array|string $keys - * @return array - */ - public static function only($array, $keys) - { - return array_intersect_key($array, array_flip((array) $keys)); - } - - /** - * Select an array of values from an array. - * - * @param array $array - * @param array|string $keys - * @return array - */ - public static function select($array, $keys) - { - $keys = static::wrap($keys); - - return static::map($array, function ($item) use ($keys) { - $result = []; - - foreach ($keys as $key) { - if (Arr::accessible($item) && Arr::exists($item, $key)) { - $result[$key] = $item[$key]; - } elseif (is_object($item) && isset($item->{$key})) { - $result[$key] = $item->{$key}; - } - } - - return $result; - }); - } - - /** - * Pluck an array of values from an array. - * - * @param iterable $array - * @param string|array|int|null $value - * @param string|array|null $key - * @return array - */ - public static function pluck($array, $value, $key = null) - { - $results = []; - - [$value, $key] = static::explodePluckParameters($value, $key); - - foreach ($array as $item) { - $itemValue = data_get($item, $value); - - // If the key is "null", we will just append the value to the array and keep - // looping. Otherwise we will key the array using the value of the key we - // received from the developer. Then we'll return the final array form. - if (is_null($key)) { - $results[] = $itemValue; - } else { - $itemKey = data_get($item, $key); - - if (is_object($itemKey) && method_exists($itemKey, '__toString')) { - $itemKey = (string) $itemKey; - } - - $results[$itemKey] = $itemValue; - } - } - - return $results; - } - - /** - * Explode the "value" and "key" arguments passed to "pluck". - * - * @param string|array $value - * @param string|array|null $key - * @return array - */ - protected static function explodePluckParameters($value, $key) - { - $value = is_string($value) ? explode('.', $value) : $value; - - $key = is_null($key) || is_array($key) ? $key : explode('.', $key); - - return [$value, $key]; - } - - /** - * Run a map over each of the items in the array. - * - * @param array $array - * @param callable $callback - * @return array - */ - public static function map(array $array, callable $callback) - { - $keys = array_keys($array); - - try { - $items = array_map($callback, $array, $keys); - } catch (ArgumentCountError) { - $items = array_map($callback, $array); - } - - return array_combine($keys, $items); - } - - /** - * Run an associative map over each of the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TKey - * @template TValue - * @template TMapWithKeysKey of array-key - * @template TMapWithKeysValue - * - * @param array $array - * @param callable(TValue, TKey): array $callback - * @return array - */ - public static function mapWithKeys(array $array, callable $callback) - { - $result = []; - - foreach ($array as $key => $value) { - $assoc = $callback($value, $key); - - foreach ($assoc as $mapKey => $mapValue) { - $result[$mapKey] = $mapValue; - } - } - - return $result; - } - - /** - * Push an item onto the beginning of an array. - * - * @param array $array - * @param mixed $value - * @param mixed $key - * @return array - */ - public static function prepend($array, $value, $key = null) - { - if (func_num_args() == 2) { - array_unshift($array, $value); - } else { - $array = [$key => $value] + $array; - } - - return $array; - } - - /** - * Get a value from the array, and remove it. - * - * @param array $array - * @param string|int $key - * @param mixed $default - * @return mixed - */ - public static function pull(&$array, $key, $default = null) - { - $value = static::get($array, $key, $default); - - static::forget($array, $key); - - return $value; - } - - /** - * Convert the array into a query string. - * - * @param array $array - * @return string - */ - public static function query($array) - { - return http_build_query($array, '', '&', PHP_QUERY_RFC3986); - } - - /** - * Get one or a specified number of random values from an array. - * - * @param array $array - * @param int|null $number - * @param bool $preserveKeys - * @return mixed - * - * @throws \InvalidArgumentException - */ - public static function random($array, $number = null, $preserveKeys = false) - { - $requested = is_null($number) ? 1 : $number; - - $count = count($array); - - if ($requested > $count) { - throw new InvalidArgumentException( - "You requested {$requested} items, but there are only {$count} items available." - ); - } - - if (is_null($number)) { - return $array[array_rand($array)]; - } - - if ((int) $number === 0) { - return []; - } - - $keys = array_rand($array, $number); - - $results = []; - - if ($preserveKeys) { - foreach ((array) $keys as $key) { - $results[$key] = $array[$key]; - } - } else { - foreach ((array) $keys as $key) { - $results[] = $array[$key]; - } - } - - return $results; - } - - /** - * Set an array item to a given value using "dot" notation. - * - * If no key is given to the method, the entire array will be replaced. - * - * @param array $array - * @param string|int|null $key - * @param mixed $value - * @return array - */ - public static function set(&$array, $key, $value) - { - if (is_null($key)) { - return $array = $value; - } - - $keys = explode('.', $key); - - foreach ($keys as $i => $key) { - if (count($keys) === 1) { - break; - } - - unset($keys[$i]); - - // If the key doesn't exist at this depth, we will just create an empty array - // to hold the next value, allowing us to create the arrays to hold final - // values at the correct depth. Then we'll keep digging into the array. - if (! isset($array[$key]) || ! is_array($array[$key])) { - $array[$key] = []; - } - - $array = &$array[$key]; - } - - $array[array_shift($keys)] = $value; - - return $array; - } - - /** - * Shuffle the given array and return the result. - * - * @param array $array - * @param int|null $seed - * @return array - */ - public static function shuffle($array, $seed = null) - { - if (is_null($seed)) { - shuffle($array); - } else { - mt_srand($seed); - shuffle($array); - mt_srand(); - } - - return $array; - } - - /** - * Sort the array using the given callback or "dot" notation. - * - * @param array $array - * @param callable|array|string|null $callback - * @return array - */ - public static function sort($array, $callback = null) - { - return Collection::make($array)->sortBy($callback)->all(); - } - - /** - * Sort the array in descending order using the given callback or "dot" notation. - * - * @param array $array - * @param callable|array|string|null $callback - * @return array - */ - public static function sortDesc($array, $callback = null) - { - return Collection::make($array)->sortByDesc($callback)->all(); - } - - /** - * Recursively sort an array by keys and values. - * - * @param array $array - * @param int $options - * @param bool $descending - * @return array - */ - public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false) - { - foreach ($array as &$value) { - if (is_array($value)) { - $value = static::sortRecursive($value, $options, $descending); - } - } - - if (! array_is_list($array)) { - $descending - ? krsort($array, $options) - : ksort($array, $options); - } else { - $descending - ? rsort($array, $options) - : sort($array, $options); - } - - return $array; - } - - /** - * Recursively sort an array by keys and values in descending order. - * - * @param array $array - * @param int $options - * @return array - */ - public static function sortRecursiveDesc($array, $options = SORT_REGULAR) - { - return static::sortRecursive($array, $options, true); - } - - /** - * Conditionally compile classes from an array into a CSS class list. - * - * @param array $array - * @return string - */ - public static function toCssClasses($array) - { - $classList = static::wrap($array); - - $classes = []; - - foreach ($classList as $class => $constraint) { - if (is_numeric($class)) { - $classes[] = $constraint; - } elseif ($constraint) { - $classes[] = $class; - } - } - - return implode(' ', $classes); - } - - /** - * Conditionally compile styles from an array into a style list. - * - * @param array $array - * @return string - */ - public static function toCssStyles($array) - { - $styleList = static::wrap($array); - - $styles = []; - - foreach ($styleList as $class => $constraint) { - if (is_numeric($class)) { - $styles[] = Str::finish($constraint, ';'); - } elseif ($constraint) { - $styles[] = Str::finish($class, ';'); - } - } - - return implode(' ', $styles); - } - - /** - * Filter the array using the given callback. - * - * @param array $array - * @param callable $callback - * @return array - */ - public static function where($array, callable $callback) - { - return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); - } - - /** - * Filter items where the value is not null. - * - * @param array $array - * @return array - */ - public static function whereNotNull($array) - { - return static::where($array, fn ($value) => ! is_null($value)); - } - - /** - * If the given value is not an array and not null, wrap it in one. - * - * @param mixed $value - * @return array - */ - public static function wrap($value) - { - if (is_null($value)) { - return []; - } - - return is_array($value) ? $value : [$value]; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/Collection.php b/lam/lib/3rdParty/composer/illuminate/collections/Collection.php deleted file mode 100644 index 2f0c768f1..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/Collection.php +++ /dev/null @@ -1,1821 +0,0 @@ - - * @implements \Illuminate\Support\Enumerable - */ -class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable -{ - /** - * @use \Illuminate\Support\Traits\EnumeratesValues - */ - use EnumeratesValues, Macroable; - - /** - * The items contained in the collection. - * - * @var array - */ - protected $items = []; - - /** - * Create a new collection. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items - * @return void - */ - public function __construct($items = []) - { - $this->items = $this->getArrayableItems($items); - } - - /** - * Create a collection with the given range. - * - * @param int $from - * @param int $to - * @return static - */ - public static function range($from, $to) - { - return new static(range($from, $to)); - } - - /** - * Get all of the items in the collection. - * - * @return array - */ - public function all() - { - return $this->items; - } - - /** - * Get a lazy collection for the items in this collection. - * - * @return \Illuminate\Support\LazyCollection - */ - public function lazy() - { - return new LazyCollection($this->items); - } - - /** - * Get the average value of a given key. - * - * @param (callable(TValue): float|int)|string|null $callback - * @return float|int|null - */ - public function avg($callback = null) - { - $callback = $this->valueRetriever($callback); - - $items = $this - ->map(fn ($value) => $callback($value)) - ->filter(fn ($value) => ! is_null($value)); - - if ($count = $items->count()) { - return $items->sum() / $count; - } - } - - /** - * Get the median of a given key. - * - * @param string|array|null $key - * @return float|int|null - */ - public function median($key = null) - { - $values = (isset($key) ? $this->pluck($key) : $this) - ->filter(fn ($item) => ! is_null($item)) - ->sort()->values(); - - $count = $values->count(); - - if ($count === 0) { - return; - } - - $middle = (int) ($count / 2); - - if ($count % 2) { - return $values->get($middle); - } - - return (new static([ - $values->get($middle - 1), $values->get($middle), - ]))->average(); - } - - /** - * Get the mode of a given key. - * - * @param string|array|null $key - * @return array|null - */ - public function mode($key = null) - { - if ($this->count() === 0) { - return; - } - - $collection = isset($key) ? $this->pluck($key) : $this; - - $counts = new static; - - $collection->each(fn ($value) => $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1); - - $sorted = $counts->sort(); - - $highestValue = $sorted->last(); - - return $sorted->filter(fn ($value) => $value == $highestValue) - ->sort()->keys()->all(); - } - - /** - * Collapse the collection of items into a single array. - * - * @return static - */ - public function collapse() - { - return new static(Arr::collapse($this->items)); - } - - /** - * Determine if an item exists in the collection. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function contains($key, $operator = null, $value = null) - { - if (func_num_args() === 1) { - if ($this->useAsCallable($key)) { - $placeholder = new stdClass; - - return $this->first($key, $placeholder) !== $placeholder; - } - - return in_array($key, $this->items); - } - - return $this->contains($this->operatorForWhere(...func_get_args())); - } - - /** - * Determine if an item exists, using strict comparison. - * - * @param (callable(TValue): bool)|TValue|array-key $key - * @param TValue|null $value - * @return bool - */ - public function containsStrict($key, $value = null) - { - if (func_num_args() === 2) { - return $this->contains(fn ($item) => data_get($item, $key) === $value); - } - - if ($this->useAsCallable($key)) { - return ! is_null($this->first($key)); - } - - return in_array($key, $this->items, true); - } - - /** - * Determine if an item is not contained in the collection. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function doesntContain($key, $operator = null, $value = null) - { - return ! $this->contains(...func_get_args()); - } - - /** - * Cross join with the given lists, returning all possible permutations. - * - * @template TCrossJoinKey - * @template TCrossJoinValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists - * @return static> - */ - public function crossJoin(...$lists) - { - return new static(Arr::crossJoin( - $this->items, ...array_map([$this, 'getArrayableItems'], $lists) - )); - } - - /** - * Get the items in the collection that are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diff($items) - { - return new static(array_diff($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection that are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function diffUsing($items, callable $callback) - { - return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Get the items in the collection whose keys and values are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffAssoc($items) - { - return new static(array_diff_assoc($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection whose keys and values are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffAssocUsing($items, callable $callback) - { - return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Get the items in the collection whose keys are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffKeys($items) - { - return new static(array_diff_key($this->items, $this->getArrayableItems($items))); - } - - /** - * Get the items in the collection whose keys are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffKeysUsing($items, callable $callback) - { - return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Retrieve duplicate items from the collection. - * - * @param (callable(TValue): bool)|string|null $callback - * @param bool $strict - * @return static - */ - public function duplicates($callback = null, $strict = false) - { - $items = $this->map($this->valueRetriever($callback)); - - $uniqueItems = $items->unique(null, $strict); - - $compare = $this->duplicateComparator($strict); - - $duplicates = new static; - - foreach ($items as $key => $value) { - if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) { - $uniqueItems->shift(); - } else { - $duplicates[$key] = $value; - } - } - - return $duplicates; - } - - /** - * Retrieve duplicate items from the collection using strict comparison. - * - * @param (callable(TValue): bool)|string|null $callback - * @return static - */ - public function duplicatesStrict($callback = null) - { - return $this->duplicates($callback, true); - } - - /** - * Get the comparison function to detect duplicates. - * - * @param bool $strict - * @return callable(TValue, TValue): bool - */ - protected function duplicateComparator($strict) - { - if ($strict) { - return fn ($a, $b) => $a === $b; - } - - return fn ($a, $b) => $a == $b; - } - - /** - * Get all items except for those with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array|string $keys - * @return static - */ - public function except($keys) - { - if (is_null($keys)) { - return new static($this->items); - } - - if ($keys instanceof Enumerable) { - $keys = $keys->all(); - } elseif (! is_array($keys)) { - $keys = func_get_args(); - } - - return new static(Arr::except($this->items, $keys)); - } - - /** - * Run a filter over each of the items. - * - * @param (callable(TValue, TKey): bool)|null $callback - * @return static - */ - public function filter(?callable $callback = null) - { - if ($callback) { - return new static(Arr::where($this->items, $callback)); - } - - return new static(array_filter($this->items)); - } - - /** - * Get the first item from the collection passing the given truth test. - * - * @template TFirstDefault - * - * @param (callable(TValue, TKey): bool)|null $callback - * @param TFirstDefault|(\Closure(): TFirstDefault) $default - * @return TValue|TFirstDefault - */ - public function first(?callable $callback = null, $default = null) - { - return Arr::first($this->items, $callback, $default); - } - - /** - * Get a flattened array of the items in the collection. - * - * @param int $depth - * @return static - */ - public function flatten($depth = INF) - { - return new static(Arr::flatten($this->items, $depth)); - } - - /** - * Flip the items in the collection. - * - * @return static - */ - public function flip() - { - return new static(array_flip($this->items)); - } - - /** - * Remove an item from the collection by key. - * - * \Illuminate\Contracts\Support\Arrayable|iterable|TKey $keys - * - * @return $this - */ - public function forget($keys) - { - foreach ($this->getArrayableItems($keys) as $key) { - $this->offsetUnset($key); - } - - return $this; - } - - /** - * Get an item from the collection by key. - * - * @template TGetDefault - * - * @param TKey $key - * @param TGetDefault|(\Closure(): TGetDefault) $default - * @return TValue|TGetDefault - */ - public function get($key, $default = null) - { - if (array_key_exists($key, $this->items)) { - return $this->items[$key]; - } - - return value($default); - } - - /** - * Get an item from the collection by key or add it to collection if it does not exist. - * - * @template TGetOrPutValue - * - * @param mixed $key - * @param TGetOrPutValue|(\Closure(): TGetOrPutValue) $value - * @return TValue|TGetOrPutValue - */ - public function getOrPut($key, $value) - { - if (array_key_exists($key, $this->items)) { - return $this->items[$key]; - } - - $this->offsetSet($key, $value = value($value)); - - return $value; - } - - /** - * Group an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $groupBy - * @param bool $preserveKeys - * @return static> - */ - public function groupBy($groupBy, $preserveKeys = false) - { - if (! $this->useAsCallable($groupBy) && is_array($groupBy)) { - $nextGroups = $groupBy; - - $groupBy = array_shift($nextGroups); - } - - $groupBy = $this->valueRetriever($groupBy); - - $results = []; - - foreach ($this->items as $key => $value) { - $groupKeys = $groupBy($value, $key); - - if (! is_array($groupKeys)) { - $groupKeys = [$groupKeys]; - } - - foreach ($groupKeys as $groupKey) { - $groupKey = match (true) { - is_bool($groupKey) => (int) $groupKey, - $groupKey instanceof \BackedEnum => $groupKey->value, - $groupKey instanceof \Stringable => (string) $groupKey, - default => $groupKey, - }; - - if (! array_key_exists($groupKey, $results)) { - $results[$groupKey] = new static; - } - - $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); - } - } - - $result = new static($results); - - if (! empty($nextGroups)) { - return $result->map->groupBy($nextGroups, $preserveKeys); - } - - return $result; - } - - /** - * Key an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $keyBy - * @return static - */ - public function keyBy($keyBy) - { - $keyBy = $this->valueRetriever($keyBy); - - $results = []; - - foreach ($this->items as $key => $item) { - $resolvedKey = $keyBy($item, $key); - - if (is_object($resolvedKey)) { - $resolvedKey = (string) $resolvedKey; - } - - $results[$resolvedKey] = $item; - } - - return new static($results); - } - - /** - * Determine if an item exists in the collection by key. - * - * @param TKey|array $key - * @return bool - */ - public function has($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if (! array_key_exists($value, $this->items)) { - return false; - } - } - - return true; - } - - /** - * Determine if any of the keys exist in the collection. - * - * @param mixed $key - * @return bool - */ - public function hasAny($key) - { - if ($this->isEmpty()) { - return false; - } - - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if ($this->has($value)) { - return true; - } - } - - return false; - } - - /** - * Concatenate values of a given key as a string. - * - * @param callable|string $value - * @param string|null $glue - * @return string - */ - public function implode($value, $glue = null) - { - if ($this->useAsCallable($value)) { - return implode($glue ?? '', $this->map($value)->all()); - } - - $first = $this->first(); - - if (is_array($first) || (is_object($first) && ! $first instanceof Stringable)) { - return implode($glue ?? '', $this->pluck($value)->all()); - } - - return implode($value ?? '', $this->items); - } - - /** - * Intersect the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersect($items) - { - return new static(array_intersect($this->items, $this->getArrayableItems($items))); - } - - /** - * Intersect the collection with the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function intersectUsing($items, callable $callback) - { - return new static(array_uintersect($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Intersect the collection with the given items with additional index check. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersectAssoc($items) - { - return new static(array_intersect_assoc($this->items, $this->getArrayableItems($items))); - } - - /** - * Intersect the collection with the given items with additional index check, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function intersectAssocUsing($items, callable $callback) - { - return new static(array_intersect_uassoc($this->items, $this->getArrayableItems($items), $callback)); - } - - /** - * Intersect the collection with the given items by key. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersectByKeys($items) - { - return new static(array_intersect_key( - $this->items, $this->getArrayableItems($items) - )); - } - - /** - * Determine if the collection is empty or not. - * - * @return bool - */ - public function isEmpty() - { - return empty($this->items); - } - - /** - * Determine if the collection contains a single item. - * - * @return bool - */ - public function containsOneItem() - { - return $this->count() === 1; - } - - /** - * Join all items from the collection using a string. The final items can use a separate glue string. - * - * @param string $glue - * @param string $finalGlue - * @return string - */ - public function join($glue, $finalGlue = '') - { - if ($finalGlue === '') { - return $this->implode($glue); - } - - $count = $this->count(); - - if ($count === 0) { - return ''; - } - - if ($count === 1) { - return $this->last(); - } - - $collection = new static($this->items); - - $finalItem = $collection->pop(); - - return $collection->implode($glue).$finalGlue.$finalItem; - } - - /** - * Get the keys of the collection items. - * - * @return static - */ - public function keys() - { - return new static(array_keys($this->items)); - } - - /** - * Get the last item from the collection. - * - * @template TLastDefault - * - * @param (callable(TValue, TKey): bool)|null $callback - * @param TLastDefault|(\Closure(): TLastDefault) $default - * @return TValue|TLastDefault - */ - public function last(?callable $callback = null, $default = null) - { - return Arr::last($this->items, $callback, $default); - } - - /** - * Get the values of a given key. - * - * @param string|int|array $value - * @param string|null $key - * @return static - */ - public function pluck($value, $key = null) - { - return new static(Arr::pluck($this->items, $value, $key)); - } - - /** - * Run a map over each of the items. - * - * @template TMapValue - * - * @param callable(TValue, TKey): TMapValue $callback - * @return static - */ - public function map(callable $callback) - { - return new static(Arr::map($this->items, $callback)); - } - - /** - * Run a dictionary map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapToDictionaryKey of array-key - * @template TMapToDictionaryValue - * - * @param callable(TValue, TKey): array $callback - * @return static> - */ - public function mapToDictionary(callable $callback) - { - $dictionary = []; - - foreach ($this->items as $key => $item) { - $pair = $callback($item, $key); - - $key = key($pair); - - $value = reset($pair); - - if (! isset($dictionary[$key])) { - $dictionary[$key] = []; - } - - $dictionary[$key][] = $value; - } - - return new static($dictionary); - } - - /** - * Run an associative map over each of the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapWithKeysKey of array-key - * @template TMapWithKeysValue - * - * @param callable(TValue, TKey): array $callback - * @return static - */ - public function mapWithKeys(callable $callback) - { - return new static(Arr::mapWithKeys($this->items, $callback)); - } - - /** - * Merge the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function merge($items) - { - return new static(array_merge($this->items, $this->getArrayableItems($items))); - } - - /** - * Recursively merge the collection with the given items. - * - * @template TMergeRecursiveValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function mergeRecursive($items) - { - return new static(array_merge_recursive($this->items, $this->getArrayableItems($items))); - } - - /** - * Create a collection by using this collection for keys and another for its values. - * - * @template TCombineValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function combine($values) - { - return new static(array_combine($this->all(), $this->getArrayableItems($values))); - } - - /** - * Union the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function union($items) - { - return new static($this->items + $this->getArrayableItems($items)); - } - - /** - * Create a new collection consisting of every n-th element. - * - * @param int $step - * @param int $offset - * @return static - */ - public function nth($step, $offset = 0) - { - $new = []; - - $position = 0; - - foreach ($this->slice($offset)->items as $item) { - if ($position % $step === 0) { - $new[] = $item; - } - - $position++; - } - - return new static($new); - } - - /** - * Get the items with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array|string|null $keys - * @return static - */ - public function only($keys) - { - if (is_null($keys)) { - return new static($this->items); - } - - if ($keys instanceof Enumerable) { - $keys = $keys->all(); - } - - $keys = is_array($keys) ? $keys : func_get_args(); - - return new static(Arr::only($this->items, $keys)); - } - - /** - * Select specific values from the items within the collection. - * - * @param \Illuminate\Support\Enumerable|array|string|null $keys - * @return static - */ - public function select($keys) - { - if (is_null($keys)) { - return new static($this->items); - } - - if ($keys instanceof Enumerable) { - $keys = $keys->all(); - } - - $keys = is_array($keys) ? $keys : func_get_args(); - - return new static(Arr::select($this->items, $keys)); - } - - /** - * Get and remove the last N items from the collection. - * - * @param int $count - * @return static|TValue|null - */ - public function pop($count = 1) - { - if ($count === 1) { - return array_pop($this->items); - } - - if ($this->isEmpty()) { - return new static; - } - - $results = []; - - $collectionCount = $this->count(); - - foreach (range(1, min($count, $collectionCount)) as $item) { - array_push($results, array_pop($this->items)); - } - - return new static($results); - } - - /** - * Push an item onto the beginning of the collection. - * - * @param TValue $value - * @param TKey $key - * @return $this - */ - public function prepend($value, $key = null) - { - $this->items = Arr::prepend($this->items, ...func_get_args()); - - return $this; - } - - /** - * Push one or more items onto the end of the collection. - * - * @param TValue ...$values - * @return $this - */ - public function push(...$values) - { - foreach ($values as $value) { - $this->items[] = $value; - } - - return $this; - } - - /** - * Push all of the given items onto the collection. - * - * @template TConcatKey of array-key - * @template TConcatValue - * - * @param iterable $source - * @return static - */ - public function concat($source) - { - $result = new static($this); - - foreach ($source as $item) { - $result->push($item); - } - - return $result; - } - - /** - * Get and remove an item from the collection. - * - * @template TPullDefault - * - * @param TKey $key - * @param TPullDefault|(\Closure(): TPullDefault) $default - * @return TValue|TPullDefault - */ - public function pull($key, $default = null) - { - return Arr::pull($this->items, $key, $default); - } - - /** - * Put an item in the collection by key. - * - * @param TKey $key - * @param TValue $value - * @return $this - */ - public function put($key, $value) - { - $this->offsetSet($key, $value); - - return $this; - } - - /** - * Get one or a specified number of items randomly from the collection. - * - * @param (callable(self): int)|int|null $number - * @param bool $preserveKeys - * @return static|TValue - * - * @throws \InvalidArgumentException - */ - public function random($number = null, $preserveKeys = false) - { - if (is_null($number)) { - return Arr::random($this->items); - } - - if (is_callable($number)) { - return new static(Arr::random($this->items, $number($this), $preserveKeys)); - } - - return new static(Arr::random($this->items, $number, $preserveKeys)); - } - - /** - * Replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replace($items) - { - return new static(array_replace($this->items, $this->getArrayableItems($items))); - } - - /** - * Recursively replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replaceRecursive($items) - { - return new static(array_replace_recursive($this->items, $this->getArrayableItems($items))); - } - - /** - * Reverse items order. - * - * @return static - */ - public function reverse() - { - return new static(array_reverse($this->items, true)); - } - - /** - * Search the collection for a given value and return the corresponding key if successful. - * - * @param TValue|(callable(TValue,TKey): bool) $value - * @param bool $strict - * @return TKey|false - */ - public function search($value, $strict = false) - { - if (! $this->useAsCallable($value)) { - return array_search($value, $this->items, $strict); - } - - foreach ($this->items as $key => $item) { - if ($value($item, $key)) { - return $key; - } - } - - return false; - } - - /** - * Get and remove the first N items from the collection. - * - * @param int $count - * @return static|TValue|null - * - * @throws \InvalidArgumentException - */ - public function shift($count = 1) - { - if ($count < 0) { - throw new InvalidArgumentException('Number of shifted items may not be less than zero.'); - } - - if ($this->isEmpty()) { - return null; - } - - if ($count === 0) { - return new static; - } - - if ($count === 1) { - return array_shift($this->items); - } - - $results = []; - - $collectionCount = $this->count(); - - foreach (range(1, min($count, $collectionCount)) as $item) { - array_push($results, array_shift($this->items)); - } - - return new static($results); - } - - /** - * Shuffle the items in the collection. - * - * @param int|null $seed - * @return static - */ - public function shuffle($seed = null) - { - return new static(Arr::shuffle($this->items, $seed)); - } - - /** - * Create chunks representing a "sliding window" view of the items in the collection. - * - * @param int $size - * @param int $step - * @return static - */ - public function sliding($size = 2, $step = 1) - { - $chunks = floor(($this->count() - $size) / $step) + 1; - - return static::times($chunks, fn ($number) => $this->slice(($number - 1) * $step, $size)); - } - - /** - * Skip the first {$count} items. - * - * @param int $count - * @return static - */ - public function skip($count) - { - return $this->slice($count); - } - - /** - * Skip items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipUntil($value) - { - return new static($this->lazy()->skipUntil($value)->all()); - } - - /** - * Skip items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipWhile($value) - { - return new static($this->lazy()->skipWhile($value)->all()); - } - - /** - * Slice the underlying collection array. - * - * @param int $offset - * @param int|null $length - * @return static - */ - public function slice($offset, $length = null) - { - return new static(array_slice($this->items, $offset, $length, true)); - } - - /** - * Split a collection into a certain number of groups. - * - * @param int $numberOfGroups - * @return static - */ - public function split($numberOfGroups) - { - if ($this->isEmpty()) { - return new static; - } - - $groups = new static; - - $groupSize = floor($this->count() / $numberOfGroups); - - $remain = $this->count() % $numberOfGroups; - - $start = 0; - - for ($i = 0; $i < $numberOfGroups; $i++) { - $size = $groupSize; - - if ($i < $remain) { - $size++; - } - - if ($size) { - $groups->push(new static(array_slice($this->items, $start, $size))); - - $start += $size; - } - } - - return $groups; - } - - /** - * Split a collection into a certain number of groups, and fill the first groups completely. - * - * @param int $numberOfGroups - * @return static - */ - public function splitIn($numberOfGroups) - { - return $this->chunk(ceil($this->count() / $numberOfGroups)); - } - - /** - * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - * @throws \Illuminate\Support\MultipleItemsFoundException - */ - public function sole($key = null, $operator = null, $value = null) - { - $filter = func_num_args() > 1 - ? $this->operatorForWhere(...func_get_args()) - : $key; - - $items = $this->unless($filter == null)->filter($filter); - - $count = $items->count(); - - if ($count === 0) { - throw new ItemNotFoundException; - } - - if ($count > 1) { - throw new MultipleItemsFoundException($count); - } - - return $items->first(); - } - - /** - * Get the first item in the collection but throw an exception if no matching items exist. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - */ - public function firstOrFail($key = null, $operator = null, $value = null) - { - $filter = func_num_args() > 1 - ? $this->operatorForWhere(...func_get_args()) - : $key; - - $placeholder = new stdClass(); - - $item = $this->first($filter, $placeholder); - - if ($item === $placeholder) { - throw new ItemNotFoundException; - } - - return $item; - } - - /** - * Chunk the collection into chunks of the given size. - * - * @param int $size - * @return static - */ - public function chunk($size) - { - if ($size <= 0) { - return new static; - } - - $chunks = []; - - foreach (array_chunk($this->items, $size, true) as $chunk) { - $chunks[] = new static($chunk); - } - - return new static($chunks); - } - - /** - * Chunk the collection into chunks with a callback. - * - * @param callable(TValue, TKey, static): bool $callback - * @return static> - */ - public function chunkWhile(callable $callback) - { - return new static( - $this->lazy()->chunkWhile($callback)->mapInto(static::class) - ); - } - - /** - * Sort through each item with a callback. - * - * @param (callable(TValue, TValue): int)|null|int $callback - * @return static - */ - public function sort($callback = null) - { - $items = $this->items; - - $callback && is_callable($callback) - ? uasort($items, $callback) - : asort($items, $callback ?? SORT_REGULAR); - - return new static($items); - } - - /** - * Sort items in descending order. - * - * @param int $options - * @return static - */ - public function sortDesc($options = SORT_REGULAR) - { - $items = $this->items; - - arsort($items, $options); - - return new static($items); - } - - /** - * Sort the collection using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @param bool $descending - * @return static - */ - public function sortBy($callback, $options = SORT_REGULAR, $descending = false) - { - if (is_array($callback) && ! is_callable($callback)) { - return $this->sortByMany($callback, $options); - } - - $results = []; - - $callback = $this->valueRetriever($callback); - - // First we will loop through the items and get the comparator from a callback - // function which we were given. Then, we will sort the returned values and - // grab all the corresponding values for the sorted keys from this array. - foreach ($this->items as $key => $value) { - $results[$key] = $callback($value, $key); - } - - $descending ? arsort($results, $options) - : asort($results, $options); - - // Once we have sorted all of the keys in the array, we will loop through them - // and grab the corresponding model so we can set the underlying items list - // to the sorted version. Then we'll just return the collection instance. - foreach (array_keys($results) as $key) { - $results[$key] = $this->items[$key]; - } - - return new static($results); - } - - /** - * Sort the collection using multiple comparisons. - * - * @param array $comparisons - * @param int $options - * @return static - */ - protected function sortByMany(array $comparisons = [], int $options = SORT_REGULAR) - { - $items = $this->items; - - uasort($items, function ($a, $b) use ($comparisons, $options) { - foreach ($comparisons as $comparison) { - $comparison = Arr::wrap($comparison); - - $prop = $comparison[0]; - - $ascending = Arr::get($comparison, 1, true) === true || - Arr::get($comparison, 1, true) === 'asc'; - - if (! is_string($prop) && is_callable($prop)) { - $result = $prop($a, $b); - } else { - $values = [data_get($a, $prop), data_get($b, $prop)]; - - if (! $ascending) { - $values = array_reverse($values); - } - - if (($options & SORT_FLAG_CASE) === SORT_FLAG_CASE) { - if (($options & SORT_NATURAL) === SORT_NATURAL) { - $result = strnatcasecmp($values[0], $values[1]); - } else { - $result = strcasecmp($values[0], $values[1]); - } - } else { - $result = match ($options) { - SORT_NUMERIC => intval($values[0]) <=> intval($values[1]), - SORT_STRING => strcmp($values[0], $values[1]), - SORT_NATURAL => strnatcmp($values[0], $values[1]), - SORT_LOCALE_STRING => strcoll($values[0], $values[1]), - default => $values[0] <=> $values[1], - }; - } - } - - if ($result === 0) { - continue; - } - - return $result; - } - }); - - return new static($items); - } - - /** - * Sort the collection in descending order using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @return static - */ - public function sortByDesc($callback, $options = SORT_REGULAR) - { - if (is_array($callback) && ! is_callable($callback)) { - foreach ($callback as $index => $key) { - $comparison = Arr::wrap($key); - - $comparison[1] = 'desc'; - - $callback[$index] = $comparison; - } - } - - return $this->sortBy($callback, $options, true); - } - - /** - * Sort the collection keys. - * - * @param int $options - * @param bool $descending - * @return static - */ - public function sortKeys($options = SORT_REGULAR, $descending = false) - { - $items = $this->items; - - $descending ? krsort($items, $options) : ksort($items, $options); - - return new static($items); - } - - /** - * Sort the collection keys in descending order. - * - * @param int $options - * @return static - */ - public function sortKeysDesc($options = SORT_REGULAR) - { - return $this->sortKeys($options, true); - } - - /** - * Sort the collection keys using a callback. - * - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function sortKeysUsing(callable $callback) - { - $items = $this->items; - - uksort($items, $callback); - - return new static($items); - } - - /** - * Splice a portion of the underlying collection array. - * - * @param int $offset - * @param int|null $length - * @param array $replacement - * @return static - */ - public function splice($offset, $length = null, $replacement = []) - { - if (func_num_args() === 1) { - return new static(array_splice($this->items, $offset)); - } - - return new static(array_splice($this->items, $offset, $length, $this->getArrayableItems($replacement))); - } - - /** - * Take the first or last {$limit} items. - * - * @param int $limit - * @return static - */ - public function take($limit) - { - if ($limit < 0) { - return $this->slice($limit, abs($limit)); - } - - return $this->slice(0, $limit); - } - - /** - * Take items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeUntil($value) - { - return new static($this->lazy()->takeUntil($value)->all()); - } - - /** - * Take items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeWhile($value) - { - return new static($this->lazy()->takeWhile($value)->all()); - } - - /** - * Transform each item in the collection using a callback. - * - * @param callable(TValue, TKey): TValue $callback - * @return $this - */ - public function transform(callable $callback) - { - $this->items = $this->map($callback)->all(); - - return $this; - } - - /** - * Flatten a multi-dimensional associative array with dots. - * - * @return static - */ - public function dot() - { - return new static(Arr::dot($this->all())); - } - - /** - * Convert a flatten "dot" notation array into an expanded array. - * - * @return static - */ - public function undot() - { - return new static(Arr::undot($this->all())); - } - - /** - * Return only unique items from the collection array. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @param bool $strict - * @return static - */ - public function unique($key = null, $strict = false) - { - if (is_null($key) && $strict === false) { - return new static(array_unique($this->items, SORT_REGULAR)); - } - - $callback = $this->valueRetriever($key); - - $exists = []; - - return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { - if (in_array($id = $callback($item, $key), $exists, $strict)) { - return true; - } - - $exists[] = $id; - }); - } - - /** - * Reset the keys on the underlying array. - * - * @return static - */ - public function values() - { - return new static(array_values($this->items)); - } - - /** - * Zip the collection together with one or more arrays. - * - * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); - * => [[1, 4], [2, 5], [3, 6]] - * - * @template TZipValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items - * @return static> - */ - public function zip($items) - { - $arrayableItems = array_map(fn ($items) => $this->getArrayableItems($items), func_get_args()); - - $params = array_merge([fn () => new static(func_get_args()), $this->items], $arrayableItems); - - return new static(array_map(...$params)); - } - - /** - * Pad collection to the specified length with a value. - * - * @template TPadValue - * - * @param int $size - * @param TPadValue $value - * @return static - */ - public function pad($size, $value) - { - return new static(array_pad($this->items, $size, $value)); - } - - /** - * Get an iterator for the items. - * - * @return \ArrayIterator - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->items); - } - - /** - * Count the number of items in the collection. - * - * @return int - */ - public function count(): int - { - return count($this->items); - } - - /** - * Count the number of items in the collection by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|string|null $countBy - * @return static - */ - public function countBy($countBy = null) - { - return new static($this->lazy()->countBy($countBy)->all()); - } - - /** - * Add an item to the collection. - * - * @param TValue $item - * @return $this - */ - public function add($item) - { - $this->items[] = $item; - - return $this; - } - - /** - * Get a base Support collection instance from this collection. - * - * @return \Illuminate\Support\Collection - */ - public function toBase() - { - return new self($this); - } - - /** - * Determine if an item exists at an offset. - * - * @param TKey $key - * @return bool - */ - public function offsetExists($key): bool - { - return isset($this->items[$key]); - } - - /** - * Get an item at a given offset. - * - * @param TKey $key - * @return TValue - */ - public function offsetGet($key): mixed - { - return $this->items[$key]; - } - - /** - * Set the item at a given offset. - * - * @param TKey|null $key - * @param TValue $value - * @return void - */ - public function offsetSet($key, $value): void - { - if (is_null($key)) { - $this->items[] = $value; - } else { - $this->items[$key] = $value; - } - } - - /** - * Unset the item at a given offset. - * - * @param TKey $key - * @return void - */ - public function offsetUnset($key): void - { - unset($this->items[$key]); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/Enumerable.php b/lam/lib/3rdParty/composer/illuminate/collections/Enumerable.php deleted file mode 100644 index 806a6923f..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/Enumerable.php +++ /dev/null @@ -1,1263 +0,0 @@ - - * @extends \IteratorAggregate - */ -interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable -{ - /** - * Create a new collection instance if the value isn't one already. - * - * @template TMakeKey of array-key - * @template TMakeValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items - * @return static - */ - public static function make($items = []); - - /** - * Create a new instance by invoking the callback a given amount of times. - * - * @param int $number - * @param callable|null $callback - * @return static - */ - public static function times($number, ?callable $callback = null); - - /** - * Create a collection with the given range. - * - * @param int $from - * @param int $to - * @return static - */ - public static function range($from, $to); - - /** - * Wrap the given value in a collection if applicable. - * - * @template TWrapValue - * - * @param iterable|TWrapValue $value - * @return static - */ - public static function wrap($value); - - /** - * Get the underlying items from the given collection if applicable. - * - * @template TUnwrapKey of array-key - * @template TUnwrapValue - * - * @param array|static $value - * @return array - */ - public static function unwrap($value); - - /** - * Create a new instance with no items. - * - * @return static - */ - public static function empty(); - - /** - * Get all items in the enumerable. - * - * @return array - */ - public function all(); - - /** - * Alias for the "avg" method. - * - * @param (callable(TValue): float|int)|string|null $callback - * @return float|int|null - */ - public function average($callback = null); - - /** - * Get the median of a given key. - * - * @param string|array|null $key - * @return float|int|null - */ - public function median($key = null); - - /** - * Get the mode of a given key. - * - * @param string|array|null $key - * @return array|null - */ - public function mode($key = null); - - /** - * Collapse the items into a single enumerable. - * - * @return static - */ - public function collapse(); - - /** - * Alias for the "contains" method. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function some($key, $operator = null, $value = null); - - /** - * Determine if an item exists, using strict comparison. - * - * @param (callable(TValue): bool)|TValue|array-key $key - * @param TValue|null $value - * @return bool - */ - public function containsStrict($key, $value = null); - - /** - * Get the average value of a given key. - * - * @param (callable(TValue): float|int)|string|null $callback - * @return float|int|null - */ - public function avg($callback = null); - - /** - * Determine if an item exists in the enumerable. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function contains($key, $operator = null, $value = null); - - /** - * Determine if an item is not contained in the collection. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function doesntContain($key, $operator = null, $value = null); - - /** - * Cross join with the given lists, returning all possible permutations. - * - * @template TCrossJoinKey - * @template TCrossJoinValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists - * @return static> - */ - public function crossJoin(...$lists); - - /** - * Dump the collection and end the script. - * - * @param mixed ...$args - * @return never - */ - public function dd(...$args); - - /** - * Dump the collection. - * - * @return $this - */ - public function dump(); - - /** - * Get the items that are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diff($items); - - /** - * Get the items that are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function diffUsing($items, callable $callback); - - /** - * Get the items whose keys and values are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffAssoc($items); - - /** - * Get the items whose keys and values are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffAssocUsing($items, callable $callback); - - /** - * Get the items whose keys are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffKeys($items); - - /** - * Get the items whose keys are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffKeysUsing($items, callable $callback); - - /** - * Retrieve duplicate items. - * - * @param (callable(TValue): bool)|string|null $callback - * @param bool $strict - * @return static - */ - public function duplicates($callback = null, $strict = false); - - /** - * Retrieve duplicate items using strict comparison. - * - * @param (callable(TValue): bool)|string|null $callback - * @return static - */ - public function duplicatesStrict($callback = null); - - /** - * Execute a callback over each item. - * - * @param callable(TValue, TKey): mixed $callback - * @return $this - */ - public function each(callable $callback); - - /** - * Execute a callback over each nested chunk of items. - * - * @param callable $callback - * @return static - */ - public function eachSpread(callable $callback); - - /** - * Determine if all items pass the given truth test. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function every($key, $operator = null, $value = null); - - /** - * Get all items except for those with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array $keys - * @return static - */ - public function except($keys); - - /** - * Run a filter over each of the items. - * - * @param (callable(TValue): bool)|null $callback - * @return static - */ - public function filter(?callable $callback = null); - - /** - * Apply the callback if the given "value" is (or resolves to) truthy. - * - * @template TWhenReturnType as null - * - * @param bool $value - * @param (callable($this): TWhenReturnType)|null $callback - * @param (callable($this): TWhenReturnType)|null $default - * @return $this|TWhenReturnType - */ - public function when($value, ?callable $callback = null, ?callable $default = null); - - /** - * Apply the callback if the collection is empty. - * - * @template TWhenEmptyReturnType - * - * @param (callable($this): TWhenEmptyReturnType) $callback - * @param (callable($this): TWhenEmptyReturnType)|null $default - * @return $this|TWhenEmptyReturnType - */ - public function whenEmpty(callable $callback, ?callable $default = null); - - /** - * Apply the callback if the collection is not empty. - * - * @template TWhenNotEmptyReturnType - * - * @param callable($this): TWhenNotEmptyReturnType $callback - * @param (callable($this): TWhenNotEmptyReturnType)|null $default - * @return $this|TWhenNotEmptyReturnType - */ - public function whenNotEmpty(callable $callback, ?callable $default = null); - - /** - * Apply the callback if the given "value" is (or resolves to) truthy. - * - * @template TUnlessReturnType - * - * @param bool $value - * @param (callable($this): TUnlessReturnType) $callback - * @param (callable($this): TUnlessReturnType)|null $default - * @return $this|TUnlessReturnType - */ - public function unless($value, callable $callback, ?callable $default = null); - - /** - * Apply the callback unless the collection is empty. - * - * @template TUnlessEmptyReturnType - * - * @param callable($this): TUnlessEmptyReturnType $callback - * @param (callable($this): TUnlessEmptyReturnType)|null $default - * @return $this|TUnlessEmptyReturnType - */ - public function unlessEmpty(callable $callback, ?callable $default = null); - - /** - * Apply the callback unless the collection is not empty. - * - * @template TUnlessNotEmptyReturnType - * - * @param callable($this): TUnlessNotEmptyReturnType $callback - * @param (callable($this): TUnlessNotEmptyReturnType)|null $default - * @return $this|TUnlessNotEmptyReturnType - */ - public function unlessNotEmpty(callable $callback, ?callable $default = null); - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param mixed $operator - * @param mixed $value - * @return static - */ - public function where($key, $operator = null, $value = null); - - /** - * Filter items where the value for the given key is null. - * - * @param string|null $key - * @return static - */ - public function whereNull($key = null); - - /** - * Filter items where the value for the given key is not null. - * - * @param string|null $key - * @return static - */ - public function whereNotNull($key = null); - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param mixed $value - * @return static - */ - public function whereStrict($key, $value); - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @param bool $strict - * @return static - */ - public function whereIn($key, $values, $strict = false); - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereInStrict($key, $values); - - /** - * Filter items such that the value of the given key is between the given values. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereBetween($key, $values); - - /** - * Filter items such that the value of the given key is not between the given values. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereNotBetween($key, $values); - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @param bool $strict - * @return static - */ - public function whereNotIn($key, $values, $strict = false); - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereNotInStrict($key, $values); - - /** - * Filter the items, removing any items that don't match the given type(s). - * - * @template TWhereInstanceOf - * - * @param class-string|array> $type - * @return static - */ - public function whereInstanceOf($type); - - /** - * Get the first item from the enumerable passing the given truth test. - * - * @template TFirstDefault - * - * @param (callable(TValue,TKey): bool)|null $callback - * @param TFirstDefault|(\Closure(): TFirstDefault) $default - * @return TValue|TFirstDefault - */ - public function first(?callable $callback = null, $default = null); - - /** - * Get the first item by the given key value pair. - * - * @param string $key - * @param mixed $operator - * @param mixed $value - * @return TValue|null - */ - public function firstWhere($key, $operator = null, $value = null); - - /** - * Get a flattened array of the items in the collection. - * - * @param int $depth - * @return static - */ - public function flatten($depth = INF); - - /** - * Flip the values with their keys. - * - * @return static - */ - public function flip(); - - /** - * Get an item from the collection by key. - * - * @template TGetDefault - * - * @param TKey $key - * @param TGetDefault|(\Closure(): TGetDefault) $default - * @return TValue|TGetDefault - */ - public function get($key, $default = null); - - /** - * Group an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $groupBy - * @param bool $preserveKeys - * @return static> - */ - public function groupBy($groupBy, $preserveKeys = false); - - /** - * Key an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $keyBy - * @return static - */ - public function keyBy($keyBy); - - /** - * Determine if an item exists in the collection by key. - * - * @param TKey|array $key - * @return bool - */ - public function has($key); - - /** - * Determine if any of the keys exist in the collection. - * - * @param mixed $key - * @return bool - */ - public function hasAny($key); - - /** - * Concatenate values of a given key as a string. - * - * @param callable|string $value - * @param string|null $glue - * @return string - */ - public function implode($value, $glue = null); - - /** - * Intersect the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersect($items); - - /** - * Intersect the collection with the given items by key. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersectByKeys($items); - - /** - * Determine if the collection is empty or not. - * - * @return bool - */ - public function isEmpty(); - - /** - * Determine if the collection is not empty. - * - * @return bool - */ - public function isNotEmpty(); - - /** - * Determine if the collection contains a single item. - * - * @return bool - */ - public function containsOneItem(); - - /** - * Join all items from the collection using a string. The final items can use a separate glue string. - * - * @param string $glue - * @param string $finalGlue - * @return string - */ - public function join($glue, $finalGlue = ''); - - /** - * Get the keys of the collection items. - * - * @return static - */ - public function keys(); - - /** - * Get the last item from the collection. - * - * @template TLastDefault - * - * @param (callable(TValue, TKey): bool)|null $callback - * @param TLastDefault|(\Closure(): TLastDefault) $default - * @return TValue|TLastDefault - */ - public function last(?callable $callback = null, $default = null); - - /** - * Run a map over each of the items. - * - * @template TMapValue - * - * @param callable(TValue, TKey): TMapValue $callback - * @return static - */ - public function map(callable $callback); - - /** - * Run a map over each nested chunk of items. - * - * @param callable $callback - * @return static - */ - public function mapSpread(callable $callback); - - /** - * Run a dictionary map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapToDictionaryKey of array-key - * @template TMapToDictionaryValue - * - * @param callable(TValue, TKey): array $callback - * @return static> - */ - public function mapToDictionary(callable $callback); - - /** - * Run a grouping map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapToGroupsKey of array-key - * @template TMapToGroupsValue - * - * @param callable(TValue, TKey): array $callback - * @return static> - */ - public function mapToGroups(callable $callback); - - /** - * Run an associative map over each of the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapWithKeysKey of array-key - * @template TMapWithKeysValue - * - * @param callable(TValue, TKey): array $callback - * @return static - */ - public function mapWithKeys(callable $callback); - - /** - * Map a collection and flatten the result by a single level. - * - * @template TFlatMapKey of array-key - * @template TFlatMapValue - * - * @param callable(TValue, TKey): (\Illuminate\Support\Collection|array) $callback - * @return static - */ - public function flatMap(callable $callback); - - /** - * Map the values into a new class. - * - * @template TMapIntoValue - * - * @param class-string $class - * @return static - */ - public function mapInto($class); - - /** - * Merge the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function merge($items); - - /** - * Recursively merge the collection with the given items. - * - * @template TMergeRecursiveValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function mergeRecursive($items); - - /** - * Create a collection by using this collection for keys and another for its values. - * - * @template TCombineValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function combine($values); - - /** - * Union the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function union($items); - - /** - * Get the min value of a given key. - * - * @param (callable(TValue):mixed)|string|null $callback - * @return mixed - */ - public function min($callback = null); - - /** - * Get the max value of a given key. - * - * @param (callable(TValue):mixed)|string|null $callback - * @return mixed - */ - public function max($callback = null); - - /** - * Create a new collection consisting of every n-th element. - * - * @param int $step - * @param int $offset - * @return static - */ - public function nth($step, $offset = 0); - - /** - * Get the items with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array|string $keys - * @return static - */ - public function only($keys); - - /** - * "Paginate" the collection by slicing it into a smaller collection. - * - * @param int $page - * @param int $perPage - * @return static - */ - public function forPage($page, $perPage); - - /** - * Partition the collection into two arrays using the given callback or key. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return static, static> - */ - public function partition($key, $operator = null, $value = null); - - /** - * Push all of the given items onto the collection. - * - * @template TConcatKey of array-key - * @template TConcatValue - * - * @param iterable $source - * @return static - */ - public function concat($source); - - /** - * Get one or a specified number of items randomly from the collection. - * - * @param int|null $number - * @return static|TValue - * - * @throws \InvalidArgumentException - */ - public function random($number = null); - - /** - * Reduce the collection to a single value. - * - * @template TReduceInitial - * @template TReduceReturnType - * - * @param callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType $callback - * @param TReduceInitial $initial - * @return TReduceReturnType - */ - public function reduce(callable $callback, $initial = null); - - /** - * Reduce the collection to multiple aggregate values. - * - * @param callable $callback - * @param mixed ...$initial - * @return array - * - * @throws \UnexpectedValueException - */ - public function reduceSpread(callable $callback, ...$initial); - - /** - * Replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replace($items); - - /** - * Recursively replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replaceRecursive($items); - - /** - * Reverse items order. - * - * @return static - */ - public function reverse(); - - /** - * Search the collection for a given value and return the corresponding key if successful. - * - * @param TValue|callable(TValue,TKey): bool $value - * @param bool $strict - * @return TKey|bool - */ - public function search($value, $strict = false); - - /** - * Shuffle the items in the collection. - * - * @param int|null $seed - * @return static - */ - public function shuffle($seed = null); - - /** - * Create chunks representing a "sliding window" view of the items in the collection. - * - * @param int $size - * @param int $step - * @return static - */ - public function sliding($size = 2, $step = 1); - - /** - * Skip the first {$count} items. - * - * @param int $count - * @return static - */ - public function skip($count); - - /** - * Skip items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipUntil($value); - - /** - * Skip items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipWhile($value); - - /** - * Get a slice of items from the enumerable. - * - * @param int $offset - * @param int|null $length - * @return static - */ - public function slice($offset, $length = null); - - /** - * Split a collection into a certain number of groups. - * - * @param int $numberOfGroups - * @return static - */ - public function split($numberOfGroups); - - /** - * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - * @throws \Illuminate\Support\MultipleItemsFoundException - */ - public function sole($key = null, $operator = null, $value = null); - - /** - * Get the first item in the collection but throw an exception if no matching items exist. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - */ - public function firstOrFail($key = null, $operator = null, $value = null); - - /** - * Chunk the collection into chunks of the given size. - * - * @param int $size - * @return static - */ - public function chunk($size); - - /** - * Chunk the collection into chunks with a callback. - * - * @param callable(TValue, TKey, static): bool $callback - * @return static> - */ - public function chunkWhile(callable $callback); - - /** - * Split a collection into a certain number of groups, and fill the first groups completely. - * - * @param int $numberOfGroups - * @return static - */ - public function splitIn($numberOfGroups); - - /** - * Sort through each item with a callback. - * - * @param (callable(TValue, TValue): int)|null|int $callback - * @return static - */ - public function sort($callback = null); - - /** - * Sort items in descending order. - * - * @param int $options - * @return static - */ - public function sortDesc($options = SORT_REGULAR); - - /** - * Sort the collection using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @param bool $descending - * @return static - */ - public function sortBy($callback, $options = SORT_REGULAR, $descending = false); - - /** - * Sort the collection in descending order using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @return static - */ - public function sortByDesc($callback, $options = SORT_REGULAR); - - /** - * Sort the collection keys. - * - * @param int $options - * @param bool $descending - * @return static - */ - public function sortKeys($options = SORT_REGULAR, $descending = false); - - /** - * Sort the collection keys in descending order. - * - * @param int $options - * @return static - */ - public function sortKeysDesc($options = SORT_REGULAR); - - /** - * Sort the collection keys using a callback. - * - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function sortKeysUsing(callable $callback); - - /** - * Get the sum of the given values. - * - * @param (callable(TValue): mixed)|string|null $callback - * @return mixed - */ - public function sum($callback = null); - - /** - * Take the first or last {$limit} items. - * - * @param int $limit - * @return static - */ - public function take($limit); - - /** - * Take items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeUntil($value); - - /** - * Take items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeWhile($value); - - /** - * Pass the collection to the given callback and then return it. - * - * @param callable(TValue): mixed $callback - * @return $this - */ - public function tap(callable $callback); - - /** - * Pass the enumerable to the given callback and return the result. - * - * @template TPipeReturnType - * - * @param callable($this): TPipeReturnType $callback - * @return TPipeReturnType - */ - public function pipe(callable $callback); - - /** - * Pass the collection into a new class. - * - * @template TPipeIntoValue - * - * @param class-string $class - * @return TPipeIntoValue - */ - public function pipeInto($class); - - /** - * Pass the collection through a series of callable pipes and return the result. - * - * @param array $pipes - * @return mixed - */ - public function pipeThrough($pipes); - - /** - * Get the values of a given key. - * - * @param string|array $value - * @param string|null $key - * @return static - */ - public function pluck($value, $key = null); - - /** - * Create a collection of all elements that do not pass a given truth test. - * - * @param (callable(TValue, TKey): bool)|bool|TValue $callback - * @return static - */ - public function reject($callback = true); - - /** - * Convert a flatten "dot" notation array into an expanded array. - * - * @return static - */ - public function undot(); - - /** - * Return only unique items from the collection array. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @param bool $strict - * @return static - */ - public function unique($key = null, $strict = false); - - /** - * Return only unique items from the collection array using strict comparison. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @return static - */ - public function uniqueStrict($key = null); - - /** - * Reset the keys on the underlying array. - * - * @return static - */ - public function values(); - - /** - * Pad collection to the specified length with a value. - * - * @template TPadValue - * - * @param int $size - * @param TPadValue $value - * @return static - */ - public function pad($size, $value); - - /** - * Get the values iterator. - * - * @return \Traversable - */ - public function getIterator(): Traversable; - - /** - * Count the number of items in the collection. - * - * @return int - */ - public function count(): int; - - /** - * Count the number of items in the collection by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|string|null $countBy - * @return static - */ - public function countBy($countBy = null); - - /** - * Zip the collection together with one or more arrays. - * - * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); - * => [[1, 4], [2, 5], [3, 6]] - * - * @template TZipValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items - * @return static> - */ - public function zip($items); - - /** - * Collect the values into a collection. - * - * @return \Illuminate\Support\Collection - */ - public function collect(); - - /** - * Get the collection of items as a plain array. - * - * @return array - */ - public function toArray(); - - /** - * Convert the object into something JSON serializable. - * - * @return mixed - */ - public function jsonSerialize(): mixed; - - /** - * Get the collection of items as JSON. - * - * @param int $options - * @return string - */ - public function toJson($options = 0); - - /** - * Get a CachingIterator instance. - * - * @param int $flags - * @return \CachingIterator - */ - public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING); - - /** - * Convert the collection to its string representation. - * - * @return string - */ - public function __toString(); - - /** - * Indicate that the model's string representation should be escaped when __toString is invoked. - * - * @param bool $escape - * @return $this - */ - public function escapeWhenCastingToString($escape = true); - - /** - * Add a method to the list of proxied methods. - * - * @param string $method - * @return void - */ - public static function proxy($method); - - /** - * Dynamically access collection proxies. - * - * @param string $key - * @return mixed - * - * @throws \Exception - */ - public function __get($key); -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/ItemNotFoundException.php b/lam/lib/3rdParty/composer/illuminate/collections/ItemNotFoundException.php deleted file mode 100644 index 05a51d954..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/ItemNotFoundException.php +++ /dev/null @@ -1,9 +0,0 @@ - - */ -class LazyCollection implements CanBeEscapedWhenCastToString, Enumerable -{ - /** - * @use \Illuminate\Support\Traits\EnumeratesValues - */ - use EnumeratesValues, Macroable; - - /** - * The source from which to generate items. - * - * @var (Closure(): \Generator)|static|array - */ - public $source; - - /** - * Create a new lazy collection instance. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable|(Closure(): \Generator)|self|array|null $source - * @return void - */ - public function __construct($source = null) - { - if ($source instanceof Closure || $source instanceof self) { - $this->source = $source; - } elseif (is_null($source)) { - $this->source = static::empty(); - } elseif ($source instanceof Generator) { - throw new InvalidArgumentException( - 'Generators should not be passed directly to LazyCollection. Instead, pass a generator function.' - ); - } else { - $this->source = $this->getArrayableItems($source); - } - } - - /** - * Create a new collection instance if the value isn't one already. - * - * @template TMakeKey of array-key - * @template TMakeValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable|(Closure(): \Generator)|self|array|null $items - * @return static - */ - public static function make($items = []) - { - return new static($items); - } - - /** - * Create a collection with the given range. - * - * @param int $from - * @param int $to - * @return static - */ - public static function range($from, $to) - { - return new static(function () use ($from, $to) { - if ($from <= $to) { - for (; $from <= $to; $from++) { - yield $from; - } - } else { - for (; $from >= $to; $from--) { - yield $from; - } - } - }); - } - - /** - * Get all items in the enumerable. - * - * @return array - */ - public function all() - { - if (is_array($this->source)) { - return $this->source; - } - - return iterator_to_array($this->getIterator()); - } - - /** - * Eager load all items into a new lazy collection backed by an array. - * - * @return static - */ - public function eager() - { - return new static($this->all()); - } - - /** - * Cache values as they're enumerated. - * - * @return static - */ - public function remember() - { - $iterator = $this->getIterator(); - - $iteratorIndex = 0; - - $cache = []; - - return new static(function () use ($iterator, &$iteratorIndex, &$cache) { - for ($index = 0; true; $index++) { - if (array_key_exists($index, $cache)) { - yield $cache[$index][0] => $cache[$index][1]; - - continue; - } - - if ($iteratorIndex < $index) { - $iterator->next(); - - $iteratorIndex++; - } - - if (! $iterator->valid()) { - break; - } - - $cache[$index] = [$iterator->key(), $iterator->current()]; - - yield $cache[$index][0] => $cache[$index][1]; - } - }); - } - - /** - * Get the average value of a given key. - * - * @param (callable(TValue): float|int)|string|null $callback - * @return float|int|null - */ - public function avg($callback = null) - { - return $this->collect()->avg($callback); - } - - /** - * Get the median of a given key. - * - * @param string|array|null $key - * @return float|int|null - */ - public function median($key = null) - { - return $this->collect()->median($key); - } - - /** - * Get the mode of a given key. - * - * @param string|array|null $key - * @return array|null - */ - public function mode($key = null) - { - return $this->collect()->mode($key); - } - - /** - * Collapse the collection of items into a single array. - * - * @return static - */ - public function collapse() - { - return new static(function () { - foreach ($this as $values) { - if (is_array($values) || $values instanceof Enumerable) { - foreach ($values as $value) { - yield $value; - } - } - } - }); - } - - /** - * Determine if an item exists in the enumerable. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function contains($key, $operator = null, $value = null) - { - if (func_num_args() === 1 && $this->useAsCallable($key)) { - $placeholder = new stdClass; - - /** @var callable $key */ - return $this->first($key, $placeholder) !== $placeholder; - } - - if (func_num_args() === 1) { - $needle = $key; - - foreach ($this as $value) { - if ($value == $needle) { - return true; - } - } - - return false; - } - - return $this->contains($this->operatorForWhere(...func_get_args())); - } - - /** - * Determine if an item exists, using strict comparison. - * - * @param (callable(TValue): bool)|TValue|array-key $key - * @param TValue|null $value - * @return bool - */ - public function containsStrict($key, $value = null) - { - if (func_num_args() === 2) { - return $this->contains(fn ($item) => data_get($item, $key) === $value); - } - - if ($this->useAsCallable($key)) { - return ! is_null($this->first($key)); - } - - foreach ($this as $item) { - if ($item === $key) { - return true; - } - } - - return false; - } - - /** - * Determine if an item is not contained in the enumerable. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function doesntContain($key, $operator = null, $value = null) - { - return ! $this->contains(...func_get_args()); - } - - /** - * Cross join the given iterables, returning all possible permutations. - * - * @template TCrossJoinKey - * @template TCrossJoinValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$arrays - * @return static> - */ - public function crossJoin(...$arrays) - { - return $this->passthru('crossJoin', func_get_args()); - } - - /** - * Count the number of items in the collection by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|string|null $countBy - * @return static - */ - public function countBy($countBy = null) - { - $countBy = is_null($countBy) - ? $this->identity() - : $this->valueRetriever($countBy); - - return new static(function () use ($countBy) { - $counts = []; - - foreach ($this as $key => $value) { - $group = $countBy($value, $key); - - if (empty($counts[$group])) { - $counts[$group] = 0; - } - - $counts[$group]++; - } - - yield from $counts; - }); - } - - /** - * Get the items that are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diff($items) - { - return $this->passthru('diff', func_get_args()); - } - - /** - * Get the items that are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function diffUsing($items, callable $callback) - { - return $this->passthru('diffUsing', func_get_args()); - } - - /** - * Get the items whose keys and values are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffAssoc($items) - { - return $this->passthru('diffAssoc', func_get_args()); - } - - /** - * Get the items whose keys and values are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffAssocUsing($items, callable $callback) - { - return $this->passthru('diffAssocUsing', func_get_args()); - } - - /** - * Get the items whose keys are not present in the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function diffKeys($items) - { - return $this->passthru('diffKeys', func_get_args()); - } - - /** - * Get the items whose keys are not present in the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function diffKeysUsing($items, callable $callback) - { - return $this->passthru('diffKeysUsing', func_get_args()); - } - - /** - * Retrieve duplicate items. - * - * @param (callable(TValue): bool)|string|null $callback - * @param bool $strict - * @return static - */ - public function duplicates($callback = null, $strict = false) - { - return $this->passthru('duplicates', func_get_args()); - } - - /** - * Retrieve duplicate items using strict comparison. - * - * @param (callable(TValue): bool)|string|null $callback - * @return static - */ - public function duplicatesStrict($callback = null) - { - return $this->passthru('duplicatesStrict', func_get_args()); - } - - /** - * Get all items except for those with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array $keys - * @return static - */ - public function except($keys) - { - return $this->passthru('except', func_get_args()); - } - - /** - * Run a filter over each of the items. - * - * @param (callable(TValue, TKey): bool)|null $callback - * @return static - */ - public function filter(?callable $callback = null) - { - if (is_null($callback)) { - $callback = fn ($value) => (bool) $value; - } - - return new static(function () use ($callback) { - foreach ($this as $key => $value) { - if ($callback($value, $key)) { - yield $key => $value; - } - } - }); - } - - /** - * Get the first item from the enumerable passing the given truth test. - * - * @template TFirstDefault - * - * @param (callable(TValue): bool)|null $callback - * @param TFirstDefault|(\Closure(): TFirstDefault) $default - * @return TValue|TFirstDefault - */ - public function first(?callable $callback = null, $default = null) - { - $iterator = $this->getIterator(); - - if (is_null($callback)) { - if (! $iterator->valid()) { - return value($default); - } - - return $iterator->current(); - } - - foreach ($iterator as $key => $value) { - if ($callback($value, $key)) { - return $value; - } - } - - return value($default); - } - - /** - * Get a flattened list of the items in the collection. - * - * @param int $depth - * @return static - */ - public function flatten($depth = INF) - { - $instance = new static(function () use ($depth) { - foreach ($this as $item) { - if (! is_array($item) && ! $item instanceof Enumerable) { - yield $item; - } elseif ($depth === 1) { - yield from $item; - } else { - yield from (new static($item))->flatten($depth - 1); - } - } - }); - - return $instance->values(); - } - - /** - * Flip the items in the collection. - * - * @return static - */ - public function flip() - { - return new static(function () { - foreach ($this as $key => $value) { - yield $value => $key; - } - }); - } - - /** - * Get an item by key. - * - * @template TGetDefault - * - * @param TKey|null $key - * @param TGetDefault|(\Closure(): TGetDefault) $default - * @return TValue|TGetDefault - */ - public function get($key, $default = null) - { - if (is_null($key)) { - return; - } - - foreach ($this as $outerKey => $outerValue) { - if ($outerKey == $key) { - return $outerValue; - } - } - - return value($default); - } - - /** - * Group an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $groupBy - * @param bool $preserveKeys - * @return static> - */ - public function groupBy($groupBy, $preserveKeys = false) - { - return $this->passthru('groupBy', func_get_args()); - } - - /** - * Key an associative array by a field or using a callback. - * - * @param (callable(TValue, TKey): array-key)|array|string $keyBy - * @return static - */ - public function keyBy($keyBy) - { - return new static(function () use ($keyBy) { - $keyBy = $this->valueRetriever($keyBy); - - foreach ($this as $key => $item) { - $resolvedKey = $keyBy($item, $key); - - if (is_object($resolvedKey)) { - $resolvedKey = (string) $resolvedKey; - } - - yield $resolvedKey => $item; - } - }); - } - - /** - * Determine if an item exists in the collection by key. - * - * @param mixed $key - * @return bool - */ - public function has($key) - { - $keys = array_flip(is_array($key) ? $key : func_get_args()); - $count = count($keys); - - foreach ($this as $key => $value) { - if (array_key_exists($key, $keys) && --$count == 0) { - return true; - } - } - - return false; - } - - /** - * Determine if any of the keys exist in the collection. - * - * @param mixed $key - * @return bool - */ - public function hasAny($key) - { - $keys = array_flip(is_array($key) ? $key : func_get_args()); - - foreach ($this as $key => $value) { - if (array_key_exists($key, $keys)) { - return true; - } - } - - return false; - } - - /** - * Concatenate values of a given key as a string. - * - * @param callable|string $value - * @param string|null $glue - * @return string - */ - public function implode($value, $glue = null) - { - return $this->collect()->implode(...func_get_args()); - } - - /** - * Intersect the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersect($items) - { - return $this->passthru('intersect', func_get_args()); - } - - /** - * Intersect the collection with the given items, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function intersectUsing() - { - return $this->passthru('intersectUsing', func_get_args()); - } - - /** - * Intersect the collection with the given items with additional index check. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersectAssoc($items) - { - return $this->passthru('intersectAssoc', func_get_args()); - } - - /** - * Intersect the collection with the given items with additional index check, using the callback. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @param callable(TValue, TValue): int $callback - * @return static - */ - public function intersectAssocUsing($items, callable $callback) - { - return $this->passthru('intersectAssocUsing', func_get_args()); - } - - /** - * Intersect the collection with the given items by key. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function intersectByKeys($items) - { - return $this->passthru('intersectByKeys', func_get_args()); - } - - /** - * Determine if the items are empty or not. - * - * @return bool - */ - public function isEmpty() - { - return ! $this->getIterator()->valid(); - } - - /** - * Determine if the collection contains a single item. - * - * @return bool - */ - public function containsOneItem() - { - return $this->take(2)->count() === 1; - } - - /** - * Join all items from the collection using a string. The final items can use a separate glue string. - * - * @param string $glue - * @param string $finalGlue - * @return string - */ - public function join($glue, $finalGlue = '') - { - return $this->collect()->join(...func_get_args()); - } - - /** - * Get the keys of the collection items. - * - * @return static - */ - public function keys() - { - return new static(function () { - foreach ($this as $key => $value) { - yield $key; - } - }); - } - - /** - * Get the last item from the collection. - * - * @template TLastDefault - * - * @param (callable(TValue, TKey): bool)|null $callback - * @param TLastDefault|(\Closure(): TLastDefault) $default - * @return TValue|TLastDefault - */ - public function last(?callable $callback = null, $default = null) - { - $needle = $placeholder = new stdClass; - - foreach ($this as $key => $value) { - if (is_null($callback) || $callback($value, $key)) { - $needle = $value; - } - } - - return $needle === $placeholder ? value($default) : $needle; - } - - /** - * Get the values of a given key. - * - * @param string|array $value - * @param string|null $key - * @return static - */ - public function pluck($value, $key = null) - { - return new static(function () use ($value, $key) { - [$value, $key] = $this->explodePluckParameters($value, $key); - - foreach ($this as $item) { - $itemValue = data_get($item, $value); - - if (is_null($key)) { - yield $itemValue; - } else { - $itemKey = data_get($item, $key); - - if (is_object($itemKey) && method_exists($itemKey, '__toString')) { - $itemKey = (string) $itemKey; - } - - yield $itemKey => $itemValue; - } - } - }); - } - - /** - * Run a map over each of the items. - * - * @template TMapValue - * - * @param callable(TValue, TKey): TMapValue $callback - * @return static - */ - public function map(callable $callback) - { - return new static(function () use ($callback) { - foreach ($this as $key => $value) { - yield $key => $callback($value, $key); - } - }); - } - - /** - * Run a dictionary map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapToDictionaryKey of array-key - * @template TMapToDictionaryValue - * - * @param callable(TValue, TKey): array $callback - * @return static> - */ - public function mapToDictionary(callable $callback) - { - return $this->passthru('mapToDictionary', func_get_args()); - } - - /** - * Run an associative map over each of the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapWithKeysKey of array-key - * @template TMapWithKeysValue - * - * @param callable(TValue, TKey): array $callback - * @return static - */ - public function mapWithKeys(callable $callback) - { - return new static(function () use ($callback) { - foreach ($this as $key => $value) { - yield from $callback($value, $key); - } - }); - } - - /** - * Merge the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function merge($items) - { - return $this->passthru('merge', func_get_args()); - } - - /** - * Recursively merge the collection with the given items. - * - * @template TMergeRecursiveValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function mergeRecursive($items) - { - return $this->passthru('mergeRecursive', func_get_args()); - } - - /** - * Create a collection by using this collection for keys and another for its values. - * - * @template TCombineValue - * - * @param \IteratorAggregate|array|(callable(): \Generator) $values - * @return static - */ - public function combine($values) - { - return new static(function () use ($values) { - $values = $this->makeIterator($values); - - $errorMessage = 'Both parameters should have an equal number of elements'; - - foreach ($this as $key) { - if (! $values->valid()) { - trigger_error($errorMessage, E_USER_WARNING); - - break; - } - - yield $key => $values->current(); - - $values->next(); - } - - if ($values->valid()) { - trigger_error($errorMessage, E_USER_WARNING); - } - }); - } - - /** - * Union the collection with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function union($items) - { - return $this->passthru('union', func_get_args()); - } - - /** - * Create a new collection consisting of every n-th element. - * - * @param int $step - * @param int $offset - * @return static - */ - public function nth($step, $offset = 0) - { - return new static(function () use ($step, $offset) { - $position = 0; - - foreach ($this->slice($offset) as $item) { - if ($position % $step === 0) { - yield $item; - } - - $position++; - } - }); - } - - /** - * Get the items with the specified keys. - * - * @param \Illuminate\Support\Enumerable|array|string $keys - * @return static - */ - public function only($keys) - { - if ($keys instanceof Enumerable) { - $keys = $keys->all(); - } elseif (! is_null($keys)) { - $keys = is_array($keys) ? $keys : func_get_args(); - } - - return new static(function () use ($keys) { - if (is_null($keys)) { - yield from $this; - } else { - $keys = array_flip($keys); - - foreach ($this as $key => $value) { - if (array_key_exists($key, $keys)) { - yield $key => $value; - - unset($keys[$key]); - - if (empty($keys)) { - break; - } - } - } - } - }); - } - - /** - * Select specific values from the items within the collection. - * - * @param \Illuminate\Support\Enumerable|array|string $keys - * @return static - */ - public function select($keys) - { - if ($keys instanceof Enumerable) { - $keys = $keys->all(); - } elseif (! is_null($keys)) { - $keys = is_array($keys) ? $keys : func_get_args(); - } - - return new static(function () use ($keys) { - if (is_null($keys)) { - yield from $this; - } else { - foreach ($this as $item) { - $result = []; - - foreach ($keys as $key) { - if (Arr::accessible($item) && Arr::exists($item, $key)) { - $result[$key] = $item[$key]; - } elseif (is_object($item) && isset($item->{$key})) { - $result[$key] = $item->{$key}; - } - } - - yield $result; - } - } - }); - } - - /** - * Push all of the given items onto the collection. - * - * @template TConcatKey of array-key - * @template TConcatValue - * - * @param iterable $source - * @return static - */ - public function concat($source) - { - return (new static(function () use ($source) { - yield from $this; - yield from $source; - }))->values(); - } - - /** - * Get one or a specified number of items randomly from the collection. - * - * @param int|null $number - * @return static|TValue - * - * @throws \InvalidArgumentException - */ - public function random($number = null) - { - $result = $this->collect()->random(...func_get_args()); - - return is_null($number) ? $result : new static($result); - } - - /** - * Replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replace($items) - { - return new static(function () use ($items) { - $items = $this->getArrayableItems($items); - - foreach ($this as $key => $value) { - if (array_key_exists($key, $items)) { - yield $key => $items[$key]; - - unset($items[$key]); - } else { - yield $key => $value; - } - } - - foreach ($items as $key => $value) { - yield $key => $value; - } - }); - } - - /** - * Recursively replace the collection items with the given items. - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable $items - * @return static - */ - public function replaceRecursive($items) - { - return $this->passthru('replaceRecursive', func_get_args()); - } - - /** - * Reverse items order. - * - * @return static - */ - public function reverse() - { - return $this->passthru('reverse', func_get_args()); - } - - /** - * Search the collection for a given value and return the corresponding key if successful. - * - * @param TValue|(callable(TValue,TKey): bool) $value - * @param bool $strict - * @return TKey|false - */ - public function search($value, $strict = false) - { - /** @var (callable(TValue,TKey): bool) $predicate */ - $predicate = $this->useAsCallable($value) - ? $value - : function ($item) use ($value, $strict) { - return $strict ? $item === $value : $item == $value; - }; - - foreach ($this as $key => $item) { - if ($predicate($item, $key)) { - return $key; - } - } - - return false; - } - - /** - * Shuffle the items in the collection. - * - * @param int|null $seed - * @return static - */ - public function shuffle($seed = null) - { - return $this->passthru('shuffle', func_get_args()); - } - - /** - * Create chunks representing a "sliding window" view of the items in the collection. - * - * @param int $size - * @param int $step - * @return static - */ - public function sliding($size = 2, $step = 1) - { - return new static(function () use ($size, $step) { - $iterator = $this->getIterator(); - - $chunk = []; - - while ($iterator->valid()) { - $chunk[$iterator->key()] = $iterator->current(); - - if (count($chunk) == $size) { - yield (new static($chunk))->tap(function () use (&$chunk, $step) { - $chunk = array_slice($chunk, $step, null, true); - }); - - // If the $step between chunks is bigger than each chunk's $size - // we will skip the extra items (which should never be in any - // chunk) before we continue to the next chunk in the loop. - if ($step > $size) { - $skip = $step - $size; - - for ($i = 0; $i < $skip && $iterator->valid(); $i++) { - $iterator->next(); - } - } - } - - $iterator->next(); - } - }); - } - - /** - * Skip the first {$count} items. - * - * @param int $count - * @return static - */ - public function skip($count) - { - return new static(function () use ($count) { - $iterator = $this->getIterator(); - - while ($iterator->valid() && $count--) { - $iterator->next(); - } - - while ($iterator->valid()) { - yield $iterator->key() => $iterator->current(); - - $iterator->next(); - } - }); - } - - /** - * Skip items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipUntil($value) - { - $callback = $this->useAsCallable($value) ? $value : $this->equality($value); - - return $this->skipWhile($this->negate($callback)); - } - - /** - * Skip items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function skipWhile($value) - { - $callback = $this->useAsCallable($value) ? $value : $this->equality($value); - - return new static(function () use ($callback) { - $iterator = $this->getIterator(); - - while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) { - $iterator->next(); - } - - while ($iterator->valid()) { - yield $iterator->key() => $iterator->current(); - - $iterator->next(); - } - }); - } - - /** - * Get a slice of items from the enumerable. - * - * @param int $offset - * @param int|null $length - * @return static - */ - public function slice($offset, $length = null) - { - if ($offset < 0 || $length < 0) { - return $this->passthru('slice', func_get_args()); - } - - $instance = $this->skip($offset); - - return is_null($length) ? $instance : $instance->take($length); - } - - /** - * Split a collection into a certain number of groups. - * - * @param int $numberOfGroups - * @return static - */ - public function split($numberOfGroups) - { - return $this->passthru('split', func_get_args()); - } - - /** - * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - * @throws \Illuminate\Support\MultipleItemsFoundException - */ - public function sole($key = null, $operator = null, $value = null) - { - $filter = func_num_args() > 1 - ? $this->operatorForWhere(...func_get_args()) - : $key; - - return $this - ->unless($filter == null) - ->filter($filter) - ->take(2) - ->collect() - ->sole(); - } - - /** - * Get the first item in the collection but throw an exception if no matching items exist. - * - * @param (callable(TValue, TKey): bool)|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue - * - * @throws \Illuminate\Support\ItemNotFoundException - */ - public function firstOrFail($key = null, $operator = null, $value = null) - { - $filter = func_num_args() > 1 - ? $this->operatorForWhere(...func_get_args()) - : $key; - - return $this - ->unless($filter == null) - ->filter($filter) - ->take(1) - ->collect() - ->firstOrFail(); - } - - /** - * Chunk the collection into chunks of the given size. - * - * @param int $size - * @return static - */ - public function chunk($size) - { - if ($size <= 0) { - return static::empty(); - } - - return new static(function () use ($size) { - $iterator = $this->getIterator(); - - while ($iterator->valid()) { - $chunk = []; - - while (true) { - $chunk[$iterator->key()] = $iterator->current(); - - if (count($chunk) < $size) { - $iterator->next(); - - if (! $iterator->valid()) { - break; - } - } else { - break; - } - } - - yield new static($chunk); - - $iterator->next(); - } - }); - } - - /** - * Split a collection into a certain number of groups, and fill the first groups completely. - * - * @param int $numberOfGroups - * @return static - */ - public function splitIn($numberOfGroups) - { - return $this->chunk(ceil($this->count() / $numberOfGroups)); - } - - /** - * Chunk the collection into chunks with a callback. - * - * @param callable(TValue, TKey, Collection): bool $callback - * @return static> - */ - public function chunkWhile(callable $callback) - { - return new static(function () use ($callback) { - $iterator = $this->getIterator(); - - $chunk = new Collection; - - if ($iterator->valid()) { - $chunk[$iterator->key()] = $iterator->current(); - - $iterator->next(); - } - - while ($iterator->valid()) { - if (! $callback($iterator->current(), $iterator->key(), $chunk)) { - yield new static($chunk); - - $chunk = new Collection; - } - - $chunk[$iterator->key()] = $iterator->current(); - - $iterator->next(); - } - - if ($chunk->isNotEmpty()) { - yield new static($chunk); - } - }); - } - - /** - * Sort through each item with a callback. - * - * @param (callable(TValue, TValue): int)|null|int $callback - * @return static - */ - public function sort($callback = null) - { - return $this->passthru('sort', func_get_args()); - } - - /** - * Sort items in descending order. - * - * @param int $options - * @return static - */ - public function sortDesc($options = SORT_REGULAR) - { - return $this->passthru('sortDesc', func_get_args()); - } - - /** - * Sort the collection using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @param bool $descending - * @return static - */ - public function sortBy($callback, $options = SORT_REGULAR, $descending = false) - { - return $this->passthru('sortBy', func_get_args()); - } - - /** - * Sort the collection in descending order using the given callback. - * - * @param array|(callable(TValue, TKey): mixed)|string $callback - * @param int $options - * @return static - */ - public function sortByDesc($callback, $options = SORT_REGULAR) - { - return $this->passthru('sortByDesc', func_get_args()); - } - - /** - * Sort the collection keys. - * - * @param int $options - * @param bool $descending - * @return static - */ - public function sortKeys($options = SORT_REGULAR, $descending = false) - { - return $this->passthru('sortKeys', func_get_args()); - } - - /** - * Sort the collection keys in descending order. - * - * @param int $options - * @return static - */ - public function sortKeysDesc($options = SORT_REGULAR) - { - return $this->passthru('sortKeysDesc', func_get_args()); - } - - /** - * Sort the collection keys using a callback. - * - * @param callable(TKey, TKey): int $callback - * @return static - */ - public function sortKeysUsing(callable $callback) - { - return $this->passthru('sortKeysUsing', func_get_args()); - } - - /** - * Take the first or last {$limit} items. - * - * @param int $limit - * @return static - */ - public function take($limit) - { - if ($limit < 0) { - return new static(function () use ($limit) { - $limit = abs($limit); - $ringBuffer = []; - $position = 0; - - foreach ($this as $key => $value) { - $ringBuffer[$position] = [$key, $value]; - $position = ($position + 1) % $limit; - } - - for ($i = 0, $end = min($limit, count($ringBuffer)); $i < $end; $i++) { - $pointer = ($position + $i) % $limit; - yield $ringBuffer[$pointer][0] => $ringBuffer[$pointer][1]; - } - }); - } - - return new static(function () use ($limit) { - $iterator = $this->getIterator(); - - while ($limit--) { - if (! $iterator->valid()) { - break; - } - - yield $iterator->key() => $iterator->current(); - - if ($limit) { - $iterator->next(); - } - } - }); - } - - /** - * Take items in the collection until the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeUntil($value) - { - /** @var callable(TValue, TKey): bool $callback */ - $callback = $this->useAsCallable($value) ? $value : $this->equality($value); - - return new static(function () use ($callback) { - foreach ($this as $key => $item) { - if ($callback($item, $key)) { - break; - } - - yield $key => $item; - } - }); - } - - /** - * Take items in the collection until a given point in time. - * - * @param \DateTimeInterface $timeout - * @return static - */ - public function takeUntilTimeout(DateTimeInterface $timeout) - { - $timeout = $timeout->getTimestamp(); - - return new static(function () use ($timeout) { - if ($this->now() >= $timeout) { - return; - } - - foreach ($this as $key => $value) { - yield $key => $value; - - if ($this->now() >= $timeout) { - break; - } - } - }); - } - - /** - * Take items in the collection while the given condition is met. - * - * @param TValue|callable(TValue,TKey): bool $value - * @return static - */ - public function takeWhile($value) - { - /** @var callable(TValue, TKey): bool $callback */ - $callback = $this->useAsCallable($value) ? $value : $this->equality($value); - - return $this->takeUntil(fn ($item, $key) => ! $callback($item, $key)); - } - - /** - * Pass each item in the collection to the given callback, lazily. - * - * @param callable(TValue, TKey): mixed $callback - * @return static - */ - public function tapEach(callable $callback) - { - return new static(function () use ($callback) { - foreach ($this as $key => $value) { - $callback($value, $key); - - yield $key => $value; - } - }); - } - - /** - * Flatten a multi-dimensional associative array with dots. - * - * @return static - */ - public function dot() - { - return $this->passthru('dot', []); - } - - /** - * Convert a flatten "dot" notation array into an expanded array. - * - * @return static - */ - public function undot() - { - return $this->passthru('undot', []); - } - - /** - * Return only unique items from the collection array. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @param bool $strict - * @return static - */ - public function unique($key = null, $strict = false) - { - $callback = $this->valueRetriever($key); - - return new static(function () use ($callback, $strict) { - $exists = []; - - foreach ($this as $key => $item) { - if (! in_array($id = $callback($item, $key), $exists, $strict)) { - yield $key => $item; - - $exists[] = $id; - } - } - }); - } - - /** - * Reset the keys on the underlying array. - * - * @return static - */ - public function values() - { - return new static(function () { - foreach ($this as $item) { - yield $item; - } - }); - } - - /** - * Zip the collection together with one or more arrays. - * - * e.g. new LazyCollection([1, 2, 3])->zip([4, 5, 6]); - * => [[1, 4], [2, 5], [3, 6]] - * - * @template TZipValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items - * @return static> - */ - public function zip($items) - { - $iterables = func_get_args(); - - return new static(function () use ($iterables) { - $iterators = Collection::make($iterables)->map(function ($iterable) { - return $this->makeIterator($iterable); - })->prepend($this->getIterator()); - - while ($iterators->contains->valid()) { - yield new static($iterators->map->current()); - - $iterators->each->next(); - } - }); - } - - /** - * Pad collection to the specified length with a value. - * - * @template TPadValue - * - * @param int $size - * @param TPadValue $value - * @return static - */ - public function pad($size, $value) - { - if ($size < 0) { - return $this->passthru('pad', func_get_args()); - } - - return new static(function () use ($size, $value) { - $yielded = 0; - - foreach ($this as $index => $item) { - yield $index => $item; - - $yielded++; - } - - while ($yielded++ < $size) { - yield $value; - } - }); - } - - /** - * Get the values iterator. - * - * @return \Traversable - */ - public function getIterator(): Traversable - { - return $this->makeIterator($this->source); - } - - /** - * Count the number of items in the collection. - * - * @return int - */ - public function count(): int - { - if (is_array($this->source)) { - return count($this->source); - } - - return iterator_count($this->getIterator()); - } - - /** - * Make an iterator from the given source. - * - * @template TIteratorKey of array-key - * @template TIteratorValue - * - * @param \IteratorAggregate|array|(callable(): \Generator) $source - * @return \Traversable - */ - protected function makeIterator($source) - { - if ($source instanceof IteratorAggregate) { - return $source->getIterator(); - } - - if (is_array($source)) { - return new ArrayIterator($source); - } - - if (is_callable($source)) { - $maybeTraversable = $source(); - - return $maybeTraversable instanceof Traversable - ? $maybeTraversable - : new ArrayIterator(Arr::wrap($maybeTraversable)); - } - - return new ArrayIterator((array) $source); - } - - /** - * Explode the "value" and "key" arguments passed to "pluck". - * - * @param string|string[] $value - * @param string|string[]|null $key - * @return array{string[],string[]|null} - */ - protected function explodePluckParameters($value, $key) - { - $value = is_string($value) ? explode('.', $value) : $value; - - $key = is_null($key) || is_array($key) ? $key : explode('.', $key); - - return [$value, $key]; - } - - /** - * Pass this lazy collection through a method on the collection class. - * - * @param string $method - * @param array $params - * @return static - */ - protected function passthru($method, array $params) - { - return new static(function () use ($method, $params) { - yield from $this->collect()->$method(...$params); - }); - } - - /** - * Get the current time. - * - * @return int - */ - protected function now() - { - return class_exists(Carbon::class) - ? Carbon::now()->timestamp - : time(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/MultipleItemsFoundException.php b/lam/lib/3rdParty/composer/illuminate/collections/MultipleItemsFoundException.php deleted file mode 100644 index d90d835b4..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/MultipleItemsFoundException.php +++ /dev/null @@ -1,40 +0,0 @@ -count = $count; - - parent::__construct("$count items were found.", $code, $previous); - } - - /** - * Get the number of items found. - * - * @return int - */ - public function getCount() - { - return $this->count; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/Traits/EnumeratesValues.php b/lam/lib/3rdParty/composer/illuminate/collections/Traits/EnumeratesValues.php deleted file mode 100644 index 9718f5bc5..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/Traits/EnumeratesValues.php +++ /dev/null @@ -1,1152 +0,0 @@ - - */ - protected static $proxies = [ - 'average', - 'avg', - 'contains', - 'doesntContain', - 'each', - 'every', - 'filter', - 'first', - 'flatMap', - 'groupBy', - 'keyBy', - 'map', - 'max', - 'min', - 'partition', - 'percentage', - 'reject', - 'skipUntil', - 'skipWhile', - 'some', - 'sortBy', - 'sortByDesc', - 'sum', - 'takeUntil', - 'takeWhile', - 'unique', - 'unless', - 'until', - 'when', - ]; - - /** - * Create a new collection instance if the value isn't one already. - * - * @template TMakeKey of array-key - * @template TMakeValue - * - * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items - * @return static - */ - public static function make($items = []) - { - return new static($items); - } - - /** - * Wrap the given value in a collection if applicable. - * - * @template TWrapValue - * - * @param iterable|TWrapValue $value - * @return static - */ - public static function wrap($value) - { - return $value instanceof Enumerable - ? new static($value) - : new static(Arr::wrap($value)); - } - - /** - * Get the underlying items from the given collection if applicable. - * - * @template TUnwrapKey of array-key - * @template TUnwrapValue - * - * @param array|static $value - * @return array - */ - public static function unwrap($value) - { - return $value instanceof Enumerable ? $value->all() : $value; - } - - /** - * Create a new instance with no items. - * - * @return static - */ - public static function empty() - { - return new static([]); - } - - /** - * Create a new collection by invoking the callback a given amount of times. - * - * @template TTimesValue - * - * @param int $number - * @param (callable(int): TTimesValue)|null $callback - * @return static - */ - public static function times($number, ?callable $callback = null) - { - if ($number < 1) { - return new static; - } - - return static::range(1, $number) - ->unless($callback == null) - ->map($callback); - } - - /** - * Alias for the "avg" method. - * - * @param (callable(TValue): float|int)|string|null $callback - * @return float|int|null - */ - public function average($callback = null) - { - return $this->avg($callback); - } - - /** - * Alias for the "contains" method. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function some($key, $operator = null, $value = null) - { - return $this->contains(...func_get_args()); - } - - /** - * Dump the items and end the script. - * - * @param mixed ...$args - * @return never - */ - public function dd(...$args) - { - $this->dump(...$args); - - exit(1); - } - - /** - * Dump the items. - * - * @return $this - */ - public function dump() - { - (new Collection(func_get_args())) - ->push($this->all()) - ->each(function ($item) { - VarDumper::dump($item); - }); - - return $this; - } - - /** - * Execute a callback over each item. - * - * @param callable(TValue, TKey): mixed $callback - * @return $this - */ - public function each(callable $callback) - { - foreach ($this as $key => $item) { - if ($callback($item, $key) === false) { - break; - } - } - - return $this; - } - - /** - * Execute a callback over each nested chunk of items. - * - * @param callable(...mixed): mixed $callback - * @return static - */ - public function eachSpread(callable $callback) - { - return $this->each(function ($chunk, $key) use ($callback) { - $chunk[] = $key; - - return $callback(...$chunk); - }); - } - - /** - * Determine if all items pass the given truth test. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function every($key, $operator = null, $value = null) - { - if (func_num_args() === 1) { - $callback = $this->valueRetriever($key); - - foreach ($this as $k => $v) { - if (! $callback($v, $k)) { - return false; - } - } - - return true; - } - - return $this->every($this->operatorForWhere(...func_get_args())); - } - - /** - * Get the first item by the given key value pair. - * - * @param callable|string $key - * @param mixed $operator - * @param mixed $value - * @return TValue|null - */ - public function firstWhere($key, $operator = null, $value = null) - { - return $this->first($this->operatorForWhere(...func_get_args())); - } - - /** - * Get a single key's value from the first matching item in the collection. - * - * @template TValueDefault - * - * @param string $key - * @param TValueDefault|(\Closure(): TValueDefault) $default - * @return TValue|TValueDefault - */ - public function value($key, $default = null) - { - if ($value = $this->firstWhere($key)) { - return data_get($value, $key, $default); - } - - return value($default); - } - - /** - * Ensure that every item in the collection is of the expected type. - * - * @template TEnsureOfType - * - * @param class-string|array> $type - * @return static - * - * @throws \UnexpectedValueException - */ - public function ensure($type) - { - $allowedTypes = is_array($type) ? $type : [$type]; - - return $this->each(function ($item) use ($allowedTypes) { - $itemType = get_debug_type($item); - - foreach ($allowedTypes as $allowedType) { - if ($itemType === $allowedType || $item instanceof $allowedType) { - return true; - } - } - - throw new UnexpectedValueException( - sprintf("Collection should only include [%s] items, but '%s' found.", implode(', ', $allowedTypes), $itemType) - ); - }); - } - - /** - * Determine if the collection is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return ! $this->isEmpty(); - } - - /** - * Run a map over each nested chunk of items. - * - * @template TMapSpreadValue - * - * @param callable(mixed...): TMapSpreadValue $callback - * @return static - */ - public function mapSpread(callable $callback) - { - return $this->map(function ($chunk, $key) use ($callback) { - $chunk[] = $key; - - return $callback(...$chunk); - }); - } - - /** - * Run a grouping map over the items. - * - * The callback should return an associative array with a single key/value pair. - * - * @template TMapToGroupsKey of array-key - * @template TMapToGroupsValue - * - * @param callable(TValue, TKey): array $callback - * @return static> - */ - public function mapToGroups(callable $callback) - { - $groups = $this->mapToDictionary($callback); - - return $groups->map([$this, 'make']); - } - - /** - * Map a collection and flatten the result by a single level. - * - * @template TFlatMapKey of array-key - * @template TFlatMapValue - * - * @param callable(TValue, TKey): (\Illuminate\Support\Collection|array) $callback - * @return static - */ - public function flatMap(callable $callback) - { - return $this->map($callback)->collapse(); - } - - /** - * Map the values into a new class. - * - * @template TMapIntoValue - * - * @param class-string $class - * @return static - */ - public function mapInto($class) - { - return $this->map(fn ($value, $key) => new $class($value, $key)); - } - - /** - * Get the min value of a given key. - * - * @param (callable(TValue):mixed)|string|null $callback - * @return mixed - */ - public function min($callback = null) - { - $callback = $this->valueRetriever($callback); - - return $this->map(fn ($value) => $callback($value)) - ->filter(fn ($value) => ! is_null($value)) - ->reduce(fn ($result, $value) => is_null($result) || $value < $result ? $value : $result); - } - - /** - * Get the max value of a given key. - * - * @param (callable(TValue):mixed)|string|null $callback - * @return mixed - */ - public function max($callback = null) - { - $callback = $this->valueRetriever($callback); - - return $this->filter(fn ($value) => ! is_null($value))->reduce(function ($result, $item) use ($callback) { - $value = $callback($item); - - return is_null($result) || $value > $result ? $value : $result; - }); - } - - /** - * "Paginate" the collection by slicing it into a smaller collection. - * - * @param int $page - * @param int $perPage - * @return static - */ - public function forPage($page, $perPage) - { - $offset = max(0, ($page - 1) * $perPage); - - return $this->slice($offset, $perPage); - } - - /** - * Partition the collection into two arrays using the given callback or key. - * - * @param (callable(TValue, TKey): bool)|TValue|string $key - * @param TValue|string|null $operator - * @param TValue|null $value - * @return static, static> - */ - public function partition($key, $operator = null, $value = null) - { - $passed = []; - $failed = []; - - $callback = func_num_args() === 1 - ? $this->valueRetriever($key) - : $this->operatorForWhere(...func_get_args()); - - foreach ($this as $key => $item) { - if ($callback($item, $key)) { - $passed[$key] = $item; - } else { - $failed[$key] = $item; - } - } - - return new static([new static($passed), new static($failed)]); - } - - /** - * Calculate the percentage of items that pass a given truth test. - * - * @param (callable(TValue, TKey): bool) $callback - * @param int $precision - * @return float|null - */ - public function percentage(callable $callback, int $precision = 2) - { - if ($this->isEmpty()) { - return null; - } - - return round( - $this->filter($callback)->count() / $this->count() * 100, - $precision - ); - } - - /** - * Get the sum of the given values. - * - * @param (callable(TValue): mixed)|string|null $callback - * @return mixed - */ - public function sum($callback = null) - { - $callback = is_null($callback) - ? $this->identity() - : $this->valueRetriever($callback); - - return $this->reduce(fn ($result, $item) => $result + $callback($item), 0); - } - - /** - * Apply the callback if the collection is empty. - * - * @template TWhenEmptyReturnType - * - * @param (callable($this): TWhenEmptyReturnType) $callback - * @param (callable($this): TWhenEmptyReturnType)|null $default - * @return $this|TWhenEmptyReturnType - */ - public function whenEmpty(callable $callback, ?callable $default = null) - { - return $this->when($this->isEmpty(), $callback, $default); - } - - /** - * Apply the callback if the collection is not empty. - * - * @template TWhenNotEmptyReturnType - * - * @param callable($this): TWhenNotEmptyReturnType $callback - * @param (callable($this): TWhenNotEmptyReturnType)|null $default - * @return $this|TWhenNotEmptyReturnType - */ - public function whenNotEmpty(callable $callback, ?callable $default = null) - { - return $this->when($this->isNotEmpty(), $callback, $default); - } - - /** - * Apply the callback unless the collection is empty. - * - * @template TUnlessEmptyReturnType - * - * @param callable($this): TUnlessEmptyReturnType $callback - * @param (callable($this): TUnlessEmptyReturnType)|null $default - * @return $this|TUnlessEmptyReturnType - */ - public function unlessEmpty(callable $callback, ?callable $default = null) - { - return $this->whenNotEmpty($callback, $default); - } - - /** - * Apply the callback unless the collection is not empty. - * - * @template TUnlessNotEmptyReturnType - * - * @param callable($this): TUnlessNotEmptyReturnType $callback - * @param (callable($this): TUnlessNotEmptyReturnType)|null $default - * @return $this|TUnlessNotEmptyReturnType - */ - public function unlessNotEmpty(callable $callback, ?callable $default = null) - { - return $this->whenEmpty($callback, $default); - } - - /** - * Filter items by the given key value pair. - * - * @param callable|string $key - * @param mixed $operator - * @param mixed $value - * @return static - */ - public function where($key, $operator = null, $value = null) - { - return $this->filter($this->operatorForWhere(...func_get_args())); - } - - /** - * Filter items where the value for the given key is null. - * - * @param string|null $key - * @return static - */ - public function whereNull($key = null) - { - return $this->whereStrict($key, null); - } - - /** - * Filter items where the value for the given key is not null. - * - * @param string|null $key - * @return static - */ - public function whereNotNull($key = null) - { - return $this->where($key, '!==', null); - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param mixed $value - * @return static - */ - public function whereStrict($key, $value) - { - return $this->where($key, '===', $value); - } - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @param bool $strict - * @return static - */ - public function whereIn($key, $values, $strict = false) - { - $values = $this->getArrayableItems($values); - - return $this->filter(fn ($item) => in_array(data_get($item, $key), $values, $strict)); - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereInStrict($key, $values) - { - return $this->whereIn($key, $values, true); - } - - /** - * Filter items such that the value of the given key is between the given values. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereBetween($key, $values) - { - return $this->where($key, '>=', reset($values))->where($key, '<=', end($values)); - } - - /** - * Filter items such that the value of the given key is not between the given values. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereNotBetween($key, $values) - { - return $this->filter( - fn ($item) => data_get($item, $key) < reset($values) || data_get($item, $key) > end($values) - ); - } - - /** - * Filter items by the given key value pair. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @param bool $strict - * @return static - */ - public function whereNotIn($key, $values, $strict = false) - { - $values = $this->getArrayableItems($values); - - return $this->reject(fn ($item) => in_array(data_get($item, $key), $values, $strict)); - } - - /** - * Filter items by the given key value pair using strict comparison. - * - * @param string $key - * @param \Illuminate\Contracts\Support\Arrayable|iterable $values - * @return static - */ - public function whereNotInStrict($key, $values) - { - return $this->whereNotIn($key, $values, true); - } - - /** - * Filter the items, removing any items that don't match the given type(s). - * - * @template TWhereInstanceOf - * - * @param class-string|array> $type - * @return static - */ - public function whereInstanceOf($type) - { - return $this->filter(function ($value) use ($type) { - if (is_array($type)) { - foreach ($type as $classType) { - if ($value instanceof $classType) { - return true; - } - } - - return false; - } - - return $value instanceof $type; - }); - } - - /** - * Pass the collection to the given callback and return the result. - * - * @template TPipeReturnType - * - * @param callable($this): TPipeReturnType $callback - * @return TPipeReturnType - */ - public function pipe(callable $callback) - { - return $callback($this); - } - - /** - * Pass the collection into a new class. - * - * @template TPipeIntoValue - * - * @param class-string $class - * @return TPipeIntoValue - */ - public function pipeInto($class) - { - return new $class($this); - } - - /** - * Pass the collection through a series of callable pipes and return the result. - * - * @param array $callbacks - * @return mixed - */ - public function pipeThrough($callbacks) - { - return Collection::make($callbacks)->reduce( - fn ($carry, $callback) => $callback($carry), - $this, - ); - } - - /** - * Reduce the collection to a single value. - * - * @template TReduceInitial - * @template TReduceReturnType - * - * @param callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType $callback - * @param TReduceInitial $initial - * @return TReduceReturnType - */ - public function reduce(callable $callback, $initial = null) - { - $result = $initial; - - foreach ($this as $key => $value) { - $result = $callback($result, $value, $key); - } - - return $result; - } - - /** - * Reduce the collection to multiple aggregate values. - * - * @param callable $callback - * @param mixed ...$initial - * @return array - * - * @throws \UnexpectedValueException - */ - public function reduceSpread(callable $callback, ...$initial) - { - $result = $initial; - - foreach ($this as $key => $value) { - $result = call_user_func_array($callback, array_merge($result, [$value, $key])); - - if (! is_array($result)) { - throw new UnexpectedValueException(sprintf( - "%s::reduceSpread expects reducer to return an array, but got a '%s' instead.", - class_basename(static::class), gettype($result) - )); - } - } - - return $result; - } - - /** - * Reduce an associative collection to a single value. - * - * @template TReduceWithKeysInitial - * @template TReduceWithKeysReturnType - * - * @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue, TKey): TReduceWithKeysReturnType $callback - * @param TReduceWithKeysInitial $initial - * @return TReduceWithKeysReturnType - */ - public function reduceWithKeys(callable $callback, $initial = null) - { - return $this->reduce($callback, $initial); - } - - /** - * Create a collection of all elements that do not pass a given truth test. - * - * @param (callable(TValue, TKey): bool)|bool|TValue $callback - * @return static - */ - public function reject($callback = true) - { - $useAsCallable = $this->useAsCallable($callback); - - return $this->filter(function ($value, $key) use ($callback, $useAsCallable) { - return $useAsCallable - ? ! $callback($value, $key) - : $value != $callback; - }); - } - - /** - * Pass the collection to the given callback and then return it. - * - * @param callable($this): mixed $callback - * @return $this - */ - public function tap(callable $callback) - { - $callback($this); - - return $this; - } - - /** - * Return only unique items from the collection array. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @param bool $strict - * @return static - */ - public function unique($key = null, $strict = false) - { - $callback = $this->valueRetriever($key); - - $exists = []; - - return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { - if (in_array($id = $callback($item, $key), $exists, $strict)) { - return true; - } - - $exists[] = $id; - }); - } - - /** - * Return only unique items from the collection array using strict comparison. - * - * @param (callable(TValue, TKey): mixed)|string|null $key - * @return static - */ - public function uniqueStrict($key = null) - { - return $this->unique($key, true); - } - - /** - * Collect the values into a collection. - * - * @return \Illuminate\Support\Collection - */ - public function collect() - { - return new Collection($this->all()); - } - - /** - * Get the collection of items as a plain array. - * - * @return array - */ - public function toArray() - { - return $this->map(fn ($value) => $value instanceof Arrayable ? $value->toArray() : $value)->all(); - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize(): array - { - return array_map(function ($value) { - if ($value instanceof JsonSerializable) { - return $value->jsonSerialize(); - } elseif ($value instanceof Jsonable) { - return json_decode($value->toJson(), true); - } elseif ($value instanceof Arrayable) { - return $value->toArray(); - } - - return $value; - }, $this->all()); - } - - /** - * Get the collection of items as JSON. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->jsonSerialize(), $options); - } - - /** - * Get a CachingIterator instance. - * - * @param int $flags - * @return \CachingIterator - */ - public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) - { - return new CachingIterator($this->getIterator(), $flags); - } - - /** - * Convert the collection to its string representation. - * - * @return string - */ - public function __toString() - { - return $this->escapeWhenCastingToString - ? e($this->toJson()) - : $this->toJson(); - } - - /** - * Indicate that the model's string representation should be escaped when __toString is invoked. - * - * @param bool $escape - * @return $this - */ - public function escapeWhenCastingToString($escape = true) - { - $this->escapeWhenCastingToString = $escape; - - return $this; - } - - /** - * Add a method to the list of proxied methods. - * - * @param string $method - * @return void - */ - public static function proxy($method) - { - static::$proxies[] = $method; - } - - /** - * Dynamically access collection proxies. - * - * @param string $key - * @return mixed - * - * @throws \Exception - */ - public function __get($key) - { - if (! in_array($key, static::$proxies)) { - throw new Exception("Property [{$key}] does not exist on this collection instance."); - } - - return new HigherOrderCollectionProxy($this, $key); - } - - /** - * Results array of items from Collection or Arrayable. - * - * @param mixed $items - * @return array - */ - protected function getArrayableItems($items) - { - if (is_array($items)) { - return $items; - } - - return match (true) { - $items instanceof WeakMap => throw new InvalidArgumentException('Collections can not be created using instances of WeakMap.'), - $items instanceof Enumerable => $items->all(), - $items instanceof Arrayable => $items->toArray(), - $items instanceof Traversable => iterator_to_array($items), - $items instanceof Jsonable => json_decode($items->toJson(), true), - $items instanceof JsonSerializable => (array) $items->jsonSerialize(), - $items instanceof UnitEnum => [$items], - default => (array) $items, - }; - } - - /** - * Get an operator checker callback. - * - * @param callable|string $key - * @param string|null $operator - * @param mixed $value - * @return \Closure - */ - protected function operatorForWhere($key, $operator = null, $value = null) - { - if ($this->useAsCallable($key)) { - return $key; - } - - if (func_num_args() === 1) { - $value = true; - - $operator = '='; - } - - if (func_num_args() === 2) { - $value = $operator; - - $operator = '='; - } - - return function ($item) use ($key, $operator, $value) { - $retrieved = data_get($item, $key); - - $strings = array_filter([$retrieved, $value], function ($value) { - return is_string($value) || (is_object($value) && method_exists($value, '__toString')); - }); - - if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) { - return in_array($operator, ['!=', '<>', '!==']); - } - - switch ($operator) { - default: - case '=': - case '==': return $retrieved == $value; - case '!=': - case '<>': return $retrieved != $value; - case '<': return $retrieved < $value; - case '>': return $retrieved > $value; - case '<=': return $retrieved <= $value; - case '>=': return $retrieved >= $value; - case '===': return $retrieved === $value; - case '!==': return $retrieved !== $value; - case '<=>': return $retrieved <=> $value; - } - }; - } - - /** - * Determine if the given value is callable, but not a string. - * - * @param mixed $value - * @return bool - */ - protected function useAsCallable($value) - { - return ! is_string($value) && is_callable($value); - } - - /** - * Get a value retrieving callback. - * - * @param callable|string|null $value - * @return callable - */ - protected function valueRetriever($value) - { - if ($this->useAsCallable($value)) { - return $value; - } - - return fn ($item) => data_get($item, $value); - } - - /** - * Make a function to check an item's equality. - * - * @param mixed $value - * @return \Closure(mixed): bool - */ - protected function equality($value) - { - return fn ($item) => $item === $value; - } - - /** - * Make a function using another function, by negating its result. - * - * @param \Closure $callback - * @return \Closure - */ - protected function negate(Closure $callback) - { - return fn (...$params) => ! $callback(...$params); - } - - /** - * Make a function that returns what's passed to it. - * - * @return \Closure(TValue): TValue - */ - protected function identity() - { - return fn ($value) => $value; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/composer.json b/lam/lib/3rdParty/composer/illuminate/collections/composer.json deleted file mode 100644 index 5e11a788e..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/composer.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "illuminate/collections", - "description": "The Illuminate Collections package.", - "license": "MIT", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "require": { - "php": "^8.1", - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0" - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - }, - "files": [ - "helpers.php" - ] - }, - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "suggest": { - "symfony/var-dumper": "Required to use the dump method (^6.2)." - }, - "config": { - "sort-packages": true - }, - "minimum-stability": "dev" -} diff --git a/lam/lib/3rdParty/composer/illuminate/collections/helpers.php b/lam/lib/3rdParty/composer/illuminate/collections/helpers.php deleted file mode 100644 index 235edceb1..000000000 --- a/lam/lib/3rdParty/composer/illuminate/collections/helpers.php +++ /dev/null @@ -1,226 +0,0 @@ -|iterable|null $value - * @return \Illuminate\Support\Collection - */ - function collect($value = []) - { - return new Collection($value); - } -} - -if (! function_exists('data_fill')) { - /** - * Fill in data where it's missing. - * - * @param mixed $target - * @param string|array $key - * @param mixed $value - * @return mixed - */ - function data_fill(&$target, $key, $value) - { - return data_set($target, $key, $value, false); - } -} - -if (! function_exists('data_get')) { - /** - * Get an item from an array or object using "dot" notation. - * - * @param mixed $target - * @param string|array|int|null $key - * @param mixed $default - * @return mixed - */ - function data_get($target, $key, $default = null) - { - if (is_null($key)) { - return $target; - } - - $key = is_array($key) ? $key : explode('.', $key); - - foreach ($key as $i => $segment) { - unset($key[$i]); - - if (is_null($segment)) { - return $target; - } - - if ($segment === '*') { - if ($target instanceof Collection) { - $target = $target->all(); - } elseif (! is_iterable($target)) { - return value($default); - } - - $result = []; - - foreach ($target as $item) { - $result[] = data_get($item, $key); - } - - return in_array('*', $key) ? Arr::collapse($result) : $result; - } - - if (Arr::accessible($target) && Arr::exists($target, $segment)) { - $target = $target[$segment]; - } elseif (is_object($target) && isset($target->{$segment})) { - $target = $target->{$segment}; - } else { - return value($default); - } - } - - return $target; - } -} - -if (! function_exists('data_set')) { - /** - * Set an item on an array or object using dot notation. - * - * @param mixed $target - * @param string|array $key - * @param mixed $value - * @param bool $overwrite - * @return mixed - */ - function data_set(&$target, $key, $value, $overwrite = true) - { - $segments = is_array($key) ? $key : explode('.', $key); - - if (($segment = array_shift($segments)) === '*') { - if (! Arr::accessible($target)) { - $target = []; - } - - if ($segments) { - foreach ($target as &$inner) { - data_set($inner, $segments, $value, $overwrite); - } - } elseif ($overwrite) { - foreach ($target as &$inner) { - $inner = $value; - } - } - } elseif (Arr::accessible($target)) { - if ($segments) { - if (! Arr::exists($target, $segment)) { - $target[$segment] = []; - } - - data_set($target[$segment], $segments, $value, $overwrite); - } elseif ($overwrite || ! Arr::exists($target, $segment)) { - $target[$segment] = $value; - } - } elseif (is_object($target)) { - if ($segments) { - if (! isset($target->{$segment})) { - $target->{$segment} = []; - } - - data_set($target->{$segment}, $segments, $value, $overwrite); - } elseif ($overwrite || ! isset($target->{$segment})) { - $target->{$segment} = $value; - } - } else { - $target = []; - - if ($segments) { - data_set($target[$segment], $segments, $value, $overwrite); - } elseif ($overwrite) { - $target[$segment] = $value; - } - } - - return $target; - } -} - -if (! function_exists('data_forget')) { - /** - * Remove / unset an item from an array or object using "dot" notation. - * - * @param mixed $target - * @param string|array|int|null $key - * @return mixed - */ - function data_forget(&$target, $key) - { - $segments = is_array($key) ? $key : explode('.', $key); - - if (($segment = array_shift($segments)) === '*' && Arr::accessible($target)) { - if ($segments) { - foreach ($target as &$inner) { - data_forget($inner, $segments); - } - } - } elseif (Arr::accessible($target)) { - if ($segments && Arr::exists($target, $segment)) { - data_forget($target[$segment], $segments); - } else { - Arr::forget($target, $segment); - } - } elseif (is_object($target)) { - if ($segments && isset($target->{$segment})) { - data_forget($target->{$segment}, $segments); - } elseif (isset($target->{$segment})) { - unset($target->{$segment}); - } - } - - return $target; - } -} - -if (! function_exists('head')) { - /** - * Get the first element of an array. Useful for method chaining. - * - * @param array $array - * @return mixed - */ - function head($array) - { - return reset($array); - } -} - -if (! function_exists('last')) { - /** - * Get the last element from an array. - * - * @param array $array - * @return mixed - */ - function last($array) - { - return end($array); - } -} - -if (! function_exists('value')) { - /** - * Return the default value of the given value. - * - * @param mixed $value - * @param mixed ...$args - * @return mixed - */ - function value($value, ...$args) - { - return $value instanceof Closure ? $value(...$args) : $value; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/conditionable/HigherOrderWhenProxy.php b/lam/lib/3rdParty/composer/illuminate/conditionable/HigherOrderWhenProxy.php deleted file mode 100644 index 579114cf1..000000000 --- a/lam/lib/3rdParty/composer/illuminate/conditionable/HigherOrderWhenProxy.php +++ /dev/null @@ -1,109 +0,0 @@ -target = $target; - } - - /** - * Set the condition on the proxy. - * - * @param bool $condition - * @return $this - */ - public function condition($condition) - { - [$this->condition, $this->hasCondition] = [$condition, true]; - - return $this; - } - - /** - * Indicate that the condition should be negated. - * - * @return $this - */ - public function negateConditionOnCapture() - { - $this->negateConditionOnCapture = true; - - return $this; - } - - /** - * Proxy accessing an attribute onto the target. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - if (! $this->hasCondition) { - $condition = $this->target->{$key}; - - return $this->condition($this->negateConditionOnCapture ? ! $condition : $condition); - } - - return $this->condition - ? $this->target->{$key} - : $this->target; - } - - /** - * Proxy a method call on the target. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - if (! $this->hasCondition) { - $condition = $this->target->{$method}(...$parameters); - - return $this->condition($this->negateConditionOnCapture ? ! $condition : $condition); - } - - return $this->condition - ? $this->target->{$method}(...$parameters) - : $this->target; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/conditionable/LICENSE.md b/lam/lib/3rdParty/composer/illuminate/conditionable/LICENSE.md deleted file mode 100644 index 79810c848..000000000 --- a/lam/lib/3rdParty/composer/illuminate/conditionable/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Taylor Otwell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/illuminate/conditionable/Traits/Conditionable.php b/lam/lib/3rdParty/composer/illuminate/conditionable/Traits/Conditionable.php deleted file mode 100644 index 5e3194bbc..000000000 --- a/lam/lib/3rdParty/composer/illuminate/conditionable/Traits/Conditionable.php +++ /dev/null @@ -1,73 +0,0 @@ -condition($value); - } - - if ($value) { - return $callback($this, $value) ?? $this; - } elseif ($default) { - return $default($this, $value) ?? $this; - } - - return $this; - } - - /** - * Apply the callback if the given "value" is (or resolves to) falsy. - * - * @template TUnlessParameter - * @template TUnlessReturnType - * - * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value - * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback - * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default - * @return $this|TUnlessReturnType - */ - public function unless($value = null, ?callable $callback = null, ?callable $default = null) - { - $value = $value instanceof Closure ? $value($this) : $value; - - if (func_num_args() === 0) { - return (new HigherOrderWhenProxy($this))->negateConditionOnCapture(); - } - - if (func_num_args() === 1) { - return (new HigherOrderWhenProxy($this))->condition(! $value); - } - - if (! $value) { - return $callback($this, $value) ?? $this; - } elseif ($default) { - return $default($this, $value) ?? $this; - } - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/conditionable/composer.json b/lam/lib/3rdParty/composer/illuminate/conditionable/composer.json deleted file mode 100644 index 40b080806..000000000 --- a/lam/lib/3rdParty/composer/illuminate/conditionable/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "illuminate/conditionable", - "description": "The Illuminate Conditionable package.", - "license": "MIT", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "require": { - "php": "^8.0.2" - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "config": { - "sort-packages": true - }, - "minimum-stability": "dev" -} diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Authorizable.php b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Authorizable.php index cedeb6ea3..2f9657c57 100644 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Authorizable.php +++ b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Authorizable.php @@ -7,9 +7,9 @@ interface Authorizable /** * Determine if the entity has a given ability. * - * @param iterable|string $abilities + * @param string $ability * @param array|mixed $arguments * @return bool */ - public function can($abilities, $arguments = []); + public function can($ability, $arguments = []); } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Gate.php b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Gate.php index 4bafab3f4..9d8389089 100644 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Gate.php +++ b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Access/Gate.php @@ -21,16 +21,6 @@ interface Gate */ public function define($ability, $callback); - /** - * Define abilities for a resource. - * - * @param string $name - * @param string $class - * @param array|null $abilities - * @return $this - */ - public function resource($name, $class, ?array $abilities = null); - /** * Define a policy class for a given class type. * @@ -57,40 +47,31 @@ interface Gate public function after(callable $callback); /** - * Determine if all of the given abilities should be granted for the current user. + * Determine if the given ability should be granted for the current user. * - * @param iterable|string $ability + * @param string $ability * @param array|mixed $arguments * @return bool */ public function allows($ability, $arguments = []); /** - * Determine if any of the given abilities should be denied for the current user. + * Determine if the given ability should be denied for the current user. * - * @param iterable|string $ability + * @param string $ability * @param array|mixed $arguments * @return bool */ public function denies($ability, $arguments = []); /** - * Determine if all of the given abilities should be granted for the current user. + * Determine if the given ability should be granted. * - * @param iterable|string $abilities + * @param string $ability * @param array|mixed $arguments * @return bool */ - public function check($abilities, $arguments = []); - - /** - * Determine if any one of the given abilities should be granted for the current user. - * - * @param iterable|string $abilities - * @param array|mixed $arguments - * @return bool - */ - public function any($abilities, $arguments = []); + public function check($ability, $arguments = []); /** * Determine if the given ability should be granted for the current user. @@ -103,26 +84,6 @@ interface Gate */ public function authorize($ability, $arguments = []); - /** - * Inspect the user for the given ability. - * - * @param string $ability - * @param array|mixed $arguments - * @return \Illuminate\Auth\Access\Response - */ - public function inspect($ability, $arguments = []); - - /** - * Get the raw result from the authorization callback. - * - * @param string $ability - * @param array|mixed $arguments - * @return mixed - * - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function raw($ability, $arguments = []); - /** * Get a policy instance for a given class. * @@ -140,11 +101,4 @@ interface Gate * @return static */ public function forUser($user); - - /** - * Get all of the defined abilities. - * - * @return array - */ - public function abilities(); } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Factory.php b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Factory.php index d76ee7648..3ee9c8ce6 100644 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Factory.php +++ b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Factory.php @@ -8,7 +8,7 @@ interface Factory * Get a guard instance by name. * * @param string|null $name - * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard + * @return mixed */ public function guard($name = null); diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Guard.php b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Guard.php index 2796f1ae6..2a2ed3d9a 100644 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Guard.php +++ b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Guard.php @@ -28,7 +28,7 @@ interface Guard /** * Get the ID for the currently authenticated user. * - * @return int|string|null + * @return int|null */ public function id(); @@ -40,13 +40,6 @@ interface Guard */ public function validate(array $credentials = []); - /** - * Determine if the guard has a user instance. - * - * @return bool - */ - public function hasUser(); - /** * Set the current user. * diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php b/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php deleted file mode 100644 index b782761f9..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php +++ /dev/null @@ -1,8 +0,0 @@ -|CastsAttributes|CastsInboundAttributes - */ - public static function castUsing(array $arguments); -} diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsAttributes.php b/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsAttributes.php deleted file mode 100644 index 89cec66a7..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsAttributes.php +++ /dev/null @@ -1,34 +0,0 @@ - $attributes - * @return TGet|null - */ - public function get(Model $model, string $key, mixed $value, array $attributes); - - /** - * Transform the attribute to its underlying model values. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param TSet|null $value - * @param array $attributes - * @return mixed - */ - public function set(Model $model, string $key, mixed $value, array $attributes); -} diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php b/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php deleted file mode 100644 index 6a3e2ef18..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php +++ /dev/null @@ -1,19 +0,0 @@ -id = $id; $this->class = $class; - $this->relations = $relations; - $this->connection = $connection; - } - - /** - * Specify the collection class that should be used when serializing / restoring collections. - * - * @param string|null $collectionClass - * @return $this - */ - public function useCollectionClass(?string $collectionClass) - { - $this->collectionClass = $collectionClass; - - return $this; } } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Query/Builder.php b/lam/lib/3rdParty/composer/illuminate/contracts/Database/Query/Builder.php deleted file mode 100644 index e116ebf41..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Database/Query/Builder.php +++ /dev/null @@ -1,12 +0,0 @@ - + * @return array */ public function getQueueableIds(); - - /** - * Get the relationships of the entities being queued. - * - * @return array - */ - public function getQueueableRelations(); - - /** - * Get the connection of the entities being queued. - * - * @return string|null - */ - public function getQueueableConnection(); } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Queue/QueueableEntity.php b/lam/lib/3rdParty/composer/illuminate/contracts/Queue/QueueableEntity.php index 366f0c84f..447e1f235 100644 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Queue/QueueableEntity.php +++ b/lam/lib/3rdParty/composer/illuminate/contracts/Queue/QueueableEntity.php @@ -10,18 +10,4 @@ interface QueueableEntity * @return mixed */ public function getQueueableId(); - - /** - * Get the relationships for the entity. - * - * @return array - */ - public function getQueueableRelations(); - - /** - * Get the connection of the entity. - * - * @return string|null - */ - public function getQueueableConnection(); } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Queue/ShouldBeEncrypted.php b/lam/lib/3rdParty/composer/illuminate/contracts/Queue/ShouldBeEncrypted.php deleted file mode 100644 index 374df8998..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Queue/ShouldBeEncrypted.php +++ /dev/null @@ -1,8 +0,0 @@ - + * @return array */ public function toArray(); } diff --git a/lam/lib/3rdParty/composer/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php b/lam/lib/3rdParty/composer/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php deleted file mode 100644 index e1be6fefa..000000000 --- a/lam/lib/3rdParty/composer/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php +++ /dev/null @@ -1,14 +0,0 @@ -=5.6.4" }, "autoload": { "psr-4": { @@ -25,7 +23,7 @@ }, "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "config": { diff --git a/lam/lib/3rdParty/composer/illuminate/macroable/LICENSE.md b/lam/lib/3rdParty/composer/illuminate/macroable/LICENSE.md deleted file mode 100644 index 79810c848..000000000 --- a/lam/lib/3rdParty/composer/illuminate/macroable/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Taylor Otwell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/illuminate/macroable/Traits/Macroable.php b/lam/lib/3rdParty/composer/illuminate/macroable/Traits/Macroable.php deleted file mode 100644 index 3e6d96a5c..000000000 --- a/lam/lib/3rdParty/composer/illuminate/macroable/Traits/Macroable.php +++ /dev/null @@ -1,125 +0,0 @@ -getMethods( - ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED - ); - - foreach ($methods as $method) { - if ($replace || ! static::hasMacro($method->name)) { - static::macro($method->name, $method->invoke($mixin)); - } - } - } - - /** - * Checks if macro is registered. - * - * @param string $name - * @return bool - */ - public static function hasMacro($name) - { - return isset(static::$macros[$name]); - } - - /** - * Flush the existing macros. - * - * @return void - */ - public static function flushMacros() - { - static::$macros = []; - } - - /** - * Dynamically handle calls to the class. - * - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - public static function __callStatic($method, $parameters) - { - if (! static::hasMacro($method)) { - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); - } - - $macro = static::$macros[$method]; - - if ($macro instanceof Closure) { - $macro = $macro->bindTo(null, static::class); - } - - return $macro(...$parameters); - } - - /** - * Dynamically handle calls to the class. - * - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - public function __call($method, $parameters) - { - if (! static::hasMacro($method)) { - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); - } - - $macro = static::$macros[$method]; - - if ($macro instanceof Closure) { - $macro = $macro->bindTo($this, static::class); - } - - return $macro(...$parameters); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/macroable/composer.json b/lam/lib/3rdParty/composer/illuminate/macroable/composer.json deleted file mode 100644 index 231d2333a..000000000 --- a/lam/lib/3rdParty/composer/illuminate/macroable/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "illuminate/macroable", - "description": "The Illuminate Macroable package.", - "license": "MIT", - "homepage": "https://laravel.com", - "support": { - "issues": "https://github.com/laravel/framework/issues", - "source": "https://github.com/laravel/framework" - }, - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "require": { - "php": "^8.1" - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - } - }, - "extra": { - "branch-alias": { - "dev-master": "10.x-dev" - } - }, - "config": { - "sort-packages": true - }, - "minimum-stability": "dev" -} diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/AbstractCursorPaginator.php b/lam/lib/3rdParty/composer/illuminate/pagination/AbstractCursorPaginator.php deleted file mode 100644 index fa3070c24..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/AbstractCursorPaginator.php +++ /dev/null @@ -1,672 +0,0 @@ -cursorName => $cursor->encode()]; - - if (count($this->query) > 0) { - $parameters = array_merge($this->query, $parameters); - } - - return $this->path() - .(str_contains($this->path(), '?') ? '&' : '?') - .Arr::query($parameters) - .$this->buildFragment(); - } - - /** - * Get the URL for the previous page. - * - * @return string|null - */ - public function previousPageUrl() - { - if (is_null($previousCursor = $this->previousCursor())) { - return null; - } - - return $this->url($previousCursor); - } - - /** - * The URL for the next page, or null. - * - * @return string|null - */ - public function nextPageUrl() - { - if (is_null($nextCursor = $this->nextCursor())) { - return null; - } - - return $this->url($nextCursor); - } - - /** - * Get the "cursor" that points to the previous set of items. - * - * @return \Illuminate\Pagination\Cursor|null - */ - public function previousCursor() - { - if (is_null($this->cursor) || - ($this->cursor->pointsToPreviousItems() && ! $this->hasMore)) { - return null; - } - - if ($this->items->isEmpty()) { - return null; - } - - return $this->getCursorForItem($this->items->first(), false); - } - - /** - * Get the "cursor" that points to the next set of items. - * - * @return \Illuminate\Pagination\Cursor|null - */ - public function nextCursor() - { - if ((is_null($this->cursor) && ! $this->hasMore) || - (! is_null($this->cursor) && $this->cursor->pointsToNextItems() && ! $this->hasMore)) { - return null; - } - - if ($this->items->isEmpty()) { - return null; - } - - return $this->getCursorForItem($this->items->last(), true); - } - - /** - * Get a cursor instance for the given item. - * - * @param \ArrayAccess|\stdClass $item - * @param bool $isNext - * @return \Illuminate\Pagination\Cursor - */ - public function getCursorForItem($item, $isNext = true) - { - return new Cursor($this->getParametersForItem($item), $isNext); - } - - /** - * Get the cursor parameters for a given object. - * - * @param \ArrayAccess|\stdClass $item - * @return array - * - * @throws \Exception - */ - public function getParametersForItem($item) - { - return collect($this->parameters) - ->filter() - ->flip() - ->map(function ($_, $parameterName) use ($item) { - if ($item instanceof JsonResource) { - $item = $item->resource; - } - - if ($item instanceof Model && - ! is_null($parameter = $this->getPivotParameterForItem($item, $parameterName))) { - return $parameter; - } elseif ($item instanceof ArrayAccess || is_array($item)) { - return $this->ensureParameterIsPrimitive( - $item[$parameterName] ?? $item[Str::afterLast($parameterName, '.')] - ); - } elseif (is_object($item)) { - return $this->ensureParameterIsPrimitive( - $item->{$parameterName} ?? $item->{Str::afterLast($parameterName, '.')} - ); - } - - throw new Exception('Only arrays and objects are supported when cursor paginating items.'); - })->toArray(); - } - - /** - * Get the cursor parameter value from a pivot model if applicable. - * - * @param \ArrayAccess|\stdClass $item - * @param string $parameterName - * @return string|null - */ - protected function getPivotParameterForItem($item, $parameterName) - { - $table = Str::beforeLast($parameterName, '.'); - - foreach ($item->getRelations() as $relation) { - if ($relation instanceof Pivot && $relation->getTable() === $table) { - return $this->ensureParameterIsPrimitive( - $relation->getAttribute(Str::afterLast($parameterName, '.')) - ); - } - } - } - - /** - * Ensure the parameter is a primitive type. - * - * This can resolve issues that arise the developer uses a value object for an attribute. - * - * @param mixed $parameter - * @return mixed - */ - protected function ensureParameterIsPrimitive($parameter) - { - return is_object($parameter) && method_exists($parameter, '__toString') - ? (string) $parameter - : $parameter; - } - - /** - * Get / set the URL fragment to be appended to URLs. - * - * @param string|null $fragment - * @return $this|string|null - */ - public function fragment($fragment = null) - { - if (is_null($fragment)) { - return $this->fragment; - } - - $this->fragment = $fragment; - - return $this; - } - - /** - * Add a set of query string values to the paginator. - * - * @param array|string|null $key - * @param string|null $value - * @return $this - */ - public function appends($key, $value = null) - { - if (is_null($key)) { - return $this; - } - - if (is_array($key)) { - return $this->appendArray($key); - } - - return $this->addQuery($key, $value); - } - - /** - * Add an array of query string values. - * - * @param array $keys - * @return $this - */ - protected function appendArray(array $keys) - { - foreach ($keys as $key => $value) { - $this->addQuery($key, $value); - } - - return $this; - } - - /** - * Add all current query string values to the paginator. - * - * @return $this - */ - public function withQueryString() - { - if (! is_null($query = Paginator::resolveQueryString())) { - return $this->appends($query); - } - - return $this; - } - - /** - * Add a query string value to the paginator. - * - * @param string $key - * @param string $value - * @return $this - */ - protected function addQuery($key, $value) - { - if ($key !== $this->cursorName) { - $this->query[$key] = $value; - } - - return $this; - } - - /** - * Build the full fragment portion of a URL. - * - * @return string - */ - protected function buildFragment() - { - return $this->fragment ? '#'.$this->fragment : ''; - } - - /** - * Load a set of relationships onto the mixed relationship collection. - * - * @param string $relation - * @param array $relations - * @return $this - */ - public function loadMorph($relation, $relations) - { - $this->getCollection()->loadMorph($relation, $relations); - - return $this; - } - - /** - * Load a set of relationship counts onto the mixed relationship collection. - * - * @param string $relation - * @param array $relations - * @return $this - */ - public function loadMorphCount($relation, $relations) - { - $this->getCollection()->loadMorphCount($relation, $relations); - - return $this; - } - - /** - * Get the slice of items being paginated. - * - * @return array - */ - public function items() - { - return $this->items->all(); - } - - /** - * Transform each item in the slice of items using a callback. - * - * @param callable $callback - * @return $this - */ - public function through(callable $callback) - { - $this->items->transform($callback); - - return $this; - } - - /** - * Get the number of items shown per page. - * - * @return int - */ - public function perPage() - { - return $this->perPage; - } - - /** - * Get the current cursor being paginated. - * - * @return \Illuminate\Pagination\Cursor|null - */ - public function cursor() - { - return $this->cursor; - } - - /** - * Get the query string variable used to store the cursor. - * - * @return string - */ - public function getCursorName() - { - return $this->cursorName; - } - - /** - * Set the query string variable used to store the cursor. - * - * @param string $name - * @return $this - */ - public function setCursorName($name) - { - $this->cursorName = $name; - - return $this; - } - - /** - * Set the base path to assign to all URLs. - * - * @param string $path - * @return $this - */ - public function withPath($path) - { - return $this->setPath($path); - } - - /** - * Set the base path to assign to all URLs. - * - * @param string $path - * @return $this - */ - public function setPath($path) - { - $this->path = $path; - - return $this; - } - - /** - * Get the base path for paginator generated URLs. - * - * @return string|null - */ - public function path() - { - return $this->path; - } - - /** - * Resolve the current cursor or return the default value. - * - * @param string $cursorName - * @return \Illuminate\Pagination\Cursor|null - */ - public static function resolveCurrentCursor($cursorName = 'cursor', $default = null) - { - if (isset(static::$currentCursorResolver)) { - return call_user_func(static::$currentCursorResolver, $cursorName); - } - - return $default; - } - - /** - * Set the current cursor resolver callback. - * - * @param \Closure $resolver - * @return void - */ - public static function currentCursorResolver(Closure $resolver) - { - static::$currentCursorResolver = $resolver; - } - - /** - * Get an instance of the view factory from the resolver. - * - * @return \Illuminate\Contracts\View\Factory - */ - public static function viewFactory() - { - return Paginator::viewFactory(); - } - - /** - * Get an iterator for the items. - * - * @return \ArrayIterator - */ - public function getIterator(): Traversable - { - return $this->items->getIterator(); - } - - /** - * Determine if the list of items is empty. - * - * @return bool - */ - public function isEmpty() - { - return $this->items->isEmpty(); - } - - /** - * Determine if the list of items is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return $this->items->isNotEmpty(); - } - - /** - * Get the number of items for the current page. - * - * @return int - */ - public function count(): int - { - return $this->items->count(); - } - - /** - * Get the paginator's underlying collection. - * - * @return \Illuminate\Support\Collection - */ - public function getCollection() - { - return $this->items; - } - - /** - * Set the paginator's underlying collection. - * - * @param \Illuminate\Support\Collection $collection - * @return $this - */ - public function setCollection(Collection $collection) - { - $this->items = $collection; - - return $this; - } - - /** - * Get the paginator options. - * - * @return array - */ - public function getOptions() - { - return $this->options; - } - - /** - * Determine if the given item exists. - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key): bool - { - return $this->items->has($key); - } - - /** - * Get the item at the given offset. - * - * @param mixed $key - * @return mixed - */ - public function offsetGet($key): mixed - { - return $this->items->get($key); - } - - /** - * Set the item at the given offset. - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value): void - { - $this->items->put($key, $value); - } - - /** - * Unset the item at the given key. - * - * @param mixed $key - * @return void - */ - public function offsetUnset($key): void - { - $this->items->forget($key); - } - - /** - * Render the contents of the paginator to HTML. - * - * @return string - */ - public function toHtml() - { - return (string) $this->render(); - } - - /** - * Make dynamic calls into the collection. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->forwardCallTo($this->getCollection(), $method, $parameters); - } - - /** - * Render the contents of the paginator when casting to a string. - * - * @return string - */ - public function __toString() - { - return (string) $this->render(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/AbstractPaginator.php b/lam/lib/3rdParty/composer/illuminate/pagination/AbstractPaginator.php index ed04d5f97..ebaf1ff71 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/AbstractPaginator.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/AbstractPaginator.php @@ -3,20 +3,16 @@ namespace Illuminate\Pagination; use Closure; -use Illuminate\Contracts\Support\Htmlable; -use Illuminate\Support\Arr; +use ArrayIterator; +use Illuminate\Support\Str; use Illuminate\Support\Collection; -use Illuminate\Support\Traits\ForwardsCalls; -use Illuminate\Support\Traits\Tappable; -use Traversable; +use Illuminate\Contracts\Support\Htmlable; /** * @mixin \Illuminate\Support\Collection */ abstract class AbstractPaginator implements Htmlable { - use ForwardsCalls, Tappable; - /** * All of the items being paginated. * @@ -66,20 +62,6 @@ abstract class AbstractPaginator implements Htmlable */ protected $pageName = 'page'; - /** - * The number of links to display on each side of current page link. - * - * @var int - */ - public $onEachSide = 3; - - /** - * The paginator options. - * - * @var array - */ - protected $options; - /** * The current path resolver callback. * @@ -94,13 +76,6 @@ abstract class AbstractPaginator implements Htmlable */ protected static $currentPageResolver; - /** - * The query string resolver callback. - * - * @var \Closure - */ - protected static $queryStringResolver; - /** * The view factory resolver callback. * @@ -113,14 +88,14 @@ abstract class AbstractPaginator implements Htmlable * * @var string */ - public static $defaultView = 'pagination::tailwind'; + public static $defaultView = 'pagination::default'; /** * The default "simple" pagination view. * * @var string */ - public static $defaultSimpleView = 'pagination::simple-tailwind'; + public static $defaultSimpleView = 'pagination::simple-default'; /** * Determine if the given value is a valid page number. @@ -180,9 +155,9 @@ abstract class AbstractPaginator implements Htmlable $parameters = array_merge($this->query, $parameters); } - return $this->path() - .(str_contains($this->path(), '?') ? '&' : '?') - .Arr::query($parameters) + return $this->path + .(Str::contains($this->path, '?') ? '&' : '?') + .http_build_query($parameters, '', '&') .$this->buildFragment(); } @@ -206,16 +181,12 @@ abstract class AbstractPaginator implements Htmlable /** * Add a set of query string values to the paginator. * - * @param array|string|null $key + * @param array|string $key * @param string|null $value * @return $this */ public function appends($key, $value = null) { - if (is_null($key)) { - return $this; - } - if (is_array($key)) { return $this->appendArray($key); } @@ -238,20 +209,6 @@ abstract class AbstractPaginator implements Htmlable return $this; } - /** - * Add all current query string values to the paginator. - * - * @return $this - */ - public function withQueryString() - { - if (isset(static::$queryStringResolver)) { - return $this->appends(call_user_func(static::$queryStringResolver)); - } - - return $this; - } - /** * Add a query string value to the paginator. * @@ -278,34 +235,6 @@ abstract class AbstractPaginator implements Htmlable return $this->fragment ? '#'.$this->fragment : ''; } - /** - * Load a set of relationships onto the mixed relationship collection. - * - * @param string $relation - * @param array $relations - * @return $this - */ - public function loadMorph($relation, $relations) - { - $this->getCollection()->loadMorph($relation, $relations); - - return $this; - } - - /** - * Load a set of relationship counts onto the mixed relationship collection. - * - * @param string $relation - * @param array $relations - * @return $this - */ - public function loadMorphCount($relation, $relations) - { - $this->getCollection()->loadMorphCount($relation, $relations); - - return $this; - } - /** * Get the slice of items being paginated. * @@ -319,7 +248,7 @@ abstract class AbstractPaginator implements Htmlable /** * Get the number of the first item in the slice. * - * @return int|null + * @return int */ public function firstItem() { @@ -329,26 +258,13 @@ abstract class AbstractPaginator implements Htmlable /** * Get the number of the last item in the slice. * - * @return int|null + * @return int */ public function lastItem() { return count($this->items) > 0 ? $this->firstItem() + $this->count() - 1 : null; } - /** - * Transform each item in the slice of items using a callback. - * - * @param callable $callback - * @return $this - */ - public function through(callable $callback) - { - $this->items->transform($callback); - - return $this; - } - /** * Get the number of items shown per page. * @@ -379,16 +295,6 @@ abstract class AbstractPaginator implements Htmlable return $this->currentPage() <= 1; } - /** - * Determine if the paginator is on the last page. - * - * @return bool - */ - public function onLastPage() - { - return ! $this->hasMorePages(); - } - /** * Get the current page. * @@ -446,29 +352,6 @@ abstract class AbstractPaginator implements Htmlable return $this; } - /** - * Set the number of links to display on each side of current page link. - * - * @param int $count - * @return $this - */ - public function onEachSide($count) - { - $this->onEachSide = $count; - - return $this; - } - - /** - * Get the base path for paginator generated URLs. - * - * @return string|null - */ - public function path() - { - return $this->path; - } - /** * Resolve the current request path or return the default value. * @@ -505,7 +388,7 @@ abstract class AbstractPaginator implements Htmlable public static function resolveCurrentPage($pageName = 'page', $default = 1) { if (isset(static::$currentPageResolver)) { - return (int) call_user_func(static::$currentPageResolver, $pageName); + return call_user_func(static::$currentPageResolver, $pageName); } return $default; @@ -522,32 +405,6 @@ abstract class AbstractPaginator implements Htmlable static::$currentPageResolver = $resolver; } - /** - * Resolve the query string or return the default value. - * - * @param string|array|null $default - * @return string - */ - public static function resolveQueryString($default = null) - { - if (isset(static::$queryStringResolver)) { - return (static::$queryStringResolver)(); - } - - return $default; - } - - /** - * Set with query string resolver callback. - * - * @param \Closure $resolver - * @return void - */ - public static function queryStringResolver(Closure $resolver) - { - static::$queryStringResolver = $resolver; - } - /** * Get an instance of the view factory from the resolver. * @@ -591,72 +448,18 @@ abstract class AbstractPaginator implements Htmlable static::$defaultSimpleView = $view; } - /** - * Indicate that Tailwind styling should be used for generated links. - * - * @return void - */ - public static function useTailwind() - { - static::defaultView('pagination::tailwind'); - static::defaultSimpleView('pagination::simple-tailwind'); - } - - /** - * Indicate that Bootstrap 4 styling should be used for generated links. - * - * @return void - */ - public static function useBootstrap() - { - static::useBootstrapFour(); - } - - /** - * Indicate that Bootstrap 3 styling should be used for generated links. - * - * @return void - */ - public static function useBootstrapThree() - { - static::defaultView('pagination::default'); - static::defaultSimpleView('pagination::simple-default'); - } - - /** - * Indicate that Bootstrap 4 styling should be used for generated links. - * - * @return void - */ - public static function useBootstrapFour() - { - static::defaultView('pagination::bootstrap-4'); - static::defaultSimpleView('pagination::simple-bootstrap-4'); - } - - /** - * Indicate that Bootstrap 5 styling should be used for generated links. - * - * @return void - */ - public static function useBootstrapFive() - { - static::defaultView('pagination::bootstrap-5'); - static::defaultSimpleView('pagination::simple-bootstrap-5'); - } - /** * Get an iterator for the items. * * @return \ArrayIterator */ - public function getIterator(): Traversable + public function getIterator() { - return $this->items->getIterator(); + return new ArrayIterator($this->items->all()); } /** - * Determine if the list of items is empty. + * Determine if the list of items is empty or not. * * @return bool */ @@ -665,22 +468,12 @@ abstract class AbstractPaginator implements Htmlable return $this->items->isEmpty(); } - /** - * Determine if the list of items is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return $this->items->isNotEmpty(); - } - /** * Get the number of items for the current page. * * @return int */ - public function count(): int + public function count() { return $this->items->count(); } @@ -708,23 +501,13 @@ abstract class AbstractPaginator implements Htmlable return $this; } - /** - * Get the paginator options. - * - * @return array - */ - public function getOptions() - { - return $this->options; - } - /** * Determine if the given item exists. * * @param mixed $key * @return bool */ - public function offsetExists($key): bool + public function offsetExists($key) { return $this->items->has($key); } @@ -735,7 +518,7 @@ abstract class AbstractPaginator implements Htmlable * @param mixed $key * @return mixed */ - public function offsetGet($key): mixed + public function offsetGet($key) { return $this->items->get($key); } @@ -747,7 +530,7 @@ abstract class AbstractPaginator implements Htmlable * @param mixed $value * @return void */ - public function offsetSet($key, $value): void + public function offsetSet($key, $value) { $this->items->put($key, $value); } @@ -758,7 +541,7 @@ abstract class AbstractPaginator implements Htmlable * @param mixed $key * @return void */ - public function offsetUnset($key): void + public function offsetUnset($key) { $this->items->forget($key); } @@ -782,11 +565,11 @@ abstract class AbstractPaginator implements Htmlable */ public function __call($method, $parameters) { - return $this->forwardCallTo($this->getCollection(), $method, $parameters); + return $this->getCollection()->$method(...$parameters); } /** - * Render the contents of the paginator when casting to a string. + * Render the contents of the paginator when casting to string. * * @return string */ diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/Cursor.php b/lam/lib/3rdParty/composer/illuminate/pagination/Cursor.php deleted file mode 100644 index 1d622808b..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/Cursor.php +++ /dev/null @@ -1,132 +0,0 @@ -parameters = $parameters; - $this->pointsToNextItems = $pointsToNextItems; - } - - /** - * Get the given parameter from the cursor. - * - * @param string $parameterName - * @return string|null - * - * @throws \UnexpectedValueException - */ - public function parameter(string $parameterName) - { - if (! array_key_exists($parameterName, $this->parameters)) { - throw new UnexpectedValueException("Unable to find parameter [{$parameterName}] in pagination item."); - } - - return $this->parameters[$parameterName]; - } - - /** - * Get the given parameters from the cursor. - * - * @param array $parameterNames - * @return array - */ - public function parameters(array $parameterNames) - { - return collect($parameterNames)->map(function ($parameterName) { - return $this->parameter($parameterName); - })->toArray(); - } - - /** - * Determine whether the cursor points to the next set of items. - * - * @return bool - */ - public function pointsToNextItems() - { - return $this->pointsToNextItems; - } - - /** - * Determine whether the cursor points to the previous set of items. - * - * @return bool - */ - public function pointsToPreviousItems() - { - return ! $this->pointsToNextItems; - } - - /** - * Get the array representation of the cursor. - * - * @return array - */ - public function toArray() - { - return array_merge($this->parameters, [ - '_pointsToNextItems' => $this->pointsToNextItems, - ]); - } - - /** - * Get the encoded string representation of the cursor to construct a URL. - * - * @return string - */ - public function encode() - { - return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($this->toArray()))); - } - - /** - * Get a cursor instance from the encoded string representation. - * - * @param string|null $encodedString - * @return static|null - */ - public static function fromEncoded($encodedString) - { - if (! is_string($encodedString)) { - return null; - } - - $parameters = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $encodedString)), true); - - if (json_last_error() !== JSON_ERROR_NONE) { - return null; - } - - $pointsToNextItems = $parameters['_pointsToNextItems']; - - unset($parameters['_pointsToNextItems']); - - return new static($parameters, $pointsToNextItems); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/CursorPaginator.php b/lam/lib/3rdParty/composer/illuminate/pagination/CursorPaginator.php deleted file mode 100644 index 4c0a8965c..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/CursorPaginator.php +++ /dev/null @@ -1,172 +0,0 @@ -options = $options; - - foreach ($options as $key => $value) { - $this->{$key} = $value; - } - - $this->perPage = (int) $perPage; - $this->cursor = $cursor; - $this->path = $this->path !== '/' ? rtrim($this->path, '/') : $this->path; - - $this->setItems($items); - } - - /** - * Set the items for the paginator. - * - * @param mixed $items - * @return void - */ - protected function setItems($items) - { - $this->items = $items instanceof Collection ? $items : Collection::make($items); - - $this->hasMore = $this->items->count() > $this->perPage; - - $this->items = $this->items->slice(0, $this->perPage); - - if (! is_null($this->cursor) && $this->cursor->pointsToPreviousItems()) { - $this->items = $this->items->reverse()->values(); - } - } - - /** - * Render the paginator using the given view. - * - * @param string|null $view - * @param array $data - * @return \Illuminate\Contracts\Support\Htmlable - */ - public function links($view = null, $data = []) - { - return $this->render($view, $data); - } - - /** - * Render the paginator using the given view. - * - * @param string|null $view - * @param array $data - * @return \Illuminate\Contracts\Support\Htmlable - */ - public function render($view = null, $data = []) - { - return static::viewFactory()->make($view ?: Paginator::$defaultSimpleView, array_merge($data, [ - 'paginator' => $this, - ])); - } - - /** - * Determine if there are more items in the data source. - * - * @return bool - */ - public function hasMorePages() - { - return (is_null($this->cursor) && $this->hasMore) || - (! is_null($this->cursor) && $this->cursor->pointsToNextItems() && $this->hasMore) || - (! is_null($this->cursor) && $this->cursor->pointsToPreviousItems()); - } - - /** - * Determine if there are enough items to split into multiple pages. - * - * @return bool - */ - public function hasPages() - { - return ! $this->onFirstPage() || $this->hasMorePages(); - } - - /** - * Determine if the paginator is on the first page. - * - * @return bool - */ - public function onFirstPage() - { - return is_null($this->cursor) || ($this->cursor->pointsToPreviousItems() && ! $this->hasMore); - } - - /** - * Determine if the paginator is on the last page. - * - * @return bool - */ - public function onLastPage() - { - return ! $this->hasMorePages(); - } - - /** - * Get the instance as an array. - * - * @return array - */ - public function toArray() - { - return [ - 'data' => $this->items->toArray(), - 'path' => $this->path(), - 'per_page' => $this->perPage(), - 'next_cursor' => $this->nextCursor()?->encode(), - 'next_page_url' => $this->nextPageUrl(), - 'prev_cursor' => $this->previousCursor()?->encode(), - 'prev_page_url' => $this->previousPageUrl(), - ]; - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize(): array - { - return $this->toArray(); - } - - /** - * Convert the object to its JSON representation. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->jsonSerialize(), $options); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/LICENSE.md b/lam/lib/3rdParty/composer/illuminate/pagination/LICENSE.md deleted file mode 100644 index 79810c848..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Taylor Otwell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/LengthAwarePaginator.php b/lam/lib/3rdParty/composer/illuminate/pagination/LengthAwarePaginator.php index 8d3e0ab77..e0cd317ae 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/LengthAwarePaginator.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/LengthAwarePaginator.php @@ -2,16 +2,17 @@ namespace Illuminate\Pagination; -use ArrayAccess; use Countable; -use Illuminate\Contracts\Pagination\LengthAwarePaginator as LengthAwarePaginatorContract; -use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Contracts\Support\Jsonable; -use Illuminate\Support\Collection; -use IteratorAggregate; +use ArrayAccess; use JsonSerializable; +use IteratorAggregate; +use Illuminate\Support\Collection; +use Illuminate\Support\HtmlString; +use Illuminate\Contracts\Support\Jsonable; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Pagination\LengthAwarePaginator as LengthAwarePaginatorContract; -class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, JsonSerializable, LengthAwarePaginatorContract +class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Jsonable, LengthAwarePaginatorContract { /** * The total number of items before slicing. @@ -34,21 +35,19 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array * @param int $total * @param int $perPage * @param int|null $currentPage - * @param array $options (path, query, fragment, pageName) + * @param array $options (path, query, fragment, pageName) * @return void */ public function __construct($items, $total, $perPage, $currentPage = null, array $options = []) { - $this->options = $options; - foreach ($options as $key => $value) { $this->{$key} = $value; } $this->total = $total; - $this->perPage = (int) $perPage; - $this->lastPage = max((int) ceil($total / $perPage), 1); - $this->path = $this->path !== '/' ? rtrim($this->path, '/') : $this->path; + $this->perPage = $perPage; + $this->lastPage = (int) ceil($total / $perPage); + $this->path = $this->path != '/' ? rtrim($this->path, '/') : $this->path; $this->currentPage = $this->setCurrentPage($currentPage, $this->pageName); $this->items = $items instanceof Collection ? $items : Collection::make($items); } @@ -70,9 +69,9 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array /** * Render the paginator using the given view. * - * @param string|null $view + * @param string $view * @param array $data - * @return \Illuminate\Contracts\Support\Htmlable + * @return string */ public function links($view = null, $data = []) { @@ -82,46 +81,16 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array /** * Render the paginator using the given view. * - * @param string|null $view + * @param string $view * @param array $data - * @return \Illuminate\Contracts\Support\Htmlable + * @return string */ public function render($view = null, $data = []) { - return static::viewFactory()->make($view ?: static::$defaultView, array_merge($data, [ + return new HtmlString(static::viewFactory()->make($view ?: static::$defaultView, array_merge($data, [ 'paginator' => $this, 'elements' => $this->elements(), - ])); - } - - /** - * Get the paginator links as a collection (for JSON responses). - * - * @return \Illuminate\Support\Collection - */ - public function linkCollection() - { - return collect($this->elements())->flatMap(function ($item) { - if (! is_array($item)) { - return [['url' => null, 'label' => '...', 'active' => false]]; - } - - return collect($item)->map(function ($url, $page) { - return [ - 'url' => $url, - 'label' => (string) $page, - 'active' => $this->currentPage() === $page, - ]; - }); - })->prepend([ - 'url' => $this->previousPageUrl(), - 'label' => function_exists('__') ? __('pagination.previous') : 'Previous', - 'active' => false, - ])->push([ - 'url' => $this->nextPageUrl(), - 'label' => function_exists('__') ? __('pagination.next') : 'Next', - 'active' => false, - ]); + ]))->render()); } /** @@ -169,7 +138,7 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array */ public function nextPageUrl() { - if ($this->hasMorePages()) { + if ($this->lastPage() > $this->currentPage()) { return $this->url($this->currentPage() + 1); } } @@ -194,13 +163,10 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array return [ 'current_page' => $this->currentPage(), 'data' => $this->items->toArray(), - 'first_page_url' => $this->url(1), 'from' => $this->firstItem(), 'last_page' => $this->lastPage(), - 'last_page_url' => $this->url($this->lastPage()), - 'links' => $this->linkCollection()->toArray(), 'next_page_url' => $this->nextPageUrl(), - 'path' => $this->path(), + 'path' => $this->path, 'per_page' => $this->perPage(), 'prev_page_url' => $this->previousPageUrl(), 'to' => $this->lastItem(), @@ -213,7 +179,7 @@ class LengthAwarePaginator extends AbstractPaginator implements Arrayable, Array * * @return array */ - public function jsonSerialize(): array + public function jsonSerialize() { return $this->toArray(); } diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/PaginationServiceProvider.php b/lam/lib/3rdParty/composer/illuminate/pagination/PaginationServiceProvider.php index e94cebd6c..d5ca6daec 100755 --- a/lam/lib/3rdParty/composer/illuminate/pagination/PaginationServiceProvider.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/PaginationServiceProvider.php @@ -29,6 +29,22 @@ class PaginationServiceProvider extends ServiceProvider */ public function register() { - PaginationState::resolveUsing($this->app); + Paginator::viewFactoryResolver(function () { + return $this->app['view']; + }); + + Paginator::currentPathResolver(function () { + return $this->app['request']->url(); + }); + + Paginator::currentPageResolver(function ($pageName = 'page') { + $page = $this->app['request']->input($pageName); + + if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { + return $page; + } + + return 1; + }); } } diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/PaginationState.php b/lam/lib/3rdParty/composer/illuminate/pagination/PaginationState.php deleted file mode 100644 index 347c6e224..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/PaginationState.php +++ /dev/null @@ -1,35 +0,0 @@ - $app['view']); - - Paginator::currentPathResolver(fn () => $app['request']->url()); - - Paginator::currentPageResolver(function ($pageName = 'page') use ($app) { - $page = $app['request']->input($pageName); - - if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { - return (int) $page; - } - - return 1; - }); - - Paginator::queryStringResolver(fn () => $app['request']->query()); - - CursorPaginator::currentCursorResolver(function ($cursorName = 'cursor') use ($app) { - return Cursor::fromEncoded($app['request']->input($cursorName)); - }); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/Paginator.php b/lam/lib/3rdParty/composer/illuminate/pagination/Paginator.php index d307ee9ff..61f33e928 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/Paginator.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/Paginator.php @@ -2,16 +2,17 @@ namespace Illuminate\Pagination; -use ArrayAccess; use Countable; -use Illuminate\Contracts\Pagination\Paginator as PaginatorContract; -use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Contracts\Support\Jsonable; -use Illuminate\Support\Collection; -use IteratorAggregate; +use ArrayAccess; use JsonSerializable; +use IteratorAggregate; +use Illuminate\Support\Collection; +use Illuminate\Support\HtmlString; +use Illuminate\Contracts\Support\Jsonable; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Pagination\Paginator as PaginatorContract; -class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, JsonSerializable, PaginatorContract +class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Jsonable, PaginatorContract { /** * Determine if there are more items in the data source. @@ -26,20 +27,18 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou * @param mixed $items * @param int $perPage * @param int|null $currentPage - * @param array $options (path, query, fragment, pageName) + * @param array $options (path, query, fragment, pageName) * @return void */ public function __construct($items, $perPage, $currentPage = null, array $options = []) { - $this->options = $options; - foreach ($options as $key => $value) { $this->{$key} = $value; } $this->perPage = $perPage; $this->currentPage = $this->setCurrentPage($currentPage); - $this->path = $this->path !== '/' ? rtrim($this->path, '/') : $this->path; + $this->path = $this->path != '/' ? rtrim($this->path, '/') : $this->path; $this->setItems($items); } @@ -67,7 +66,7 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou { $this->items = $items instanceof Collection ? $items : Collection::make($items); - $this->hasMore = $this->items->count() > $this->perPage; + $this->hasMore = count($this->items) > ($this->perPage); $this->items = $this->items->slice(0, $this->perPage); } @@ -101,24 +100,26 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou * * @param string|null $view * @param array $data - * @return \Illuminate\Contracts\Support\Htmlable + * @return string */ public function render($view = null, $data = []) { - return static::viewFactory()->make($view ?: static::$defaultSimpleView, array_merge($data, [ - 'paginator' => $this, - ])); + return new HtmlString( + static::viewFactory()->make($view ?: static::$defaultSimpleView, array_merge($data, [ + 'paginator' => $this, + ]))->render() + ); } /** * Manually indicate that the paginator does have more pages. * - * @param bool $hasMore + * @param bool $value * @return $this */ - public function hasMorePagesWhen($hasMore = true) + public function hasMorePagesWhen($value = true) { - $this->hasMore = $hasMore; + $this->hasMore = $value; return $this; } @@ -143,10 +144,9 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou return [ 'current_page' => $this->currentPage(), 'data' => $this->items->toArray(), - 'first_page_url' => $this->url(1), 'from' => $this->firstItem(), 'next_page_url' => $this->nextPageUrl(), - 'path' => $this->path(), + 'path' => $this->path, 'per_page' => $this->perPage(), 'prev_page_url' => $this->previousPageUrl(), 'to' => $this->lastItem(), @@ -158,7 +158,7 @@ class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Cou * * @return array */ - public function jsonSerialize(): array + public function jsonSerialize() { return $this->toArray(); } diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/UrlWindow.php b/lam/lib/3rdParty/composer/illuminate/pagination/UrlWindow.php index 99286f7b3..6ec0b0c9d 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/UrlWindow.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/UrlWindow.php @@ -28,23 +28,23 @@ class UrlWindow * Create a new URL window instance. * * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator + * @param int $onEachSide * @return array */ - public static function make(PaginatorContract $paginator) + public static function make(PaginatorContract $paginator, $onEachSide = 3) { - return (new static($paginator))->get(); + return (new static($paginator))->get($onEachSide); } /** * Get the window of URLs to be shown. * + * @param int $onEachSide * @return array */ - public function get() + public function get($onEachSide = 3) { - $onEachSide = $this->paginator->onEachSide; - - if ($this->paginator->lastPage() < ($onEachSide * 2) + 8) { + if ($this->paginator->lastPage() < ($onEachSide * 2) + 6) { return $this->getSmallSlider(); } @@ -59,9 +59,9 @@ class UrlWindow protected function getSmallSlider() { return [ - 'first' => $this->paginator->getUrlRange(1, $this->lastPage()), + 'first' => $this->paginator->getUrlRange(1, $this->lastPage()), 'slider' => null, - 'last' => null, + 'last' => null, ]; } @@ -73,7 +73,7 @@ class UrlWindow */ protected function getUrlSlider($onEachSide) { - $window = $onEachSide + 4; + $window = $onEachSide * 2; if (! $this->hasPages()) { return ['first' => null, 'slider' => null, 'last' => null]; @@ -83,14 +83,14 @@ class UrlWindow // just render the beginning of the page range, followed by the last 2 of the // links in this list, since we will not have room to create a full slider. if ($this->currentPage() <= $window) { - return $this->getSliderTooCloseToBeginning($window, $onEachSide); + return $this->getSliderTooCloseToBeginning($window); } // If the current page is close to the ending of the page range we will just get // this first couple pages, followed by a larger window of these ending pages // since we're too close to the end of the list to create a full on slider. elseif ($this->currentPage() > ($this->lastPage() - $window)) { - return $this->getSliderTooCloseToEnding($window, $onEachSide); + return $this->getSliderTooCloseToEnding($window); } // If we have enough room on both sides of the current page to build a slider we @@ -100,32 +100,30 @@ class UrlWindow } /** - * Get the slider of URLs when too close to the beginning of the window. + * Get the slider of URLs when too close to beginning of window. * * @param int $window - * @param int $onEachSide * @return array */ - protected function getSliderTooCloseToBeginning($window, $onEachSide) + protected function getSliderTooCloseToBeginning($window) { return [ - 'first' => $this->paginator->getUrlRange(1, $window + $onEachSide), + 'first' => $this->paginator->getUrlRange(1, $window + 2), 'slider' => null, 'last' => $this->getFinish(), ]; } /** - * Get the slider of URLs when too close to the ending of the window. + * Get the slider of URLs when too close to ending of window. * * @param int $window - * @param int $onEachSide * @return array */ - protected function getSliderTooCloseToEnding($window, $onEachSide) + protected function getSliderTooCloseToEnding($window) { $last = $this->paginator->getUrlRange( - $this->lastPage() - ($window + ($onEachSide - 1)), + $this->lastPage() - ($window + 2), $this->lastPage() ); @@ -145,9 +143,9 @@ class UrlWindow protected function getFullSlider($onEachSide) { return [ - 'first' => $this->getStart(), + 'first' => $this->getStart(), 'slider' => $this->getAdjacentUrlRange($onEachSide), - 'last' => $this->getFinish(), + 'last' => $this->getFinish(), ]; } diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/composer.json b/lam/lib/3rdParty/composer/illuminate/pagination/composer.json index 2fc61394b..09563f60b 100755 --- a/lam/lib/3rdParty/composer/illuminate/pagination/composer.json +++ b/lam/lib/3rdParty/composer/illuminate/pagination/composer.json @@ -14,11 +14,9 @@ } ], "require": { - "php": "^8.1", - "ext-filter": "*", - "illuminate/collections": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/support": "^10.0" + "php": ">=5.6.4", + "illuminate/contracts": "5.4.*", + "illuminate/support": "5.4.*" }, "autoload": { "psr-4": { @@ -27,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "config": { diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-4.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-4.blade.php index 63c6f56b5..3f984557b 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-4.blade.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-4.blade.php @@ -1,46 +1,36 @@ @if ($paginator->hasPages()) - + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + @else +
  • »
  • + @endif +
@endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-5.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-5.blade.php deleted file mode 100644 index a1795a4d8..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/bootstrap-5.blade.php +++ /dev/null @@ -1,88 +0,0 @@ -@if ($paginator->hasPages()) - -@endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/default.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/default.blade.php index 0db70b562..4e795ff41 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/default.blade.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/default.blade.php @@ -1,46 +1,36 @@ @if ($paginator->hasPages()) - + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + @else +
  • »
  • + @endif + @endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/semantic-ui.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/semantic-ui.blade.php deleted file mode 100644 index ef0dbb184..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/semantic-ui.blade.php +++ /dev/null @@ -1,36 +0,0 @@ -@if ($paginator->hasPages()) - -@endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-4.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-4.blade.php index 4bb491742..a9a18d32a 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-4.blade.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-4.blade.php @@ -1,27 +1,17 @@ @if ($paginator->hasPages()) - + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + @else +
  • @lang('pagination.next')
  • + @endif + @endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-5.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-5.blade.php deleted file mode 100644 index a89005ee7..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-bootstrap-5.blade.php +++ /dev/null @@ -1,29 +0,0 @@ -@if ($paginator->hasPages()) - -@endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-default.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-default.blade.php index 36bdbc18c..18016092d 100644 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-default.blade.php +++ b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-default.blade.php @@ -1,19 +1,17 @@ @if ($paginator->hasPages()) - + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + @else +
  • @lang('pagination.next')
  • + @endif + @endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-tailwind.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-tailwind.blade.php deleted file mode 100644 index ea02400f4..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/simple-tailwind.blade.php +++ /dev/null @@ -1,25 +0,0 @@ -@if ($paginator->hasPages()) - -@endif diff --git a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/tailwind.blade.php b/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/tailwind.blade.php deleted file mode 100644 index aee2ad28e..000000000 --- a/lam/lib/3rdParty/composer/illuminate/pagination/resources/views/tailwind.blade.php +++ /dev/null @@ -1,106 +0,0 @@ -@if ($paginator->hasPages()) - -@endif diff --git a/lam/lib/3rdParty/composer/illuminate/support/Arr.php b/lam/lib/3rdParty/composer/illuminate/support/Arr.php new file mode 100755 index 000000000..4b3e44715 --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Arr.php @@ -0,0 +1,602 @@ +all(); + } elseif (! is_array($values)) { + continue; + } + + $results = array_merge($results, $values); + } + + return $results; + } + + /** + * Cross join the given arrays, returning all possible permutations. + * + * @param array ...$arrays + * @return array + */ + public static function crossJoin(...$arrays) + { + $results = [[]]; + + foreach ($arrays as $index => $array) { + $append = []; + + foreach ($results as $product) { + foreach ($array as $item) { + $product[$index] = $item; + + $append[] = $product; + } + } + + $results = $append; + } + + return $results; + } + + /** + * Divide an array into two arrays. One with keys and the other with values. + * + * @param array $array + * @return array + */ + public static function divide($array) + { + return [array_keys($array), array_values($array)]; + } + + /** + * Flatten a multi-dimensional associative array with dots. + * + * @param array $array + * @param string $prepend + * @return array + */ + public static function dot($array, $prepend = '') + { + $results = []; + + foreach ($array as $key => $value) { + if (is_array($value) && ! empty($value)) { + $results = array_merge($results, static::dot($value, $prepend.$key.'.')); + } else { + $results[$prepend.$key] = $value; + } + } + + return $results; + } + + /** + * Get all of the given array except for a specified array of items. + * + * @param array $array + * @param array|string $keys + * @return array + */ + public static function except($array, $keys) + { + static::forget($array, $keys); + + return $array; + } + + /** + * Determine if the given key exists in the provided array. + * + * @param \ArrayAccess|array $array + * @param string|int $key + * @return bool + */ + public static function exists($array, $key) + { + if ($array instanceof ArrayAccess) { + return $array->offsetExists($key); + } + + return array_key_exists($key, $array); + } + + /** + * Return the first element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public static function first($array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + if (empty($array)) { + return value($default); + } + + foreach ($array as $item) { + return $item; + } + } + + foreach ($array as $key => $value) { + if (call_user_func($callback, $value, $key)) { + return $value; + } + } + + return value($default); + } + + /** + * Return the last element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public static function last($array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + return empty($array) ? value($default) : end($array); + } + + return static::first(array_reverse($array, true), $callback, $default); + } + + /** + * Flatten a multi-dimensional array into a single level. + * + * @param array $array + * @param int $depth + * @return array + */ + public static function flatten($array, $depth = INF) + { + return array_reduce($array, function ($result, $item) use ($depth) { + $item = $item instanceof Collection ? $item->all() : $item; + + if (! is_array($item)) { + return array_merge($result, [$item]); + } elseif ($depth === 1) { + return array_merge($result, array_values($item)); + } else { + return array_merge($result, static::flatten($item, $depth - 1)); + } + }, []); + } + + /** + * Remove one or many array items from a given array using "dot" notation. + * + * @param array $array + * @param array|string $keys + * @return void + */ + public static function forget(&$array, $keys) + { + $original = &$array; + + $keys = (array) $keys; + + if (count($keys) === 0) { + return; + } + + foreach ($keys as $key) { + // if the exact key exists in the top-level, remove it + if (static::exists($array, $key)) { + unset($array[$key]); + + continue; + } + + $parts = explode('.', $key); + + // clean up before each pass + $array = &$original; + + while (count($parts) > 1) { + $part = array_shift($parts); + + if (isset($array[$part]) && is_array($array[$part])) { + $array = &$array[$part]; + } else { + continue 2; + } + } + + unset($array[array_shift($parts)]); + } + } + + /** + * Get an item from an array using "dot" notation. + * + * @param \ArrayAccess|array $array + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function get($array, $key, $default = null) + { + if (! static::accessible($array)) { + return value($default); + } + + if (is_null($key)) { + return $array; + } + + if (static::exists($array, $key)) { + return $array[$key]; + } + + foreach (explode('.', $key) as $segment) { + if (static::accessible($array) && static::exists($array, $segment)) { + $array = $array[$segment]; + } else { + return value($default); + } + } + + return $array; + } + + /** + * Check if an item or items exist in an array using "dot" notation. + * + * @param \ArrayAccess|array $array + * @param string|array $keys + * @return bool + */ + public static function has($array, $keys) + { + if (is_null($keys)) { + return false; + } + + $keys = (array) $keys; + + if (! $array) { + return false; + } + + if ($keys === []) { + return false; + } + + foreach ($keys as $key) { + $subKeyArray = $array; + + if (static::exists($array, $key)) { + continue; + } + + foreach (explode('.', $key) as $segment) { + if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { + $subKeyArray = $subKeyArray[$segment]; + } else { + return false; + } + } + } + + return true; + } + + /** + * Determines if an array is associative. + * + * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. + * + * @param array $array + * @return bool + */ + public static function isAssoc(array $array) + { + $keys = array_keys($array); + + return array_keys($keys) !== $keys; + } + + /** + * Get a subset of the items from the given array. + * + * @param array $array + * @param array|string $keys + * @return array + */ + public static function only($array, $keys) + { + return array_intersect_key($array, array_flip((array) $keys)); + } + + /** + * Pluck an array of values from an array. + * + * @param array $array + * @param string|array $value + * @param string|array|null $key + * @return array + */ + public static function pluck($array, $value, $key = null) + { + $results = []; + + list($value, $key) = static::explodePluckParameters($value, $key); + + foreach ($array as $item) { + $itemValue = data_get($item, $value); + + // If the key is "null", we will just append the value to the array and keep + // looping. Otherwise we will key the array using the value of the key we + // received from the developer. Then we'll return the final array form. + if (is_null($key)) { + $results[] = $itemValue; + } else { + $itemKey = data_get($item, $key); + + if (is_object($itemKey) && method_exists($itemKey, '__toString')) { + $itemKey = (string) $itemKey; + } + + $results[$itemKey] = $itemValue; + } + } + + return $results; + } + + /** + * Explode the "value" and "key" arguments passed to "pluck". + * + * @param string|array $value + * @param string|array|null $key + * @return array + */ + protected static function explodePluckParameters($value, $key) + { + $value = is_string($value) ? explode('.', $value) : $value; + + $key = is_null($key) || is_array($key) ? $key : explode('.', $key); + + return [$value, $key]; + } + + /** + * Push an item onto the beginning of an array. + * + * @param array $array + * @param mixed $value + * @param mixed $key + * @return array + */ + public static function prepend($array, $value, $key = null) + { + if (is_null($key)) { + array_unshift($array, $value); + } else { + $array = [$key => $value] + $array; + } + + return $array; + } + + /** + * Get a value from the array, and remove it. + * + * @param array $array + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function pull(&$array, $key, $default = null) + { + $value = static::get($array, $key, $default); + + static::forget($array, $key); + + return $value; + } + + /** + * Get one or a specified number of random values from an array. + * + * @param array $array + * @param int|null $number + * @return mixed + * + * @throws \InvalidArgumentException + */ + public static function random($array, $number = null) + { + $requested = is_null($number) ? 1 : $number; + + $count = count($array); + + if ($requested > $count) { + throw new InvalidArgumentException( + "You requested {$requested} items, but there are only {$count} items available." + ); + } + + if (is_null($number)) { + return $array[array_rand($array)]; + } + + if ((int) $number === 0) { + return []; + } + + $keys = array_rand($array, $number); + + $results = []; + + foreach ((array) $keys as $key) { + $results[] = $array[$key]; + } + + return $results; + } + + /** + * Set an array item to a given value using "dot" notation. + * + * If no key is given to the method, the entire array will be replaced. + * + * @param array $array + * @param string $key + * @param mixed $value + * @return array + */ + public static function set(&$array, $key, $value) + { + if (is_null($key)) { + return $array = $value; + } + + $keys = explode('.', $key); + + while (count($keys) > 1) { + $key = array_shift($keys); + + // If the key doesn't exist at this depth, we will just create an empty array + // to hold the next value, allowing us to create the arrays to hold final + // values at the correct depth. Then we'll keep digging into the array. + if (! isset($array[$key]) || ! is_array($array[$key])) { + $array[$key] = []; + } + + $array = &$array[$key]; + } + + $array[array_shift($keys)] = $value; + + return $array; + } + + /** + * Shuffle the given array and return the result. + * + * @param array $array + * @return array + */ + public static function shuffle($array) + { + shuffle($array); + + return $array; + } + + /** + * Sort the array using the given callback or "dot" notation. + * + * @param array $array + * @param callable|string $callback + * @return array + */ + public static function sort($array, $callback) + { + return Collection::make($array)->sortBy($callback)->all(); + } + + /** + * Recursively sort an array by keys and values. + * + * @param array $array + * @return array + */ + public static function sortRecursive($array) + { + foreach ($array as &$value) { + if (is_array($value)) { + $value = static::sortRecursive($value); + } + } + + if (static::isAssoc($array)) { + ksort($array); + } else { + sort($array); + } + + return $array; + } + + /** + * Filter the array using the given callback. + * + * @param array $array + * @param callable $callback + * @return array + */ + public static function where($array, callable $callback) + { + return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); + } + + /** + * If the given value is not an array, wrap it in one. + * + * @param mixed $value + * @return array + */ + public static function wrap($value) + { + return ! is_array($value) ? [$value] : $value; + } +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Benchmark.php b/lam/lib/3rdParty/composer/illuminate/support/Benchmark.php deleted file mode 100644 index 20519e0ed..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Benchmark.php +++ /dev/null @@ -1,69 +0,0 @@ -map(function ($callback) use ($iterations) { - return collect(range(1, $iterations))->map(function () use ($callback) { - gc_collect_cycles(); - - $start = hrtime(true); - - $callback(); - - return (hrtime(true) - $start) / 1000000; - })->average(); - })->when( - $benchmarkables instanceof Closure, - fn ($c) => $c->first(), - fn ($c) => $c->all(), - ); - } - - /** - * Measure a callable once and return the duration and result. - * - * @template TReturn of mixed - * - * @param (callable(): TReturn) $callback - * @return array{0: TReturn, 1: float} - */ - public static function value(callable $callback): array - { - gc_collect_cycles(); - - $start = hrtime(true); - - $result = $callback(); - - return [$result, (hrtime(true) - $start) / 1000000]; - } - - /** - * Measure a callable or array of callables over the given number of iterations, then dump and die. - * - * @param \Closure|array $benchmarkables - * @param int $iterations - * @return never - */ - public static function dd(Closure|array $benchmarkables, int $iterations = 1): void - { - $result = collect(static::measure(Arr::wrap($benchmarkables), $iterations)) - ->map(fn ($average) => number_format($average, 3).'ms') - ->when($benchmarkables instanceof Closure, fn ($c) => $c->first(), fn ($c) => $c->all()); - - dd($result); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Carbon.php b/lam/lib/3rdParty/composer/illuminate/support/Carbon.php deleted file mode 100644 index 343918991..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Carbon.php +++ /dev/null @@ -1,61 +0,0 @@ -getDateTime()); - } - - /** - * Dump the instance and end the script. - * - * @param mixed ...$args - * @return never - */ - public function dd(...$args) - { - dd($this, ...$args); - } - - /** - * Dump the instance. - * - * @return $this - */ - public function dump() - { - dump($this); - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Collection.php b/lam/lib/3rdParty/composer/illuminate/support/Collection.php new file mode 100644 index 000000000..fa7a8505a --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Collection.php @@ -0,0 +1,1655 @@ +items = $this->getArrayableItems($items); + } + + /** + * Create a new collection instance if the value isn't one already. + * + * @param mixed $items + * @return static + */ + public static function make($items = []) + { + return new static($items); + } + + /** + * Create a new collection by invoking the callback a given number of times. + * + * @param int $number + * @param callable $callback + * @return static + */ + public static function times($number, callable $callback = null) + { + if ($number < 1) { + return new static; + } + + if (is_null($callback)) { + return new static(range(1, $number)); + } + + return (new static(range(1, $number)))->map($callback); + } + + /** + * Get all of the items in the collection. + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Get the average value of a given key. + * + * @param callable|string|null $callback + * @return mixed + */ + public function avg($callback = null) + { + if ($count = $this->count()) { + return $this->sum($callback) / $count; + } + } + + /** + * Alias for the "avg" method. + * + * @param callable|string|null $callback + * @return mixed + */ + public function average($callback = null) + { + return $this->avg($callback); + } + + /** + * Get the median of a given key. + * + * @param null $key + * @return mixed + */ + public function median($key = null) + { + $count = $this->count(); + + if ($count == 0) { + return; + } + + $values = with(isset($key) ? $this->pluck($key) : $this) + ->sort()->values(); + + $middle = (int) ($count / 2); + + if ($count % 2) { + return $values->get($middle); + } + + return (new static([ + $values->get($middle - 1), $values->get($middle), + ]))->average(); + } + + /** + * Get the mode of a given key. + * + * @param mixed $key + * @return array|null + */ + public function mode($key = null) + { + $count = $this->count(); + + if ($count == 0) { + return; + } + + $collection = isset($key) ? $this->pluck($key) : $this; + + $counts = new self; + + $collection->each(function ($value) use ($counts) { + $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1; + }); + + $sorted = $counts->sort(); + + $highestValue = $sorted->last(); + + return $sorted->filter(function ($value) use ($highestValue) { + return $value == $highestValue; + })->sort()->keys()->all(); + } + + /** + * Collapse the collection of items into a single array. + * + * @return static + */ + public function collapse() + { + return new static(Arr::collapse($this->items)); + } + + /** + * Determine if an item exists in the collection. + * + * @param mixed $key + * @param mixed $operator + * @param mixed $value + * @return bool + */ + public function contains($key, $operator = null, $value = null) + { + if (func_num_args() == 1) { + if ($this->useAsCallable($key)) { + return ! is_null($this->first($key)); + } + + return in_array($key, $this->items); + } + + if (func_num_args() == 2) { + $value = $operator; + + $operator = '='; + } + + return $this->contains($this->operatorForWhere($key, $operator, $value)); + } + + /** + * Determine if an item exists in the collection using strict comparison. + * + * @param mixed $key + * @param mixed $value + * @return bool + */ + public function containsStrict($key, $value = null) + { + if (func_num_args() == 2) { + return $this->contains(function ($item) use ($key, $value) { + return data_get($item, $key) === $value; + }); + } + + if ($this->useAsCallable($key)) { + return ! is_null($this->first($key)); + } + + return in_array($key, $this->items, true); + } + + /** + * Cross join with the given lists, returning all possible permutations. + * + * @param mixed ...$lists + * @return static + */ + public function crossJoin(...$lists) + { + return new static(Arr::crossJoin( + $this->items, ...array_map([$this, 'getArrayableItems'], $lists) + )); + } + + /** + * Get the items in the collection that are not present in the given items. + * + * @param mixed $items + * @return static + */ + public function diff($items) + { + return new static(array_diff($this->items, $this->getArrayableItems($items))); + } + + /** + * Get the items in the collection whose keys and values are not present in the given items. + * + * @param mixed $items + * @return static + */ + public function diffAssoc($items) + { + return new static(array_diff_assoc($this->items, $this->getArrayableItems($items))); + } + + /** + * Get the items in the collection whose keys are not present in the given items. + * + * @param mixed $items + * @return static + */ + public function diffKeys($items) + { + return new static(array_diff_key($this->items, $this->getArrayableItems($items))); + } + + /** + * Execute a callback over each item. + * + * @param callable $callback + * @return $this + */ + public function each(callable $callback) + { + foreach ($this->items as $key => $item) { + if ($callback($item, $key) === false) { + break; + } + } + + return $this; + } + + /** + * Execute a callback over each nested chunk of items. + * + * @param callable $callback + * @return static + */ + public function eachSpread(callable $callback) + { + return $this->each(function ($chunk) use ($callback) { + return $callback(...$chunk); + }); + } + + /** + * Determine if all items in the collection pass the given test. + * + * @param string|callable $key + * @param mixed $operator + * @param mixed $value + * @return bool + */ + public function every($key, $operator = null, $value = null) + { + if (func_num_args() == 1) { + $callback = $this->valueRetriever($key); + + foreach ($this->items as $k => $v) { + if (! $callback($v, $k)) { + return false; + } + } + + return true; + } + + if (func_num_args() == 2) { + $value = $operator; + + $operator = '='; + } + + return $this->every($this->operatorForWhere($key, $operator, $value)); + } + + /** + * Get all items except for those with the specified keys. + * + * @param mixed $keys + * @return static + */ + public function except($keys) + { + $keys = is_array($keys) ? $keys : func_get_args(); + + return new static(Arr::except($this->items, $keys)); + } + + /** + * Run a filter over each of the items. + * + * @param callable|null $callback + * @return static + */ + public function filter(callable $callback = null) + { + if ($callback) { + return new static(Arr::where($this->items, $callback)); + } + + return new static(array_filter($this->items)); + } + + /** + * Apply the callback if the value is truthy. + * + * @param bool $value + * @param callable $callback + * @param callable $default + * @return mixed + */ + public function when($value, callable $callback, callable $default = null) + { + if ($value) { + return $callback($this); + } elseif ($default) { + return $default($this); + } + + return $this; + } + + /** + * Apply the callback if the value is falsy. + * + * @param bool $value + * @param callable $callback + * @param callable $default + * @return mixed + */ + public function unless($value, callable $callback, callable $default = null) + { + return $this->when(! $value, $callback, $default); + } + + /** + * Filter items by the given key value pair. + * + * @param string $key + * @param mixed $operator + * @param mixed $value + * @return static + */ + public function where($key, $operator, $value = null) + { + if (func_num_args() == 2) { + $value = $operator; + + $operator = '='; + } + + return $this->filter($this->operatorForWhere($key, $operator, $value)); + } + + /** + * Get an operator checker callback. + * + * @param string $key + * @param string $operator + * @param mixed $value + * @return \Closure + */ + protected function operatorForWhere($key, $operator, $value) + { + return function ($item) use ($key, $operator, $value) { + $retrieved = data_get($item, $key); + + switch ($operator) { + default: + case '=': + case '==': return $retrieved == $value; + case '!=': + case '<>': return $retrieved != $value; + case '<': return $retrieved < $value; + case '>': return $retrieved > $value; + case '<=': return $retrieved <= $value; + case '>=': return $retrieved >= $value; + case '===': return $retrieved === $value; + case '!==': return $retrieved !== $value; + } + }; + } + + /** + * Filter items by the given key value pair using strict comparison. + * + * @param string $key + * @param mixed $value + * @return static + */ + public function whereStrict($key, $value) + { + return $this->where($key, '===', $value); + } + + /** + * Filter items by the given key value pair. + * + * @param string $key + * @param mixed $values + * @param bool $strict + * @return static + */ + public function whereIn($key, $values, $strict = false) + { + $values = $this->getArrayableItems($values); + + return $this->filter(function ($item) use ($key, $values, $strict) { + return in_array(data_get($item, $key), $values, $strict); + }); + } + + /** + * Filter items by the given key value pair using strict comparison. + * + * @param string $key + * @param mixed $values + * @return static + */ + public function whereInStrict($key, $values) + { + return $this->whereIn($key, $values, true); + } + + /** + * Filter items by the given key value pair. + * + * @param string $key + * @param mixed $values + * @param bool $strict + * @return static + */ + public function whereNotIn($key, $values, $strict = false) + { + $values = $this->getArrayableItems($values); + + return $this->reject(function ($item) use ($key, $values, $strict) { + return in_array(data_get($item, $key), $values, $strict); + }); + } + + /** + * Filter items by the given key value pair using strict comparison. + * + * @param string $key + * @param mixed $values + * @return static + */ + public function whereNotInStrict($key, $values) + { + return $this->whereNotIn($key, $values, true); + } + + /** + * Get the first item from the collection. + * + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public function first(callable $callback = null, $default = null) + { + return Arr::first($this->items, $callback, $default); + } + + /** + * Get a flattened array of the items in the collection. + * + * @param int $depth + * @return static + */ + public function flatten($depth = INF) + { + return new static(Arr::flatten($this->items, $depth)); + } + + /** + * Flip the items in the collection. + * + * @return static + */ + public function flip() + { + return new static(array_flip($this->items)); + } + + /** + * Remove an item from the collection by key. + * + * @param string|array $keys + * @return $this + */ + public function forget($keys) + { + foreach ((array) $keys as $key) { + $this->offsetUnset($key); + } + + return $this; + } + + /** + * Get an item from the collection by key. + * + * @param mixed $key + * @param mixed $default + * @return mixed + */ + public function get($key, $default = null) + { + if ($this->offsetExists($key)) { + return $this->items[$key]; + } + + return value($default); + } + + /** + * Group an associative array by a field or using a callback. + * + * @param callable|string $groupBy + * @param bool $preserveKeys + * @return static + */ + public function groupBy($groupBy, $preserveKeys = false) + { + $groupBy = $this->valueRetriever($groupBy); + + $results = []; + + foreach ($this->items as $key => $value) { + $groupKeys = $groupBy($value, $key); + + if (! is_array($groupKeys)) { + $groupKeys = [$groupKeys]; + } + + foreach ($groupKeys as $groupKey) { + $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey; + + if (! array_key_exists($groupKey, $results)) { + $results[$groupKey] = new static; + } + + $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); + } + } + + return new static($results); + } + + /** + * Key an associative array by a field or using a callback. + * + * @param callable|string $keyBy + * @return static + */ + public function keyBy($keyBy) + { + $keyBy = $this->valueRetriever($keyBy); + + $results = []; + + foreach ($this->items as $key => $item) { + $resolvedKey = $keyBy($item, $key); + + if (is_object($resolvedKey)) { + $resolvedKey = (string) $resolvedKey; + } + + $results[$resolvedKey] = $item; + } + + return new static($results); + } + + /** + * Determine if an item exists in the collection by key. + * + * @param mixed $key + * @return bool + */ + public function has($key) + { + return $this->offsetExists($key); + } + + /** + * Concatenate values of a given key as a string. + * + * @param string $value + * @param string $glue + * @return string + */ + public function implode($value, $glue = null) + { + $first = $this->first(); + + if (is_array($first) || is_object($first)) { + return implode($glue, $this->pluck($value)->all()); + } + + return implode($value, $this->items); + } + + /** + * Intersect the collection with the given items. + * + * @param mixed $items + * @return static + */ + public function intersect($items) + { + return new static(array_intersect($this->items, $this->getArrayableItems($items))); + } + + /** + * Intersect the collection with the given items by key. + * + * @param mixed $items + * @return static + */ + public function intersectKey($items) + { + return new static(array_intersect_key($this->items, $this->getArrayableItems($items))); + } + + /** + * Determine if the collection is empty or not. + * + * @return bool + */ + public function isEmpty() + { + return empty($this->items); + } + + /** + * Determine if the collection is not empty. + * + * @return bool + */ + public function isNotEmpty() + { + return ! $this->isEmpty(); + } + + /** + * Determine if the given value is callable, but not a string. + * + * @param mixed $value + * @return bool + */ + protected function useAsCallable($value) + { + return ! is_string($value) && is_callable($value); + } + + /** + * Get the keys of the collection items. + * + * @return static + */ + public function keys() + { + return new static(array_keys($this->items)); + } + + /** + * Get the last item from the collection. + * + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public function last(callable $callback = null, $default = null) + { + return Arr::last($this->items, $callback, $default); + } + + /** + * Get the values of a given key. + * + * @param string|array $value + * @param string|null $key + * @return static + */ + public function pluck($value, $key = null) + { + return new static(Arr::pluck($this->items, $value, $key)); + } + + /** + * Run a map over each of the items. + * + * @param callable $callback + * @return static + */ + public function map(callable $callback) + { + $keys = array_keys($this->items); + + $items = array_map($callback, $this->items, $keys); + + return new static(array_combine($keys, $items)); + } + + /** + * Run a map over each nested chunk of items. + * + * @param callable $callback + * @return static + */ + public function mapSpread(callable $callback) + { + return $this->map(function ($chunk) use ($callback) { + return $callback(...$chunk); + }); + } + + /** + * Run a grouping map over the items. + * + * The callback should return an associative array with a single key/value pair. + * + * @param callable $callback + * @return static + */ + public function mapToGroups(callable $callback) + { + $groups = $this->map($callback)->reduce(function ($groups, $pair) { + $groups[key($pair)][] = reset($pair); + + return $groups; + }, []); + + return (new static($groups))->map([$this, 'make']); + } + + /** + * Run an associative map over each of the items. + * + * The callback should return an associative array with a single key/value pair. + * + * @param callable $callback + * @return static + */ + public function mapWithKeys(callable $callback) + { + $result = []; + + foreach ($this->items as $key => $value) { + $assoc = $callback($value, $key); + + foreach ($assoc as $mapKey => $mapValue) { + $result[$mapKey] = $mapValue; + } + } + + return new static($result); + } + + /** + * Map a collection and flatten the result by a single level. + * + * @param callable $callback + * @return static + */ + public function flatMap(callable $callback) + { + return $this->map($callback)->collapse(); + } + + /** + * Get the max value of a given key. + * + * @param callable|string|null $callback + * @return mixed + */ + public function max($callback = null) + { + $callback = $this->valueRetriever($callback); + + return $this->filter(function ($value) { + return ! is_null($value); + })->reduce(function ($result, $item) use ($callback) { + $value = $callback($item); + + return is_null($result) || $value > $result ? $value : $result; + }); + } + + /** + * Merge the collection with the given items. + * + * @param mixed $items + * @return static + */ + public function merge($items) + { + return new static(array_merge($this->items, $this->getArrayableItems($items))); + } + + /** + * Create a collection by using this collection for keys and another for its values. + * + * @param mixed $values + * @return static + */ + public function combine($values) + { + return new static(array_combine($this->all(), $this->getArrayableItems($values))); + } + + /** + * Union the collection with the given items. + * + * @param mixed $items + * @return static + */ + public function union($items) + { + return new static($this->items + $this->getArrayableItems($items)); + } + + /** + * Get the min value of a given key. + * + * @param callable|string|null $callback + * @return mixed + */ + public function min($callback = null) + { + $callback = $this->valueRetriever($callback); + + return $this->filter(function ($value) { + return ! is_null($value); + })->reduce(function ($result, $item) use ($callback) { + $value = $callback($item); + + return is_null($result) || $value < $result ? $value : $result; + }); + } + + /** + * Create a new collection consisting of every n-th element. + * + * @param int $step + * @param int $offset + * @return static + */ + public function nth($step, $offset = 0) + { + $new = []; + + $position = 0; + + foreach ($this->items as $item) { + if ($position % $step === $offset) { + $new[] = $item; + } + + $position++; + } + + return new static($new); + } + + /** + * Get the items with the specified keys. + * + * @param mixed $keys + * @return static + */ + public function only($keys) + { + if (is_null($keys)) { + return new static($this->items); + } + + $keys = is_array($keys) ? $keys : func_get_args(); + + return new static(Arr::only($this->items, $keys)); + } + + /** + * "Paginate" the collection by slicing it into a smaller collection. + * + * @param int $page + * @param int $perPage + * @return static + */ + public function forPage($page, $perPage) + { + return $this->slice(($page - 1) * $perPage, $perPage); + } + + /** + * Partition the collection into two arrays using the given callback or key. + * + * @param callable|string $callback + * @return static + */ + public function partition($callback) + { + $partitions = [new static, new static]; + + $callback = $this->valueRetriever($callback); + + foreach ($this->items as $key => $item) { + $partitions[(int) ! $callback($item)][$key] = $item; + } + + return new static($partitions); + } + + /** + * Pass the collection to the given callback and return the result. + * + * @param callable $callback + * @return mixed + */ + public function pipe(callable $callback) + { + return $callback($this); + } + + /** + * Get and remove the last item from the collection. + * + * @return mixed + */ + public function pop() + { + return array_pop($this->items); + } + + /** + * Push an item onto the beginning of the collection. + * + * @param mixed $value + * @param mixed $key + * @return $this + */ + public function prepend($value, $key = null) + { + $this->items = Arr::prepend($this->items, $value, $key); + + return $this; + } + + /** + * Push an item onto the end of the collection. + * + * @param mixed $value + * @return $this + */ + public function push($value) + { + $this->offsetSet(null, $value); + + return $this; + } + + /** + * Push all of the given items onto the collection. + * + * @param \Traversable $source + * @return self + */ + public function concat($source) + { + $result = new static($this); + + foreach ($source as $item) { + $result->push($item); + } + + return $result; + } + + /** + * Get and remove an item from the collection. + * + * @param mixed $key + * @param mixed $default + * @return mixed + */ + public function pull($key, $default = null) + { + return Arr::pull($this->items, $key, $default); + } + + /** + * Put an item in the collection by key. + * + * @param mixed $key + * @param mixed $value + * @return $this + */ + public function put($key, $value) + { + $this->offsetSet($key, $value); + + return $this; + } + + /** + * Get one or a specified number of items randomly from the collection. + * + * @param int|null $number + * @return mixed + * + * @throws \InvalidArgumentException + */ + public function random($number = null) + { + if (is_null($number)) { + return Arr::random($this->items); + } + + return new static(Arr::random($this->items, $number)); + } + + /** + * Reduce the collection to a single value. + * + * @param callable $callback + * @param mixed $initial + * @return mixed + */ + public function reduce(callable $callback, $initial = null) + { + return array_reduce($this->items, $callback, $initial); + } + + /** + * Create a collection of all elements that do not pass a given truth test. + * + * @param callable|mixed $callback + * @return static + */ + public function reject($callback) + { + if ($this->useAsCallable($callback)) { + return $this->filter(function ($value, $key) use ($callback) { + return ! $callback($value, $key); + }); + } + + return $this->filter(function ($item) use ($callback) { + return $item != $callback; + }); + } + + /** + * Reverse items order. + * + * @return static + */ + public function reverse() + { + return new static(array_reverse($this->items, true)); + } + + /** + * Search the collection for a given value and return the corresponding key if successful. + * + * @param mixed $value + * @param bool $strict + * @return mixed + */ + public function search($value, $strict = false) + { + if (! $this->useAsCallable($value)) { + return array_search($value, $this->items, $strict); + } + + foreach ($this->items as $key => $item) { + if (call_user_func($value, $item, $key)) { + return $key; + } + } + + return false; + } + + /** + * Get and remove the first item from the collection. + * + * @return mixed + */ + public function shift() + { + return array_shift($this->items); + } + + /** + * Shuffle the items in the collection. + * + * @param int $seed + * @return static + */ + public function shuffle($seed = null) + { + $items = $this->items; + + if (is_null($seed)) { + shuffle($items); + } else { + srand($seed); + + usort($items, function () { + return rand(-1, 1); + }); + } + + return new static($items); + } + + /** + * Slice the underlying collection array. + * + * @param int $offset + * @param int $length + * @return static + */ + public function slice($offset, $length = null) + { + return new static(array_slice($this->items, $offset, $length, true)); + } + + /** + * Split a collection into a certain number of groups. + * + * @param int $numberOfGroups + * @return static + */ + public function split($numberOfGroups) + { + if ($this->isEmpty()) { + return new static; + } + + $groupSize = ceil($this->count() / $numberOfGroups); + + return $this->chunk($groupSize); + } + + /** + * Chunk the underlying collection array. + * + * @param int $size + * @return static + */ + public function chunk($size) + { + if ($size <= 0) { + return new static; + } + + $chunks = []; + + foreach (array_chunk($this->items, $size, true) as $chunk) { + $chunks[] = new static($chunk); + } + + return new static($chunks); + } + + /** + * Sort through each item with a callback. + * + * @param callable|null $callback + * @return static + */ + public function sort(callable $callback = null) + { + $items = $this->items; + + $callback + ? uasort($items, $callback) + : asort($items); + + return new static($items); + } + + /** + * Sort the collection using the given callback. + * + * @param callable|string $callback + * @param int $options + * @param bool $descending + * @return static + */ + public function sortBy($callback, $options = SORT_REGULAR, $descending = false) + { + $results = []; + + $callback = $this->valueRetriever($callback); + + // First we will loop through the items and get the comparator from a callback + // function which we were given. Then, we will sort the returned values and + // and grab the corresponding values for the sorted keys from this array. + foreach ($this->items as $key => $value) { + $results[$key] = $callback($value, $key); + } + + $descending ? arsort($results, $options) + : asort($results, $options); + + // Once we have sorted all of the keys in the array, we will loop through them + // and grab the corresponding model so we can set the underlying items list + // to the sorted version. Then we'll just return the collection instance. + foreach (array_keys($results) as $key) { + $results[$key] = $this->items[$key]; + } + + return new static($results); + } + + /** + * Sort the collection in descending order using the given callback. + * + * @param callable|string $callback + * @param int $options + * @return static + */ + public function sortByDesc($callback, $options = SORT_REGULAR) + { + return $this->sortBy($callback, $options, true); + } + + /** + * Splice a portion of the underlying collection array. + * + * @param int $offset + * @param int|null $length + * @param mixed $replacement + * @return static + */ + public function splice($offset, $length = null, $replacement = []) + { + if (func_num_args() == 1) { + return new static(array_splice($this->items, $offset)); + } + + return new static(array_splice($this->items, $offset, $length, $replacement)); + } + + /** + * Get the sum of the given values. + * + * @param callable|string|null $callback + * @return mixed + */ + public function sum($callback = null) + { + if (is_null($callback)) { + return array_sum($this->items); + } + + $callback = $this->valueRetriever($callback); + + return $this->reduce(function ($result, $item) use ($callback) { + return $result + $callback($item); + }, 0); + } + + /** + * Take the first or last {$limit} items. + * + * @param int $limit + * @return static + */ + public function take($limit) + { + if ($limit < 0) { + return $this->slice($limit, abs($limit)); + } + + return $this->slice(0, $limit); + } + + /** + * Pass the collection to the given callback and then return it. + * + * @param callable $callback + * @return $this + */ + public function tap(callable $callback) + { + $callback(new static($this->items)); + + return $this; + } + + /** + * Transform each item in the collection using a callback. + * + * @param callable $callback + * @return $this + */ + public function transform(callable $callback) + { + $this->items = $this->map($callback)->all(); + + return $this; + } + + /** + * Return only unique items from the collection array. + * + * @param string|callable|null $key + * @param bool $strict + * @return static + */ + public function unique($key = null, $strict = false) + { + if (is_null($key)) { + return new static(array_unique($this->items, SORT_REGULAR)); + } + + $callback = $this->valueRetriever($key); + + $exists = []; + + return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { + if (in_array($id = $callback($item, $key), $exists, $strict)) { + return true; + } + + $exists[] = $id; + }); + } + + /** + * Return only unique items from the collection array using strict comparison. + * + * @param string|callable|null $key + * @return static + */ + public function uniqueStrict($key = null) + { + return $this->unique($key, true); + } + + /** + * Reset the keys on the underlying array. + * + * @return static + */ + public function values() + { + return new static(array_values($this->items)); + } + + /** + * Get a value retrieving callback. + * + * @param string $value + * @return callable + */ + protected function valueRetriever($value) + { + if ($this->useAsCallable($value)) { + return $value; + } + + return function ($item) use ($value) { + return data_get($item, $value); + }; + } + + /** + * Zip the collection together with one or more arrays. + * + * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); + * => [[1, 4], [2, 5], [3, 6]] + * + * @param mixed ...$items + * @return static + */ + public function zip($items) + { + $arrayableItems = array_map(function ($items) { + return $this->getArrayableItems($items); + }, func_get_args()); + + $params = array_merge([function () { + return new static(func_get_args()); + }, $this->items], $arrayableItems); + + return new static(call_user_func_array('array_map', $params)); + } + + /** + * Get the collection of items as a plain array. + * + * @return array + */ + public function toArray() + { + return array_map(function ($value) { + return $value instanceof Arrayable ? $value->toArray() : $value; + }, $this->items); + } + + /** + * Convert the object into something JSON serializable. + * + * @return array + */ + public function jsonSerialize() + { + return array_map(function ($value) { + if ($value instanceof JsonSerializable) { + return $value->jsonSerialize(); + } elseif ($value instanceof Jsonable) { + return json_decode($value->toJson(), true); + } elseif ($value instanceof Arrayable) { + return $value->toArray(); + } else { + return $value; + } + }, $this->items); + } + + /** + * Get the collection of items as JSON. + * + * @param int $options + * @return string + */ + public function toJson($options = 0) + { + return json_encode($this->jsonSerialize(), $options); + } + + /** + * Get an iterator for the items. + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /** + * Get a CachingIterator instance. + * + * @param int $flags + * @return \CachingIterator + */ + public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) + { + return new CachingIterator($this->getIterator(), $flags); + } + + /** + * Count the number of items in the collection. + * + * @return int + */ + public function count() + { + return count($this->items); + } + + /** + * Get a base Support collection instance from this collection. + * + * @return \Illuminate\Support\Collection + */ + public function toBase() + { + return new self($this); + } + + /** + * Determine if an item exists at an offset. + * + * @param mixed $key + * @return bool + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->items); + } + + /** + * Get an item at a given offset. + * + * @param mixed $key + * @return mixed + */ + public function offsetGet($key) + { + return $this->items[$key]; + } + + /** + * Set the item at a given offset. + * + * @param mixed $key + * @param mixed $value + * @return void + */ + public function offsetSet($key, $value) + { + if (is_null($key)) { + $this->items[] = $value; + } else { + $this->items[$key] = $value; + } + } + + /** + * Unset the item at a given offset. + * + * @param string $key + * @return void + */ + public function offsetUnset($key) + { + unset($this->items[$key]); + } + + /** + * Convert the collection to its string representation. + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } + + /** + * Results array of items from Collection or Arrayable. + * + * @param mixed $items + * @return array + */ + protected function getArrayableItems($items) + { + if (is_array($items)) { + return $items; + } elseif ($items instanceof self) { + return $items->all(); + } elseif ($items instanceof Arrayable) { + return $items->toArray(); + } elseif ($items instanceof Jsonable) { + return json_decode($items->toJson(), true); + } elseif ($items instanceof JsonSerializable) { + return $items->jsonSerialize(); + } elseif ($items instanceof Traversable) { + return iterator_to_array($items); + } + + return (array) $items; + } + + /** + * Add a method to the list of proxied methods. + * + * @param string $method + * @return void + */ + public static function proxy($method) + { + static::$proxies[] = $method; + } + + /** + * Dynamically access collection proxies. + * + * @param string $key + * @return mixed + * + * @throws \Exception + */ + public function __get($key) + { + if (! in_array($key, static::$proxies)) { + throw new Exception("Property [{$key}] does not exist on this collection instance."); + } + + return new HigherOrderCollectionProxy($this, $key); + } +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Composer.php b/lam/lib/3rdParty/composer/illuminate/support/Composer.php index ad976c0d8..b0eaa9236 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Composer.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Composer.php @@ -2,12 +2,10 @@ namespace Illuminate\Support; -use Closure; use Illuminate\Filesystem\Filesystem; -use RuntimeException; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessUtils; +use Symfony\Component\Process\PhpExecutableFinder; class Composer { @@ -21,7 +19,7 @@ class Composer /** * The working path to regenerate from. * - * @var string|null + * @var string */ protected $workingPath; @@ -38,185 +36,53 @@ class Composer $this->workingPath = $workingPath; } - /** - * Determine if the given Composer package is installed. - * - * @param string $package - * @return bool - * - * @throw \RuntimeException - */ - protected function hasPackage($package) - { - $composer = json_decode(file_get_contents($this->findComposerFile()), true); - - return array_key_exists($package, $composer['require'] ?? []) - || array_key_exists($package, $composer['require-dev'] ?? []); - } - - /** - * Install the given Composer packages into the application. - * - * @param array $packages - * @param bool $dev - * @param \Closure|\Symfony\Component\Console\Output\OutputInterface|null $output - * @param string|null $composerBinary - * @return bool - */ - public function requirePackages(array $packages, bool $dev = false, Closure|OutputInterface|null $output = null, $composerBinary = null) - { - $command = collect([ - ...$this->findComposer($composerBinary), - 'require', - ...$packages, - ]) - ->when($dev, function ($command) { - $command->push('--dev'); - })->all(); - - return 0 === $this->getProcess($command, ['COMPOSER_MEMORY_LIMIT' => '-1']) - ->run( - $output instanceof OutputInterface - ? function ($type, $line) use ($output) { - $output->write(' '.$line); - } : $output - ); - } - - /** - * Remove the given Composer packages from the application. - * - * @param array $packages - * @param bool $dev - * @param \Closure|\Symfony\Component\Console\Output\OutputInterface|null $output - * @param string|null $composerBinary - * @return bool - */ - public function removePackages(array $packages, bool $dev = false, Closure|OutputInterface|null $output = null, $composerBinary = null) - { - $command = collect([ - ...$this->findComposer($composerBinary), - 'remove', - ...$packages, - ]) - ->when($dev, function ($command) { - $command->push('--dev'); - })->all(); - - return 0 === $this->getProcess($command, ['COMPOSER_MEMORY_LIMIT' => '-1']) - ->run( - $output instanceof OutputInterface - ? function ($type, $line) use ($output) { - $output->write(' '.$line); - } : $output - ); - } - - /** - * Modify the "composer.json" file contents using the given callback. - * - * @param callable(array):array $callback - * @return void - * - * @throw \RuntimeException - */ - public function modify(callable $callback) - { - $composerFile = $this->findComposerFile(); - - $composer = json_decode(file_get_contents($composerFile), true, 512, JSON_THROW_ON_ERROR); - - file_put_contents( - $composerFile, - json_encode( - call_user_func($callback, $composer), - JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE - ) - ); - } - /** * Regenerate the Composer autoloader files. * - * @param string|array $extra - * @param string|null $composerBinary - * @return int + * @param string $extra + * @return void */ - public function dumpAutoloads($extra = '', $composerBinary = null) + public function dumpAutoloads($extra = '') { - $extra = $extra ? (array) $extra : []; + $process = $this->getProcess(); - $command = array_merge($this->findComposer($composerBinary), ['dump-autoload'], $extra); + $process->setCommandLine(trim($this->findComposer().' dump-autoload '.$extra)); - return $this->getProcess($command)->run(); + $process->run(); } /** * Regenerate the optimized Composer autoloader files. * - * @param string|null $composerBinary - * @return int + * @return void */ - public function dumpOptimized($composerBinary = null) + public function dumpOptimized() { - return $this->dumpAutoloads('--optimize', $composerBinary); + $this->dumpAutoloads('--optimize'); } /** - * Get the Composer binary / command for the environment. - * - * @param string|null $composerBinary - * @return array - */ - public function findComposer($composerBinary = null) - { - if (! is_null($composerBinary) && $this->files->exists($composerBinary)) { - return [$this->phpBinary(), $composerBinary]; - } elseif ($this->files->exists($this->workingPath.'/composer.phar')) { - return [$this->phpBinary(), 'composer.phar']; - } - - return ['composer']; - } - - /** - * Get the path to the "composer.json" file. - * - * @return string - * - * @throw \RuntimeException - */ - protected function findComposerFile() - { - $composerFile = "{$this->workingPath}/composer.json"; - - if (! file_exists($composerFile)) { - throw new RuntimeException("Unable to locate `composer.json` file at [{$this->workingPath}]."); - } - - return $composerFile; - } - - /** - * Get the PHP binary. + * Get the composer command for the environment. * * @return string */ - protected function phpBinary() + protected function findComposer() { - return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)); + if ($this->files->exists($this->workingPath.'/composer.phar')) { + return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false)).' composer.phar'; + } + + return 'composer'; } /** * Get a new Symfony process instance. * - * @param array $command - * @param array $env * @return \Symfony\Component\Process\Process */ - protected function getProcess(array $command, array $env = []) + protected function getProcess() { - return (new Process($command, $this->workingPath, $env))->setTimeout(null); + return (new Process('', $this->workingPath))->setTimeout(null); } /** @@ -231,26 +97,4 @@ class Composer return $this; } - - /** - * Get the version of Composer. - * - * @return string|null - */ - public function getVersion() - { - $command = array_merge($this->findComposer(), ['-V', '--no-ansi']); - - $process = $this->getProcess($command); - - $process->run(); - - $output = $process->getOutput(); - - if (preg_match('/(\d+(\.\d+){2})/', $output, $version)) { - return $version[1]; - } - - return explode(' ', $output)[2] ?? null; - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/ConfigurationUrlParser.php b/lam/lib/3rdParty/composer/illuminate/support/ConfigurationUrlParser.php deleted file mode 100644 index a1b933709..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/ConfigurationUrlParser.php +++ /dev/null @@ -1,191 +0,0 @@ - 'sqlsrv', - 'mysql2' => 'mysql', // RDS - 'postgres' => 'pgsql', - 'postgresql' => 'pgsql', - 'sqlite3' => 'sqlite', - 'redis' => 'tcp', - 'rediss' => 'tls', - ]; - - /** - * Parse the database configuration, hydrating options using a database configuration URL if possible. - * - * @param array|string $config - * @return array - */ - public function parseConfiguration($config) - { - if (is_string($config)) { - $config = ['url' => $config]; - } - - $url = Arr::pull($config, 'url'); - - if (! $url) { - return $config; - } - - $rawComponents = $this->parseUrl($url); - - $decodedComponents = $this->parseStringsToNativeTypes( - array_map('rawurldecode', $rawComponents) - ); - - return array_merge( - $config, - $this->getPrimaryOptions($decodedComponents), - $this->getQueryOptions($rawComponents) - ); - } - - /** - * Get the primary database connection options. - * - * @param array $url - * @return array - */ - protected function getPrimaryOptions($url) - { - return array_filter([ - 'driver' => $this->getDriver($url), - 'database' => $this->getDatabase($url), - 'host' => $url['host'] ?? null, - 'port' => $url['port'] ?? null, - 'username' => $url['user'] ?? null, - 'password' => $url['pass'] ?? null, - ], fn ($value) => ! is_null($value)); - } - - /** - * Get the database driver from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDriver($url) - { - $alias = $url['scheme'] ?? null; - - if (! $alias) { - return; - } - - return static::$driverAliases[$alias] ?? $alias; - } - - /** - * Get the database name from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDatabase($url) - { - $path = $url['path'] ?? null; - - return $path && $path !== '/' ? substr($path, 1) : null; - } - - /** - * Get all of the additional database options from the query string. - * - * @param array $url - * @return array - */ - protected function getQueryOptions($url) - { - $queryString = $url['query'] ?? null; - - if (! $queryString) { - return []; - } - - $query = []; - - parse_str($queryString, $query); - - return $this->parseStringsToNativeTypes($query); - } - - /** - * Parse the string URL to an array of components. - * - * @param string $url - * @return array - * - * @throws \InvalidArgumentException - */ - protected function parseUrl($url) - { - $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url); - - $parsedUrl = parse_url($url); - - if ($parsedUrl === false) { - throw new InvalidArgumentException('The database configuration URL is malformed.'); - } - - return $parsedUrl; - } - - /** - * Convert string casted values to their native types. - * - * @param mixed $value - * @return mixed - */ - protected function parseStringsToNativeTypes($value) - { - if (is_array($value)) { - return array_map([$this, 'parseStringsToNativeTypes'], $value); - } - - if (! is_string($value)) { - return $value; - } - - $parsedValue = json_decode($value, true); - - if (json_last_error() === JSON_ERROR_NONE) { - return $parsedValue; - } - - return $value; - } - - /** - * Get all of the current drivers' aliases. - * - * @return array - */ - public static function getDriverAliases() - { - return static::$driverAliases; - } - - /** - * Add the given driver alias to the driver aliases array. - * - * @param string $alias - * @param string $driver - * @return void - */ - public static function addDriverAlias($alias, $driver) - { - static::$driverAliases[$alias] = $driver; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/DateFactory.php b/lam/lib/3rdParty/composer/illuminate/support/DateFactory.php deleted file mode 100644 index 3d0cd04df..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/DateFactory.php +++ /dev/null @@ -1,231 +0,0 @@ -$method(...$parameters); - } - - $dateClass = static::$dateClass ?: $defaultClassName; - - // Check if the date can be created using the public class method... - if (method_exists($dateClass, $method) || - method_exists($dateClass, 'hasMacro') && $dateClass::hasMacro($method)) { - return $dateClass::$method(...$parameters); - } - - // If that fails, create the date with the default class... - $date = $defaultClassName::$method(...$parameters); - - // If the configured class has an "instance" method, we'll try to pass our date into there... - if (method_exists($dateClass, 'instance')) { - return $dateClass::instance($date); - } - - // Otherwise, assume the configured class has a DateTime compatible constructor... - return new $dateClass($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Debug/Dumper.php b/lam/lib/3rdParty/composer/illuminate/support/Debug/Dumper.php new file mode 100644 index 000000000..0c84a8b19 --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Debug/Dumper.php @@ -0,0 +1,26 @@ +dump((new VarCloner)->cloneVar($value)); + } else { + var_dump($value); + } + } +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Debug/HtmlDumper.php b/lam/lib/3rdParty/composer/illuminate/support/Debug/HtmlDumper.php new file mode 100644 index 000000000..5825ac8db --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Debug/HtmlDumper.php @@ -0,0 +1,29 @@ + 'background-color:#fff; color:#222; line-height:1.2em; font-weight:normal; font:12px Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:100000', + 'num' => 'color:#a71d5d', + 'const' => 'color:#795da3', + 'str' => 'color:#df5000', + 'cchr' => 'color:#222', + 'note' => 'color:#a71d5d', + 'ref' => 'color:#a0a0a0', + 'public' => 'color:#795da3', + 'protected' => 'color:#795da3', + 'private' => 'color:#795da3', + 'meta' => 'color:#b729d9', + 'key' => 'color:#df5000', + 'index' => 'color:#a71d5d', + ]; +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/DefaultProviders.php b/lam/lib/3rdParty/composer/illuminate/support/DefaultProviders.php deleted file mode 100644 index 395b7cb9e..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/DefaultProviders.php +++ /dev/null @@ -1,102 +0,0 @@ -providers = $providers ?: [ - \Illuminate\Auth\AuthServiceProvider::class, - \Illuminate\Broadcasting\BroadcastServiceProvider::class, - \Illuminate\Bus\BusServiceProvider::class, - \Illuminate\Cache\CacheServiceProvider::class, - \Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, - \Illuminate\Cookie\CookieServiceProvider::class, - \Illuminate\Database\DatabaseServiceProvider::class, - \Illuminate\Encryption\EncryptionServiceProvider::class, - \Illuminate\Filesystem\FilesystemServiceProvider::class, - \Illuminate\Foundation\Providers\FoundationServiceProvider::class, - \Illuminate\Hashing\HashServiceProvider::class, - \Illuminate\Mail\MailServiceProvider::class, - \Illuminate\Notifications\NotificationServiceProvider::class, - \Illuminate\Pagination\PaginationServiceProvider::class, - \Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, - \Illuminate\Pipeline\PipelineServiceProvider::class, - \Illuminate\Queue\QueueServiceProvider::class, - \Illuminate\Redis\RedisServiceProvider::class, - \Illuminate\Session\SessionServiceProvider::class, - \Illuminate\Translation\TranslationServiceProvider::class, - \Illuminate\Validation\ValidationServiceProvider::class, - \Illuminate\View\ViewServiceProvider::class, - ]; - } - - /** - * Merge the given providers into the provider collection. - * - * @param array $providers - * @return static - */ - public function merge(array $providers) - { - $this->providers = array_merge($this->providers, $providers); - - return new static($this->providers); - } - - /** - * Replace the given providers with other providers. - * - * @param array $items - * @return static - */ - public function replace(array $replacements) - { - $current = collect($this->providers); - - foreach ($replacements as $from => $to) { - $key = $current->search($from); - - $current = is_int($key) ? $current->replace([$key => $to]) : $current; - } - - return new static($current->values()->toArray()); - } - - /** - * Disable the given providers. - * - * @param array $providers - * @return static - */ - public function except(array $providers) - { - return new static(collect($this->providers) - ->reject(fn ($p) => in_array($p, $providers)) - ->values() - ->toArray()); - } - - /** - * Convert the provider collection to an array. - * - * @return array - */ - public function toArray() - { - return $this->providers; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Env.php b/lam/lib/3rdParty/composer/illuminate/support/Env.php deleted file mode 100644 index 51ea918e0..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Env.php +++ /dev/null @@ -1,125 +0,0 @@ -addAdapter(PutenvAdapter::class); - } - - static::$repository = $builder->immutable()->make(); - } - - return static::$repository; - } - - /** - * Get the value of an environment variable. - * - * @param string $key - * @param mixed $default - * @return mixed - */ - public static function get($key, $default = null) - { - return self::getOption($key)->getOrCall(fn () => value($default)); - } - - /** - * Get the value of a required environment variable. - * - * @param string $key - * @return mixed - * - * @throws \RuntimeException - */ - public static function getOrFail($key) - { - return self::getOption($key)->getOrThrow(new RuntimeException("Environment variable [$key] has no value.")); - } - - /** - * Get the possible option for this environment variable. - * - * @param string $key - * @return \PhpOption\Option|\PhpOption\Some - */ - protected static function getOption($key) - { - return Option::fromValue(static::getRepository()->get($key)) - ->map(function ($value) { - switch (strtolower($value)) { - case 'true': - case '(true)': - return true; - case 'false': - case '(false)': - return false; - case 'empty': - case '(empty)': - return ''; - case 'null': - case '(null)': - return; - } - - if (preg_match('/\A([\'"])(.*)\1\z/', $value, $matches)) { - return $matches[2]; - } - - return $value; - }); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Exceptions/MathException.php b/lam/lib/3rdParty/composer/illuminate/support/Exceptions/MathException.php deleted file mode 100644 index 6f9158df0..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Exceptions/MathException.php +++ /dev/null @@ -1,10 +0,0 @@ -providerIsLoaded(UiServiceProvider::class)) { - throw new RuntimeException('In order to use the Auth::routes() method, please install the laravel/ui package.'); - } - - static::$app->make('router')->auth($options); + static::$app->make('router')->auth(); } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Blade.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Blade.php index 3d32cf862..b016a46c2 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Blade.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Blade.php @@ -3,48 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static void compile(string|null $path = null) - * @method static string getPath() - * @method static void setPath(string $path) - * @method static string compileString(string $value) - * @method static string render(string $string, array $data = [], bool $deleteCachedView = false) - * @method static string renderComponent(\Illuminate\View\Component $component) - * @method static string stripParentheses(string $expression) - * @method static void extend(callable $compiler) - * @method static array getExtensions() - * @method static void if(string $name, callable $callback) - * @method static bool check(string $name, mixed ...$parameters) - * @method static void component(string $class, string|null $alias = null, string $prefix = '') - * @method static void components(array $components, string $prefix = '') - * @method static array getClassComponentAliases() - * @method static void anonymousComponentPath(string $path, string|null $prefix = null) - * @method static void anonymousComponentNamespace(string $directory, string|null $prefix = null) - * @method static void componentNamespace(string $namespace, string $prefix) - * @method static array getAnonymousComponentPaths() - * @method static array getAnonymousComponentNamespaces() - * @method static array getClassComponentNamespaces() - * @method static void aliasComponent(string $path, string|null $alias = null) - * @method static void include(string $path, string|null $alias = null) - * @method static void aliasInclude(string $path, string|null $alias = null) - * @method static void directive(string $name, callable $handler) - * @method static array getCustomDirectives() - * @method static \Illuminate\View\Compilers\BladeCompiler prepareStringsForCompilationUsing(callable $callback) - * @method static void precompiler(callable $precompiler) - * @method static void setEchoFormat(string $format) - * @method static void withDoubleEncoding() - * @method static void withoutDoubleEncoding() - * @method static void withoutComponentTags() - * @method static string getCompiledPath(string $path) - * @method static bool isExpired(string $path) - * @method static string newComponentHash(string $component) - * @method static string compileClassComponentOpening(string $component, string $alias, string $data, string $hash) - * @method static string compileEndComponentClass() - * @method static mixed sanitizeComponentAttribute(mixed $value) - * @method static string compileEndOnce() - * @method static void stringable(string|callable $class, callable|null $handler = null) - * @method static string compileEchos(string $value) - * @method static string applyEchoHandler(string $value) - * * @see \Illuminate\View\Compilers\BladeCompiler */ class Blade extends Facade @@ -56,6 +14,6 @@ class Blade extends Facade */ protected static function getFacadeAccessor() { - return 'blade.compiler'; + return static::$app['view']->getEngineResolver()->resolve('blade')->getCompiler(); } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Broadcast.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Broadcast.php index 7078e2cba..81af93217 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Broadcast.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Broadcast.php @@ -5,33 +5,7 @@ namespace Illuminate\Support\Facades; use Illuminate\Contracts\Broadcasting\Factory as BroadcastingFactoryContract; /** - * @method static void routes(array|null $attributes = null) - * @method static void userRoutes(array|null $attributes = null) - * @method static void channelRoutes(array|null $attributes = null) - * @method static string|null socket(\Illuminate\Http\Request|null $request = null) - * @method static \Illuminate\Broadcasting\PendingBroadcast event(mixed|null $event = null) - * @method static void queue(mixed $event) - * @method static mixed connection(string|null $driver = null) - * @method static mixed driver(string|null $name = null) - * @method static \Pusher\Pusher pusher(array $config) - * @method static \Ably\AblyRest ably(array $config) - * @method static string getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static void purge(string|null $name = null) - * @method static \Illuminate\Broadcasting\BroadcastManager extend(string $driver, \Closure $callback) - * @method static \Illuminate\Contracts\Foundation\Application getApplication() - * @method static \Illuminate\Broadcasting\BroadcastManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static \Illuminate\Broadcasting\BroadcastManager forgetDrivers() - * @method static mixed auth(\Illuminate\Http\Request $request) - * @method static mixed validAuthenticationResponse(\Illuminate\Http\Request $request, mixed $result) - * @method static void broadcast(array $channels, string $event, array $payload = []) - * @method static array|null resolveAuthenticatedUser(\Illuminate\Http\Request $request) - * @method static void resolveAuthenticatedUserUsing(\Closure $callback) - * @method static \Illuminate\Broadcasting\Broadcasters\Broadcaster channel(\Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $channel, callable|string $callback, array $options = []) - * @method static \Illuminate\Support\Collection getChannels() - * - * @see \Illuminate\Broadcasting\BroadcastManager - * @see \Illuminate\Broadcasting\Broadcasters\Broadcaster + * @see \Illuminate\Contracts\Broadcasting\Factory */ class Broadcast extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Bus.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Bus.php index 6c22e027e..eeebac4f5 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Bus.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Bus.php @@ -2,87 +2,22 @@ namespace Illuminate\Support\Facades; -use Illuminate\Bus\BatchRepository; -use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract; -use Illuminate\Foundation\Bus\PendingChain; use Illuminate\Support\Testing\Fakes\BusFake; +use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract; /** - * @method static mixed dispatch(mixed $command) - * @method static mixed dispatchSync(mixed $command, mixed $handler = null) - * @method static mixed dispatchNow(mixed $command, mixed $handler = null) - * @method static \Illuminate\Bus\Batch|null findBatch(string $batchId) - * @method static \Illuminate\Bus\PendingBatch batch(\Illuminate\Support\Collection|array|mixed $jobs) - * @method static \Illuminate\Foundation\Bus\PendingChain chain(\Illuminate\Support\Collection|array $jobs) - * @method static bool hasCommandHandler(mixed $command) - * @method static bool|mixed getCommandHandler(mixed $command) - * @method static mixed dispatchToQueue(mixed $command) - * @method static void dispatchAfterResponse(mixed $command, mixed $handler = null) - * @method static \Illuminate\Bus\Dispatcher pipeThrough(array $pipes) - * @method static \Illuminate\Bus\Dispatcher map(array $map) - * @method static \Illuminate\Support\Testing\Fakes\BusFake except(array|string $jobsToDispatch) - * @method static void assertDispatched(string|\Closure $command, callable|int|null $callback = null) - * @method static void assertDispatchedTimes(string|\Closure $command, int $times = 1) - * @method static void assertNotDispatched(string|\Closure $command, callable|null $callback = null) - * @method static void assertNothingDispatched() - * @method static void assertDispatchedSync(string|\Closure $command, callable|int|null $callback = null) - * @method static void assertDispatchedSyncTimes(string|\Closure $command, int $times = 1) - * @method static void assertNotDispatchedSync(string|\Closure $command, callable|null $callback = null) - * @method static void assertDispatchedAfterResponse(string|\Closure $command, callable|int|null $callback = null) - * @method static void assertDispatchedAfterResponseTimes(string|\Closure $command, int $times = 1) - * @method static void assertNotDispatchedAfterResponse(string|\Closure $command, callable|null $callback = null) - * @method static void assertChained(array $expectedChain) - * @method static void assertDispatchedWithoutChain(string|\Closure $command, callable|null $callback = null) - * @method static \Illuminate\Support\Testing\Fakes\ChainedBatchTruthTest chainedBatch(\Closure $callback) - * @method static void assertBatched(callable $callback) - * @method static void assertBatchCount(int $count) - * @method static void assertNothingBatched() - * @method static \Illuminate\Support\Collection dispatched(string $command, callable|null $callback = null) - * @method static \Illuminate\Support\Collection dispatchedSync(string $command, callable|null $callback = null) - * @method static \Illuminate\Support\Collection dispatchedAfterResponse(string $command, callable|null $callback = null) - * @method static \Illuminate\Support\Collection batched(callable $callback) - * @method static bool hasDispatched(string $command) - * @method static bool hasDispatchedSync(string $command) - * @method static bool hasDispatchedAfterResponse(string $command) - * @method static \Illuminate\Bus\Batch dispatchFakeBatch(string $name = '') - * @method static \Illuminate\Bus\Batch recordPendingBatch(\Illuminate\Bus\PendingBatch $pendingBatch) - * @method static \Illuminate\Support\Testing\Fakes\BusFake serializeAndRestore(bool $serializeAndRestore = true) - * - * @see \Illuminate\Bus\Dispatcher - * @see \Illuminate\Support\Testing\Fakes\BusFake + * @see \Illuminate\Contracts\Bus\Dispatcher */ class Bus extends Facade { /** * Replace the bound instance with a fake. * - * @param array|string $jobsToFake - * @param \Illuminate\Bus\BatchRepository|null $batchRepository - * @return \Illuminate\Support\Testing\Fakes\BusFake + * @return void */ - public static function fake($jobsToFake = [], ?BatchRepository $batchRepository = null) + public static function fake() { - $actualDispatcher = static::isFake() - ? static::getFacadeRoot()->dispatcher - : static::getFacadeRoot(); - - return tap(new BusFake($actualDispatcher, $jobsToFake, $batchRepository), function ($fake) { - static::swap($fake); - }); - } - - /** - * Dispatch the given chain of jobs. - * - * @param array|mixed $jobs - * @return \Illuminate\Foundation\Bus\PendingDispatch - */ - public static function dispatchChain($jobs) - { - $jobs = is_array($jobs) ? $jobs : func_get_args(); - - return (new PendingChain(array_shift($jobs), $jobs)) - ->dispatch(); + static::swap(new BusFake); } /** diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Cache.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Cache.php index 054b0e24c..2e32301fa 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Cache.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Cache.php @@ -3,59 +3,8 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) - * @method static \Illuminate\Contracts\Cache\Repository driver(string|null $driver = null) - * @method static \Illuminate\Contracts\Cache\Repository resolve(string $name) - * @method static \Illuminate\Cache\Repository repository(\Illuminate\Contracts\Cache\Store $store) - * @method static void refreshEventDispatcher() - * @method static string getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static \Illuminate\Cache\CacheManager forgetDriver(array|string|null $name = null) - * @method static void purge(string|null $name = null) - * @method static \Illuminate\Cache\CacheManager extend(string $driver, \Closure $callback) - * @method static \Illuminate\Cache\CacheManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static bool has(array|string $key) - * @method static bool missing(string $key) - * @method static mixed get(array|string $key, mixed|\Closure $default = null) - * @method static array many(array $keys) - * @method static iterable getMultiple(iterable $keys, mixed $default = null) - * @method static mixed pull(array|string $key, mixed|\Closure $default = null) - * @method static bool put(array|string $key, mixed $value, \DateTimeInterface|\DateInterval|int|null $ttl = null) - * @method static bool set(string $key, mixed $value, null|int|\DateInterval $ttl = null) - * @method static bool putMany(array $values, \DateTimeInterface|\DateInterval|int|null $ttl = null) - * @method static bool setMultiple(iterable $values, null|int|\DateInterval $ttl = null) - * @method static bool add(string $key, mixed $value, \DateTimeInterface|\DateInterval|int|null $ttl = null) - * @method static int|bool increment(string $key, mixed $value = 1) - * @method static int|bool decrement(string $key, mixed $value = 1) - * @method static bool forever(string $key, mixed $value) - * @method static mixed remember(string $key, \Closure|\DateTimeInterface|\DateInterval|int|null $ttl, \Closure $callback) - * @method static mixed sear(string $key, \Closure $callback) - * @method static mixed rememberForever(string $key, \Closure $callback) - * @method static bool forget(string $key) - * @method static bool delete(string $key) - * @method static bool deleteMultiple(iterable $keys) - * @method static bool clear() - * @method static \Illuminate\Cache\TaggedCache tags(array|mixed $names) - * @method static bool supportsTags() - * @method static int|null getDefaultCacheTime() - * @method static \Illuminate\Cache\Repository setDefaultCacheTime(int|null $seconds) - * @method static \Illuminate\Contracts\Cache\Store getStore() - * @method static \Illuminate\Cache\Repository setStore(\Illuminate\Contracts\Cache\Store $store) - * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() - * @method static void setEventDispatcher(\Illuminate\Contracts\Events\Dispatcher $events) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * @method static mixed macroCall(string $method, array $parameters) - * @method static bool flush() - * @method static string getPrefix() - * @method static \Illuminate\Contracts\Cache\Lock lock(string $name, int $seconds = 0, string|null $owner = null) - * @method static \Illuminate\Contracts\Cache\Lock restoreLock(string $name, string $owner) - * * @see \Illuminate\Cache\CacheManager - * - * @mixin \Illuminate\Cache\Repository + * @see \Illuminate\Cache\Repository */ class Cache extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Config.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Config.php index e4d6a62c2..3eb4fdf35 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Config.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Config.php @@ -3,18 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static bool has(string $key) - * @method static mixed get(array|string $key, mixed $default = null) - * @method static array getMany(array $keys) - * @method static void set(array|string $key, mixed $value = null) - * @method static void prepend(string $key, mixed $value) - * @method static void push(string $key, mixed $value) - * @method static array all() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Config\Repository */ class Config extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Cookie.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Cookie.php index 3592f5839..bbcd5a30f 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Cookie.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Cookie.php @@ -3,22 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static \Symfony\Component\HttpFoundation\Cookie make(string $name, string $value, int $minutes = 0, string|null $path = null, string|null $domain = null, bool|null $secure = null, bool $httpOnly = true, bool $raw = false, string|null $sameSite = null) - * @method static \Symfony\Component\HttpFoundation\Cookie forever(string $name, string $value, string|null $path = null, string|null $domain = null, bool|null $secure = null, bool $httpOnly = true, bool $raw = false, string|null $sameSite = null) - * @method static \Symfony\Component\HttpFoundation\Cookie forget(string $name, string|null $path = null, string|null $domain = null) - * @method static bool hasQueued(string $key, string|null $path = null) - * @method static \Symfony\Component\HttpFoundation\Cookie|null queued(string $key, mixed $default = null, string|null $path = null) - * @method static void queue(mixed ...$parameters) - * @method static void expire(string $name, string|null $path = null, string|null $domain = null) - * @method static void unqueue(string $name, string|null $path = null) - * @method static \Illuminate\Cookie\CookieJar setDefaultPathAndDomain(string $path, string|null $domain, bool|null $secure = false, string|null $sameSite = null) - * @method static \Symfony\Component\HttpFoundation\Cookie[] getQueuedCookies() - * @method static \Illuminate\Cookie\CookieJar flushQueuedCookies() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Cookie\CookieJar */ class Cookie extends Facade @@ -37,9 +21,9 @@ class Cookie extends Facade /** * Retrieve a cookie from the request. * - * @param string|null $key - * @param mixed $default - * @return string|array|null + * @param string $key + * @param mixed $default + * @return string */ public static function get($key = null, $default = null) { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Crypt.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Crypt.php index 20f269d9b..0eef08d1b 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Crypt.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Crypt.php @@ -3,14 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static bool supported(string $key, string $cipher) - * @method static string generateKey(string $cipher) - * @method static string encrypt(mixed $value, bool $serialize = true) - * @method static string encryptString(string $value) - * @method static mixed decrypt(string $payload, bool $unserialize = true) - * @method static string decryptString(string $payload) - * @method static string getKey() - * * @see \Illuminate\Encryption\Encrypter */ class Crypt extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/DB.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/DB.php index a132a47aa..0369128e3 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/DB.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/DB.php @@ -3,114 +3,8 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Database\Connection connection(string|null $name = null) - * @method static \Illuminate\Database\ConnectionInterface connectUsing(string $name, array $config, bool $force = false) - * @method static void registerDoctrineType(string $class, string $name, string $type) - * @method static void purge(string|null $name = null) - * @method static void disconnect(string|null $name = null) - * @method static \Illuminate\Database\Connection reconnect(string|null $name = null) - * @method static mixed usingConnection(string $name, callable $callback) - * @method static string getDefaultConnection() - * @method static void setDefaultConnection(string $name) - * @method static string[] supportedDrivers() - * @method static string[] availableDrivers() - * @method static void extend(string $name, callable $resolver) - * @method static void forgetExtension(string $name) - * @method static array getConnections() - * @method static void setReconnector(callable $reconnector) - * @method static \Illuminate\Database\DatabaseManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * @method static mixed macroCall(string $method, array $parameters) - * @method static void useDefaultQueryGrammar() - * @method static void useDefaultSchemaGrammar() - * @method static void useDefaultPostProcessor() - * @method static \Illuminate\Database\Schema\Builder getSchemaBuilder() - * @method static \Illuminate\Database\Query\Builder table(\Closure|\Illuminate\Database\Query\Builder|\Illuminate\Contracts\Database\Query\Expression|string $table, string|null $as = null) - * @method static \Illuminate\Database\Query\Builder query() - * @method static mixed selectOne(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static mixed scalar(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static array selectFromWriteConnection(string $query, array $bindings = []) - * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static array selectResultSets(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static \Generator cursor(string $query, array $bindings = [], bool $useReadPdo = true) - * @method static bool insert(string $query, array $bindings = []) - * @method static int update(string $query, array $bindings = []) - * @method static int delete(string $query, array $bindings = []) - * @method static bool statement(string $query, array $bindings = []) - * @method static int affectingStatement(string $query, array $bindings = []) - * @method static bool unprepared(string $query) - * @method static array pretend(\Closure $callback) - * @method static mixed withoutPretending(\Closure $callback) - * @method static void bindValues(\PDOStatement $statement, array $bindings) - * @method static array prepareBindings(array $bindings) - * @method static void logQuery(string $query, array $bindings, float|null $time = null) - * @method static void whenQueryingForLongerThan(\DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold, callable $handler) - * @method static void allowQueryDurationHandlersToRunAgain() - * @method static float totalQueryDuration() - * @method static void resetTotalQueryDuration() - * @method static void reconnectIfMissingConnection() - * @method static \Illuminate\Database\Connection beforeStartingTransaction(\Closure $callback) - * @method static \Illuminate\Database\Connection beforeExecuting(\Closure $callback) - * @method static void listen(\Closure $callback) - * @method static \Illuminate\Contracts\Database\Query\Expression raw(mixed $value) - * @method static string escape(string|float|int|bool|null $value, bool $binary = false) - * @method static bool hasModifiedRecords() - * @method static void recordsHaveBeenModified(bool $value = true) - * @method static \Illuminate\Database\Connection setRecordModificationState(bool $value) - * @method static void forgetRecordModificationState() - * @method static \Illuminate\Database\Connection useWriteConnectionWhenReading(bool $value = true) - * @method static bool isDoctrineAvailable() - * @method static bool usingNativeSchemaOperations() - * @method static \Doctrine\DBAL\Schema\Column getDoctrineColumn(string $table, string $column) - * @method static \Doctrine\DBAL\Schema\AbstractSchemaManager getDoctrineSchemaManager() - * @method static \Doctrine\DBAL\Connection getDoctrineConnection() - * @method static \PDO getPdo() - * @method static \PDO|\Closure|null getRawPdo() - * @method static \PDO getReadPdo() - * @method static \PDO|\Closure|null getRawReadPdo() - * @method static \Illuminate\Database\Connection setPdo(\PDO|\Closure|null $pdo) - * @method static \Illuminate\Database\Connection setReadPdo(\PDO|\Closure|null $pdo) - * @method static string|null getName() - * @method static string|null getNameWithReadWriteType() - * @method static mixed getConfig(string|null $option = null) - * @method static string getDriverName() - * @method static \Illuminate\Database\Query\Grammars\Grammar getQueryGrammar() - * @method static \Illuminate\Database\Connection setQueryGrammar(\Illuminate\Database\Query\Grammars\Grammar $grammar) - * @method static \Illuminate\Database\Schema\Grammars\Grammar getSchemaGrammar() - * @method static \Illuminate\Database\Connection setSchemaGrammar(\Illuminate\Database\Schema\Grammars\Grammar $grammar) - * @method static \Illuminate\Database\Query\Processors\Processor getPostProcessor() - * @method static \Illuminate\Database\Connection setPostProcessor(\Illuminate\Database\Query\Processors\Processor $processor) - * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() - * @method static \Illuminate\Database\Connection setEventDispatcher(\Illuminate\Contracts\Events\Dispatcher $events) - * @method static void unsetEventDispatcher() - * @method static \Illuminate\Database\Connection setTransactionManager(\Illuminate\Database\DatabaseTransactionsManager $manager) - * @method static void unsetTransactionManager() - * @method static bool pretending() - * @method static array getQueryLog() - * @method static array getRawQueryLog() - * @method static void flushQueryLog() - * @method static void enableQueryLog() - * @method static void disableQueryLog() - * @method static bool logging() - * @method static string getDatabaseName() - * @method static \Illuminate\Database\Connection setDatabaseName(string $database) - * @method static \Illuminate\Database\Connection setReadWriteType(string|null $readWriteType) - * @method static string getTablePrefix() - * @method static \Illuminate\Database\Connection setTablePrefix(string $prefix) - * @method static \Illuminate\Database\Grammar withTablePrefix(\Illuminate\Database\Grammar $grammar) - * @method static void resolverFor(string $driver, \Closure $callback) - * @method static mixed getResolver(string $driver) - * @method static mixed transaction(\Closure $callback, int $attempts = 1) - * @method static void beginTransaction() - * @method static void commit() - * @method static void rollBack(int|null $toLevel = null) - * @method static int transactionLevel() - * @method static void afterCommit(callable $callback) - * * @see \Illuminate\Database\DatabaseManager + * @see \Illuminate\Database\Connection */ class DB extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Date.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Date.php deleted file mode 100644 index 7d4607f99..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Date.php +++ /dev/null @@ -1,122 +0,0 @@ -dispatcher - : static::getFacadeRoot(); + static::swap($fake = new EventFake); - return tap(new EventFake($actualDispatcher, $eventsToFake), function ($fake) { - static::swap($fake); - - Model::setEventDispatcher($fake); - Cache::refreshEventDispatcher(); - }); - } - - /** - * Replace the bound instance with a fake that fakes all events except the given events. - * - * @param string[]|string $eventsToAllow - * @return \Illuminate\Support\Testing\Fakes\EventFake - */ - public static function fakeExcept($eventsToAllow) - { - return static::fake([ - function ($eventName) use ($eventsToAllow) { - return ! in_array($eventName, (array) $eventsToAllow); - }, - ]); - } - - /** - * Replace the bound instance with a fake during the given callable's execution. - * - * @param callable $callable - * @param array $eventsToFake - * @return mixed - */ - public static function fakeFor(callable $callable, array $eventsToFake = []) - { - $originalDispatcher = static::getFacadeRoot(); - - static::fake($eventsToFake); - - return tap($callable(), function () use ($originalDispatcher) { - static::swap($originalDispatcher); - - Model::setEventDispatcher($originalDispatcher); - Cache::refreshEventDispatcher(); - }); - } - - /** - * Replace the bound instance with a fake during the given callable's execution. - * - * @param callable $callable - * @param array $eventsToAllow - * @return mixed - */ - public static function fakeExceptFor(callable $callable, array $eventsToAllow = []) - { - $originalDispatcher = static::getFacadeRoot(); - - static::fakeExcept($eventsToAllow); - - return tap($callable(), function () use ($originalDispatcher) { - static::swap($originalDispatcher); - - Model::setEventDispatcher($originalDispatcher); - Cache::refreshEventDispatcher(); - }); + Model::setEventDispatcher($fake); } /** diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Facade.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Facade.php index 2dbf100cd..c53180ccf 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Facade.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Facade.php @@ -2,23 +2,16 @@ namespace Illuminate\Support\Facades; -use Closure; -use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Arr; -use Illuminate\Support\Js; -use Illuminate\Support\Number; -use Illuminate\Support\Str; -use Illuminate\Support\Testing\Fakes\Fake; use Mockery; -use Mockery\LegacyMockInterface; use RuntimeException; +use Mockery\MockInterface; abstract class Facade { /** * The application instance being facaded. * - * @var \Illuminate\Contracts\Foundation\Application|null + * @var \Illuminate\Contracts\Foundation\Application */ protected static $app; @@ -29,64 +22,20 @@ abstract class Facade */ protected static $resolvedInstance; - /** - * Indicates if the resolved instance should be cached. - * - * @var bool - */ - protected static $cached = true; - - /** - * Run a Closure when the facade has been resolved. - * - * @param \Closure $callback - * @return void - */ - public static function resolved(Closure $callback) - { - $accessor = static::getFacadeAccessor(); - - if (static::$app->resolved($accessor) === true) { - $callback(static::getFacadeRoot(), static::$app); - } - - static::$app->afterResolving($accessor, function ($service, $app) use ($callback) { - $callback($service, $app); - }); - } - /** * Convert the facade into a Mockery spy. * - * @return \Mockery\MockInterface + * @return void */ public static function spy() { if (! static::isMock()) { $class = static::getMockableClass(); - return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) { - static::swap($spy); - }); + static::swap($class ? Mockery::spy($class) : Mockery::spy()); } } - /** - * Initiate a partial mock on the facade. - * - * @return \Mockery\MockInterface - */ - public static function partialMock() - { - $name = static::getFacadeAccessor(); - - $mock = static::isMock() - ? static::$resolvedInstance[$name] - : static::createFreshMockInstance(); - - return $mock->makePartial(); - } - /** * Initiate a mock expectation on the facade. * @@ -97,32 +46,16 @@ abstract class Facade $name = static::getFacadeAccessor(); $mock = static::isMock() - ? static::$resolvedInstance[$name] - : static::createFreshMockInstance(); + ? static::$resolvedInstance[$name] + : static::createFreshMockInstance(); return $mock->shouldReceive(...func_get_args()); } - /** - * Initiate a mock expectation on the facade. - * - * @return \Mockery\Expectation - */ - public static function expects() - { - $name = static::getFacadeAccessor(); - - $mock = static::isMock() - ? static::$resolvedInstance[$name] - : static::createFreshMockInstance(); - - return $mock->expects(...func_get_args()); - } - /** * Create a fresh mock instance for the given class. * - * @return \Mockery\MockInterface + * @return \Mockery\Expectation */ protected static function createFreshMockInstance() { @@ -155,7 +88,7 @@ abstract class Facade $name = static::getFacadeAccessor(); return isset(static::$resolvedInstance[$name]) && - static::$resolvedInstance[$name] instanceof LegacyMockInterface; + static::$resolvedInstance[$name] instanceof MockInterface; } /** @@ -185,19 +118,6 @@ abstract class Facade } } - /** - * Determines whether a "fake" has been set as the facade instance. - * - * @return bool - */ - protected static function isFake() - { - $name = static::getFacadeAccessor(); - - return isset(static::$resolvedInstance[$name]) && - static::$resolvedInstance[$name] instanceof Fake; - } - /** * Get the root object behind the facade. * @@ -223,22 +143,20 @@ abstract class Facade /** * Resolve the facade root instance from the container. * - * @param string $name + * @param string|object $name * @return mixed */ protected static function resolveFacadeInstance($name) { + if (is_object($name)) { + return $name; + } + if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } - if (static::$app) { - if (static::$cached) { - return static::$resolvedInstance[$name] = static::$app[$name]; - } - - return static::$app[$name]; - } + return static::$resolvedInstance[$name] = static::$app[$name]; } /** @@ -262,62 +180,10 @@ abstract class Facade static::$resolvedInstance = []; } - /** - * Get the application default aliases. - * - * @return \Illuminate\Support\Collection - */ - public static function defaultAliases() - { - return collect([ - 'App' => App::class, - 'Arr' => Arr::class, - 'Artisan' => Artisan::class, - 'Auth' => Auth::class, - 'Blade' => Blade::class, - 'Broadcast' => Broadcast::class, - 'Bus' => Bus::class, - 'Cache' => Cache::class, - 'Config' => Config::class, - 'Cookie' => Cookie::class, - 'Crypt' => Crypt::class, - 'Date' => Date::class, - 'DB' => DB::class, - 'Eloquent' => Model::class, - 'Event' => Event::class, - 'File' => File::class, - 'Gate' => Gate::class, - 'Hash' => Hash::class, - 'Http' => Http::class, - 'Js' => Js::class, - 'Lang' => Lang::class, - 'Log' => Log::class, - 'Mail' => Mail::class, - 'Notification' => Notification::class, - 'Number' => Number::class, - 'Password' => Password::class, - 'Process' => Process::class, - 'Queue' => Queue::class, - 'RateLimiter' => RateLimiter::class, - 'Redirect' => Redirect::class, - 'Request' => Request::class, - 'Response' => Response::class, - 'Route' => Route::class, - 'Schema' => Schema::class, - 'Session' => Session::class, - 'Storage' => Storage::class, - 'Str' => Str::class, - 'URL' => URL::class, - 'Validator' => Validator::class, - 'View' => View::class, - 'Vite' => Vite::class, - ]); - } - /** * Get the application instance behind the facade. * - * @return \Illuminate\Contracts\Foundation\Application|null + * @return \Illuminate\Contracts\Foundation\Application */ public static function getFacadeApplication() { @@ -327,7 +193,7 @@ abstract class Facade /** * Set the application instance. * - * @param \Illuminate\Contracts\Foundation\Application|null $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public static function setFacadeApplication($app) @@ -339,7 +205,7 @@ abstract class Facade * Handle dynamic, static calls to the object. * * @param string $method - * @param array $args + * @param array $args * @return mixed * * @throws \RuntimeException diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/File.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/File.php index fd43b658e..0f81bf62a 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/File.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/File.php @@ -3,59 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static bool exists(string $path) - * @method static bool missing(string $path) - * @method static string get(string $path, bool $lock = false) - * @method static array json(string $path, int $flags = 0, bool $lock = false) - * @method static string sharedGet(string $path) - * @method static mixed getRequire(string $path, array $data = []) - * @method static mixed requireOnce(string $path, array $data = []) - * @method static \Illuminate\Support\LazyCollection lines(string $path) - * @method static string hash(string $path, string $algorithm = 'md5') - * @method static int|bool put(string $path, string $contents, bool $lock = false) - * @method static void replace(string $path, string $content, int|null $mode = null) - * @method static void replaceInFile(array|string $search, array|string $replace, string $path) - * @method static int prepend(string $path, string $data) - * @method static int append(string $path, string $data, bool $lock = false) - * @method static mixed chmod(string $path, int|null $mode = null) - * @method static bool delete(string|array $paths) - * @method static bool move(string $path, string $target) - * @method static bool copy(string $path, string $target) - * @method static bool|null link(string $target, string $link) - * @method static void relativeLink(string $target, string $link) - * @method static string name(string $path) - * @method static string basename(string $path) - * @method static string dirname(string $path) - * @method static string extension(string $path) - * @method static string|null guessExtension(string $path) - * @method static string type(string $path) - * @method static string|false mimeType(string $path) - * @method static int size(string $path) - * @method static int lastModified(string $path) - * @method static bool isDirectory(string $directory) - * @method static bool isEmptyDirectory(string $directory, bool $ignoreDotFiles = false) - * @method static bool isReadable(string $path) - * @method static bool isWritable(string $path) - * @method static bool hasSameHash(string $firstFile, string $secondFile) - * @method static bool isFile(string $file) - * @method static array glob(string $pattern, int $flags = 0) - * @method static \Symfony\Component\Finder\SplFileInfo[] files(string $directory, bool $hidden = false) - * @method static \Symfony\Component\Finder\SplFileInfo[] allFiles(string $directory, bool $hidden = false) - * @method static array directories(string $directory) - * @method static void ensureDirectoryExists(string $path, int $mode = 0755, bool $recursive = true) - * @method static bool makeDirectory(string $path, int $mode = 0755, bool $recursive = false, bool $force = false) - * @method static bool moveDirectory(string $from, string $to, bool $overwrite = false) - * @method static bool copyDirectory(string $directory, string $destination, int|null $options = null) - * @method static bool deleteDirectory(string $directory, bool $preserve = false) - * @method static bool deleteDirectories(string $directory) - * @method static bool cleanDirectory(string $directory) - * @method static \Illuminate\Filesystem\Filesystem|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * @method static \Illuminate\Filesystem\Filesystem|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Filesystem\Filesystem */ class File extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Gate.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Gate.php index 4423a1d6a..62977c63e 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Gate.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Gate.php @@ -5,34 +5,7 @@ namespace Illuminate\Support\Facades; use Illuminate\Contracts\Auth\Access\Gate as GateContract; /** - * @method static bool has(string|array $ability) - * @method static \Illuminate\Auth\Access\Response allowIf(\Illuminate\Auth\Access\Response|\Closure|bool $condition, string|null $message = null, string|null $code = null) - * @method static \Illuminate\Auth\Access\Response denyIf(\Illuminate\Auth\Access\Response|\Closure|bool $condition, string|null $message = null, string|null $code = null) - * @method static \Illuminate\Auth\Access\Gate define(string $ability, callable|array|string $callback) - * @method static \Illuminate\Auth\Access\Gate resource(string $name, string $class, array|null $abilities = null) - * @method static \Illuminate\Auth\Access\Gate policy(string $class, string $policy) - * @method static \Illuminate\Auth\Access\Gate before(callable $callback) - * @method static \Illuminate\Auth\Access\Gate after(callable $callback) - * @method static bool allows(iterable|string $ability, array|mixed $arguments = []) - * @method static bool denies(iterable|string $ability, array|mixed $arguments = []) - * @method static bool check(iterable|string $abilities, array|mixed $arguments = []) - * @method static bool any(iterable|string $abilities, array|mixed $arguments = []) - * @method static bool none(iterable|string $abilities, array|mixed $arguments = []) - * @method static \Illuminate\Auth\Access\Response authorize(string $ability, array|mixed $arguments = []) - * @method static \Illuminate\Auth\Access\Response inspect(string $ability, array|mixed $arguments = []) - * @method static mixed raw(string $ability, array|mixed $arguments = []) - * @method static mixed getPolicyFor(object|string $class) - * @method static \Illuminate\Auth\Access\Gate guessPolicyNamesUsing(callable $callback) - * @method static mixed resolvePolicy(object|string $class) - * @method static \Illuminate\Auth\Access\Gate forUser(\Illuminate\Contracts\Auth\Authenticatable|mixed $user) - * @method static array abilities() - * @method static array policies() - * @method static \Illuminate\Auth\Access\Gate defaultDenialResponse(\Illuminate\Auth\Access\Response $response) - * @method static \Illuminate\Auth\Access\Gate setContainer(\Illuminate\Contracts\Container\Container $container) - * @method static \Illuminate\Auth\Access\Response denyWithStatus(int $status, string|null $message = null, int|null $code = null) - * @method static \Illuminate\Auth\Access\Response denyAsNotFound(string|null $message = null, int|null $code = null) - * - * @see \Illuminate\Auth\Access\Gate + * @see \Illuminate\Contracts\Auth\Access\Gate */ class Gate extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Hash.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Hash.php index 280585d6e..848642543 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Hash.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Hash.php @@ -3,24 +3,7 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Hashing\BcryptHasher createBcryptDriver() - * @method static \Illuminate\Hashing\ArgonHasher createArgonDriver() - * @method static \Illuminate\Hashing\Argon2IdHasher createArgon2idDriver() - * @method static array info(string $hashedValue) - * @method static string make(string $value, array $options = []) - * @method static bool check(string $value, string $hashedValue, array $options = []) - * @method static bool needsRehash(string $hashedValue, array $options = []) - * @method static bool isHashed(string $value) - * @method static string getDefaultDriver() - * @method static mixed driver(string|null $driver = null) - * @method static \Illuminate\Hashing\HashManager extend(string $driver, \Closure $callback) - * @method static array getDrivers() - * @method static \Illuminate\Contracts\Container\Container getContainer() - * @method static \Illuminate\Hashing\HashManager setContainer(\Illuminate\Contracts\Container\Container $container) - * @method static \Illuminate\Hashing\HashManager forgetDrivers() - * - * @see \Illuminate\Hashing\HashManager - * @see \Illuminate\Hashing\AbstractHasher + * @see \Illuminate\Hashing\BcryptHasher */ class Hash extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Http.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Http.php deleted file mode 100644 index c472d699e..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Http.php +++ /dev/null @@ -1,160 +0,0 @@ -fake($callback)); - }); - } - - /** - * Register a response sequence for the given URL pattern. - * - * @param string $urlPattern - * @return \Illuminate\Http\Client\ResponseSequence - */ - public static function fakeSequence(string $urlPattern = '*') - { - $fake = tap(static::getFacadeRoot(), function ($fake) { - static::swap($fake); - }); - - return $fake->fakeSequence($urlPattern); - } - - /** - * Indicate that an exception should be thrown if any request is not faked. - * - * @return \Illuminate\Http\Client\Factory - */ - public static function preventStrayRequests() - { - return tap(static::getFacadeRoot(), function ($fake) { - static::swap($fake->preventStrayRequests()); - }); - } - - /** - * Stub the given URL using the given callback. - * - * @param string $url - * @param \Illuminate\Http\Client\Response|\GuzzleHttp\Promise\PromiseInterface|callable $callback - * @return \Illuminate\Http\Client\Factory - */ - public static function stubUrl($url, $callback) - { - return tap(static::getFacadeRoot(), function ($fake) use ($url, $callback) { - static::swap($fake->stubUrl($url, $callback)); - }); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Input.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Input.php new file mode 100755 index 000000000..35f52d563 --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Input.php @@ -0,0 +1,33 @@ +input($key, $default); + } + + /** + * Get the registered name of the component. + * + * @return string + */ + protected static function getFacadeAccessor() + { + return 'request'; + } +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Lang.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Lang.php index a341b5fab..e5862b993 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Lang.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Lang.php @@ -3,34 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static bool hasForLocale(string $key, string|null $locale = null) - * @method static bool has(string $key, string|null $locale = null, bool $fallback = true) - * @method static string|array get(string $key, array $replace = [], string|null $locale = null, bool $fallback = true) - * @method static string choice(string $key, \Countable|int|float|array $number, array $replace = [], string|null $locale = null) - * @method static void addLines(array $lines, string $locale, string $namespace = '*') - * @method static void load(string $namespace, string $group, string $locale) - * @method static \Illuminate\Translation\Translator handleMissingKeysUsing(callable|null $callback) - * @method static void addNamespace(string $namespace, string $hint) - * @method static void addJsonPath(string $path) - * @method static array parseKey(string $key) - * @method static void determineLocalesUsing(callable $callback) - * @method static \Illuminate\Translation\MessageSelector getSelector() - * @method static void setSelector(\Illuminate\Translation\MessageSelector $selector) - * @method static \Illuminate\Contracts\Translation\Loader getLoader() - * @method static string locale() - * @method static string getLocale() - * @method static void setLocale(string $locale) - * @method static string getFallback() - * @method static void setFallback(string $fallback) - * @method static void setLoaded(array $loaded) - * @method static void stringable(callable|string $class, callable|null $handler = null) - * @method static void setParsedKey(string $key, array $parsed) - * @method static void flushParsedKeys() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Translation\Translator */ class Lang extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Log.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Log.php index ba4096528..b10e06478 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Log.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Log.php @@ -2,39 +2,10 @@ namespace Illuminate\Support\Facades; +use Psr\Log\LoggerInterface; + /** - * @method static \Psr\Log\LoggerInterface build(array $config) - * @method static \Psr\Log\LoggerInterface stack(array $channels, string|null $channel = null) - * @method static \Psr\Log\LoggerInterface channel(string|null $channel = null) - * @method static \Psr\Log\LoggerInterface driver(string|null $driver = null) - * @method static \Illuminate\Log\LogManager shareContext(array $context) - * @method static array sharedContext() - * @method static \Illuminate\Log\LogManager withoutContext() - * @method static \Illuminate\Log\LogManager flushSharedContext() - * @method static string|null getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static \Illuminate\Log\LogManager extend(string $driver, \Closure $callback) - * @method static void forgetChannel(string|null $driver = null) - * @method static array getChannels() - * @method static void emergency(string|\Stringable $message, array $context = []) - * @method static void alert(string|\Stringable $message, array $context = []) - * @method static void critical(string|\Stringable $message, array $context = []) - * @method static void error(string|\Stringable $message, array $context = []) - * @method static void warning(string|\Stringable $message, array $context = []) - * @method static void notice(string|\Stringable $message, array $context = []) - * @method static void info(string|\Stringable $message, array $context = []) - * @method static void debug(string|\Stringable $message, array $context = []) - * @method static void log(mixed $level, string|\Stringable $message, array $context = []) - * @method static void write(string $level, \Illuminate\Contracts\Support\Arrayable|\Illuminate\Contracts\Support\Jsonable|\Illuminate\Support\Stringable|array|string $message, array $context = []) - * @method static \Illuminate\Log\Logger withContext(array $context = []) - * @method static void listen(\Closure $callback) - * @method static \Psr\Log\LoggerInterface getLogger() - * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() - * @method static void setEventDispatcher(\Illuminate\Contracts\Events\Dispatcher $dispatcher) - * @method static \Illuminate\Log\Logger|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * @method static \Illuminate\Log\Logger|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * - * @see \Illuminate\Log\LogManager + * @see \Illuminate\Log\Writer */ class Log extends Facade { @@ -45,6 +16,6 @@ class Log extends Facade */ protected static function getFacadeAccessor() { - return 'log'; + return LoggerInterface::class; } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Mail.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Mail.php index d5ea8c729..f5140c476 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Mail.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Mail.php @@ -5,76 +5,18 @@ namespace Illuminate\Support\Facades; use Illuminate\Support\Testing\Fakes\MailFake; /** - * @method static \Illuminate\Contracts\Mail\Mailer mailer(string|null $name = null) - * @method static \Illuminate\Mail\Mailer driver(string|null $driver = null) - * @method static \Symfony\Component\Mailer\Transport\TransportInterface createSymfonyTransport(array $config) - * @method static string getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static void purge(string|null $name = null) - * @method static \Illuminate\Mail\MailManager extend(string $driver, \Closure $callback) - * @method static \Illuminate\Contracts\Foundation\Application getApplication() - * @method static \Illuminate\Mail\MailManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static \Illuminate\Mail\MailManager forgetMailers() - * @method static void alwaysFrom(string $address, string|null $name = null) - * @method static void alwaysReplyTo(string $address, string|null $name = null) - * @method static void alwaysReturnPath(string $address) - * @method static void alwaysTo(string $address, string|null $name = null) - * @method static \Illuminate\Mail\PendingMail to(mixed $users, string|null $name = null) - * @method static \Illuminate\Mail\PendingMail cc(mixed $users, string|null $name = null) - * @method static \Illuminate\Mail\PendingMail bcc(mixed $users, string|null $name = null) - * @method static \Illuminate\Mail\SentMessage|null html(string $html, mixed $callback) - * @method static \Illuminate\Mail\SentMessage|null raw(string $text, mixed $callback) - * @method static \Illuminate\Mail\SentMessage|null plain(string $view, array $data, mixed $callback) - * @method static string render(string|array $view, array $data = []) - * @method static \Illuminate\Mail\SentMessage|null send(\Illuminate\Contracts\Mail\Mailable|string|array $view, array $data = [], \Closure|string|null $callback = null) - * @method static mixed queue(\Illuminate\Contracts\Mail\Mailable|string|array $view, string|null $queue = null) - * @method static mixed onQueue(string $queue, \Illuminate\Contracts\Mail\Mailable $view) - * @method static mixed queueOn(string $queue, \Illuminate\Contracts\Mail\Mailable $view) - * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, \Illuminate\Contracts\Mail\Mailable $view, string|null $queue = null) - * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, \Illuminate\Contracts\Mail\Mailable $view) - * @method static \Symfony\Component\Mailer\Transport\TransportInterface getSymfonyTransport() - * @method static \Illuminate\Contracts\View\Factory getViewFactory() - * @method static void setSymfonyTransport(\Symfony\Component\Mailer\Transport\TransportInterface $transport) - * @method static \Illuminate\Mail\Mailer setQueue(\Illuminate\Contracts\Queue\Factory $queue) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * @method static void assertSent(string|\Closure $mailable, callable|int|null $callback = null) - * @method static void assertNotOutgoing(string|\Closure $mailable, callable|null $callback = null) - * @method static void assertNotSent(string|\Closure $mailable, callable|null $callback = null) - * @method static void assertNothingOutgoing() - * @method static void assertNothingSent() - * @method static void assertQueued(string|\Closure $mailable, callable|int|null $callback = null) - * @method static void assertNotQueued(string|\Closure $mailable, callable|null $callback = null) - * @method static void assertNothingQueued() - * @method static void assertSentCount(int $count) - * @method static void assertQueuedCount(int $count) - * @method static void assertOutgoingCount(int $count) - * @method static \Illuminate\Support\Collection sent(string|\Closure $mailable, callable|null $callback = null) - * @method static bool hasSent(string $mailable) - * @method static \Illuminate\Support\Collection queued(string|\Closure $mailable, callable|null $callback = null) - * @method static bool hasQueued(string $mailable) - * - * @see \Illuminate\Mail\MailManager - * @see \Illuminate\Support\Testing\Fakes\MailFake + * @see \Illuminate\Mail\Mailer */ class Mail extends Facade { /** * Replace the bound instance with a fake. * - * @return \Illuminate\Support\Testing\Fakes\MailFake + * @return void */ public static function fake() { - $actualMailManager = static::isFake() - ? static::getFacadeRoot()->manager - : static::getFacadeRoot(); - - return tap(new MailFake($actualMailManager), function ($fake) { - static::swap($fake); - }); + static::swap(new MailFake); } /** @@ -84,6 +26,6 @@ class Mail extends Facade */ protected static function getFacadeAccessor() { - return 'mail.manager'; + return 'mailer'; } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Notification.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Notification.php index 8b30997e7..268d2045e 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Notification.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Notification.php @@ -2,86 +2,22 @@ namespace Illuminate\Support\Facades; -use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Notifications\ChannelManager; use Illuminate\Support\Testing\Fakes\NotificationFake; /** - * @method static void send(\Illuminate\Support\Collection|array|mixed $notifiables, mixed $notification) - * @method static void sendNow(\Illuminate\Support\Collection|array|mixed $notifiables, mixed $notification, array|null $channels = null) - * @method static mixed channel(string|null $name = null) - * @method static string getDefaultDriver() - * @method static string deliversVia() - * @method static void deliverVia(string $channel) - * @method static \Illuminate\Notifications\ChannelManager locale(string $locale) - * @method static mixed driver(string|null $driver = null) - * @method static \Illuminate\Notifications\ChannelManager extend(string $driver, \Closure $callback) - * @method static array getDrivers() - * @method static \Illuminate\Contracts\Container\Container getContainer() - * @method static \Illuminate\Notifications\ChannelManager setContainer(\Illuminate\Contracts\Container\Container $container) - * @method static \Illuminate\Notifications\ChannelManager forgetDrivers() - * @method static void assertSentOnDemand(string|\Closure $notification, callable|null $callback = null) - * @method static void assertSentTo(mixed $notifiable, string|\Closure $notification, callable|null $callback = null) - * @method static void assertSentOnDemandTimes(string $notification, int $times = 1) - * @method static void assertSentToTimes(mixed $notifiable, string $notification, int $times = 1) - * @method static void assertNotSentTo(mixed $notifiable, string|\Closure $notification, callable|null $callback = null) - * @method static void assertNothingSent() - * @method static void assertNothingSentTo(mixed $notifiable) - * @method static void assertSentTimes(string $notification, int $expectedCount) - * @method static void assertCount(int $expectedCount) - * @method static \Illuminate\Support\Collection sent(mixed $notifiable, string $notification, callable|null $callback = null) - * @method static bool hasSent(mixed $notifiable, string $notification) - * @method static \Illuminate\Support\Testing\Fakes\NotificationFake serializeAndRestore(bool $serializeAndRestore = true) - * @method static array sentNotifications() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Notifications\ChannelManager - * @see \Illuminate\Support\Testing\Fakes\NotificationFake */ class Notification extends Facade { /** * Replace the bound instance with a fake. * - * @return \Illuminate\Support\Testing\Fakes\NotificationFake + * @return void */ public static function fake() { - return tap(new NotificationFake, function ($fake) { - static::swap($fake); - }); - } - - /** - * Begin sending a notification to an anonymous notifiable on the given channels. - * - * @param array $channels - * @return \Illuminate\Notifications\AnonymousNotifiable - */ - public static function routes(array $channels) - { - $notifiable = new AnonymousNotifiable; - - foreach ($channels as $channel => $route) { - $notifiable->route($channel, $route); - } - - return $notifiable; - } - - /** - * Begin sending a notification to an anonymous notifiable. - * - * @param string $channel - * @param mixed $route - * @return \Illuminate\Notifications\AnonymousNotifiable - */ - public static function route($channel, $route) - { - return (new AnonymousNotifiable)->route($channel, $route); + static::swap(new NotificationFake); } /** diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/ParallelTesting.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/ParallelTesting.php deleted file mode 100644 index d91558c1c..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/ParallelTesting.php +++ /dev/null @@ -1,34 +0,0 @@ -fake($callback)); - }); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Queue.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Queue.php index 50e2c7b81..647312f27 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Queue.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Queue.php @@ -2,90 +2,22 @@ namespace Illuminate\Support\Facades; -use Illuminate\Queue\Worker; use Illuminate\Support\Testing\Fakes\QueueFake; /** - * @method static void before(mixed $callback) - * @method static void after(mixed $callback) - * @method static void exceptionOccurred(mixed $callback) - * @method static void looping(mixed $callback) - * @method static void failing(mixed $callback) - * @method static void stopping(mixed $callback) - * @method static bool connected(string|null $name = null) - * @method static \Illuminate\Contracts\Queue\Queue connection(string|null $name = null) - * @method static void extend(string $driver, \Closure $resolver) - * @method static void addConnector(string $driver, \Closure $resolver) - * @method static string getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static string getName(string|null $connection = null) - * @method static \Illuminate\Contracts\Foundation\Application getApplication() - * @method static \Illuminate\Queue\QueueManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static int size(string|null $queue = null) - * @method static mixed push(string|object $job, mixed $data = '', string|null $queue = null) - * @method static mixed pushOn(string $queue, string|object $job, mixed $data = '') - * @method static mixed pushRaw(string $payload, string|null $queue = null, array $options = []) - * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '', string|null $queue = null) - * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '') - * @method static mixed bulk(array $jobs, mixed $data = '', string|null $queue = null) - * @method static \Illuminate\Contracts\Queue\Job|null pop(string|null $queue = null) - * @method static string getConnectionName() - * @method static \Illuminate\Contracts\Queue\Queue setConnectionName(string $name) - * @method static mixed getJobTries(mixed $job) - * @method static mixed getJobBackoff(mixed $job) - * @method static mixed getJobExpiration(mixed $job) - * @method static void createPayloadUsing(callable|null $callback) - * @method static \Illuminate\Container\Container getContainer() - * @method static void setContainer(\Illuminate\Container\Container $container) - * @method static \Illuminate\Support\Testing\Fakes\QueueFake except(array|string $jobsToBeQueued) - * @method static void assertPushed(string|\Closure $job, callable|int|null $callback = null) - * @method static void assertPushedOn(string $queue, string|\Closure $job, callable|null $callback = null) - * @method static void assertPushedWithChain(string $job, array $expectedChain = [], callable|null $callback = null) - * @method static void assertPushedWithoutChain(string $job, callable|null $callback = null) - * @method static void assertClosurePushed(callable|int|null $callback = null) - * @method static void assertClosureNotPushed(callable|null $callback = null) - * @method static void assertNotPushed(string|\Closure $job, callable|null $callback = null) - * @method static void assertCount(int $expectedCount) - * @method static void assertNothingPushed() - * @method static \Illuminate\Support\Collection pushed(string $job, callable|null $callback = null) - * @method static bool hasPushed(string $job) - * @method static bool shouldFakeJob(object $job) - * @method static array pushedJobs() - * @method static \Illuminate\Support\Testing\Fakes\QueueFake serializeAndRestore(bool $serializeAndRestore = true) - * * @see \Illuminate\Queue\QueueManager * @see \Illuminate\Queue\Queue - * @see \Illuminate\Support\Testing\Fakes\QueueFake */ class Queue extends Facade { - /** - * Register a callback to be executed to pick jobs. - * - * @param string $workerName - * @param callable $callback - * @return void - */ - public static function popUsing($workerName, $callback) - { - return Worker::popUsing($workerName, $callback); - } - /** * Replace the bound instance with a fake. * - * @param array|string $jobsToFake - * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @return void */ - public static function fake($jobsToFake = []) + public static function fake() { - $actualQueueManager = static::isFake() - ? static::getFacadeRoot()->queue - : static::getFacadeRoot(); - - return tap(new QueueFake(static::getFacadeApplication(), $jobsToFake, $actualQueueManager), function ($fake) { - static::swap($fake); - }); + static::swap(new QueueFake(static::getFacadeApplication())); } /** diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/RateLimiter.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/RateLimiter.php deleted file mode 100644 index e8b3ab3fe..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/RateLimiter.php +++ /dev/null @@ -1,33 +0,0 @@ -connection()->getSchemaBuilder(); } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Session.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Session.php index 125b3dbb4..bc9b5fd9a 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Session.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Session.php @@ -3,71 +3,8 @@ namespace Illuminate\Support\Facades; /** - * @method static bool shouldBlock() - * @method static string|null blockDriver() - * @method static int defaultRouteBlockLockSeconds() - * @method static int defaultRouteBlockWaitSeconds() - * @method static array getSessionConfig() - * @method static string getDefaultDriver() - * @method static void setDefaultDriver(string $name) - * @method static mixed driver(string|null $driver = null) - * @method static \Illuminate\Session\SessionManager extend(string $driver, \Closure $callback) - * @method static array getDrivers() - * @method static \Illuminate\Contracts\Container\Container getContainer() - * @method static \Illuminate\Session\SessionManager setContainer(\Illuminate\Contracts\Container\Container $container) - * @method static \Illuminate\Session\SessionManager forgetDrivers() - * @method static bool start() - * @method static void save() - * @method static void ageFlashData() - * @method static array all() - * @method static array only(array $keys) - * @method static array except(array $keys) - * @method static bool exists(string|array $key) - * @method static bool missing(string|array $key) - * @method static bool has(string|array $key) - * @method static mixed get(string $key, mixed $default = null) - * @method static mixed pull(string $key, mixed $default = null) - * @method static bool hasOldInput(string|null $key = null) - * @method static mixed getOldInput(string|null $key = null, mixed $default = null) - * @method static void replace(array $attributes) - * @method static void put(string|array $key, mixed $value = null) - * @method static mixed remember(string $key, \Closure $callback) - * @method static void push(string $key, mixed $value) - * @method static mixed increment(string $key, int $amount = 1) - * @method static int decrement(string $key, int $amount = 1) - * @method static void flash(string $key, mixed $value = true) - * @method static void now(string $key, mixed $value) - * @method static void reflash() - * @method static void keep(array|mixed $keys = null) - * @method static void flashInput(array $value) - * @method static mixed remove(string $key) - * @method static void forget(string|array $keys) - * @method static void flush() - * @method static bool invalidate() - * @method static bool regenerate(bool $destroy = false) - * @method static bool migrate(bool $destroy = false) - * @method static bool isStarted() - * @method static string getName() - * @method static void setName(string $name) - * @method static string getId() - * @method static void setId(string|null $id) - * @method static bool isValidId(string|null $id) - * @method static void setExists(bool $value) - * @method static string token() - * @method static void regenerateToken() - * @method static string|null previousUrl() - * @method static void setPreviousUrl(string $url) - * @method static void passwordConfirmed() - * @method static \SessionHandlerInterface getHandler() - * @method static \SessionHandlerInterface setHandler(\SessionHandlerInterface $handler) - * @method static bool handlerNeedsRequest() - * @method static void setRequestOnHandler(\Illuminate\Http\Request $request) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Session\SessionManager + * @see \Illuminate\Session\Store */ class Session extends Facade { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Storage.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Storage.php index 5279c04f0..e5460ff4b 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Storage.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Storage.php @@ -5,81 +5,6 @@ namespace Illuminate\Support\Facades; use Illuminate\Filesystem\Filesystem; /** - * @method static \Illuminate\Contracts\Filesystem\Filesystem drive(string|null $name = null) - * @method static \Illuminate\Contracts\Filesystem\Filesystem disk(string|null $name = null) - * @method static \Illuminate\Contracts\Filesystem\Cloud cloud() - * @method static \Illuminate\Contracts\Filesystem\Filesystem build(string|array $config) - * @method static \Illuminate\Contracts\Filesystem\Filesystem createLocalDriver(array $config) - * @method static \Illuminate\Contracts\Filesystem\Filesystem createFtpDriver(array $config) - * @method static \Illuminate\Contracts\Filesystem\Filesystem createSftpDriver(array $config) - * @method static \Illuminate\Contracts\Filesystem\Cloud createS3Driver(array $config) - * @method static \Illuminate\Contracts\Filesystem\Filesystem createScopedDriver(array $config) - * @method static \Illuminate\Filesystem\FilesystemManager set(string $name, mixed $disk) - * @method static string getDefaultDriver() - * @method static string getDefaultCloudDriver() - * @method static \Illuminate\Filesystem\FilesystemManager forgetDisk(array|string $disk) - * @method static void purge(string|null $name = null) - * @method static \Illuminate\Filesystem\FilesystemManager extend(string $driver, \Closure $callback) - * @method static \Illuminate\Filesystem\FilesystemManager setApplication(\Illuminate\Contracts\Foundation\Application $app) - * @method static bool exists(string $path) - * @method static string|null get(string $path) - * @method static resource|null readStream(string $path) - * @method static bool put(string $path, \Psr\Http\Message\StreamInterface|\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|resource $contents, mixed $options = []) - * @method static bool writeStream(string $path, resource $resource, array $options = []) - * @method static string getVisibility(string $path) - * @method static bool setVisibility(string $path, string $visibility) - * @method static bool prepend(string $path, string $data) - * @method static bool append(string $path, string $data) - * @method static bool delete(string|array $paths) - * @method static bool copy(string $from, string $to) - * @method static bool move(string $from, string $to) - * @method static int size(string $path) - * @method static int lastModified(string $path) - * @method static array files(string|null $directory = null, bool $recursive = false) - * @method static array allFiles(string|null $directory = null) - * @method static array directories(string|null $directory = null, bool $recursive = false) - * @method static array allDirectories(string|null $directory = null) - * @method static bool makeDirectory(string $path) - * @method static bool deleteDirectory(string $directory) - * @method static \Illuminate\Filesystem\FilesystemAdapter assertExists(string|array $path, string|null $content = null) - * @method static \Illuminate\Filesystem\FilesystemAdapter assertMissing(string|array $path) - * @method static \Illuminate\Filesystem\FilesystemAdapter assertDirectoryEmpty(string $path) - * @method static bool missing(string $path) - * @method static bool fileExists(string $path) - * @method static bool fileMissing(string $path) - * @method static bool directoryExists(string $path) - * @method static bool directoryMissing(string $path) - * @method static string path(string $path) - * @method static array|null json(string $path, int $flags = 0) - * @method static \Symfony\Component\HttpFoundation\StreamedResponse response(string $path, string|null $name = null, array $headers = [], string|null $disposition = 'inline') - * @method static \Symfony\Component\HttpFoundation\StreamedResponse download(string $path, string|null $name = null, array $headers = []) - * @method static string|false putFile(\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path, \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file = null, mixed $options = []) - * @method static string|false putFileAs(\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path, \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file, string|array|null $name = null, mixed $options = []) - * @method static string|false checksum(string $path, array $options = []) - * @method static string|false mimeType(string $path) - * @method static string url(string $path) - * @method static bool providesTemporaryUrls() - * @method static string temporaryUrl(string $path, \DateTimeInterface $expiration, array $options = []) - * @method static array temporaryUploadUrl(string $path, \DateTimeInterface $expiration, array $options = []) - * @method static \League\Flysystem\FilesystemOperator getDriver() - * @method static \League\Flysystem\FilesystemAdapter getAdapter() - * @method static array getConfig() - * @method static void buildTemporaryUrlsUsing(\Closure $callback) - * @method static \Illuminate\Filesystem\FilesystemAdapter|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * @method static \Illuminate\Filesystem\FilesystemAdapter|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * @method static mixed macroCall(string $method, array $parameters) - * @method static bool has(string $location) - * @method static string read(string $location) - * @method static \League\Flysystem\DirectoryListing listContents(string $location, bool $deep = false) - * @method static int fileSize(string $path) - * @method static string visibility(string $path) - * @method static void write(string $location, string $contents, array $config = []) - * @method static void createDirectory(string $location, array $config = []) - * * @see \Illuminate\Filesystem\FilesystemManager */ class Storage extends Facade @@ -87,47 +12,30 @@ class Storage extends Facade /** * Replace the given disk with a local testing disk. * - * @param string|null $disk - * @param array $config - * @return \Illuminate\Contracts\Filesystem\Filesystem + * @param string $disk + * + * @return void */ - public static function fake($disk = null, array $config = []) + public static function fake($disk) { - $disk = $disk ?: static::$app['config']->get('filesystems.default'); + (new Filesystem)->cleanDirectory( + $root = storage_path('framework/testing/disks/'.$disk) + ); - $root = storage_path('framework/testing/disks/'.$disk); - - if ($token = ParallelTesting::token()) { - $root = "{$root}_test_{$token}"; - } - - (new Filesystem)->cleanDirectory($root); - - static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ - 'root' => $root, - ]))); - - return tap($fake)->buildTemporaryUrlsUsing(function ($path, $expiration) { - return URL::to($path.'?expiration='.$expiration->getTimestamp()); - }); + static::set($disk, self::createLocalDriver(['root' => $root])); } /** * Replace the given disk with a persistent local testing disk. * - * @param string|null $disk - * @param array $config - * @return \Illuminate\Contracts\Filesystem\Filesystem + * @param string $disk + * @return void */ - public static function persistentFake($disk = null, array $config = []) + public static function persistentFake($disk) { - $disk = $disk ?: static::$app['config']->get('filesystems.default'); - - static::set($disk, $fake = static::createLocalDriver(array_merge($config, [ + static::set($disk, self::createLocalDriver([ 'root' => storage_path('framework/testing/disks/'.$disk), - ]))); - - return $fake; + ])); } /** diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/URL.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/URL.php index 984b2acde..e17414bc0 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/URL.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/URL.php @@ -3,50 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static string full() - * @method static string current() - * @method static string previous(mixed $fallback = false) - * @method static string previousPath(mixed $fallback = false) - * @method static string to(string $path, mixed $extra = [], bool|null $secure = null) - * @method static string secure(string $path, array $parameters = []) - * @method static string asset(string $path, bool|null $secure = null) - * @method static string secureAsset(string $path) - * @method static string assetFrom(string $root, string $path, bool|null $secure = null) - * @method static string formatScheme(bool|null $secure = null) - * @method static string signedRoute(string $name, mixed $parameters = [], \DateTimeInterface|\DateInterval|int|null $expiration = null, bool $absolute = true) - * @method static string temporarySignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true) - * @method static bool hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true, array $ignoreQuery = []) - * @method static bool hasValidRelativeSignature(\Illuminate\Http\Request $request, array $ignoreQuery = []) - * @method static bool hasCorrectSignature(\Illuminate\Http\Request $request, bool $absolute = true, array $ignoreQuery = []) - * @method static bool signatureHasNotExpired(\Illuminate\Http\Request $request) - * @method static string route(string $name, mixed $parameters = [], bool $absolute = true) - * @method static string toRoute(\Illuminate\Routing\Route $route, mixed $parameters, bool $absolute) - * @method static string action(string|array $action, mixed $parameters = [], bool $absolute = true) - * @method static array formatParameters(mixed|array $parameters) - * @method static string formatRoot(string $scheme, string|null $root = null) - * @method static string format(string $root, string $path, \Illuminate\Routing\Route|null $route = null) - * @method static bool isValidUrl(string $path) - * @method static void defaults(array $defaults) - * @method static array getDefaultParameters() - * @method static void forceScheme(string|null $scheme) - * @method static void forceRootUrl(string|null $root) - * @method static \Illuminate\Routing\UrlGenerator formatHostUsing(\Closure $callback) - * @method static \Illuminate\Routing\UrlGenerator formatPathUsing(\Closure $callback) - * @method static \Closure pathFormatter() - * @method static \Illuminate\Http\Request getRequest() - * @method static void setRequest(\Illuminate\Http\Request $request) - * @method static \Illuminate\Routing\UrlGenerator setRoutes(\Illuminate\Routing\RouteCollectionInterface $routes) - * @method static \Illuminate\Routing\UrlGenerator setSessionResolver(callable $sessionResolver) - * @method static \Illuminate\Routing\UrlGenerator setKeyResolver(callable $keyResolver) - * @method static \Illuminate\Routing\UrlGenerator withKeyResolver(callable $keyResolver) - * @method static \Illuminate\Routing\UrlGenerator resolveMissingNamedRoutesUsing(callable $missingNamedRouteResolver) - * @method static string getRootControllerNamespace() - * @method static \Illuminate\Routing\UrlGenerator setRootControllerNamespace(string $rootNamespace) - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * * @see \Illuminate\Routing\UrlGenerator */ class URL extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Validator.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Validator.php index a032cc53e..e3e1ba4dc 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Validator.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/Validator.php @@ -3,21 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Validation\Validator make(array $data, array $rules, array $messages = [], array $attributes = []) - * @method static array validate(array $data, array $rules, array $messages = [], array $attributes = []) - * @method static void extend(string $rule, \Closure|string $extension, string|null $message = null) - * @method static void extendImplicit(string $rule, \Closure|string $extension, string|null $message = null) - * @method static void extendDependent(string $rule, \Closure|string $extension, string|null $message = null) - * @method static void replacer(string $rule, \Closure|string $replacer) - * @method static void includeUnvalidatedArrayKeys() - * @method static void excludeUnvalidatedArrayKeys() - * @method static void resolver(\Closure $resolver) - * @method static \Illuminate\Contracts\Translation\Translator getTranslator() - * @method static \Illuminate\Validation\PresenceVerifierInterface getPresenceVerifier() - * @method static void setPresenceVerifier(\Illuminate\Validation\PresenceVerifierInterface $presenceVerifier) - * @method static \Illuminate\Contracts\Container\Container|null getContainer() - * @method static \Illuminate\Validation\Factory setContainer(\Illuminate\Contracts\Container\Container $container) - * * @see \Illuminate\Validation\Factory */ class Validator extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/View.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/View.php index 10eaa645d..9de57c328 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/View.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Facades/View.php @@ -3,84 +3,6 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Contracts\View\View file(string $path, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) - * @method static \Illuminate\Contracts\View\View make(string $view, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) - * @method static \Illuminate\Contracts\View\View first(array $views, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) - * @method static string renderWhen(bool $condition, string $view, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) - * @method static string renderUnless(bool $condition, string $view, \Illuminate\Contracts\Support\Arrayable|array $data = [], array $mergeData = []) - * @method static string renderEach(string $view, array $data, string $iterator, string $empty = 'raw|') - * @method static bool exists(string $view) - * @method static \Illuminate\Contracts\View\Engine getEngineFromPath(string $path) - * @method static mixed share(array|string $key, mixed|null $value = null) - * @method static void incrementRender() - * @method static void decrementRender() - * @method static bool doneRendering() - * @method static bool hasRenderedOnce(string $id) - * @method static void markAsRenderedOnce(string $id) - * @method static void addLocation(string $location) - * @method static \Illuminate\View\Factory addNamespace(string $namespace, string|array $hints) - * @method static \Illuminate\View\Factory prependNamespace(string $namespace, string|array $hints) - * @method static \Illuminate\View\Factory replaceNamespace(string $namespace, string|array $hints) - * @method static void addExtension(string $extension, string $engine, \Closure|null $resolver = null) - * @method static void flushState() - * @method static void flushStateIfDoneRendering() - * @method static array getExtensions() - * @method static \Illuminate\View\Engines\EngineResolver getEngineResolver() - * @method static \Illuminate\View\ViewFinderInterface getFinder() - * @method static void setFinder(\Illuminate\View\ViewFinderInterface $finder) - * @method static void flushFinderCache() - * @method static \Illuminate\Contracts\Events\Dispatcher getDispatcher() - * @method static void setDispatcher(\Illuminate\Contracts\Events\Dispatcher $events) - * @method static \Illuminate\Contracts\Container\Container getContainer() - * @method static void setContainer(\Illuminate\Contracts\Container\Container $container) - * @method static mixed shared(string $key, mixed $default = null) - * @method static array getShared() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() - * @method static void startComponent(\Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string $view, array $data = []) - * @method static void startComponentFirst(array $names, array $data = []) - * @method static string renderComponent() - * @method static mixed|null getConsumableComponentData(string $key, mixed $default = null) - * @method static void slot(string $name, string|null $content = null, array $attributes = []) - * @method static void endSlot() - * @method static array creator(array|string $views, \Closure|string $callback) - * @method static array composers(array $composers) - * @method static array composer(array|string $views, \Closure|string $callback) - * @method static void callComposer(\Illuminate\Contracts\View\View $view) - * @method static void callCreator(\Illuminate\Contracts\View\View $view) - * @method static void startFragment(string $fragment) - * @method static string stopFragment() - * @method static mixed getFragment(string $name, string|null $default = null) - * @method static array getFragments() - * @method static void flushFragments() - * @method static void startSection(string $section, string|null $content = null) - * @method static void inject(string $section, string $content) - * @method static string yieldSection() - * @method static string stopSection(bool $overwrite = false) - * @method static string appendSection() - * @method static string yieldContent(string $section, string $default = '') - * @method static string parentPlaceholder(string $section = '') - * @method static bool hasSection(string $name) - * @method static bool sectionMissing(string $name) - * @method static mixed getSection(string $name, string|null $default = null) - * @method static array getSections() - * @method static void flushSections() - * @method static void addLoop(\Countable|array $data) - * @method static void incrementLoopIndices() - * @method static void popLoop() - * @method static \stdClass|null getLastLoop() - * @method static array getLoopStack() - * @method static void startPush(string $section, string $content = '') - * @method static string stopPush() - * @method static void startPrepend(string $section, string $content = '') - * @method static string stopPrepend() - * @method static string yieldPushContent(string $section, string $default = '') - * @method static void flushStacks() - * @method static void startTranslation(array $replacements = []) - * @method static string renderTranslation() - * * @see \Illuminate\View\Factory */ class View extends Facade diff --git a/lam/lib/3rdParty/composer/illuminate/support/Facades/Vite.php b/lam/lib/3rdParty/composer/illuminate/support/Facades/Vite.php deleted file mode 100644 index 2f37c6753..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Facades/Vite.php +++ /dev/null @@ -1,43 +0,0 @@ - - * @implements \ArrayAccess - */ -class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable +class Fluent implements ArrayAccess, Arrayable, Jsonable, JsonSerializable { /** - * All of the attributes set on the fluent instance. + * All of the attributes set on the container. * - * @var array + * @var array */ protected $attributes = []; /** - * Create a new fluent instance. + * Create a new fluent container instance. * - * @param iterable $attributes + * @param array|object $attributes * @return void */ public function __construct($attributes = []) @@ -37,13 +30,11 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable } /** - * Get an attribute from the fluent instance. + * Get an attribute from the container. * - * @template TGetDefault - * - * @param TKey $key - * @param TGetDefault|(\Closure(): TGetDefault) $default - * @return TValue|TGetDefault + * @param string $key + * @param mixed $default + * @return mixed */ public function get($key, $default = null) { @@ -55,9 +46,9 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable } /** - * Get the attributes from the fluent instance. + * Get the attributes from the container. * - * @return array + * @return array */ public function getAttributes() { @@ -65,9 +56,9 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable } /** - * Convert the fluent instance to an array. + * Convert the Fluent instance to an array. * - * @return array + * @return array */ public function toArray() { @@ -77,15 +68,15 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable /** * Convert the object into something JSON serializable. * - * @return array + * @return array */ - public function jsonSerialize(): array + public function jsonSerialize() { return $this->toArray(); } /** - * Convert the fluent instance to JSON. + * Convert the Fluent instance to JSON. * * @param int $options * @return string @@ -98,58 +89,58 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable /** * Determine if the given offset exists. * - * @param TKey $offset + * @param string $offset * @return bool */ - public function offsetExists($offset): bool + public function offsetExists($offset) { - return isset($this->attributes[$offset]); + return isset($this->{$offset}); } /** * Get the value for a given offset. * - * @param TKey $offset - * @return TValue|null + * @param string $offset + * @return mixed */ - public function offsetGet($offset): mixed + public function offsetGet($offset) { - return $this->get($offset); + return $this->{$offset}; } /** * Set the value at the given offset. * - * @param TKey $offset - * @param TValue $value + * @param string $offset + * @param mixed $value * @return void */ - public function offsetSet($offset, $value): void + public function offsetSet($offset, $value) { - $this->attributes[$offset] = $value; + $this->{$offset} = $value; } /** * Unset the value at the given offset. * - * @param TKey $offset + * @param string $offset * @return void */ - public function offsetUnset($offset): void + public function offsetUnset($offset) { - unset($this->attributes[$offset]); + unset($this->{$offset}); } /** - * Handle dynamic calls to the fluent instance to set attributes. + * Handle dynamic calls to the container to set attributes. * - * @param TKey $method - * @param array{0: ?TValue} $parameters + * @param string $method + * @param array $parameters * @return $this */ public function __call($method, $parameters) { - $this->attributes[$method] = count($parameters) > 0 ? reset($parameters) : true; + $this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true; return $this; } @@ -157,8 +148,8 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable /** * Dynamically retrieve the value of an attribute. * - * @param TKey $key - * @return TValue|null + * @param string $key + * @return mixed */ public function __get($key) { @@ -168,34 +159,34 @@ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable /** * Dynamically set the value of an attribute. * - * @param TKey $key - * @param TValue $value + * @param string $key + * @param mixed $value * @return void */ public function __set($key, $value) { - $this->offsetSet($key, $value); + $this->attributes[$key] = $value; } /** * Dynamically check if an attribute is set. * - * @param TKey $key + * @param string $key * @return bool */ public function __isset($key) { - return $this->offsetExists($key); + return isset($this->attributes[$key]); } /** * Dynamically unset an attribute. * - * @param TKey $key + * @param string $key * @return void */ public function __unset($key) { - $this->offsetUnset($key); + unset($this->attributes[$key]); } } diff --git a/lam/lib/3rdParty/composer/illuminate/collections/HigherOrderCollectionProxy.php b/lam/lib/3rdParty/composer/illuminate/support/HigherOrderCollectionProxy.php similarity index 85% rename from lam/lib/3rdParty/composer/illuminate/collections/HigherOrderCollectionProxy.php rename to lam/lib/3rdParty/composer/illuminate/support/HigherOrderCollectionProxy.php index 106356c3a..7a781a021 100644 --- a/lam/lib/3rdParty/composer/illuminate/collections/HigherOrderCollectionProxy.php +++ b/lam/lib/3rdParty/composer/illuminate/support/HigherOrderCollectionProxy.php @@ -3,14 +3,14 @@ namespace Illuminate\Support; /** - * @mixin \Illuminate\Support\Enumerable + * @mixin \Illuminate\Support\Collection */ class HigherOrderCollectionProxy { /** * The collection being operated on. * - * @var \Illuminate\Support\Enumerable + * @var \Illuminate\Support\Collection */ protected $collection; @@ -24,11 +24,11 @@ class HigherOrderCollectionProxy /** * Create a new proxy instance. * - * @param \Illuminate\Support\Enumerable $collection + * @param \Illuminate\Support\Collection $collection * @param string $method * @return void */ - public function __construct(Enumerable $collection, $method) + public function __construct(Collection $collection, $method) { $this->method = $method; $this->collection = $collection; diff --git a/lam/lib/3rdParty/composer/illuminate/support/HtmlString.php b/lam/lib/3rdParty/composer/illuminate/support/HtmlString.php index d6b71d46c..c13adfd47 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/HtmlString.php +++ b/lam/lib/3rdParty/composer/illuminate/support/HtmlString.php @@ -19,7 +19,7 @@ class HtmlString implements Htmlable * @param string $html * @return void */ - public function __construct($html = '') + public function __construct($html) { $this->html = $html; } @@ -34,26 +34,6 @@ class HtmlString implements Htmlable return $this->html; } - /** - * Determine if the given HTML string is empty. - * - * @return bool - */ - public function isEmpty() - { - return $this->html === ''; - } - - /** - * Determine if the given HTML string is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return ! $this->isEmpty(); - } - /** * Get the HTML string. * diff --git a/lam/lib/3rdParty/composer/illuminate/support/InteractsWithTime.php b/lam/lib/3rdParty/composer/illuminate/support/InteractsWithTime.php deleted file mode 100644 index 2b617c392..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/InteractsWithTime.php +++ /dev/null @@ -1,64 +0,0 @@ -parseDateInterval($delay); - - return $delay instanceof DateTimeInterface - ? max(0, $delay->getTimestamp() - $this->currentTime()) - : (int) $delay; - } - - /** - * Get the "available at" UNIX timestamp. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @return int - */ - protected function availableAt($delay = 0) - { - $delay = $this->parseDateInterval($delay); - - return $delay instanceof DateTimeInterface - ? $delay->getTimestamp() - : Carbon::now()->addRealSeconds($delay)->getTimestamp(); - } - - /** - * If the given value is an interval, convert it to a DateTime instance. - * - * @param \DateTimeInterface|\DateInterval|int $delay - * @return \DateTimeInterface|int - */ - protected function parseDateInterval($delay) - { - if ($delay instanceof DateInterval) { - $delay = Carbon::now()->add($delay); - } - - return $delay; - } - - /** - * Get the current system time as a UNIX timestamp. - * - * @return int - */ - protected function currentTime() - { - return Carbon::now()->getTimestamp(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Js.php b/lam/lib/3rdParty/composer/illuminate/support/Js.php deleted file mode 100644 index c924d1c83..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Js.php +++ /dev/null @@ -1,150 +0,0 @@ -js = $this->convertDataToJavaScriptExpression($data, $flags, $depth); - } - - /** - * Create a new JavaScript string from the given data. - * - * @param mixed $data - * @param int $flags - * @param int $depth - * @return static - * - * @throws \JsonException - */ - public static function from($data, $flags = 0, $depth = 512) - { - return new static($data, $flags, $depth); - } - - /** - * Convert the given data to a JavaScript expression. - * - * @param mixed $data - * @param int $flags - * @param int $depth - * @return string - * - * @throws \JsonException - */ - protected function convertDataToJavaScriptExpression($data, $flags = 0, $depth = 512) - { - if ($data instanceof self) { - return $data->toHtml(); - } - - if ($data instanceof BackedEnum) { - $data = $data->value; - } - - $json = static::encode($data, $flags, $depth); - - if (is_string($data)) { - return "'".substr($json, 1, -1)."'"; - } - - return $this->convertJsonToJavaScriptExpression($json, $flags); - } - - /** - * Encode the given data as JSON. - * - * @param mixed $data - * @param int $flags - * @param int $depth - * @return string - * - * @throws \JsonException - */ - public static function encode($data, $flags = 0, $depth = 512) - { - if ($data instanceof Jsonable) { - return $data->toJson($flags | static::REQUIRED_FLAGS); - } - - if ($data instanceof Arrayable && ! ($data instanceof JsonSerializable)) { - $data = $data->toArray(); - } - - return json_encode($data, $flags | static::REQUIRED_FLAGS, $depth); - } - - /** - * Convert the given JSON to a JavaScript expression. - * - * @param string $json - * @param int $flags - * @return string - * - * @throws \JsonException - */ - protected function convertJsonToJavaScriptExpression($json, $flags = 0) - { - if ($json === '[]' || $json === '{}') { - return $json; - } - - if (Str::startsWith($json, ['"', '{', '['])) { - return "JSON.parse('".substr(json_encode($json, $flags | static::REQUIRED_FLAGS), 1, -1)."')"; - } - - return $json; - } - - /** - * Get the string representation of the data for use in HTML. - * - * @return string - */ - public function toHtml() - { - return $this->js; - } - - /** - * Get the string representation of the data for use in HTML. - * - * @return string - */ - public function __toString() - { - return $this->toHtml(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/LICENSE.md b/lam/lib/3rdParty/composer/illuminate/support/LICENSE.md deleted file mode 100644 index 79810c848..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Taylor Otwell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/illuminate/support/Lottery.php b/lam/lib/3rdParty/composer/illuminate/support/Lottery.php deleted file mode 100644 index 9bf3b47d0..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Lottery.php +++ /dev/null @@ -1,271 +0,0 @@ - 1) { - throw new RuntimeException('Float must not be greater than 1.'); - } - - $this->chances = $chances; - - $this->outOf = $outOf; - } - - /** - * Create a new Lottery instance. - * - * @param int|float $chances - * @param int|null $outOf - * @return static - */ - public static function odds($chances, $outOf = null) - { - return new static($chances, $outOf); - } - - /** - * Set the winner callback. - * - * @param callable $callback - * @return $this - */ - public function winner($callback) - { - $this->winner = $callback; - - return $this; - } - - /** - * Set the loser callback. - * - * @param callable $callback - * @return $this - */ - public function loser($callback) - { - $this->loser = $callback; - - return $this; - } - - /** - * Run the lottery. - * - * @param mixed ...$args - * @return mixed - */ - public function __invoke(...$args) - { - return $this->runCallback(...$args); - } - - /** - * Run the lottery. - * - * @param null|int $times - * @return mixed - */ - public function choose($times = null) - { - if ($times === null) { - return $this->runCallback(); - } - - $results = []; - - for ($i = 0; $i < $times; $i++) { - $results[] = $this->runCallback(); - } - - return $results; - } - - /** - * Run the winner or loser callback, randomly. - * - * @param mixed ...$args - * @return callable - */ - protected function runCallback(...$args) - { - return $this->wins() - ? ($this->winner ?? fn () => true)(...$args) - : ($this->loser ?? fn () => false)(...$args); - } - - /** - * Determine if the lottery "wins" or "loses". - * - * @return bool - */ - protected function wins() - { - return static::resultFactory()($this->chances, $this->outOf); - } - - /** - * The factory that determines the lottery result. - * - * @return callable - */ - protected static function resultFactory() - { - return static::$resultFactory ?? fn ($chances, $outOf) => $outOf === null - ? random_int(0, PHP_INT_MAX) / PHP_INT_MAX <= $chances - : random_int(1, $outOf) <= $chances; - } - - /** - * Force the lottery to always result in a win. - * - * @param callable|null $callback - * @return void - */ - public static function alwaysWin($callback = null) - { - self::setResultFactory(fn () => true); - - if ($callback === null) { - return; - } - - $callback(); - - static::determineResultNormally(); - } - - /** - * Force the lottery to always result in a lose. - * - * @param callable|null $callback - * @return void - */ - public static function alwaysLose($callback = null) - { - self::setResultFactory(fn () => false); - - if ($callback === null) { - return; - } - - $callback(); - - static::determineResultNormally(); - } - - /** - * Set the sequence that will be used to determine lottery results. - * - * @param array $sequence - * @param callable|null $whenMissing - * @return void - */ - public static function fix($sequence, $whenMissing = null) - { - return static::forceResultWithSequence($sequence, $whenMissing); - } - - /** - * Set the sequence that will be used to determine lottery results. - * - * @param array $sequence - * @param callable|null $whenMissing - * @return void - */ - public static function forceResultWithSequence($sequence, $whenMissing = null) - { - $next = 0; - - $whenMissing ??= function ($chances, $outOf) use (&$next) { - $factoryCache = static::$resultFactory; - - static::$resultFactory = null; - - $result = static::resultFactory()($chances, $outOf); - - static::$resultFactory = $factoryCache; - - $next++; - - return $result; - }; - - static::setResultFactory(function ($chances, $outOf) use (&$next, $sequence, $whenMissing) { - if (array_key_exists($next, $sequence)) { - return $sequence[$next++]; - } - - return $whenMissing($chances, $outOf); - }); - } - - /** - * Indicate that the lottery results should be determined normally. - * - * @return void - */ - public static function determineResultNormally() - { - static::$resultFactory = null; - } - - /** - * Set the factory that should be used to determine the lottery results. - * - * @param callable $factory - * @return void - */ - public static function setResultFactory($factory) - { - self::$resultFactory = $factory; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Manager.php b/lam/lib/3rdParty/composer/illuminate/support/Manager.php index dac473122..592776c2c 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Manager.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Manager.php @@ -3,24 +3,16 @@ namespace Illuminate\Support; use Closure; -use Illuminate\Contracts\Container\Container; use InvalidArgumentException; abstract class Manager { /** - * The container instance. + * The application instance. * - * @var \Illuminate\Contracts\Container\Container + * @var \Illuminate\Foundation\Application */ - protected $container; - - /** - * The configuration repository instance. - * - * @var \Illuminate\Contracts\Config\Repository - */ - protected $config; + protected $app; /** * The registered custom driver creators. @@ -39,13 +31,12 @@ abstract class Manager /** * Create a new manager instance. * - * @param \Illuminate\Contracts\Container\Container $container + * @param \Illuminate\Foundation\Application $app * @return void */ - public function __construct(Container $container) + public function __construct($app) { - $this->container = $container; - $this->config = $container->make('config'); + $this->app = $app; } /** @@ -58,21 +49,13 @@ abstract class Manager /** * Get a driver instance. * - * @param string|null $driver + * @param string $driver * @return mixed - * - * @throws \InvalidArgumentException */ public function driver($driver = null) { $driver = $driver ?: $this->getDefaultDriver(); - if (is_null($driver)) { - throw new InvalidArgumentException(sprintf( - 'Unable to resolve NULL driver for [%s].', static::class - )); - } - // If the given driver has not been created before, we will create the instances // here and cache it so we can return it next time very quickly. If there is // already a driver created by this name, we'll just return that instance. @@ -93,19 +76,18 @@ abstract class Manager */ protected function createDriver($driver) { - // First, we will determine if a custom driver creator exists for the given driver and - // if it does not we will check for a creator method for the driver. Custom creator - // callbacks allow developers to build their own "drivers" easily using Closures. + // We'll check to see if a creator method exists for the given driver. If not we + // will check for a custom driver creator, which allows developers to create + // drivers using their own customized driver creator Closure to create it. if (isset($this->customCreators[$driver])) { return $this->callCustomCreator($driver); + } else { + $method = 'create'.Str::studly($driver).'Driver'; + + if (method_exists($this, $method)) { + return $this->$method(); + } } - - $method = 'create'.Str::studly($driver).'Driver'; - - if (method_exists($this, $method)) { - return $this->$method(); - } - throw new InvalidArgumentException("Driver [$driver] not supported."); } @@ -117,13 +99,13 @@ abstract class Manager */ protected function callCustomCreator($driver) { - return $this->customCreators[$driver]($this->container); + return $this->customCreators[$driver]($this->app); } /** * Register a custom driver creator Closure. * - * @param string $driver + * @param string $driver * @param \Closure $callback * @return $this */ @@ -144,46 +126,11 @@ abstract class Manager return $this->drivers; } - /** - * Get the container instance used by the manager. - * - * @return \Illuminate\Contracts\Container\Container - */ - public function getContainer() - { - return $this->container; - } - - /** - * Set the container instance used by the manager. - * - * @param \Illuminate\Contracts\Container\Container $container - * @return $this - */ - public function setContainer(Container $container) - { - $this->container = $container; - - return $this; - } - - /** - * Forget all of the resolved driver instances. - * - * @return $this - */ - public function forgetDrivers() - { - $this->drivers = []; - - return $this; - } - /** * Dynamically call the default driver instance. * * @param string $method - * @param array $parameters + * @param array $parameters * @return mixed */ public function __call($method, $parameters) diff --git a/lam/lib/3rdParty/composer/illuminate/support/MessageBag.php b/lam/lib/3rdParty/composer/illuminate/support/MessageBag.php index 4b303168d..657b8acf2 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/MessageBag.php +++ b/lam/lib/3rdParty/composer/illuminate/support/MessageBag.php @@ -2,13 +2,14 @@ namespace Illuminate\Support; -use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Contracts\Support\Jsonable; -use Illuminate\Contracts\Support\MessageBag as MessageBagContract; -use Illuminate\Contracts\Support\MessageProvider; +use Countable; use JsonSerializable; +use Illuminate\Contracts\Support\Jsonable; +use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Support\MessageProvider; +use Illuminate\Contracts\Support\MessageBag as MessageBagContract; -class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, MessageProvider +class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, MessageBagContract, MessageProvider { /** * All of the registered messages. @@ -33,9 +34,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess public function __construct(array $messages = []) { foreach ($messages as $key => $value) { - $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; - - $this->messages[$key] = array_unique($value); + $this->messages[$key] = (array) $value; } } @@ -50,7 +49,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Add a message to the message bag. + * Add a message to the bag. * * @param string $key * @param string $message @@ -65,19 +64,6 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess return $this; } - /** - * Add a message to the message bag if the given conditional is "true". - * - * @param bool $boolean - * @param string $key - * @param string $message - * @return $this - */ - public function addIf($boolean, $key, $message) - { - return $boolean ? $this->add($key, $message) : $this; - } - /** * Determine if a key and message combination already exists. * @@ -93,7 +79,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Merge a new array of messages into the message bag. + * Merge a new array of messages into the bag. * * @param \Illuminate\Contracts\Support\MessageProvider|array $messages * @return $this @@ -112,15 +98,11 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess /** * Determine if messages exist for all of the given keys. * - * @param array|string|null $key + * @param array|string $key * @return bool */ public function has($key) { - if ($this->isEmpty()) { - return false; - } - if (is_null($key)) { return $this->any(); } @@ -139,15 +121,11 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess /** * Determine if messages exist for any of the given keys. * - * @param array|string|null $keys + * @param array|string $keys * @return bool */ public function hasAny($keys = []) { - if ($this->isEmpty()) { - return false; - } - $keys = is_array($keys) ? $keys : func_get_args(); foreach ($keys as $key) { @@ -160,23 +138,10 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Determine if messages don't exist for all of the given keys. + * Get the first message from the bag for a given key. * - * @param array|string|null $key - * @return bool - */ - public function missing($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - return ! $this->hasAny($keys); - } - - /** - * Get the first message from the message bag for a given key. - * - * @param string|null $key - * @param string|null $format + * @param string $key + * @param string $format * @return string */ public function first($key = null, $format = null) @@ -189,24 +154,24 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get all of the messages from the message bag for a given key. + * Get all of the messages from the bag for a given key. * * @param string $key - * @param string|null $format + * @param string $format * @return array */ public function get($key, $format = null) { - // If the message exists in the message bag, we will transform it and return - // the message. Otherwise, we will check if the key is implicit & collect - // all the messages that match the given key and output it as an array. + // If the message exists in the container, we will transform it and return + // the message. Otherwise, we'll check if the key is implicit & collect + // all the messages that match a given key and output it as an array. if (array_key_exists($key, $this->messages)) { return $this->transform( $this->messages[$key], $this->checkFormat($format), $key ); } - if (str_contains($key, '*')) { + if (Str::contains($key, '*')) { return $this->getMessagesForWildcardKey($key, $format); } @@ -234,9 +199,9 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get all of the messages for every key in the message bag. + * Get all of the messages for every key in the bag. * - * @param string|null $format + * @param string $format * @return array */ public function all($format = null) @@ -253,9 +218,9 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get all of the unique messages for every key in the message bag. + * Get all of the unique messages for every key in the bag. * - * @param string|null $format + * @param string $format * @return array */ public function unique($format = null) @@ -263,33 +228,16 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess return array_unique($this->all($format)); } - /** - * Remove a message from the message bag. - * - * @param string $key - * @return $this - */ - public function forget($key) - { - unset($this->messages[$key]); - - return $this; - } - /** * Format an array of messages. * - * @param array $messages + * @param array $messages * @param string $format * @param string $messageKey * @return array */ protected function transform($messages, $format, $messageKey) { - if ($format == ':message') { - return (array) $messages; - } - return collect((array) $messages) ->map(function ($message) use ($format, $messageKey) { // We will simply spin through the given messages and transform each one @@ -311,7 +259,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get the raw messages in the message bag. + * Get the raw messages in the container. * * @return array */ @@ -321,7 +269,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get the raw messages in the message bag. + * Get the raw messages in the container. * * @return array */ @@ -373,16 +321,6 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess return ! $this->any(); } - /** - * Determine if the message bag has any messages. - * - * @return bool - */ - public function isNotEmpty() - { - return $this->any(); - } - /** * Determine if the message bag has any messages. * @@ -394,11 +332,11 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess } /** - * Get the number of messages in the message bag. + * Get the number of messages in the container. * * @return int */ - public function count(): int + public function count() { return count($this->messages, COUNT_RECURSIVE) - count($this->messages); } @@ -418,7 +356,7 @@ class MessageBag implements Jsonable, JsonSerializable, MessageBagContract, Mess * * @return array */ - public function jsonSerialize(): array + public function jsonSerialize() { return $this->toArray(); } diff --git a/lam/lib/3rdParty/composer/illuminate/support/MultipleInstanceManager.php b/lam/lib/3rdParty/composer/illuminate/support/MultipleInstanceManager.php deleted file mode 100644 index 8544bdf71..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/MultipleInstanceManager.php +++ /dev/null @@ -1,191 +0,0 @@ -app = $app; - } - - /** - * Get the default instance name. - * - * @return string - */ - abstract public function getDefaultInstance(); - - /** - * Set the default instance name. - * - * @param string $name - * @return void - */ - abstract public function setDefaultInstance($name); - - /** - * Get the instance specific configuration. - * - * @param string $name - * @return array - */ - abstract public function getInstanceConfig($name); - - /** - * Get an instance instance by name. - * - * @param string|null $name - * @return mixed - */ - public function instance($name = null) - { - $name = $name ?: $this->getDefaultInstance(); - - return $this->instances[$name] = $this->get($name); - } - - /** - * Attempt to get an instance from the local cache. - * - * @param string $name - * @return mixed - */ - protected function get($name) - { - return $this->instances[$name] ?? $this->resolve($name); - } - - /** - * Resolve the given instance. - * - * @param string $name - * @return mixed - * - * @throws \InvalidArgumentException - */ - protected function resolve($name) - { - $config = $this->getInstanceConfig($name); - - if (is_null($config)) { - throw new InvalidArgumentException("Instance [{$name}] is not defined."); - } - - if (! array_key_exists('driver', $config)) { - throw new RuntimeException("Instance [{$name}] does not specify a driver."); - } - - if (isset($this->customCreators[$config['driver']])) { - return $this->callCustomCreator($config); - } else { - $driverMethod = 'create'.ucfirst($config['driver']).'Driver'; - - if (method_exists($this, $driverMethod)) { - return $this->{$driverMethod}($config); - } else { - throw new InvalidArgumentException("Instance driver [{$config['driver']}] is not supported."); - } - } - } - - /** - * Call a custom instance creator. - * - * @param array $config - * @return mixed - */ - protected function callCustomCreator(array $config) - { - return $this->customCreators[$config['driver']]($this->app, $config); - } - - /** - * Unset the given instances. - * - * @param array|string|null $name - * @return $this - */ - public function forgetInstance($name = null) - { - $name ??= $this->getDefaultInstance(); - - foreach ((array) $name as $instanceName) { - if (isset($this->instances[$instanceName])) { - unset($this->instances[$instanceName]); - } - } - - return $this; - } - - /** - * Disconnect the given instance and remove from local cache. - * - * @param string|null $name - * @return void - */ - public function purge($name = null) - { - $name ??= $this->getDefaultInstance(); - - unset($this->instances[$name]); - } - - /** - * Register a custom instance creator Closure. - * - * @param string $name - * @param \Closure $callback - * @return $this - */ - public function extend($name, Closure $callback) - { - $this->customCreators[$name] = $callback->bindTo($this, $this); - - return $this; - } - - /** - * Dynamically call the default instance. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->instance()->$method(...$parameters); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/NamespacedItemResolver.php b/lam/lib/3rdParty/composer/illuminate/support/NamespacedItemResolver.php index a059c6daf..cdf6cf9b5 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/NamespacedItemResolver.php +++ b/lam/lib/3rdParty/composer/illuminate/support/NamespacedItemResolver.php @@ -29,7 +29,7 @@ class NamespacedItemResolver // If the key does not contain a double colon, it means the key is not in a // namespace, and is just a regular configuration item. Namespaces are a // tool for organizing configuration items for things such as modules. - if (! str_contains($key, '::')) { + if (strpos($key, '::') === false) { $segments = explode('.', $key); $parsed = $this->parseBasicSegments($segments); @@ -56,14 +56,18 @@ class NamespacedItemResolver // just pulling an entire group out of the array and not a single item. $group = $segments[0]; + if (count($segments) == 1) { + return [null, $group, null]; + } + // If there is more than one segment in this group, it means we are pulling // a specific item out of a group and will need to return this item name // as well as the group so we know which item to pull from the arrays. - $item = count($segments) === 1 - ? null - : implode('.', array_slice($segments, 1)); + else { + $item = implode('.', array_slice($segments, 1)); - return [null, $group, $item]; + return [null, $group, $item]; + } } /** @@ -74,7 +78,7 @@ class NamespacedItemResolver */ protected function parseNamespacedSegments($key) { - [$namespace, $item] = explode('::', $key); + list($namespace, $item) = explode('::', $key); // First we'll just explode the first segment to get the namespace and group // since the item should be in the remaining segments. Once we have these @@ -92,21 +96,11 @@ class NamespacedItemResolver * Set the parsed value of a key. * * @param string $key - * @param array $parsed + * @param array $parsed * @return void */ public function setParsedKey($key, $parsed) { $this->parsed[$key] = $parsed; } - - /** - * Flush the cache of parsed keys. - * - * @return void - */ - public function flushParsedKeys() - { - $this->parsed = []; - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Number.php b/lam/lib/3rdParty/composer/illuminate/support/Number.php deleted file mode 100644 index 7719055f6..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Number.php +++ /dev/null @@ -1,275 +0,0 @@ -setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); - } elseif (! is_null($precision)) { - $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); - } - - return $formatter->format($number); - } - - /** - * Spell out the given number in the given locale. - * - * @param int|float $number - * @param string|null $locale - * @param int|null $after - * @param int|null $until - * @return string - */ - public static function spell(int|float $number, ?string $locale = null, ?int $after = null, ?int $until = null) - { - static::ensureIntlExtensionIsInstalled(); - - if (! is_null($after) && $number <= $after) { - return static::format($number, locale: $locale); - } - - if (! is_null($until) && $number >= $until) { - return static::format($number, locale: $locale); - } - - $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::SPELLOUT); - - return $formatter->format($number); - } - - /** - * Convert the given number to ordinal form. - * - * @param int|float $number - * @param string|null $locale - * @return string - */ - public static function ordinal(int|float $number, ?string $locale = null) - { - static::ensureIntlExtensionIsInstalled(); - - $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::ORDINAL); - - return $formatter->format($number); - } - - /** - * Convert the given number to its percentage equivalent. - * - * @param int|float $number - * @param int $precision - * @param int|null $maxPrecision - * @param string|null $locale - * @return string|false - */ - public static function percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null) - { - static::ensureIntlExtensionIsInstalled(); - - $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::PERCENT); - - if (! is_null($maxPrecision)) { - $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); - } else { - $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); - } - - return $formatter->format($number / 100); - } - - /** - * Convert the given number to its currency equivalent. - * - * @param int|float $number - * @param string $in - * @param string|null $locale - * @return string|false - */ - public static function currency(int|float $number, string $in = 'USD', ?string $locale = null) - { - static::ensureIntlExtensionIsInstalled(); - - $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::CURRENCY); - - return $formatter->formatCurrency($number, $in); - } - - /** - * Convert the given number to its file size equivalent. - * - * @param int|float $bytes - * @param int $precision - * @param int|null $maxPrecision - * @return string - */ - public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxPrecision = null) - { - $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - - for ($i = 0; ($bytes / 1024) > 0.9 && ($i < count($units) - 1); $i++) { - $bytes /= 1024; - } - - return sprintf('%s %s', static::format($bytes, $precision, $maxPrecision), $units[$i]); - } - - /** - * Convert the number to its human-readable equivalent. - * - * @param int|float $number - * @param int $precision - * @param int|null $maxPrecision - * @return bool|string - */ - public static function abbreviate(int|float $number, int $precision = 0, ?int $maxPrecision = null) - { - return static::forHumans($number, $precision, $maxPrecision, abbreviate: true); - } - - /** - * Convert the number to its human-readable equivalent. - * - * @param int|float $number - * @param int $precision - * @param int|null $maxPrecision - * @param bool $abbreviate - * @return bool|string - */ - public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null, bool $abbreviate = false) - { - return static::summarize($number, $precision, $maxPrecision, $abbreviate ? [ - 3 => 'K', - 6 => 'M', - 9 => 'B', - 12 => 'T', - 15 => 'Q', - ] : [ - 3 => ' thousand', - 6 => ' million', - 9 => ' billion', - 12 => ' trillion', - 15 => ' quadrillion', - ]); - } - - /** - * Convert the number to its human-readable equivalent. - * - * @param int|float $number - * @param int $precision - * @param int|null $maxPrecision - * @param array $units - * @return string|false - */ - protected static function summarize(int|float $number, int $precision = 0, ?int $maxPrecision = null, array $units = []) - { - if (empty($units)) { - $units = [ - 3 => 'K', - 6 => 'M', - 9 => 'B', - 12 => 'T', - 15 => 'Q', - ]; - } - - switch (true) { - case floatval($number) === 0.0: - return $precision > 0 ? static::format(0, $precision, $maxPrecision) : '0'; - case $number < 0: - return sprintf('-%s', static::summarize(abs($number), $precision, $maxPrecision, $units)); - case $number >= 1e15: - return sprintf('%s'.end($units), static::summarize($number / 1e15, $precision, $maxPrecision, $units)); - } - - $numberExponent = floor(log10($number)); - $displayExponent = $numberExponent - ($numberExponent % 3); - $number /= pow(10, $displayExponent); - - return trim(sprintf('%s%s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); - } - - /** - * Clamp the given number between the given minimum and maximum. - * - * @param int|float $number - * @param int|float $min - * @param int|float $max - * @return int|float - */ - public static function clamp(int|float $number, int|float $min, int|float $max) - { - return min(max($number, $min), $max); - } - - /** - * Execute the given callback using the given locale. - * - * @param string $locale - * @param callable $callback - * @return mixed - */ - public static function withLocale(string $locale, callable $callback) - { - $previousLocale = static::$locale; - - static::useLocale($locale); - - return tap($callback(), fn () => static::useLocale($previousLocale)); - } - - /** - * Set the default locale. - * - * @param string $locale - * @return void - */ - public static function useLocale(string $locale) - { - static::$locale = $locale; - } - - /** - * Ensure the "intl" PHP extension is installed. - * - * @return void - */ - protected static function ensureIntlExtensionIsInstalled() - { - if (! extension_loaded('intl')) { - $method = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function']; - - throw new RuntimeException('The "intl" PHP extension is required to use the ['.$method.'] method.'); - } - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Optional.php b/lam/lib/3rdParty/composer/illuminate/support/Optional.php deleted file mode 100644 index ba84a2ccf..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Optional.php +++ /dev/null @@ -1,131 +0,0 @@ -value = $value; - } - - /** - * Dynamically access a property on the underlying object. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - if (is_object($this->value)) { - return $this->value->{$key} ?? null; - } - } - - /** - * Dynamically check a property exists on the underlying object. - * - * @param mixed $name - * @return bool - */ - public function __isset($name) - { - if (is_object($this->value)) { - return isset($this->value->{$name}); - } - - if (is_array($this->value) || $this->value instanceof ArrayObject) { - return isset($this->value[$name]); - } - - return false; - } - - /** - * Determine if an item exists at an offset. - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key): bool - { - return Arr::accessible($this->value) && Arr::exists($this->value, $key); - } - - /** - * Get an item at a given offset. - * - * @param mixed $key - * @return mixed - */ - public function offsetGet($key): mixed - { - return Arr::get($this->value, $key); - } - - /** - * Set the item at a given offset. - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value): void - { - if (Arr::accessible($this->value)) { - $this->value[$key] = $value; - } - } - - /** - * Unset the item at a given offset. - * - * @param string $key - * @return void - */ - public function offsetUnset($key): void - { - if (Arr::accessible($this->value)) { - unset($this->value[$key]); - } - } - - /** - * Dynamically pass a method to the underlying object. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - if (static::hasMacro($method)) { - return $this->macroCall($method, $parameters); - } - - if (is_object($this->value)) { - return $this->value->{$method}(...$parameters); - } - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Pluralizer.php b/lam/lib/3rdParty/composer/illuminate/support/Pluralizer.php index 0d909de1e..4d845aa89 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/Pluralizer.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Pluralizer.php @@ -2,54 +2,68 @@ namespace Illuminate\Support; -use Doctrine\Inflector\InflectorFactory; +use Doctrine\Common\Inflector\Inflector; class Pluralizer { /** - * The cached inflector instance. + * Uncountable word forms. * - * @var static - */ - protected static $inflector; - - /** - * The language that should be used by the inflector. - * - * @var string - */ - protected static $language = 'english'; - - /** - * Uncountable non-nouns word forms. - * - * Contains words supported by Doctrine/Inflector/Rules/English/Uninflected.php - * - * @var string[] + * @var array */ public static $uncountable = [ - 'recommended', - 'related', + 'audio', + 'bison', + 'chassis', + 'compensation', + 'coreopsis', + 'data', + 'deer', + 'education', + 'emoji', + 'equipment', + 'evidence', + 'feedback', + 'fish', + 'furniture', + 'gold', + 'information', + 'jedi', + 'knowledge', + 'love', + 'metadata', + 'money', + 'moose', + 'news', + 'nutrition', + 'offspring', + 'plankton', + 'pokemon', + 'police', + 'rain', + 'rice', + 'series', + 'sheep', + 'species', + 'swine', + 'traffic', + 'wheat', ]; /** * Get the plural form of an English word. * * @param string $value - * @param int|array|\Countable $count + * @param int $count * @return string */ public static function plural($value, $count = 2) { - if (is_countable($count)) { - $count = count($count); - } - - if ((int) abs($count) === 1 || static::uncountable($value) || preg_match('/^(.*)[A-Za-z0-9\x{0080}-\x{FFFF}]$/u', $value) == 0) { + if ((int) $count === 1 || static::uncountable($value)) { return $value; } - $plural = static::inflector()->pluralize($value); + $plural = Inflector::pluralize($value); return static::matchCase($plural, $value); } @@ -62,7 +76,7 @@ class Pluralizer */ public static function singular($value) { - $singular = static::inflector()->singularize($value); + $singular = Inflector::singularize($value); return static::matchCase($singular, $value); } @@ -90,38 +104,11 @@ class Pluralizer $functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords']; foreach ($functions as $function) { - if ($function($comparison) === $comparison) { - return $function($value); + if (call_user_func($function, $comparison) === $comparison) { + return call_user_func($function, $value); } } return $value; } - - /** - * Get the inflector instance. - * - * @return \Doctrine\Inflector\Inflector - */ - public static function inflector() - { - if (is_null(static::$inflector)) { - static::$inflector = InflectorFactory::createForLanguage(static::$language)->build(); - } - - return static::$inflector; - } - - /** - * Specify the language that should be used by the inflector. - * - * @param string $language - * @return void - */ - public static function useLanguage(string $language) - { - static::$language = $language; - - static::$inflector = null; - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/ProcessUtils.php b/lam/lib/3rdParty/composer/illuminate/support/ProcessUtils.php deleted file mode 100644 index 165e75168..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/ProcessUtils.php +++ /dev/null @@ -1,69 +0,0 @@ - 2 && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Reflector.php b/lam/lib/3rdParty/composer/illuminate/support/Reflector.php deleted file mode 100644 index a767d5ea7..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Reflector.php +++ /dev/null @@ -1,170 +0,0 @@ -isPublic(); - } - - if (is_object($var[0]) && method_exists($class, '__call')) { - return (new ReflectionMethod($class, '__call'))->isPublic(); - } - - if (! is_object($var[0]) && method_exists($class, '__callStatic')) { - return (new ReflectionMethod($class, '__callStatic'))->isPublic(); - } - - return false; - } - - /** - * Get the class name of the given parameter's type, if possible. - * - * @param \ReflectionParameter $parameter - * @return string|null - */ - public static function getParameterClassName($parameter) - { - $type = $parameter->getType(); - - if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) { - return; - } - - return static::getTypeName($parameter, $type); - } - - /** - * Get the class names of the given parameter's type, including union types. - * - * @param \ReflectionParameter $parameter - * @return array - */ - public static function getParameterClassNames($parameter) - { - $type = $parameter->getType(); - - if (! $type instanceof ReflectionUnionType) { - return array_filter([static::getParameterClassName($parameter)]); - } - - $unionTypes = []; - - foreach ($type->getTypes() as $listedType) { - if (! $listedType instanceof ReflectionNamedType || $listedType->isBuiltin()) { - continue; - } - - $unionTypes[] = static::getTypeName($parameter, $listedType); - } - - return array_filter($unionTypes); - } - - /** - * Get the given type's class name. - * - * @param \ReflectionParameter $parameter - * @param \ReflectionNamedType $type - * @return string - */ - protected static function getTypeName($parameter, $type) - { - $name = $type->getName(); - - if (! is_null($class = $parameter->getDeclaringClass())) { - if ($name === 'self') { - return $class->getName(); - } - - if ($name === 'parent' && $parent = $class->getParentClass()) { - return $parent->getName(); - } - } - - return $name; - } - - /** - * Determine if the parameter's type is a subclass of the given type. - * - * @param \ReflectionParameter $parameter - * @param string $className - * @return bool - */ - public static function isParameterSubclassOf($parameter, $className) - { - $paramClassName = static::getParameterClassName($parameter); - - return $paramClassName - && (class_exists($paramClassName) || interface_exists($paramClassName)) - && (new ReflectionClass($paramClassName))->isSubclassOf($className); - } - - /** - * Determine if the parameter's type is a Backed Enum with a string backing type. - * - * @param \ReflectionParameter $parameter - * @return bool - */ - public static function isParameterBackedEnumWithStringBackingType($parameter) - { - if (! $parameter->getType() instanceof ReflectionNamedType) { - return false; - } - - $backedEnumClass = $parameter->getType()?->getName(); - - if (is_null($backedEnumClass)) { - return false; - } - - if (enum_exists($backedEnumClass)) { - $reflectionBackedEnum = new ReflectionEnum($backedEnumClass); - - return $reflectionBackedEnum->isBacked() - && $reflectionBackedEnum->getBackingType()->getName() == 'string'; - } - - return false; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/ServiceProvider.php b/lam/lib/3rdParty/composer/illuminate/support/ServiceProvider.php index a46ba2969..acb1a83be 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/ServiceProvider.php +++ b/lam/lib/3rdParty/composer/illuminate/support/ServiceProvider.php @@ -2,13 +2,7 @@ namespace Illuminate\Support; -use Closure; use Illuminate\Console\Application as Artisan; -use Illuminate\Contracts\Foundation\CachesConfiguration; -use Illuminate\Contracts\Foundation\CachesRoutes; -use Illuminate\Contracts\Support\DeferrableProvider; -use Illuminate\Database\Eloquent\Factory as ModelFactory; -use Illuminate\View\Compilers\BladeCompiler; abstract class ServiceProvider { @@ -20,37 +14,30 @@ abstract class ServiceProvider protected $app; /** - * All of the registered booting callbacks. + * Indicates if loading of the provider is deferred. * - * @var array + * @var bool */ - protected $bootingCallbacks = []; - - /** - * All of the registered booted callbacks. - * - * @var array - */ - protected $bootedCallbacks = []; + protected $defer = false; /** * The paths that should be published. * * @var array */ - public static $publishes = []; + protected static $publishes = []; /** * The paths that should be published by group. * * @var array */ - public static $publishGroups = []; + protected static $publishGroups = []; /** * Create a new service provider instance. * - * @param \Illuminate\Contracts\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) @@ -58,70 +45,6 @@ abstract class ServiceProvider $this->app = $app; } - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } - - /** - * Register a booting callback to be run before the "boot" method is called. - * - * @param \Closure $callback - * @return void - */ - public function booting(Closure $callback) - { - $this->bootingCallbacks[] = $callback; - } - - /** - * Register a booted callback to be run after the "boot" method is called. - * - * @param \Closure $callback - * @return void - */ - public function booted(Closure $callback) - { - $this->bootedCallbacks[] = $callback; - } - - /** - * Call the registered booting callbacks. - * - * @return void - */ - public function callBootingCallbacks() - { - $index = 0; - - while ($index < count($this->bootingCallbacks)) { - $this->app->call($this->bootingCallbacks[$index]); - - $index++; - } - } - - /** - * Call the registered booted callbacks. - * - * @return void - */ - public function callBootedCallbacks() - { - $index = 0; - - while ($index < count($this->bootedCallbacks)) { - $this->app->call($this->bootedCallbacks[$index]); - - $index++; - } - } - /** * Merge the given configuration with the existing configuration. * @@ -131,13 +54,9 @@ abstract class ServiceProvider */ protected function mergeConfigFrom($path, $key) { - if (! ($this->app instanceof CachesConfiguration && $this->app->configurationIsCached())) { - $config = $this->app->make('config'); + $config = $this->app['config']->get($key, []); - $config->set($key, array_merge( - require $path, $config->get($key, []) - )); - } + $this->app['config']->set($key, array_merge(require $path, $config)); } /** @@ -148,7 +67,7 @@ abstract class ServiceProvider */ protected function loadRoutesFrom($path) { - if (! ($this->app instanceof CachesRoutes && $this->app->routesAreCached())) { + if (! $this->app->routesAreCached()) { require $path; } } @@ -156,40 +75,17 @@ abstract class ServiceProvider /** * Register a view file namespace. * - * @param string|array $path + * @param string $path * @param string $namespace * @return void */ protected function loadViewsFrom($path, $namespace) { - $this->callAfterResolving('view', function ($view) use ($path, $namespace) { - if (isset($this->app->config['view']['paths']) && - is_array($this->app->config['view']['paths'])) { - foreach ($this->app->config['view']['paths'] as $viewPath) { - if (is_dir($appPath = $viewPath.'/vendor/'.$namespace)) { - $view->addNamespace($namespace, $appPath); - } - } - } + if (is_dir($appPath = $this->app->resourcePath().'/views/vendor/'.$namespace)) { + $this->app['view']->addNamespace($namespace, $appPath); + } - $view->addNamespace($namespace, $path); - }); - } - - /** - * Register the given view components with a custom prefix. - * - * @param string $prefix - * @param array $components - * @return void - */ - protected function loadViewComponentsAs($prefix, array $components) - { - $this->callAfterResolving(BladeCompiler::class, function ($blade) use ($prefix, $components) { - foreach ($components as $alias => $component) { - $blade->component($component, is_string($alias) ? $alias : null, $prefix); - } - }); + $this->app['view']->addNamespace($namespace, $path); } /** @@ -201,86 +97,38 @@ abstract class ServiceProvider */ protected function loadTranslationsFrom($path, $namespace) { - $this->callAfterResolving('translator', function ($translator) use ($path, $namespace) { - $translator->addNamespace($namespace, $path); - }); + $this->app['translator']->addNamespace($namespace, $path); } /** - * Register a JSON translation file path. - * - * @param string $path - * @return void - */ - protected function loadJsonTranslationsFrom($path) - { - $this->callAfterResolving('translator', function ($translator) use ($path) { - $translator->addJsonPath($path); - }); - } - - /** - * Register database migration paths. + * Register a database migration path. * * @param array|string $paths * @return void */ protected function loadMigrationsFrom($paths) { - $this->callAfterResolving('migrator', function ($migrator) use ($paths) { + $this->app->afterResolving('migrator', function ($migrator) use ($paths) { foreach ((array) $paths as $path) { $migrator->path($path); } }); } - /** - * Register Eloquent model factory paths. - * - * @deprecated Will be removed in a future Laravel version. - * - * @param array|string $paths - * @return void - */ - protected function loadFactoriesFrom($paths) - { - $this->callAfterResolving(ModelFactory::class, function ($factory) use ($paths) { - foreach ((array) $paths as $path) { - $factory->load($path); - } - }); - } - - /** - * Setup an after resolving listener, or fire immediately if already resolved. - * - * @param string $name - * @param callable $callback - * @return void - */ - protected function callAfterResolving($name, $callback) - { - $this->app->afterResolving($name, $callback); - - if ($this->app->resolved($name)) { - $callback($this->app->make($name), $this->app); - } - } - /** * Register paths to be published by the publish command. * * @param array $paths - * @param mixed $groups + * @param string $group * @return void */ - protected function publishes(array $paths, $groups = null) + protected function publishes(array $paths, $group = null) { $this->ensurePublishArrayInitialized($class = static::class); static::$publishes[$class] = array_merge(static::$publishes[$class], $paths); - foreach ((array) $groups as $group) { + if ($group) { $this->addPublishGroup($group, $paths); } } @@ -319,8 +167,8 @@ abstract class ServiceProvider /** * Get the paths to publish. * - * @param string|null $provider - * @param string|null $group + * @param string $provider + * @param string $group * @return array */ public static function pathsToPublish($provider = null, $group = null) @@ -370,26 +218,6 @@ abstract class ServiceProvider return []; } - /** - * Get the service providers available for publishing. - * - * @return array - */ - public static function publishableProviders() - { - return array_keys(static::$publishes); - } - - /** - * Get the groups available for publishing. - * - * @return array - */ - public static function publishableGroups() - { - return array_keys(static::$publishGroups); - } - /** * Register the package's custom Artisan commands. * @@ -432,16 +260,18 @@ abstract class ServiceProvider */ public function isDeferred() { - return $this instanceof DeferrableProvider; + return $this->defer; } /** - * Get the default providers for a Laravel application. + * Get a list of files that should be compiled for the package. * - * @return \Illuminate\Support\DefaultProviders + * @deprecated + * + * @return array */ - public static function defaultProviders() + public static function compiles() { - return new DefaultProviders; + return []; } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Sleep.php b/lam/lib/3rdParty/composer/illuminate/support/Sleep.php deleted file mode 100644 index 54cefe633..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Sleep.php +++ /dev/null @@ -1,483 +0,0 @@ - - */ - protected static $sequence = []; - - /** - * Indicates if the instance should sleep. - * - * @var bool - */ - protected $shouldSleep = true; - - /** - * Create a new class instance. - * - * @param int|float|\DateInterval $duration - * @return void - */ - public function __construct($duration) - { - $this->duration($duration); - } - - /** - * Sleep for the given duration. - * - * @param \DateInterval|int|float $duration - * @return static - */ - public static function for($duration) - { - return new static($duration); - } - - /** - * Sleep until the given timestamp. - * - * @param \DateTimeInterface|int|float|numeric-string $timestamp - * @return static - */ - public static function until($timestamp) - { - if (is_numeric($timestamp)) { - $timestamp = Carbon::createFromTimestamp($timestamp); - } - - return new static(Carbon::now()->diff($timestamp)); - } - - /** - * Sleep for the given number of microseconds. - * - * @param int $duration - * @return static - */ - public static function usleep($duration) - { - return (new static($duration))->microseconds(); - } - - /** - * Sleep for the given number of seconds. - * - * @param int|float $duration - * @return static - */ - public static function sleep($duration) - { - return (new static($duration))->seconds(); - } - - /** - * Sleep for the given duration. Replaces any previously defined duration. - * - * @param \DateInterval|int|float $duration - * @return $this - */ - protected function duration($duration) - { - if (! $duration instanceof DateInterval) { - $this->duration = CarbonInterval::microsecond(0); - - $this->pending = $duration; - } else { - $duration = CarbonInterval::instance($duration); - - if ($duration->totalMicroseconds < 0) { - $duration = CarbonInterval::seconds(0); - } - - $this->duration = $duration; - $this->pending = null; - } - - return $this; - } - - /** - * Sleep for the given number of minutes. - * - * @return $this - */ - public function minutes() - { - $this->duration->add('minutes', $this->pullPending()); - - return $this; - } - - /** - * Sleep for one minute. - * - * @return $this - */ - public function minute() - { - return $this->minutes(); - } - - /** - * Sleep for the given number of seconds. - * - * @return $this - */ - public function seconds() - { - $this->duration->add('seconds', $this->pullPending()); - - return $this; - } - - /** - * Sleep for one second. - * - * @return $this - */ - public function second() - { - return $this->seconds(); - } - - /** - * Sleep for the given number of milliseconds. - * - * @return $this - */ - public function milliseconds() - { - $this->duration->add('milliseconds', $this->pullPending()); - - return $this; - } - - /** - * Sleep for one millisecond. - * - * @return $this - */ - public function millisecond() - { - return $this->milliseconds(); - } - - /** - * Sleep for the given number of microseconds. - * - * @return $this - */ - public function microseconds() - { - $this->duration->add('microseconds', $this->pullPending()); - - return $this; - } - - /** - * Sleep for on microsecond. - * - * @return $this - */ - public function microsecond() - { - return $this->microseconds(); - } - - /** - * Add additional time to sleep for. - * - * @param int|float $duration - * @return $this - */ - public function and($duration) - { - $this->pending = $duration; - - return $this; - } - - /** - * Handle the object's destruction. - * - * @return void - */ - public function __destruct() - { - if (! $this->shouldSleep) { - return; - } - - if ($this->pending !== null) { - throw new RuntimeException('Unknown duration unit.'); - } - - if (static::$fake) { - static::$sequence[] = $this->duration; - - if (static::$syncWithCarbon) { - Carbon::setTestNow(Carbon::now()->add($this->duration)); - } - - foreach (static::$fakeSleepCallbacks as $callback) { - $callback($this->duration); - } - - return; - } - - $remaining = $this->duration->copy(); - - $seconds = (int) $remaining->totalSeconds; - - if ($seconds > 0) { - sleep($seconds); - - $remaining = $remaining->subSeconds($seconds); - } - - $microseconds = (int) $remaining->totalMicroseconds; - - if ($microseconds > 0) { - usleep($microseconds); - } - } - - /** - * Resolve the pending duration. - * - * @return int|float - */ - protected function pullPending() - { - if ($this->pending === null) { - $this->shouldNotSleep(); - - throw new RuntimeException('No duration specified.'); - } - - if ($this->pending < 0) { - $this->pending = 0; - } - - return tap($this->pending, function () { - $this->pending = null; - }); - } - - /** - * Stay awake and capture any attempts to sleep. - * - * @param bool $value - * @param bool $syncWithCarbon - * @return void - */ - public static function fake($value = true, $syncWithCarbon = false) - { - static::$fake = $value; - - static::$sequence = []; - static::$fakeSleepCallbacks = []; - static::$syncWithCarbon = $syncWithCarbon; - } - - /** - * Assert a given amount of sleeping occurred a specific number of times. - * - * @param \Closure $expected - * @param int $times - * @return void - */ - public static function assertSlept($expected, $times = 1) - { - $count = collect(static::$sequence)->filter($expected)->count(); - - PHPUnit::assertSame( - $times, - $count, - "The expected sleep was found [{$count}] times instead of [{$times}]." - ); - } - - /** - * Assert sleeping occurred a given number of times. - * - * @param int $expected - * @return void - */ - public static function assertSleptTimes($expected) - { - PHPUnit::assertSame($expected, $count = count(static::$sequence), "Expected [{$expected}] sleeps but found [{$count}]."); - } - - /** - * Assert the given sleep sequence was encountered. - * - * @param array $sequence - * @return void - */ - public static function assertSequence($sequence) - { - static::assertSleptTimes(count($sequence)); - - collect($sequence) - ->zip(static::$sequence) - ->eachSpread(function (?Sleep $expected, CarbonInterval $actual) { - if ($expected === null) { - return; - } - - PHPUnit::assertTrue( - $expected->shouldNotSleep()->duration->equalTo($actual), - vsprintf('Expected sleep duration of [%s] but actually slept for [%s].', [ - $expected->duration->cascade()->forHumans([ - 'options' => 0, - 'minimumUnit' => 'microsecond', - ]), - $actual->cascade()->forHumans([ - 'options' => 0, - 'minimumUnit' => 'microsecond', - ]), - ]) - ); - }); - } - - /** - * Assert that no sleeping occurred. - * - * @return void - */ - public static function assertNeverSlept() - { - return static::assertSleptTimes(0); - } - - /** - * Assert that no sleeping occurred. - * - * @return void - */ - public static function assertInsomniac() - { - if (static::$sequence === []) { - PHPUnit::assertTrue(true); - } - - foreach (static::$sequence as $duration) { - PHPUnit::assertSame(0, $duration->totalMicroseconds, vsprintf('Unexpected sleep duration of [%s] found.', [ - $duration->cascade()->forHumans([ - 'options' => 0, - 'minimumUnit' => 'microsecond', - ]), - ])); - } - } - - /** - * Indicate that the instance should not sleep. - * - * @return $this - */ - protected function shouldNotSleep() - { - $this->shouldSleep = false; - - return $this; - } - - /** - * Only sleep when the given condition is true. - * - * @param (\Closure($this): bool)|bool $condition - * @return $this - */ - public function when($condition) - { - $this->shouldSleep = (bool) value($condition, $this); - - return $this; - } - - /** - * Don't sleep when the given condition is true. - * - * @param (\Closure($this): bool)|bool $condition - * @return $this - */ - public function unless($condition) - { - return $this->when(! value($condition, $this)); - } - - /** - * Specify a callback that should be invoked when faking sleep within a test. - * - * @param callable $callback - * @return void - */ - public static function whenFakingSleep($callback) - { - static::$fakeSleepCallbacks[] = $callback; - } - - /** - * Indicate that Carbon's "now" should be kept in sync when sleeping. - * - * @return void - */ - public static function syncWithCarbon($value = true) - { - static::$syncWithCarbon = $value; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Str.php b/lam/lib/3rdParty/composer/illuminate/support/Str.php index d614ac628..3b5b33c77 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Str.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Str.php @@ -2,22 +2,7 @@ namespace Illuminate\Support; -use Closure; use Illuminate\Support\Traits\Macroable; -use JsonException; -use League\CommonMark\Environment\Environment; -use League\CommonMark\Extension\GithubFlavoredMarkdownExtension; -use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension; -use League\CommonMark\GithubFlavoredMarkdownConverter; -use League\CommonMark\MarkdownConverter; -use Ramsey\Uuid\Codec\TimestampFirstCombCodec; -use Ramsey\Uuid\Generator\CombGenerator; -use Ramsey\Uuid\Uuid; -use Ramsey\Uuid\UuidFactory; -use Symfony\Component\Uid\Ulid; -use Throwable; -use Traversable; -use voku\helper\ASCII; class Str { @@ -45,39 +30,7 @@ class Str protected static $studlyCache = []; /** - * The callback that should be used to generate UUIDs. - * - * @var callable|null - */ - protected static $uuidFactory; - - /** - * The callback that should be used to generate ULIDs. - * - * @var callable|null - */ - protected static $ulidFactory; - - /** - * The callback that should be used to generate random strings. - * - * @var callable|null - */ - protected static $randomStringFactory; - - /** - * Get a new stringable object from the given string. - * - * @param string $string - * @return \Illuminate\Support\Stringable - */ - public static function of($string) - { - return new Stringable($string); - } - - /** - * Return the remainder of a string after the first occurrence of a given value. + * Return the remainder of a string after a given value. * * @param string $subject * @param string $search @@ -85,128 +38,32 @@ class Str */ public static function after($subject, $search) { - return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0]; - } - - /** - * Return the remainder of a string after the last occurrence of a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function afterLast($subject, $search) - { - if ($search === '') { + if ($search == '') { return $subject; } - $position = strrpos($subject, (string) $search); + $pos = strpos($subject, $search); - if ($position === false) { + if ($pos === false) { return $subject; } - return substr($subject, $position + strlen($search)); + return substr($subject, $pos + strlen($search)); } /** * Transliterate a UTF-8 value to ASCII. * * @param string $value - * @param string $language * @return string */ - public static function ascii($value, $language = 'en') + public static function ascii($value) { - return ASCII::to_ascii((string) $value, $language); - } - - /** - * Transliterate a string to its closest ASCII representation. - * - * @param string $string - * @param string|null $unknown - * @param bool|null $strict - * @return string - */ - public static function transliterate($string, $unknown = '?', $strict = false) - { - return ASCII::to_transliterate($string, $unknown, $strict); - } - - /** - * Get the portion of a string before the first occurrence of a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function before($subject, $search) - { - if ($search === '') { - return $subject; + foreach (static::charsArray() as $key => $val) { + $value = str_replace($val, $key, $value); } - $result = strstr($subject, (string) $search, true); - - return $result === false ? $subject : $result; - } - - /** - * Get the portion of a string before the last occurrence of a given value. - * - * @param string $subject - * @param string $search - * @return string - */ - public static function beforeLast($subject, $search) - { - if ($search === '') { - return $subject; - } - - $pos = mb_strrpos($subject, $search); - - if ($pos === false) { - return $subject; - } - - return static::substr($subject, 0, $pos); - } - - /** - * Get the portion of a string between two given values. - * - * @param string $subject - * @param string $from - * @param string $to - * @return string - */ - public static function between($subject, $from, $to) - { - if ($from === '' || $to === '') { - return $subject; - } - - return static::beforeLast(static::after($subject, $from), $to); - } - - /** - * Get the smallest possible portion of a string between two given values. - * - * @param string $subject - * @param string $from - * @param string $to - * @return string - */ - public static function betweenFirst($subject, $from, $to) - { - if ($from === '' || $to === '') { - return $subject; - } - - return static::before(static::after($subject, $from), $to); + return preg_replace('/[^\x20-\x7E]/u', '', $value); } /** @@ -224,48 +81,17 @@ class Str return static::$camelCache[$value] = lcfirst(static::studly($value)); } - /** - * Get the character at the specified index. - * - * @param string $subject - * @param int $index - * @return string|false - */ - public static function charAt($subject, $index) - { - $length = mb_strlen($subject); - - if ($index < 0 ? $index < -$length : $index > $length - 1) { - return false; - } - - return mb_substr($subject, $index, 1); - } - /** * Determine if a given string contains a given substring. * * @param string $haystack - * @param string|iterable $needles - * @param bool $ignoreCase + * @param string|array $needles * @return bool */ - public static function contains($haystack, $needles, $ignoreCase = false) + public static function contains($haystack, $needles) { - if ($ignoreCase) { - $haystack = mb_strtolower($haystack); - } - - if (! is_iterable($needles)) { - $needles = (array) $needles; - } - - foreach ($needles as $needle) { - if ($ignoreCase) { - $needle = mb_strtolower($needle); - } - - if ($needle !== '' && str_contains($haystack, $needle)) { + foreach ((array) $needles as $needle) { + if ($needle != '' && mb_strpos($haystack, $needle) !== false) { return true; } } @@ -273,53 +99,17 @@ class Str return false; } - /** - * Determine if a given string contains all array values. - * - * @param string $haystack - * @param iterable $needles - * @param bool $ignoreCase - * @return bool - */ - public static function containsAll($haystack, $needles, $ignoreCase = false) - { - foreach ($needles as $needle) { - if (! static::contains($haystack, $needle, $ignoreCase)) { - return false; - } - } - - return true; - } - - /** - * Convert the case of a string. - * - * @param string $string - * @param int $mode - * @param string|null $encoding - * @return string - */ - public static function convertCase(string $string, int $mode = MB_CASE_FOLD, ?string $encoding = 'UTF-8') - { - return mb_convert_case($string, $mode, $encoding); - } - /** * Determine if a given string ends with a given substring. * * @param string $haystack - * @param string|iterable $needles + * @param string|array $needles * @return bool */ public static function endsWith($haystack, $needles) { - if (! is_iterable($needles)) { - $needles = (array) $needles; - } - - foreach ($needles as $needle) { - if ((string) $needle !== '' && str_ends_with($haystack, $needle)) { + foreach ((array) $needles as $needle) { + if (substr($haystack, -strlen($needle)) === (string) $needle) { return true; } } @@ -327,42 +117,6 @@ class Str return false; } - /** - * Extracts an excerpt from text that matches the first instance of a phrase. - * - * @param string $text - * @param string $phrase - * @param array $options - * @return string|null - */ - public static function excerpt($text, $phrase = '', $options = []) - { - $radius = $options['radius'] ?? 100; - $omission = $options['omission'] ?? '...'; - - preg_match('/^(.*?)('.preg_quote((string) $phrase, '/').')(.*)$/iu', (string) $text, $matches); - - if (empty($matches)) { - return null; - } - - $start = ltrim($matches[1]); - - $start = str(mb_substr($start, max(mb_strlen($start, 'UTF-8') - $radius, 0), $radius, 'UTF-8'))->ltrim()->unless( - fn ($startWithRadius) => $startWithRadius->exactly($start), - fn ($startWithRadius) => $startWithRadius->prepend($omission), - ); - - $end = rtrim($matches[3]); - - $end = str(mb_substr($end, 0, $radius, 'UTF-8'))->rtrim()->unless( - fn ($endWithRadius) => $endWithRadius->exactly($end), - fn ($endWithRadius) => $endWithRadius->append($omission), - ); - - return $start->append($matches[2], $end)->toString(); - } - /** * Cap a string with a single instance of a given value. * @@ -377,187 +131,27 @@ class Str return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; } - /** - * Wrap the string with the given strings. - * - * @param string $value - * @param string $before - * @param string|null $after - * @return string - */ - public static function wrap($value, $before, $after = null) - { - return $before.$value.($after ??= $before); - } - - /** - * Unwrap the string with the given strings. - * - * @param string $value - * @param string $before - * @param string|null $after - * @return string - */ - public static function unwrap($value, $before, $after = null) - { - if (static::startsWith($value, $before)) { - $value = static::substr($value, static::length($before)); - } - - if (static::endsWith($value, $after ??= $before)) { - $value = static::substr($value, 0, -static::length($after)); - } - - return $value; - } - /** * Determine if a given string matches a given pattern. * - * @param string|iterable $pattern + * @param string $pattern * @param string $value * @return bool */ public static function is($pattern, $value) { - $value = (string) $value; - - if (! is_iterable($pattern)) { - $pattern = [$pattern]; + if ($pattern == $value) { + return true; } - foreach ($pattern as $pattern) { - $pattern = (string) $pattern; + $pattern = preg_quote($pattern, '#'); - // If the given value is an exact match we can of course return true right - // from the beginning. Otherwise, we will translate asterisks and do an - // actual pattern match against the two strings to see if they match. - if ($pattern === $value) { - return true; - } + // Asterisks are translated into zero-or-more regular expression wildcards + // to make it convenient to check if the strings starts with the given + // pattern such as "library/*", making any string check convenient. + $pattern = str_replace('\*', '.*', $pattern); - $pattern = preg_quote($pattern, '#'); - - // Asterisks are translated into zero-or-more regular expression wildcards - // to make it convenient to check if the strings starts with the given - // pattern such as "library/*", making any string check convenient. - $pattern = str_replace('\*', '.*', $pattern); - - if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { - return true; - } - } - - return false; - } - - /** - * Determine if a given string is 7 bit ASCII. - * - * @param string $value - * @return bool - */ - public static function isAscii($value) - { - return ASCII::is_ascii((string) $value); - } - - /** - * Determine if a given value is valid JSON. - * - * @param mixed $value - * @return bool - */ - public static function isJson($value) - { - if (! is_string($value)) { - return false; - } - - if (function_exists('json_validate')) { - return json_validate($value, 512); - } - - try { - json_decode($value, true, 512, JSON_THROW_ON_ERROR); - } catch (JsonException) { - return false; - } - - return true; - } - - /** - * Determine if a given value is a valid URL. - * - * @param mixed $value - * @param array $protocols - * @return bool - */ - public static function isUrl($value, array $protocols = []) - { - if (! is_string($value)) { - return false; - } - - $protocolList = empty($protocols) - ? 'aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|tg|things|thismessage|tip|tn3270|tool|ts3server|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s' - : implode('|', $protocols); - - /* - * This pattern is derived from Symfony\Component\Validator\Constraints\UrlValidator (5.0.7). - * - * (c) Fabien Potencier http://symfony.com - */ - $pattern = '~^ - (LARAVEL_PROTOCOLS):// # protocol - (((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+)@)? # basic auth - ( - ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name - | # or - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address - | # or - \[ - (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::)))) - \] # an IPv6 address - ) - (:[0-9]+)? # a port (optional) - (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})* )* # a path - (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a query (optional) - (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a fragment (optional) - $~ixu'; - - return preg_match(str_replace('LARAVEL_PROTOCOLS', $protocolList, $pattern), $value) > 0; - } - - /** - * Determine if a given value is a valid UUID. - * - * @param mixed $value - * @return bool - */ - public static function isUuid($value) - { - if (! is_string($value)) { - return false; - } - - return preg_match('/^[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}$/D', $value) > 0; - } - - /** - * Determine if a given value is a valid ULID. - * - * @param mixed $value - * @return bool - */ - public static function isUlid($value) - { - if (! is_string($value)) { - return false; - } - - return Ulid::isValid($value); + return (bool) preg_match('#^'.$pattern.'\z#u', $value); } /** @@ -575,19 +169,23 @@ class Str * Return the length of the given string. * * @param string $value - * @param string|null $encoding + * @param string $encoding * @return int */ public static function length($value, $encoding = null) { - return mb_strlen($value, $encoding); + if ($encoding) { + return mb_strlen($value, $encoding); + } + + return mb_strlen($value); } /** * Limit the number of characters in a string. * * @param string $value - * @param int $limit + * @param int $limit * @param string $end * @return string */ @@ -615,7 +213,7 @@ class Str * Limit the number of words in a string. * * @param string $value - * @param int $words + * @param int $words * @param string $end * @return string */ @@ -631,217 +229,14 @@ class Str } /** - * Converts GitHub flavored Markdown into HTML. - * - * @param string $string - * @param array $options - * @return string - */ - public static function markdown($string, array $options = []) - { - $converter = new GithubFlavoredMarkdownConverter($options); - - return (string) $converter->convert($string); - } - - /** - * Converts inline Markdown into HTML. - * - * @param string $string - * @param array $options - * @return string - */ - public static function inlineMarkdown($string, array $options = []) - { - $environment = new Environment($options); - - $environment->addExtension(new GithubFlavoredMarkdownExtension()); - $environment->addExtension(new InlinesOnlyExtension()); - - $converter = new MarkdownConverter($environment); - - return (string) $converter->convert($string); - } - - /** - * Masks a portion of a string with a repeated character. - * - * @param string $string - * @param string $character - * @param int $index - * @param int|null $length - * @param string $encoding - * @return string - */ - public static function mask($string, $character, $index, $length = null, $encoding = 'UTF-8') - { - if ($character === '') { - return $string; - } - - $segment = mb_substr($string, $index, $length, $encoding); - - if ($segment === '') { - return $string; - } - - $strlen = mb_strlen($string, $encoding); - $startIndex = $index; - - if ($index < 0) { - $startIndex = $index < -$strlen ? 0 : $strlen + $index; - } - - $start = mb_substr($string, 0, $startIndex, $encoding); - $segmentLen = mb_strlen($segment, $encoding); - $end = mb_substr($string, $startIndex + $segmentLen); - - return $start.str_repeat(mb_substr($character, 0, 1, $encoding), $segmentLen).$end; - } - - /** - * Get the string matching the given pattern. - * - * @param string $pattern - * @param string $subject - * @return string - */ - public static function match($pattern, $subject) - { - preg_match($pattern, $subject, $matches); - - if (! $matches) { - return ''; - } - - return $matches[1] ?? $matches[0]; - } - - /** - * Determine if a given string matches a given pattern. - * - * @param string|iterable $pattern - * @param string $value - * @return bool - */ - public static function isMatch($pattern, $value) - { - $value = (string) $value; - - if (! is_iterable($pattern)) { - $pattern = [$pattern]; - } - - foreach ($pattern as $pattern) { - $pattern = (string) $pattern; - - if (preg_match($pattern, $value) === 1) { - return true; - } - } - - return false; - } - - /** - * Get the string matching the given pattern. - * - * @param string $pattern - * @param string $subject - * @return \Illuminate\Support\Collection - */ - public static function matchAll($pattern, $subject) - { - preg_match_all($pattern, $subject, $matches); - - if (empty($matches[0])) { - return collect(); - } - - return collect($matches[1] ?? $matches[0]); - } - - /** - * Pad both sides of a string with another. - * - * @param string $value - * @param int $length - * @param string $pad - * @return string - */ - public static function padBoth($value, $length, $pad = ' ') - { - if (function_exists('mb_str_pad')) { - return mb_str_pad($value, $length, $pad, STR_PAD_BOTH); - } - - $short = max(0, $length - mb_strlen($value)); - $shortLeft = floor($short / 2); - $shortRight = ceil($short / 2); - - return mb_substr(str_repeat($pad, $shortLeft), 0, $shortLeft). - $value. - mb_substr(str_repeat($pad, $shortRight), 0, $shortRight); - } - - /** - * Pad the left side of a string with another. - * - * @param string $value - * @param int $length - * @param string $pad - * @return string - */ - public static function padLeft($value, $length, $pad = ' ') - { - if (function_exists('mb_str_pad')) { - return mb_str_pad($value, $length, $pad, STR_PAD_LEFT); - } - - $short = max(0, $length - mb_strlen($value)); - - return mb_substr(str_repeat($pad, $short), 0, $short).$value; - } - - /** - * Pad the right side of a string with another. - * - * @param string $value - * @param int $length - * @param string $pad - * @return string - */ - public static function padRight($value, $length, $pad = ' ') - { - if (function_exists('mb_str_pad')) { - return mb_str_pad($value, $length, $pad, STR_PAD_RIGHT); - } - - $short = max(0, $length - mb_strlen($value)); - - return $value.mb_substr(str_repeat($pad, $short), 0, $short); - } - - /** - * Parse a Class[@]method style callback into class and method. + * Parse a Class@method style callback into class and method. * * @param string $callback * @param string|null $default - * @return array + * @return array */ public static function parseCallback($callback, $default = null) { - if (static::contains($callback, "@anonymous\0")) { - if (static::substrCount($callback, '@') > 1) { - return [ - static::beforeLast($callback, '@'), - static::afterLast($callback, '@'), - ]; - } - - return [$callback, $default]; - } - return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default]; } @@ -849,7 +244,7 @@ class Str * Get the plural form of an English word. * * @param string $value - * @param int|array|\Countable $count + * @param int $count * @return string */ public static function plural($value, $count = 2) @@ -857,77 +252,6 @@ class Str return Pluralizer::plural($value, $count); } - /** - * Pluralize the last word of an English, studly caps case string. - * - * @param string $value - * @param int|array|\Countable $count - * @return string - */ - public static function pluralStudly($value, $count = 2) - { - $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); - - $lastWord = array_pop($parts); - - return implode('', $parts).self::plural($lastWord, $count); - } - - /** - * Generate a random, secure password. - * - * @param int $length - * @param bool $letters - * @param bool $numbers - * @param bool $symbols - * @param bool $spaces - * @return string - */ - public static function password($length = 32, $letters = true, $numbers = true, $symbols = true, $spaces = false) - { - $password = new Collection(); - - $options = (new Collection([ - 'letters' => $letters === true ? [ - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - ] : null, - 'numbers' => $numbers === true ? [ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - ] : null, - 'symbols' => $symbols === true ? [ - '~', '!', '#', '$', '%', '^', '&', '*', '(', ')', '-', - '_', '.', ',', '<', '>', '?', '/', '\\', '{', '}', '[', - ']', '|', ':', ';', - ] : null, - 'spaces' => $spaces === true ? [' '] : null, - ]))->filter()->each(fn ($c) => $password->push($c[random_int(0, count($c) - 1)]) - )->flatten(); - - $length = $length - $password->count(); - - return $password->merge($options->pipe( - fn ($c) => Collection::times($length, fn () => $c[random_int(0, $c->count() - 1)]) - ))->shuffle()->implode(''); - } - - /** - * Find the multi-byte safe position of the first occurrence of a given substring in a string. - * - * @param string $haystack - * @param string $needle - * @param int $offset - * @param string|null $encoding - * @return int|false - */ - public static function position($haystack, $needle, $offset = 0, $encoding = null) - { - return mb_strpos($haystack, (string) $needle, $offset, $encoding); - } - /** * Generate a more truly "random" alpha-numeric string. * @@ -936,157 +260,55 @@ class Str */ public static function random($length = 16) { - return (static::$randomStringFactory ?? function ($length) { - $string = ''; + $string = ''; - while (($len = strlen($string)) < $length) { - $size = $length - $len; + while (($len = strlen($string)) < $length) { + $size = $length - $len; - $bytesSize = (int) ceil($size / 3) * 3; + $bytes = random_bytes($size); - $bytes = random_bytes($bytesSize); + $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size); + } - $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size); - } - - return $string; - })($length); + return $string; } /** - * Set the callable that will be used to generate random strings. + * Generate a "random" alpha-numeric string. * - * @param callable|null $factory - * @return void - */ - public static function createRandomStringsUsing(?callable $factory = null) - { - static::$randomStringFactory = $factory; - } - - /** - * Set the sequence that will be used to generate random strings. + * Should not be considered sufficient for cryptography, etc. * - * @param array $sequence - * @param callable|null $whenMissing - * @return void - */ - public static function createRandomStringsUsingSequence(array $sequence, $whenMissing = null) - { - $next = 0; - - $whenMissing ??= function ($length) use (&$next) { - $factoryCache = static::$randomStringFactory; - - static::$randomStringFactory = null; - - $randomString = static::random($length); - - static::$randomStringFactory = $factoryCache; - - $next++; - - return $randomString; - }; - - static::createRandomStringsUsing(function ($length) use (&$next, $sequence, $whenMissing) { - if (array_key_exists($next, $sequence)) { - return $sequence[$next++]; - } - - return $whenMissing($length); - }); - } - - /** - * Indicate that random strings should be created normally and not using a custom factory. + * @deprecated since version 5.3. Use the "random" method directly. * - * @return void - */ - public static function createRandomStringsNormally() - { - static::$randomStringFactory = null; - } - - /** - * Repeat the given string. - * - * @param string $string - * @param int $times + * @param int $length * @return string */ - public static function repeat(string $string, int $times) + public static function quickRandom($length = 16) { - return str_repeat($string, $times); + if (PHP_MAJOR_VERSION > 5) { + return static::random($length); + } + + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + return substr(str_shuffle(str_repeat($pool, $length)), 0, $length); } /** * Replace a given value in the string sequentially with an array. * * @param string $search - * @param iterable $replace + * @param array $replace * @param string $subject * @return string */ - public static function replaceArray($search, $replace, $subject) + public static function replaceArray($search, array $replace, $subject) { - if ($replace instanceof Traversable) { - $replace = collect($replace)->all(); + foreach ($replace as $value) { + $subject = static::replaceFirst($search, $value, $subject); } - $segments = explode($search, $subject); - - $result = array_shift($segments); - - foreach ($segments as $segment) { - $result .= self::toStringOr(array_shift($replace) ?? $search, $search).$segment; - } - - return $result; - } - - /** - * Convert the given value to a string or return the given fallback on failure. - * - * @param mixed $value - * @param string $fallback - * @return string - */ - private static function toStringOr($value, $fallback) - { - try { - return (string) $value; - } catch (Throwable $e) { - return $fallback; - } - } - - /** - * Replace the given value in the given string. - * - * @param string|iterable $search - * @param string|iterable $replace - * @param string|iterable $subject - * @param bool $caseSensitive - * @return string|string[] - */ - public static function replace($search, $replace, $subject, $caseSensitive = true) - { - if ($search instanceof Traversable) { - $search = collect($search)->all(); - } - - if ($replace instanceof Traversable) { - $replace = collect($replace)->all(); - } - - if ($subject instanceof Traversable) { - $subject = collect($subject)->all(); - } - - return $caseSensitive - ? str_replace($search, $replace, $subject) - : str_ireplace($search, $replace, $subject); + return $subject; } /** @@ -1099,9 +321,7 @@ class Str */ public static function replaceFirst($search, $replace, $subject) { - $search = (string) $search; - - if ($search === '') { + if ($search == '') { return $subject; } @@ -1114,29 +334,6 @@ class Str return $subject; } - /** - * Replace the first occurrence of the given value if it appears at the start of the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - */ - public static function replaceStart($search, $replace, $subject) - { - $search = (string) $search; - - if ($search === '') { - return $subject; - } - - if (static::startsWith($subject, $search)) { - return static::replaceFirst($search, $replace, $subject); - } - - return $subject; - } - /** * Replace the last occurrence of a given value in the string. * @@ -1147,12 +344,6 @@ class Str */ public static function replaceLast($search, $replace, $subject) { - $search = (string) $search; - - if ($search === '') { - return $subject; - } - $position = strrpos($subject, $search); if ($position !== false) { @@ -1162,77 +353,6 @@ class Str return $subject; } - /** - * Replace the last occurrence of a given value if it appears at the end of the string. - * - * @param string $search - * @param string $replace - * @param string $subject - * @return string - */ - public static function replaceEnd($search, $replace, $subject) - { - $search = (string) $search; - - if ($search === '') { - return $subject; - } - - if (static::endsWith($subject, $search)) { - return static::replaceLast($search, $replace, $subject); - } - - return $subject; - } - - /** - * Replace the patterns matching the given regular expression. - * - * @param array|string $pattern - * @param \Closure|string $replace - * @param array|string $subject - * @param int $limit - * @return string|string[]|null - */ - public static function replaceMatches($pattern, $replace, $subject, $limit = -1) - { - if ($replace instanceof Closure) { - return preg_replace_callback($pattern, $replace, $subject, $limit); - } - - return preg_replace($pattern, $replace, $subject, $limit); - } - - /** - * Remove any occurrence of the given string in the subject. - * - * @param string|iterable $search - * @param string|iterable $subject - * @param bool $caseSensitive - * @return string - */ - public static function remove($search, $subject, $caseSensitive = true) - { - if ($search instanceof Traversable) { - $search = collect($search)->all(); - } - - return $caseSensitive - ? str_replace($search, '', $subject) - : str_ireplace($search, '', $subject); - } - - /** - * Reverse the given string. - * - * @param string $value - * @return string - */ - public static function reverse(string $value) - { - return implode(array_reverse(mb_str_split($value))); - } - /** * Begin a string with a single instance of a given value. * @@ -1259,7 +379,7 @@ class Str } /** - * Convert the given string to proper case. + * Convert the given string to title case. * * @param string $value * @return string @@ -1269,76 +389,6 @@ class Str return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); } - /** - * Convert the given string to proper case for each word. - * - * @param string $value - * @return string - */ - public static function headline($value) - { - $parts = explode(' ', $value); - - $parts = count($parts) > 1 - ? array_map([static::class, 'title'], $parts) - : array_map([static::class, 'title'], static::ucsplit(implode('_', $parts))); - - $collapsed = static::replace(['-', '_', ' '], '_', implode('_', $parts)); - - return implode(' ', array_filter(explode('_', $collapsed))); - } - - /** - * Convert the given string to APA-style title case. - * - * See: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case - * - * @param string $value - * @return string - */ - public static function apa($value) - { - if (trim($value) === '') { - return $value; - } - - $minorWords = [ - 'and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet', 'a', 'an', - 'the', 'at', 'by', 'for', 'in', 'of', 'off', 'on', 'per', 'to', 'up', 'via', - 'et', 'ou', 'un', 'une', 'la', 'le', 'les', 'de', 'du', 'des', 'par', 'à', - ]; - - $endPunctuation = ['.', '!', '?', ':', '—', ',']; - - $words = preg_split('/\s+/', $value, -1, PREG_SPLIT_NO_EMPTY); - - for ($i = 0; $i < count($words); $i++) { - $lowercaseWord = mb_strtolower($words[$i]); - - if (str_contains($lowercaseWord, '-')) { - $hyphenatedWords = explode('-', $lowercaseWord); - - $hyphenatedWords = array_map(function ($part) use ($minorWords) { - return (in_array($part, $minorWords) && mb_strlen($part) <= 3) - ? $part - : mb_strtoupper(mb_substr($part, 0, 1)).mb_substr($part, 1); - }, $hyphenatedWords); - - $words[$i] = implode('-', $hyphenatedWords); - } else { - if (in_array($lowercaseWord, $minorWords) && - mb_strlen($lowercaseWord) <= 3 && - ! ($i === 0 || in_array(mb_substr($words[$i - 1], -1), $endPunctuation))) { - $words[$i] = $lowercaseWord; - } else { - $words[$i] = mb_strtoupper(mb_substr($lowercaseWord, 0, 1)).mb_substr($lowercaseWord, 1); - } - } - } - - return implode(' ', $words); - } - /** * Get the singular form of an English word. * @@ -1355,28 +405,19 @@ class Str * * @param string $title * @param string $separator - * @param string|null $language - * @param array $dictionary * @return string */ - public static function slug($title, $separator = '-', $language = 'en', $dictionary = ['@' => 'at']) + public static function slug($title, $separator = '-') { - $title = $language ? static::ascii($title, $language) : $title; + $title = static::ascii($title); // Convert all dashes/underscores into separator - $flip = $separator === '-' ? '_' : '-'; + $flip = $separator == '-' ? '_' : '-'; $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); - // Replace dictionary words - foreach ($dictionary as $key => $value) { - $dictionary[$key] = $separator.$value.$separator; - } - - $title = str_replace(array_keys($dictionary), array_values($dictionary), $title); - - // Remove all characters that are not the separator, letters, numbers, or whitespace - $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title)); + // Remove all characters that are not the separator, letters, numbers, or whitespace. + $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', mb_strtolower($title)); // Replace all separator characters and whitespace by a single separator $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); @@ -1400,7 +441,7 @@ class Str } if (! ctype_lower($value)) { - $value = preg_replace('/\s+/u', '', ucwords($value)); + $value = preg_replace('/\s+/u', '', $value); $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); } @@ -1408,32 +449,17 @@ class Str return static::$snakeCache[$key][$delimiter] = $value; } - /** - * Remove all "extra" blank space from the given string. - * - * @param string $value - * @return string - */ - public static function squish($value) - { - return preg_replace('~(\s|\x{3164}|\x{1160})+~u', ' ', preg_replace('~^[\s\x{FEFF}]+|[\s\x{FEFF}]+$~u', '', $value)); - } - /** * Determine if a given string starts with a given substring. * * @param string $haystack - * @param string|iterable $needles + * @param string|array $needles * @return bool */ public static function startsWith($haystack, $needles) { - if (! is_iterable($needles)) { - $needles = [$needles]; - } - - foreach ($needles as $needle) { - if ((string) $needle !== '' && str_starts_with($haystack, $needle)) { + foreach ((array) $needles as $needle) { + if ($needle != '' && substr($haystack, 0, strlen($needle)) === (string) $needle) { return true; } } @@ -1455,123 +481,22 @@ class Str return static::$studlyCache[$key]; } - $words = explode(' ', static::replace(['-', '_'], ' ', $value)); + $value = ucwords(str_replace(['-', '_'], ' ', $value)); - $studlyWords = array_map(fn ($word) => static::ucfirst($word), $words); - - return static::$studlyCache[$key] = implode($studlyWords); + return static::$studlyCache[$key] = str_replace(' ', '', $value); } /** - * Returns the portion of the string specified by the start and length parameters. + * Returns the portion of string specified by the start and length parameters. * * @param string $string * @param int $start * @param int|null $length - * @param string $encoding * @return string */ - public static function substr($string, $start, $length = null, $encoding = 'UTF-8') + public static function substr($string, $start, $length = null) { - return mb_substr($string, $start, $length, $encoding); - } - - /** - * Returns the number of substring occurrences. - * - * @param string $haystack - * @param string $needle - * @param int $offset - * @param int|null $length - * @return int - */ - public static function substrCount($haystack, $needle, $offset = 0, $length = null) - { - if (! is_null($length)) { - return substr_count($haystack, $needle, $offset, $length); - } - - return substr_count($haystack, $needle, $offset); - } - - /** - * Replace text within a portion of a string. - * - * @param string|string[] $string - * @param string|string[] $replace - * @param int|int[] $offset - * @param int|int[]|null $length - * @return string|string[] - */ - public static function substrReplace($string, $replace, $offset = 0, $length = null) - { - if ($length === null) { - $length = strlen($string); - } - - return substr_replace($string, $replace, $offset, $length); - } - - /** - * Swap multiple keywords in a string with other keywords. - * - * @param array $map - * @param string $subject - * @return string - */ - public static function swap(array $map, $subject) - { - return strtr($subject, $map); - } - - /** - * Take the first or last {$limit} characters of a string. - * - * @param string $string - * @param int $limit - * @return string - */ - public static function take($string, int $limit): string - { - if ($limit < 0) { - return static::substr($string, $limit); - } - - return static::substr($string, 0, $limit); - } - - /** - * Convert the given string to Base64 encoding. - * - * @param string $string - * @return string - */ - public static function toBase64($string): string - { - return base64_encode($string); - } - - /** - * Decode the given Base64 encoded string. - * - * @param string $string - * @param bool $strict - * @return string|false - */ - public static function fromBase64($string, $strict = false) - { - return base64_decode($string, $strict); - } - - /** - * Make a string's first character lowercase. - * - * @param string $string - * @return string - */ - public static function lcfirst($string) - { - return static::lower(static::substr($string, 0, 1)).static::substr($string, 1); + return mb_substr($string, $start, $length, 'UTF-8'); } /** @@ -1586,263 +511,136 @@ class Str } /** - * Split a string into pieces by uppercase characters. + * Returns the replacements for the ascii method. * - * @param string $string - * @return string[] + * Note: Adapted from Stringy\Stringy. + * + * @see https://github.com/danielstjules/Stringy/blob/2.3.1/LICENSE.txt + * + * @return array */ - public static function ucsplit($string) + protected static function charsArray() { - return preg_split('/(?=\p{Lu})/u', $string, -1, PREG_SPLIT_NO_EMPTY); - } + static $charsArray; - /** - * Get the number of words a string contains. - * - * @param string $string - * @param string|null $characters - * @return int - */ - public static function wordCount($string, $characters = null) - { - return str_word_count($string, 0, $characters); - } - - /** - * Wrap a string to a given number of characters. - * - * @param string $string - * @param int $characters - * @param string $break - * @param bool $cutLongWords - * @return string - */ - public static function wordWrap($string, $characters = 75, $break = "\n", $cutLongWords = false) - { - return wordwrap($string, $characters, $break, $cutLongWords); - } - - /** - * Generate a UUID (version 4). - * - * @return \Ramsey\Uuid\UuidInterface - */ - public static function uuid() - { - return static::$uuidFactory - ? call_user_func(static::$uuidFactory) - : Uuid::uuid4(); - } - - /** - * Generate a time-ordered UUID. - * - * @return \Ramsey\Uuid\UuidInterface - */ - public static function orderedUuid() - { - if (static::$uuidFactory) { - return call_user_func(static::$uuidFactory); + if (isset($charsArray)) { + return $charsArray; } - $factory = new UuidFactory; - - $factory->setRandomGenerator(new CombGenerator( - $factory->getRandomGenerator(), - $factory->getNumberConverter() - )); - - $factory->setCodec(new TimestampFirstCombCodec( - $factory->getUuidBuilder() - )); - - return $factory->uuid4(); - } - - /** - * Set the callable that will be used to generate UUIDs. - * - * @param callable|null $factory - * @return void - */ - public static function createUuidsUsing(?callable $factory = null) - { - static::$uuidFactory = $factory; - } - - /** - * Set the sequence that will be used to generate UUIDs. - * - * @param array $sequence - * @param callable|null $whenMissing - * @return void - */ - public static function createUuidsUsingSequence(array $sequence, $whenMissing = null) - { - $next = 0; - - $whenMissing ??= function () use (&$next) { - $factoryCache = static::$uuidFactory; - - static::$uuidFactory = null; - - $uuid = static::uuid(); - - static::$uuidFactory = $factoryCache; - - $next++; - - return $uuid; - }; - - static::createUuidsUsing(function () use (&$next, $sequence, $whenMissing) { - if (array_key_exists($next, $sequence)) { - return $sequence[$next++]; - } - - return $whenMissing(); - }); - } - - /** - * Always return the same UUID when generating new UUIDs. - * - * @param \Closure|null $callback - * @return \Ramsey\Uuid\UuidInterface - */ - public static function freezeUuids(?Closure $callback = null) - { - $uuid = Str::uuid(); - - Str::createUuidsUsing(fn () => $uuid); - - if ($callback !== null) { - try { - $callback($uuid); - } finally { - Str::createUuidsNormally(); - } - } - - return $uuid; - } - - /** - * Indicate that UUIDs should be created normally and not using a custom factory. - * - * @return void - */ - public static function createUuidsNormally() - { - static::$uuidFactory = null; - } - - /** - * Generate a ULID. - * - * @param \DateTimeInterface|null $time - * @return \Symfony\Component\Uid\Ulid - */ - public static function ulid($time = null) - { - if (static::$ulidFactory) { - return call_user_func(static::$ulidFactory); - } - - if ($time === null) { - return new Ulid(); - } - - return new Ulid(Ulid::generate($time)); - } - - /** - * Indicate that ULIDs should be created normally and not using a custom factory. - * - * @return void - */ - public static function createUlidsNormally() - { - static::$ulidFactory = null; - } - - /** - * Set the callable that will be used to generate ULIDs. - * - * @param callable|null $factory - * @return void - */ - public static function createUlidsUsing(?callable $factory = null) - { - static::$ulidFactory = $factory; - } - - /** - * Set the sequence that will be used to generate ULIDs. - * - * @param array $sequence - * @param callable|null $whenMissing - * @return void - */ - public static function createUlidsUsingSequence(array $sequence, $whenMissing = null) - { - $next = 0; - - $whenMissing ??= function () use (&$next) { - $factoryCache = static::$ulidFactory; - - static::$ulidFactory = null; - - $ulid = static::ulid(); - - static::$ulidFactory = $factoryCache; - - $next++; - - return $ulid; - }; - - static::createUlidsUsing(function () use (&$next, $sequence, $whenMissing) { - if (array_key_exists($next, $sequence)) { - return $sequence[$next++]; - } - - return $whenMissing(); - }); - } - - /** - * Always return the same ULID when generating new ULIDs. - * - * @param Closure|null $callback - * @return Ulid - */ - public static function freezeUlids(?Closure $callback = null) - { - $ulid = Str::ulid(); - - Str::createUlidsUsing(fn () => $ulid); - - if ($callback !== null) { - try { - $callback($ulid); - } finally { - Str::createUlidsNormally(); - } - } - - return $ulid; - } - - /** - * Remove all strings from the casing caches. - * - * @return void - */ - public static function flushCache() - { - static::$snakeCache = []; - static::$camelCache = []; - static::$studlyCache = []; + return $charsArray = [ + '0' => ['°', '₀', '۰'], + '1' => ['¹', '₁', '۱'], + '2' => ['²', '₂', '۲'], + '3' => ['³', '₃', '۳'], + '4' => ['⁴', '₄', '۴', '٤'], + '5' => ['⁵', '₅', '۵', '٥'], + '6' => ['⁶', '₆', '۶', '٦'], + '7' => ['⁷', '₇', '۷'], + '8' => ['⁸', '₈', '۸'], + '9' => ['⁹', '₉', '۹'], + 'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا'], + 'b' => ['б', 'β', 'Ъ', 'Ь', 'ب', 'ဗ', 'ბ'], + 'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ'], + 'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ'], + 'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ'], + 'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ'], + 'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ'], + 'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ'], + 'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', 'इ'], + 'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج'], + 'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', 'ک'], + 'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ'], + 'm' => ['м', 'μ', 'م', 'မ', 'მ'], + 'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ'], + 'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ'], + 'p' => ['п', 'π', 'ပ', 'პ', 'پ'], + 'q' => ['ყ'], + 'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ'], + 's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს'], + 't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ'], + 'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ'], + 'v' => ['в', 'ვ', 'ϐ'], + 'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ'], + 'x' => ['χ', 'ξ'], + 'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ'], + 'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ'], + 'aa' => ['ع', 'आ', 'آ'], + 'ae' => ['ä', 'æ', 'ǽ'], + 'ai' => ['ऐ'], + 'at' => ['@'], + 'ch' => ['ч', 'ჩ', 'ჭ', 'چ'], + 'dj' => ['ђ', 'đ'], + 'dz' => ['џ', 'ძ'], + 'ei' => ['ऍ'], + 'gh' => ['غ', 'ღ'], + 'ii' => ['ई'], + 'ij' => ['ij'], + 'kh' => ['х', 'خ', 'ხ'], + 'lj' => ['љ'], + 'nj' => ['њ'], + 'oe' => ['ö', 'œ', 'ؤ'], + 'oi' => ['ऑ'], + 'oii' => ['ऒ'], + 'ps' => ['ψ'], + 'sh' => ['ш', 'შ', 'ش'], + 'shch' => ['щ'], + 'ss' => ['ß'], + 'sx' => ['ŝ'], + 'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'], + 'ts' => ['ц', 'ც', 'წ'], + 'ue' => ['ü'], + 'uu' => ['ऊ'], + 'ya' => ['я'], + 'yu' => ['ю'], + 'zh' => ['ж', 'ჟ', 'ژ'], + '(c)' => ['©'], + 'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ'], + 'B' => ['Б', 'Β', 'ब'], + 'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'], + 'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'], + 'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə'], + 'F' => ['Ф', 'Φ'], + 'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'], + 'H' => ['Η', 'Ή', 'Ħ'], + 'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ'], + 'K' => ['К', 'Κ'], + 'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल'], + 'M' => ['М', 'Μ'], + 'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'], + 'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ'], + 'P' => ['П', 'Π'], + 'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ'], + 'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'], + 'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'], + 'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', 'Ǘ', 'Ǚ', 'Ǜ'], + 'V' => ['В'], + 'W' => ['Ω', 'Ώ', 'Ŵ'], + 'X' => ['Χ', 'Ξ'], + 'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ'], + 'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ'], + 'AE' => ['Ä', 'Æ', 'Ǽ'], + 'CH' => ['Ч'], + 'DJ' => ['Ђ'], + 'DZ' => ['Џ'], + 'GX' => ['Ĝ'], + 'HX' => ['Ĥ'], + 'IJ' => ['IJ'], + 'JX' => ['Ĵ'], + 'KH' => ['Х'], + 'LJ' => ['Љ'], + 'NJ' => ['Њ'], + 'OE' => ['Ö', 'Œ'], + 'PS' => ['Ψ'], + 'SH' => ['Ш'], + 'SHCH' => ['Щ'], + 'SS' => ['ẞ'], + 'TH' => ['Þ'], + 'TS' => ['Ц'], + 'UE' => ['Ü'], + 'YA' => ['Я'], + 'YU' => ['Ю'], + 'ZH' => ['Ж'], + ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"], + ]; } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Stringable.php b/lam/lib/3rdParty/composer/illuminate/support/Stringable.php deleted file mode 100644 index 3a37ff11e..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Stringable.php +++ /dev/null @@ -1,1439 +0,0 @@ -value = (string) $value; - } - - /** - * Return the remainder of a string after the first occurrence of a given value. - * - * @param string $search - * @return static - */ - public function after($search) - { - return new static(Str::after($this->value, $search)); - } - - /** - * Return the remainder of a string after the last occurrence of a given value. - * - * @param string $search - * @return static - */ - public function afterLast($search) - { - return new static(Str::afterLast($this->value, $search)); - } - - /** - * Append the given values to the string. - * - * @param array|string ...$values - * @return static - */ - public function append(...$values) - { - return new static($this->value.implode('', $values)); - } - - /** - * Append a new line to the string. - * - * @param int $count - * @return $this - */ - public function newLine($count = 1) - { - return $this->append(str_repeat(PHP_EOL, $count)); - } - - /** - * Transliterate a UTF-8 value to ASCII. - * - * @param string $language - * @return static - */ - public function ascii($language = 'en') - { - return new static(Str::ascii($this->value, $language)); - } - - /** - * Get the trailing name component of the path. - * - * @param string $suffix - * @return static - */ - public function basename($suffix = '') - { - return new static(basename($this->value, $suffix)); - } - - /** - * Get the character at the specified index. - * - * @param int $index - * @return string|false - */ - public function charAt($index) - { - return Str::charAt($this->value, $index); - } - - /** - * Get the basename of the class path. - * - * @return static - */ - public function classBasename() - { - return new static(class_basename($this->value)); - } - - /** - * Get the portion of a string before the first occurrence of a given value. - * - * @param string $search - * @return static - */ - public function before($search) - { - return new static(Str::before($this->value, $search)); - } - - /** - * Get the portion of a string before the last occurrence of a given value. - * - * @param string $search - * @return static - */ - public function beforeLast($search) - { - return new static(Str::beforeLast($this->value, $search)); - } - - /** - * Get the portion of a string between two given values. - * - * @param string $from - * @param string $to - * @return static - */ - public function between($from, $to) - { - return new static(Str::between($this->value, $from, $to)); - } - - /** - * Get the smallest possible portion of a string between two given values. - * - * @param string $from - * @param string $to - * @return static - */ - public function betweenFirst($from, $to) - { - return new static(Str::betweenFirst($this->value, $from, $to)); - } - - /** - * Convert a value to camel case. - * - * @return static - */ - public function camel() - { - return new static(Str::camel($this->value)); - } - - /** - * Determine if a given string contains a given substring. - * - * @param string|iterable $needles - * @param bool $ignoreCase - * @return bool - */ - public function contains($needles, $ignoreCase = false) - { - return Str::contains($this->value, $needles, $ignoreCase); - } - - /** - * Determine if a given string contains all array values. - * - * @param iterable $needles - * @param bool $ignoreCase - * @return bool - */ - public function containsAll($needles, $ignoreCase = false) - { - return Str::containsAll($this->value, $needles, $ignoreCase); - } - - /** - * Convert the case of a string. - * - * @param int $mode - * @param string|null $encoding - * @return static - */ - public function convertCase(int $mode = MB_CASE_FOLD, ?string $encoding = 'UTF-8') - { - return new static(Str::convertCase($this->value, $mode, $encoding)); - } - - /** - * Get the parent directory's path. - * - * @param int $levels - * @return static - */ - public function dirname($levels = 1) - { - return new static(dirname($this->value, $levels)); - } - - /** - * Determine if a given string ends with a given substring. - * - * @param string|iterable $needles - * @return bool - */ - public function endsWith($needles) - { - return Str::endsWith($this->value, $needles); - } - - /** - * Determine if the string is an exact match with the given value. - * - * @param \Illuminate\Support\Stringable|string $value - * @return bool - */ - public function exactly($value) - { - if ($value instanceof Stringable) { - $value = $value->toString(); - } - - return $this->value === $value; - } - - /** - * Extracts an excerpt from text that matches the first instance of a phrase. - * - * @param string $phrase - * @param array $options - * @return string|null - */ - public function excerpt($phrase = '', $options = []) - { - return Str::excerpt($this->value, $phrase, $options); - } - - /** - * Explode the string into an array. - * - * @param string $delimiter - * @param int $limit - * @return \Illuminate\Support\Collection - */ - public function explode($delimiter, $limit = PHP_INT_MAX) - { - return collect(explode($delimiter, $this->value, $limit)); - } - - /** - * Split a string using a regular expression or by length. - * - * @param string|int $pattern - * @param int $limit - * @param int $flags - * @return \Illuminate\Support\Collection - */ - public function split($pattern, $limit = -1, $flags = 0) - { - if (filter_var($pattern, FILTER_VALIDATE_INT) !== false) { - return collect(mb_str_split($this->value, $pattern)); - } - - $segments = preg_split($pattern, $this->value, $limit, $flags); - - return ! empty($segments) ? collect($segments) : collect(); - } - - /** - * Cap a string with a single instance of a given value. - * - * @param string $cap - * @return static - */ - public function finish($cap) - { - return new static(Str::finish($this->value, $cap)); - } - - /** - * Determine if a given string matches a given pattern. - * - * @param string|iterable $pattern - * @return bool - */ - public function is($pattern) - { - return Str::is($pattern, $this->value); - } - - /** - * Determine if a given string is 7 bit ASCII. - * - * @return bool - */ - public function isAscii() - { - return Str::isAscii($this->value); - } - - /** - * Determine if a given string is valid JSON. - * - * @return bool - */ - public function isJson() - { - return Str::isJson($this->value); - } - - /** - * Determine if a given value is a valid URL. - * - * @return bool - */ - public function isUrl() - { - return Str::isUrl($this->value); - } - - /** - * Determine if a given string is a valid UUID. - * - * @return bool - */ - public function isUuid() - { - return Str::isUuid($this->value); - } - - /** - * Determine if a given string is a valid ULID. - * - * @return bool - */ - public function isUlid() - { - return Str::isUlid($this->value); - } - - /** - * Determine if the given string is empty. - * - * @return bool - */ - public function isEmpty() - { - return $this->value === ''; - } - - /** - * Determine if the given string is not empty. - * - * @return bool - */ - public function isNotEmpty() - { - return ! $this->isEmpty(); - } - - /** - * Convert a string to kebab case. - * - * @return static - */ - public function kebab() - { - return new static(Str::kebab($this->value)); - } - - /** - * Return the length of the given string. - * - * @param string|null $encoding - * @return int - */ - public function length($encoding = null) - { - return Str::length($this->value, $encoding); - } - - /** - * Limit the number of characters in a string. - * - * @param int $limit - * @param string $end - * @return static - */ - public function limit($limit = 100, $end = '...') - { - return new static(Str::limit($this->value, $limit, $end)); - } - - /** - * Convert the given string to lower-case. - * - * @return static - */ - public function lower() - { - return new static(Str::lower($this->value)); - } - - /** - * Convert GitHub flavored Markdown into HTML. - * - * @param array $options - * @return static - */ - public function markdown(array $options = []) - { - return new static(Str::markdown($this->value, $options)); - } - - /** - * Convert inline Markdown into HTML. - * - * @param array $options - * @return static - */ - public function inlineMarkdown(array $options = []) - { - return new static(Str::inlineMarkdown($this->value, $options)); - } - - /** - * Masks a portion of a string with a repeated character. - * - * @param string $character - * @param int $index - * @param int|null $length - * @param string $encoding - * @return static - */ - public function mask($character, $index, $length = null, $encoding = 'UTF-8') - { - return new static(Str::mask($this->value, $character, $index, $length, $encoding)); - } - - /** - * Get the string matching the given pattern. - * - * @param string $pattern - * @return static - */ - public function match($pattern) - { - return new static(Str::match($pattern, $this->value)); - } - - /** - * Determine if a given string matches a given pattern. - * - * @param string|iterable $pattern - * @return bool - */ - public function isMatch($pattern) - { - return Str::isMatch($pattern, $this->value); - } - - /** - * Get the string matching the given pattern. - * - * @param string $pattern - * @return \Illuminate\Support\Collection - */ - public function matchAll($pattern) - { - return Str::matchAll($pattern, $this->value); - } - - /** - * Determine if the string matches the given pattern. - * - * @param string $pattern - * @return bool - */ - public function test($pattern) - { - return $this->isMatch($pattern); - } - - /** - * Pad both sides of the string with another. - * - * @param int $length - * @param string $pad - * @return static - */ - public function padBoth($length, $pad = ' ') - { - return new static(Str::padBoth($this->value, $length, $pad)); - } - - /** - * Pad the left side of the string with another. - * - * @param int $length - * @param string $pad - * @return static - */ - public function padLeft($length, $pad = ' ') - { - return new static(Str::padLeft($this->value, $length, $pad)); - } - - /** - * Pad the right side of the string with another. - * - * @param int $length - * @param string $pad - * @return static - */ - public function padRight($length, $pad = ' ') - { - return new static(Str::padRight($this->value, $length, $pad)); - } - - /** - * Parse a Class@method style callback into class and method. - * - * @param string|null $default - * @return array - */ - public function parseCallback($default = null) - { - return Str::parseCallback($this->value, $default); - } - - /** - * Call the given callback and return a new string. - * - * @param callable $callback - * @return static - */ - public function pipe(callable $callback) - { - return new static($callback($this)); - } - - /** - * Get the plural form of an English word. - * - * @param int|array|\Countable $count - * @return static - */ - public function plural($count = 2) - { - return new static(Str::plural($this->value, $count)); - } - - /** - * Pluralize the last word of an English, studly caps case string. - * - * @param int|array|\Countable $count - * @return static - */ - public function pluralStudly($count = 2) - { - return new static(Str::pluralStudly($this->value, $count)); - } - - /** - * Find the multi-byte safe position of the first occurrence of the given substring. - * - * @param string $needle - * @param int $offset - * @param string|null $encoding - * @return int|false - */ - public function position($needle, $offset = 0, $encoding = null) - { - return Str::position($this->value, $needle, $offset, $encoding); - } - - /** - * Prepend the given values to the string. - * - * @param string ...$values - * @return static - */ - public function prepend(...$values) - { - return new static(implode('', $values).$this->value); - } - - /** - * Remove any occurrence of the given string in the subject. - * - * @param string|iterable $search - * @param bool $caseSensitive - * @return static - */ - public function remove($search, $caseSensitive = true) - { - return new static(Str::remove($search, $this->value, $caseSensitive)); - } - - /** - * Reverse the string. - * - * @return static - */ - public function reverse() - { - return new static(Str::reverse($this->value)); - } - - /** - * Repeat the string. - * - * @param int $times - * @return static - */ - public function repeat(int $times) - { - return new static(str_repeat($this->value, $times)); - } - - /** - * Replace the given value in the given string. - * - * @param string|iterable $search - * @param string|iterable $replace - * @param bool $caseSensitive - * @return static - */ - public function replace($search, $replace, $caseSensitive = true) - { - return new static(Str::replace($search, $replace, $this->value, $caseSensitive)); - } - - /** - * Replace a given value in the string sequentially with an array. - * - * @param string $search - * @param iterable $replace - * @return static - */ - public function replaceArray($search, $replace) - { - return new static(Str::replaceArray($search, $replace, $this->value)); - } - - /** - * Replace the first occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @return static - */ - public function replaceFirst($search, $replace) - { - return new static(Str::replaceFirst($search, $replace, $this->value)); - } - - /** - * Replace the first occurrence of the given value if it appears at the start of the string. - * - * @param string $search - * @param string $replace - * @return static - */ - public function replaceStart($search, $replace) - { - return new static(Str::replaceStart($search, $replace, $this->value)); - } - - /** - * Replace the last occurrence of a given value in the string. - * - * @param string $search - * @param string $replace - * @return static - */ - public function replaceLast($search, $replace) - { - return new static(Str::replaceLast($search, $replace, $this->value)); - } - - /** - * Replace the last occurrence of a given value if it appears at the end of the string. - * - * @param string $search - * @param string $replace - * @return static - */ - public function replaceEnd($search, $replace) - { - return new static(Str::replaceEnd($search, $replace, $this->value)); - } - - /** - * Replace the patterns matching the given regular expression. - * - * @param array|string $pattern - * @param \Closure|string $replace - * @param int $limit - * @return static - */ - public function replaceMatches($pattern, $replace, $limit = -1) - { - if ($replace instanceof Closure) { - return new static(preg_replace_callback($pattern, $replace, $this->value, $limit)); - } - - return new static(preg_replace($pattern, $replace, $this->value, $limit)); - } - - /** - * Parse input from a string to a collection, according to a format. - * - * @param string $format - * @return \Illuminate\Support\Collection - */ - public function scan($format) - { - return collect(sscanf($this->value, $format)); - } - - /** - * Remove all "extra" blank space from the given string. - * - * @return static - */ - public function squish() - { - return new static(Str::squish($this->value)); - } - - /** - * Begin a string with a single instance of a given value. - * - * @param string $prefix - * @return static - */ - public function start($prefix) - { - return new static(Str::start($this->value, $prefix)); - } - - /** - * Strip HTML and PHP tags from the given string. - * - * @param string[]|string|null $allowedTags - * @return static - */ - public function stripTags($allowedTags = null) - { - return new static(strip_tags($this->value, $allowedTags)); - } - - /** - * Convert the given string to upper-case. - * - * @return static - */ - public function upper() - { - return new static(Str::upper($this->value)); - } - - /** - * Convert the given string to proper case. - * - * @return static - */ - public function title() - { - return new static(Str::title($this->value)); - } - - /** - * Convert the given string to proper case for each word. - * - * @return static - */ - public function headline() - { - return new static(Str::headline($this->value)); - } - - /** - * Convert the given string to APA-style title case. - * - * @return static - */ - public function apa() - { - return new static(Str::apa($this->value)); - } - - /** - * Transliterate a string to its closest ASCII representation. - * - * @param string|null $unknown - * @param bool|null $strict - * @return static - */ - public function transliterate($unknown = '?', $strict = false) - { - return new static(Str::transliterate($this->value, $unknown, $strict)); - } - - /** - * Get the singular form of an English word. - * - * @return static - */ - public function singular() - { - return new static(Str::singular($this->value)); - } - - /** - * Generate a URL friendly "slug" from a given string. - * - * @param string $separator - * @param string|null $language - * @param array $dictionary - * @return static - */ - public function slug($separator = '-', $language = 'en', $dictionary = ['@' => 'at']) - { - return new static(Str::slug($this->value, $separator, $language, $dictionary)); - } - - /** - * Convert a string to snake case. - * - * @param string $delimiter - * @return static - */ - public function snake($delimiter = '_') - { - return new static(Str::snake($this->value, $delimiter)); - } - - /** - * Determine if a given string starts with a given substring. - * - * @param string|iterable $needles - * @return bool - */ - public function startsWith($needles) - { - return Str::startsWith($this->value, $needles); - } - - /** - * Convert a value to studly caps case. - * - * @return static - */ - public function studly() - { - return new static(Str::studly($this->value)); - } - - /** - * Returns the portion of the string specified by the start and length parameters. - * - * @param int $start - * @param int|null $length - * @param string $encoding - * @return static - */ - public function substr($start, $length = null, $encoding = 'UTF-8') - { - return new static(Str::substr($this->value, $start, $length, $encoding)); - } - - /** - * Returns the number of substring occurrences. - * - * @param string $needle - * @param int $offset - * @param int|null $length - * @return int - */ - public function substrCount($needle, $offset = 0, $length = null) - { - return Str::substrCount($this->value, $needle, $offset, $length); - } - - /** - * Replace text within a portion of a string. - * - * @param string|string[] $replace - * @param int|int[] $offset - * @param int|int[]|null $length - * @return static - */ - public function substrReplace($replace, $offset = 0, $length = null) - { - return new static(Str::substrReplace($this->value, $replace, $offset, $length)); - } - - /** - * Swap multiple keywords in a string with other keywords. - * - * @param array $map - * @return static - */ - public function swap(array $map) - { - return new static(strtr($this->value, $map)); - } - - /** - * Take the first or last {$limit} characters. - * - * @param int $limit - * @return static - */ - public function take(int $limit) - { - if ($limit < 0) { - return $this->substr($limit); - } - - return $this->substr(0, $limit); - } - - /** - * Trim the string of the given characters. - * - * @param string $characters - * @return static - */ - public function trim($characters = null) - { - return new static(trim(...array_merge([$this->value], func_get_args()))); - } - - /** - * Left trim the string of the given characters. - * - * @param string $characters - * @return static - */ - public function ltrim($characters = null) - { - return new static(ltrim(...array_merge([$this->value], func_get_args()))); - } - - /** - * Right trim the string of the given characters. - * - * @param string $characters - * @return static - */ - public function rtrim($characters = null) - { - return new static(rtrim(...array_merge([$this->value], func_get_args()))); - } - - /** - * Make a string's first character lowercase. - * - * @return static - */ - public function lcfirst() - { - return new static(Str::lcfirst($this->value)); - } - - /** - * Make a string's first character uppercase. - * - * @return static - */ - public function ucfirst() - { - return new static(Str::ucfirst($this->value)); - } - - /** - * Split a string by uppercase characters. - * - * @return \Illuminate\Support\Collection - */ - public function ucsplit() - { - return collect(Str::ucsplit($this->value)); - } - - /** - * Execute the given callback if the string contains a given substring. - * - * @param string|iterable $needles - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenContains($needles, $callback, $default = null) - { - return $this->when($this->contains($needles), $callback, $default); - } - - /** - * Execute the given callback if the string contains all array values. - * - * @param iterable $needles - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenContainsAll(array $needles, $callback, $default = null) - { - return $this->when($this->containsAll($needles), $callback, $default); - } - - /** - * Execute the given callback if the string is empty. - * - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenEmpty($callback, $default = null) - { - return $this->when($this->isEmpty(), $callback, $default); - } - - /** - * Execute the given callback if the string is not empty. - * - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenNotEmpty($callback, $default = null) - { - return $this->when($this->isNotEmpty(), $callback, $default); - } - - /** - * Execute the given callback if the string ends with a given substring. - * - * @param string|iterable $needles - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenEndsWith($needles, $callback, $default = null) - { - return $this->when($this->endsWith($needles), $callback, $default); - } - - /** - * Execute the given callback if the string is an exact match with the given value. - * - * @param string $value - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenExactly($value, $callback, $default = null) - { - return $this->when($this->exactly($value), $callback, $default); - } - - /** - * Execute the given callback if the string is not an exact match with the given value. - * - * @param string $value - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenNotExactly($value, $callback, $default = null) - { - return $this->when(! $this->exactly($value), $callback, $default); - } - - /** - * Execute the given callback if the string matches a given pattern. - * - * @param string|iterable $pattern - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenIs($pattern, $callback, $default = null) - { - return $this->when($this->is($pattern), $callback, $default); - } - - /** - * Execute the given callback if the string is 7 bit ASCII. - * - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenIsAscii($callback, $default = null) - { - return $this->when($this->isAscii(), $callback, $default); - } - - /** - * Execute the given callback if the string is a valid UUID. - * - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenIsUuid($callback, $default = null) - { - return $this->when($this->isUuid(), $callback, $default); - } - - /** - * Execute the given callback if the string is a valid ULID. - * - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenIsUlid($callback, $default = null) - { - return $this->when($this->isUlid(), $callback, $default); - } - - /** - * Execute the given callback if the string starts with a given substring. - * - * @param string|iterable $needles - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenStartsWith($needles, $callback, $default = null) - { - return $this->when($this->startsWith($needles), $callback, $default); - } - - /** - * Execute the given callback if the string matches the given pattern. - * - * @param string $pattern - * @param callable $callback - * @param callable|null $default - * @return static - */ - public function whenTest($pattern, $callback, $default = null) - { - return $this->when($this->test($pattern), $callback, $default); - } - - /** - * Limit the number of words in a string. - * - * @param int $words - * @param string $end - * @return static - */ - public function words($words = 100, $end = '...') - { - return new static(Str::words($this->value, $words, $end)); - } - - /** - * Get the number of words a string contains. - * - * @param string|null $characters - * @return int - */ - public function wordCount($characters = null) - { - return Str::wordCount($this->value, $characters); - } - - /** - * Wrap a string to a given number of characters. - * - * @param int $characters - * @param string $break - * @param bool $cutLongWords - * @return static - */ - public function wordWrap($characters = 75, $break = "\n", $cutLongWords = false) - { - return new static(Str::wordWrap($this->value, $characters, $break, $cutLongWords)); - } - - /** - * Wrap the string with the given strings. - * - * @param string $before - * @param string|null $after - * @return static - */ - public function wrap($before, $after = null) - { - return new static(Str::wrap($this->value, $before, $after)); - } - - /** - * Unwrap the string with the given strings. - * - * @param string $before - * @param string|null $after - * @return static - */ - public function unwrap($before, $after = null) - { - return new static(Str::unwrap($this->value, $before, $after)); - } - - /** - * Convert the string into a `HtmlString` instance. - * - * @return \Illuminate\Support\HtmlString - */ - public function toHtmlString() - { - return new HtmlString($this->value); - } - - /** - * Convert the string to Base64 encoding. - * - * @return static - */ - public function toBase64() - { - return new static(base64_encode($this->value)); - } - - /** - * Decode the Base64 encoded string. - * - * @param bool $strict - * @return static - */ - public function fromBase64($strict = false) - { - return new static(base64_decode($this->value, $strict)); - } - - /** - * Dump the string. - * - * @return $this - */ - public function dump() - { - VarDumper::dump($this->value); - - return $this; - } - - /** - * Dump the string and end the script. - * - * @return never - */ - public function dd() - { - $this->dump(); - - exit(1); - } - - /** - * Get the underlying string value. - * - * @return string - */ - public function value() - { - return $this->toString(); - } - - /** - * Get the underlying string value. - * - * @return string - */ - public function toString() - { - return $this->value; - } - - /** - * Get the underlying string value as an integer. - * - * @param int $base - * @return int - */ - public function toInteger($base = 10) - { - return intval($this->value, $base); - } - - /** - * Get the underlying string value as a float. - * - * @return float - */ - public function toFloat() - { - return floatval($this->value); - } - - /** - * Get the underlying string value as a boolean. - * - * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. - * - * @return bool - */ - public function toBoolean() - { - return filter_var($this->value, FILTER_VALIDATE_BOOLEAN); - } - - /** - * Get the underlying string value as a Carbon instance. - * - * @param string|null $format - * @param string|null $tz - * @return \Illuminate\Support\Carbon - * - * @throws \Carbon\Exceptions\InvalidFormatException - */ - public function toDate($format = null, $tz = null) - { - if (is_null($format)) { - return Date::parse($this->value, $tz); - } - - return Date::createFromFormat($format, $this->value, $tz); - } - - /** - * Convert the object to a string when JSON encoded. - * - * @return string - */ - public function jsonSerialize(): string - { - return $this->__toString(); - } - - /** - * Determine if the given offset exists. - * - * @param mixed $offset - * @return bool - */ - public function offsetExists(mixed $offset): bool - { - return isset($this->value[$offset]); - } - - /** - * Get the value at the given offset. - * - * @param mixed $offset - * @return string - */ - public function offsetGet(mixed $offset): string - { - return $this->value[$offset]; - } - - /** - * Set the value at the given offset. - * - * @param mixed $offset - * @return void - */ - public function offsetSet(mixed $offset, mixed $value): void - { - $this->value[$offset] = $value; - } - - /** - * Unset the value at the given offset. - * - * @param mixed $offset - * @return void - */ - public function offsetUnset(mixed $offset): void - { - unset($this->value[$offset]); - } - - /** - * Proxy dynamic properties onto methods. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - return $this->{$key}(); - } - - /** - * Get the raw string value. - * - * @return string - */ - public function __toString() - { - return (string) $this->value; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchFake.php deleted file mode 100644 index 034f55c79..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchFake.php +++ /dev/null @@ -1,166 +0,0 @@ -id = $id; - $this->name = $name; - $this->totalJobs = $totalJobs; - $this->pendingJobs = $pendingJobs; - $this->failedJobs = $failedJobs; - $this->failedJobIds = $failedJobIds; - $this->options = $options; - $this->createdAt = $createdAt; - $this->cancelledAt = $cancelledAt; - $this->finishedAt = $finishedAt; - } - - /** - * Get a fresh instance of the batch represented by this ID. - * - * @return self - */ - public function fresh() - { - return $this; - } - - /** - * Add additional jobs to the batch. - * - * @param \Illuminate\Support\Enumerable|object|array $jobs - * @return self - */ - public function add($jobs) - { - $jobs = Collection::wrap($jobs); - - foreach ($jobs as $job) { - $this->added[] = $job; - } - - return $this; - } - - /** - * Record that a job within the batch finished successfully, executing any callbacks if necessary. - * - * @param string $jobId - * @return void - */ - public function recordSuccessfulJob(string $jobId) - { - // - } - - /** - * Decrement the pending jobs for the batch. - * - * @param string $jobId - * @return \Illuminate\Bus\UpdatedBatchJobCounts - */ - public function decrementPendingJobs(string $jobId) - { - // - } - - /** - * Record that a job within the batch failed to finish successfully, executing any callbacks if necessary. - * - * @param string $jobId - * @param \Throwable $e - * @return void - */ - public function recordFailedJob(string $jobId, $e) - { - // - } - - /** - * Increment the failed jobs for the batch. - * - * @param string $jobId - * @return \Illuminate\Bus\UpdatedBatchJobCounts - */ - public function incrementFailedJobs(string $jobId) - { - return new UpdatedBatchJobCounts; - } - - /** - * Cancel the batch. - * - * @return void - */ - public function cancel() - { - $this->cancelledAt = Carbon::now(); - } - - /** - * Delete the batch from storage. - * - * @return void - */ - public function delete() - { - $this->deleted = true; - } - - /** - * Determine if the batch has been deleted. - * - * @return bool - */ - public function deleted() - { - return $this->deleted; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchRepositoryFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchRepositoryFake.php deleted file mode 100644 index 021c73f27..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BatchRepositoryFake.php +++ /dev/null @@ -1,153 +0,0 @@ -batches; - } - - /** - * Retrieve information about an existing batch. - * - * @param string $batchId - * @return \Illuminate\Bus\Batch|null - */ - public function find(string $batchId) - { - return $this->batches[$batchId] ?? null; - } - - /** - * Store a new pending batch. - * - * @param \Illuminate\Bus\PendingBatch $batch - * @return \Illuminate\Bus\Batch - */ - public function store(PendingBatch $batch) - { - $id = (string) Str::orderedUuid(); - - $this->batches[$id] = new BatchFake( - $id, - $batch->name, - count($batch->jobs), - count($batch->jobs), - 0, - [], - $batch->options, - CarbonImmutable::now(), - null, - null - ); - - return $this->batches[$id]; - } - - /** - * Increment the total number of jobs within the batch. - * - * @param string $batchId - * @param int $amount - * @return void - */ - public function incrementTotalJobs(string $batchId, int $amount) - { - // - } - - /** - * Decrement the total number of pending jobs for the batch. - * - * @param string $batchId - * @param string $jobId - * @return \Illuminate\Bus\UpdatedBatchJobCounts - */ - public function decrementPendingJobs(string $batchId, string $jobId) - { - return new UpdatedBatchJobCounts; - } - - /** - * Increment the total number of failed jobs for the batch. - * - * @param string $batchId - * @param string $jobId - * @return \Illuminate\Bus\UpdatedBatchJobCounts - */ - public function incrementFailedJobs(string $batchId, string $jobId) - { - return new UpdatedBatchJobCounts; - } - - /** - * Mark the batch that has the given ID as finished. - * - * @param string $batchId - * @return void - */ - public function markAsFinished(string $batchId) - { - if (isset($this->batches[$batchId])) { - $this->batches[$batchId]->finishedAt = now(); - } - } - - /** - * Cancel the batch that has the given ID. - * - * @param string $batchId - * @return void - */ - public function cancel(string $batchId) - { - if (isset($this->batches[$batchId])) { - $this->batches[$batchId]->cancel(); - } - } - - /** - * Delete the batch that has the given ID. - * - * @param string $batchId - * @return void - */ - public function delete(string $batchId) - { - unset($this->batches[$batchId]); - } - - /** - * Execute the given Closure within a storage specific transaction. - * - * @param \Closure $callback - * @return mixed - */ - public function transaction(Closure $callback) - { - return $callback(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BusFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BusFake.php index 780b2929c..a90fedb99 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BusFake.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/BusFake.php @@ -2,49 +2,11 @@ namespace Illuminate\Support\Testing\Fakes; -use Closure; -use Illuminate\Bus\BatchRepository; -use Illuminate\Bus\ChainedBatch; -use Illuminate\Bus\PendingBatch; -use Illuminate\Contracts\Bus\QueueingDispatcher; -use Illuminate\Support\Arr; -use Illuminate\Support\Collection; -use Illuminate\Support\Traits\ReflectsClosures; +use Illuminate\Contracts\Bus\Dispatcher; use PHPUnit\Framework\Assert as PHPUnit; -use RuntimeException; -class BusFake implements Fake, QueueingDispatcher +class BusFake implements Dispatcher { - use ReflectsClosures; - - /** - * The original Bus dispatcher implementation. - * - * @var \Illuminate\Contracts\Bus\QueueingDispatcher - */ - public $dispatcher; - - /** - * The job types that should be intercepted instead of dispatched. - * - * @var array - */ - protected $jobsToFake = []; - - /** - * The job types that should be dispatched instead of faked. - * - * @var array - */ - protected $jobsToDispatch = []; - - /** - * The fake repository to track batched jobs. - * - * @var \Illuminate\Bus\BatchRepository - */ - protected $batchRepository; - /** * The commands that have been dispatched. * @@ -52,451 +14,36 @@ class BusFake implements Fake, QueueingDispatcher */ protected $commands = []; - /** - * The commands that have been dispatched synchronously. - * - * @var array - */ - protected $commandsSync = []; - - /** - * The commands that have been dispatched after the response has been sent. - * - * @var array - */ - protected $commandsAfterResponse = []; - - /** - * The batches that have been dispatched. - * - * @var array - */ - protected $batches = []; - - /** - * Indicates if commands should be serialized and restored when pushed to the Bus. - * - * @var bool - */ - protected bool $serializeAndRestore = false; - - /** - * Create a new bus fake instance. - * - * @param \Illuminate\Contracts\Bus\QueueingDispatcher $dispatcher - * @param array|string $jobsToFake - * @param \Illuminate\Bus\BatchRepository|null $batchRepository - * @return void - */ - public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [], ?BatchRepository $batchRepository = null) - { - $this->dispatcher = $dispatcher; - $this->jobsToFake = Arr::wrap($jobsToFake); - $this->batchRepository = $batchRepository ?: new BatchRepositoryFake; - } - - /** - * Specify the jobs that should be dispatched instead of faked. - * - * @param array|string $jobsToDispatch - * @return $this - */ - public function except($jobsToDispatch) - { - $this->jobsToDispatch = array_merge($this->jobsToDispatch, Arr::wrap($jobsToDispatch)); - - return $this; - } - /** * Assert if a job was dispatched based on a truth-test callback. * - * @param string|\Closure $command - * @param callable|int|null $callback + * @param string $command + * @param callable|null $callback * @return void */ public function assertDispatched($command, $callback = null) { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - if (is_numeric($callback)) { - return $this->assertDispatchedTimes($command, $callback); - } - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->count() > 0 || - $this->dispatchedAfterResponse($command, $callback)->count() > 0 || - $this->dispatchedSync($command, $callback)->count() > 0, + $this->dispatched($command, $callback)->count() > 0, "The expected [{$command}] job was not dispatched." ); } - /** - * Assert if a job was pushed a number of times. - * - * @param string|\Closure $command - * @param int $times - * @return void - */ - public function assertDispatchedTimes($command, $times = 1) - { - $callback = null; - - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - $count = $this->dispatched($command, $callback)->count() + - $this->dispatchedAfterResponse($command, $callback)->count() + - $this->dispatchedSync($command, $callback)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$command}] job was pushed {$count} times instead of {$times} times." - ); - } - /** * Determine if a job was dispatched based on a truth-test callback. * - * @param string|\Closure $command + * @param string $command * @param callable|null $callback * @return void */ public function assertNotDispatched($command, $callback = null) { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->count() === 0 && - $this->dispatchedAfterResponse($command, $callback)->count() === 0 && - $this->dispatchedSync($command, $callback)->count() === 0, + $this->dispatched($command, $callback)->count() === 0, "The unexpected [{$command}] job was dispatched." ); } - /** - * Assert that no jobs were dispatched. - * - * @return void - */ - public function assertNothingDispatched() - { - PHPUnit::assertEmpty($this->commands, 'Jobs were dispatched unexpectedly.'); - } - - /** - * Assert if a job was explicitly dispatched synchronously based on a truth-test callback. - * - * @param string|\Closure $command - * @param callable|int|null $callback - * @return void - */ - public function assertDispatchedSync($command, $callback = null) - { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - if (is_numeric($callback)) { - return $this->assertDispatchedSyncTimes($command, $callback); - } - - PHPUnit::assertTrue( - $this->dispatchedSync($command, $callback)->count() > 0, - "The expected [{$command}] job was not dispatched synchronously." - ); - } - - /** - * Assert if a job was pushed synchronously a number of times. - * - * @param string|\Closure $command - * @param int $times - * @return void - */ - public function assertDispatchedSyncTimes($command, $times = 1) - { - $callback = null; - - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - $count = $this->dispatchedSync($command, $callback)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$command}] job was synchronously pushed {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a job was dispatched based on a truth-test callback. - * - * @param string|\Closure $command - * @param callable|null $callback - * @return void - */ - public function assertNotDispatchedSync($command, $callback = null) - { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - PHPUnit::assertCount( - 0, $this->dispatchedSync($command, $callback), - "The unexpected [{$command}] job was dispatched synchronously." - ); - } - - /** - * Assert if a job was dispatched after the response was sent based on a truth-test callback. - * - * @param string|\Closure $command - * @param callable|int|null $callback - * @return void - */ - public function assertDispatchedAfterResponse($command, $callback = null) - { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - if (is_numeric($callback)) { - return $this->assertDispatchedAfterResponseTimes($command, $callback); - } - - PHPUnit::assertTrue( - $this->dispatchedAfterResponse($command, $callback)->count() > 0, - "The expected [{$command}] job was not dispatched after sending the response." - ); - } - - /** - * Assert if a job was pushed after the response was sent a number of times. - * - * @param string|\Closure $command - * @param int $times - * @return void - */ - public function assertDispatchedAfterResponseTimes($command, $times = 1) - { - $callback = null; - - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - $count = $this->dispatchedAfterResponse($command, $callback)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$command}] job was pushed {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a job was dispatched based on a truth-test callback. - * - * @param string|\Closure $command - * @param callable|null $callback - * @return void - */ - public function assertNotDispatchedAfterResponse($command, $callback = null) - { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - PHPUnit::assertCount( - 0, $this->dispatchedAfterResponse($command, $callback), - "The unexpected [{$command}] job was dispatched after sending the response." - ); - } - - /** - * Assert if a chain of jobs was dispatched. - * - * @param array $expectedChain - * @return void - */ - public function assertChained(array $expectedChain) - { - $command = $expectedChain[0]; - - $expectedChain = array_slice($expectedChain, 1); - - $callback = null; - - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } elseif ($command instanceof ChainedBatchTruthTest) { - $instance = $command; - - $command = ChainedBatch::class; - - $callback = fn ($job) => $instance($job->toPendingBatch()); - } elseif (! is_string($command)) { - $instance = $command; - - $command = get_class($instance); - - $callback = function ($job) use ($instance) { - return serialize($this->resetChainPropertiesToDefaults($job)) === serialize($instance); - }; - } - - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->isNotEmpty(), - "The expected [{$command}] job was not dispatched." - ); - - $this->assertDispatchedWithChainOfObjects($command, $expectedChain, $callback); - } - - /** - * Reset the chain properties to their default values on the job. - * - * @param mixed $job - * @return mixed - */ - protected function resetChainPropertiesToDefaults($job) - { - return tap(clone $job, function ($job) { - $job->chainConnection = null; - $job->chainQueue = null; - $job->chainCatchCallbacks = null; - $job->chained = []; - }); - } - - /** - * Assert if a job was dispatched with an empty chain based on a truth-test callback. - * - * @param string|\Closure $command - * @param callable|null $callback - * @return void - */ - public function assertDispatchedWithoutChain($command, $callback = null) - { - if ($command instanceof Closure) { - [$command, $callback] = [$this->firstClosureParameterType($command), $command]; - } - - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->isNotEmpty(), - "The expected [{$command}] job was not dispatched." - ); - - $this->assertDispatchedWithChainOfObjects($command, [], $callback); - } - - /** - * Assert if a job was dispatched with chained jobs based on a truth-test callback. - * - * @param string $command - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - protected function assertDispatchedWithChainOfObjects($command, $expectedChain, $callback) - { - $chain = $expectedChain; - - PHPUnit::assertTrue( - $this->dispatched($command, $callback)->filter(function ($job) use ($chain) { - if (count($chain) !== count($job->chained)) { - return false; - } - - foreach ($job->chained as $index => $serializedChainedJob) { - if ($chain[$index] instanceof ChainedBatchTruthTest) { - $chainedBatch = unserialize($serializedChainedJob); - - if (! $chainedBatch instanceof ChainedBatch || - ! $chain[$index]($chainedBatch->toPendingBatch())) { - return false; - } - } elseif ($chain[$index] instanceof Closure) { - [$expectedType, $callback] = [$this->firstClosureParameterType($chain[$index]), $chain[$index]]; - - $chainedJob = unserialize($serializedChainedJob); - - if (! $chainedJob instanceof $expectedType) { - throw new RuntimeException('The chained job was expected to be of type '.$expectedType.', '.$chainedJob::class.' chained.'); - } - - if (! $callback($chainedJob)) { - return false; - } - } elseif (is_string($chain[$index])) { - if ($chain[$index] != get_class(unserialize($serializedChainedJob))) { - return false; - } - } elseif (serialize($chain[$index]) != $serializedChainedJob) { - return false; - } - } - - return true; - })->isNotEmpty(), - 'The expected chain was not dispatched.' - ); - } - - /** - * Create a new assertion about a chained batch. - * - * @param \Closure $callback - * @return \Illuminate\Support\Testing\Fakes\ChainedBatchTruthTest - */ - public function chainedBatch(Closure $callback) - { - return new ChainedBatchTruthTest($callback); - } - - /** - * Assert if a batch was dispatched based on a truth-test callback. - * - * @param callable $callback - * @return void - */ - public function assertBatched(callable $callback) - { - PHPUnit::assertTrue( - $this->batched($callback)->count() > 0, - 'The expected batch was not dispatched.' - ); - } - - /** - * Assert the number of batches that have been dispatched. - * - * @param int $count - * @return void - */ - public function assertBatchCount($count) - { - PHPUnit::assertCount( - $count, $this->batches, - ); - } - - /** - * Assert that no batched jobs were dispatched. - * - * @return void - */ - public function assertNothingBatched() - { - PHPUnit::assertEmpty($this->batches, 'Batched jobs were dispatched unexpectedly.'); - } - /** * Get all of the jobs matching a truth-test callback. * @@ -510,60 +57,13 @@ class BusFake implements Fake, QueueingDispatcher return collect(); } - $callback = $callback ?: fn () => true; + $callback = $callback ?: function () { + return true; + }; - return collect($this->commands[$command])->filter(fn ($command) => $callback($command)); - } - - /** - * Get all of the jobs dispatched synchronously matching a truth-test callback. - * - * @param string $command - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function dispatchedSync(string $command, $callback = null) - { - if (! $this->hasDispatchedSync($command)) { - return collect(); - } - - $callback = $callback ?: fn () => true; - - return collect($this->commandsSync[$command])->filter(fn ($command) => $callback($command)); - } - - /** - * Get all of the jobs dispatched after the response was sent matching a truth-test callback. - * - * @param string $command - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function dispatchedAfterResponse(string $command, $callback = null) - { - if (! $this->hasDispatchedAfterResponse($command)) { - return collect(); - } - - $callback = $callback ?: fn () => true; - - return collect($this->commandsAfterResponse[$command])->filter(fn ($command) => $callback($command)); - } - - /** - * Get all of the pending batches matching a truth-test callback. - * - * @param callable $callback - * @return \Illuminate\Support\Collection - */ - public function batched(callable $callback) - { - if (empty($this->batches)) { - return collect(); - } - - return collect($this->batches)->filter(fn ($batch) => $callback($batch)); + return collect($this->commands[$command])->filter(function ($command) use ($callback) { + return $callback($command); + }); } /** @@ -577,28 +77,6 @@ class BusFake implements Fake, QueueingDispatcher return isset($this->commands[$command]) && ! empty($this->commands[$command]); } - /** - * Determine if there are any stored commands for a given class. - * - * @param string $command - * @return bool - */ - public function hasDispatchedSync($command) - { - return isset($this->commandsSync[$command]) && ! empty($this->commandsSync[$command]); - } - - /** - * Determine if there are any stored commands for a given class. - * - * @param string $command - * @return bool - */ - public function hasDispatchedAfterResponse($command) - { - return isset($this->commandsAfterResponse[$command]) && ! empty($this->commandsAfterResponse[$command]); - } - /** * Dispatch a command to its appropriate handler. * @@ -607,29 +85,7 @@ class BusFake implements Fake, QueueingDispatcher */ public function dispatch($command) { - if ($this->shouldFakeJob($command)) { - $this->commands[get_class($command)][] = $this->getCommandRepresentation($command); - } else { - return $this->dispatcher->dispatch($command); - } - } - - /** - * Dispatch a command to its appropriate handler in the current process. - * - * Queueable jobs will be dispatched to the "sync" queue. - * - * @param mixed $command - * @param mixed $handler - * @return mixed - */ - public function dispatchSync($command, $handler = null) - { - if ($this->shouldFakeJob($command)) { - $this->commandsSync[get_class($command)][] = $this->getCommandRepresentation($command); - } else { - return $this->dispatcher->dispatchSync($command, $handler); - } + return $this->dispatchNow($command); } /** @@ -641,176 +97,7 @@ class BusFake implements Fake, QueueingDispatcher */ public function dispatchNow($command, $handler = null) { - if ($this->shouldFakeJob($command)) { - $this->commands[get_class($command)][] = $this->getCommandRepresentation($command); - } else { - return $this->dispatcher->dispatchNow($command, $handler); - } - } - - /** - * Dispatch a command to its appropriate handler behind a queue. - * - * @param mixed $command - * @return mixed - */ - public function dispatchToQueue($command) - { - if ($this->shouldFakeJob($command)) { - $this->commands[get_class($command)][] = $this->getCommandRepresentation($command); - } else { - return $this->dispatcher->dispatchToQueue($command); - } - } - - /** - * Dispatch a command to its appropriate handler. - * - * @param mixed $command - * @return mixed - */ - public function dispatchAfterResponse($command) - { - if ($this->shouldFakeJob($command)) { - $this->commandsAfterResponse[get_class($command)][] = $this->getCommandRepresentation($command); - } else { - return $this->dispatcher->dispatch($command); - } - } - - /** - * Create a new chain of queueable jobs. - * - * @param \Illuminate\Support\Collection|array $jobs - * @return \Illuminate\Foundation\Bus\PendingChain - */ - public function chain($jobs) - { - $jobs = Collection::wrap($jobs); - $jobs = ChainedBatch::prepareNestedBatches($jobs); - - return new PendingChainFake($this, $jobs->shift(), $jobs->toArray()); - } - - /** - * Attempt to find the batch with the given ID. - * - * @param string $batchId - * @return \Illuminate\Bus\Batch|null - */ - public function findBatch(string $batchId) - { - return $this->batchRepository->find($batchId); - } - - /** - * Create a new batch of queueable jobs. - * - * @param \Illuminate\Support\Collection|array $jobs - * @return \Illuminate\Bus\PendingBatch - */ - public function batch($jobs) - { - return new PendingBatchFake($this, Collection::wrap($jobs)); - } - - /** - * Dispatch an empty job batch for testing. - * - * @param string $name - * @return \Illuminate\Bus\Batch - */ - public function dispatchFakeBatch($name = '') - { - return $this->batch([])->name($name)->dispatch(); - } - - /** - * Record the fake pending batch dispatch. - * - * @param \Illuminate\Bus\PendingBatch $pendingBatch - * @return \Illuminate\Bus\Batch - */ - public function recordPendingBatch(PendingBatch $pendingBatch) - { - $this->batches[] = $pendingBatch; - - return $this->batchRepository->store($pendingBatch); - } - - /** - * Determine if a command should be faked or actually dispatched. - * - * @param mixed $command - * @return bool - */ - protected function shouldFakeJob($command) - { - if ($this->shouldDispatchCommand($command)) { - return false; - } - - if (empty($this->jobsToFake)) { - return true; - } - - return collect($this->jobsToFake) - ->filter(function ($job) use ($command) { - return $job instanceof Closure - ? $job($command) - : $job === get_class($command); - })->isNotEmpty(); - } - - /** - * Determine if a command should be dispatched or not. - * - * @param mixed $command - * @return bool - */ - protected function shouldDispatchCommand($command) - { - return collect($this->jobsToDispatch) - ->filter(function ($job) use ($command) { - return $job instanceof Closure - ? $job($command) - : $job === get_class($command); - })->isNotEmpty(); - } - - /** - * Specify if commands should be serialized and restored when being batched. - * - * @param bool $serializeAndRestore - * @return $this - */ - public function serializeAndRestore(bool $serializeAndRestore = true) - { - $this->serializeAndRestore = $serializeAndRestore; - - return $this; - } - - /** - * Serialize and unserialize the command to simulate the queueing process. - * - * @param mixed $command - * @return mixed - */ - protected function serializeAndRestoreCommand($command) - { - return unserialize(serialize($command)); - } - - /** - * Return the command representation that should be stored. - * - * @param mixed $command - * @return mixed - */ - protected function getCommandRepresentation($command) - { - return $this->serializeAndRestore ? $this->serializeAndRestoreCommand($command) : $command; + $this->commands[get_class($command)][] = $command; } /** @@ -821,43 +108,6 @@ class BusFake implements Fake, QueueingDispatcher */ public function pipeThrough(array $pipes) { - $this->dispatcher->pipeThrough($pipes); - - return $this; - } - - /** - * Determine if the given command has a handler. - * - * @param mixed $command - * @return bool - */ - public function hasCommandHandler($command) - { - return $this->dispatcher->hasCommandHandler($command); - } - - /** - * Retrieve the handler for a command. - * - * @param mixed $command - * @return mixed - */ - public function getCommandHandler($command) - { - return $this->dispatcher->getCommandHandler($command); - } - - /** - * Map a command to a handler. - * - * @param array $map - * @return $this - */ - public function map(array $map) - { - $this->dispatcher->map($map); - - return $this; + // } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/ChainedBatchTruthTest.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/ChainedBatchTruthTest.php deleted file mode 100644 index 4d1cec732..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/ChainedBatchTruthTest.php +++ /dev/null @@ -1,37 +0,0 @@ -callback = $callback; - } - - /** - * Invoke the truth test with the given pending batch. - * - * @param \Illuminate\Bus\PendingBatch - * @return bool - */ - public function __invoke($pendingBatch) - { - return call_user_func($this->callback, $pendingBatch); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/EventFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/EventFake.php index 4a4fc7c5b..e21f666d2 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/EventFake.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/EventFake.php @@ -2,202 +2,48 @@ namespace Illuminate\Support\Testing\Fakes; -use Closure; -use Illuminate\Container\Container; -use Illuminate\Contracts\Events\Dispatcher; -use Illuminate\Contracts\Events\ShouldDispatchAfterCommit; -use Illuminate\Support\Arr; -use Illuminate\Support\Str; -use Illuminate\Support\Traits\ForwardsCalls; -use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; -use ReflectionFunction; +use Illuminate\Contracts\Events\Dispatcher; -class EventFake implements Dispatcher, Fake +class EventFake implements Dispatcher { - use ForwardsCalls, ReflectsClosures; - /** - * The original event dispatcher. - * - * @var \Illuminate\Contracts\Events\Dispatcher - */ - public $dispatcher; - - /** - * The event types that should be intercepted instead of dispatched. - * - * @var array - */ - protected $eventsToFake = []; - - /** - * The event types that should be dispatched instead of intercepted. - * - * @var array - */ - protected $eventsToDispatch = []; - - /** - * All of the events that have been intercepted keyed by type. + * All of the events that have been dispatched keyed by type. * * @var array */ protected $events = []; - /** - * Create a new event fake instance. - * - * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher - * @param array|string $eventsToFake - * @return void - */ - public function __construct(Dispatcher $dispatcher, $eventsToFake = []) - { - $this->dispatcher = $dispatcher; - - $this->eventsToFake = Arr::wrap($eventsToFake); - } - - /** - * Specify the events that should be dispatched instead of faked. - * - * @param array|string $eventsToDispatch - * @return $this - */ - public function except($eventsToDispatch) - { - $this->eventsToDispatch = array_merge( - $this->eventsToDispatch, - Arr::wrap($eventsToDispatch) - ); - - return $this; - } - - /** - * Assert if an event has a listener attached to it. - * - * @param string $expectedEvent - * @param string|array $expectedListener - * @return void - */ - public function assertListening($expectedEvent, $expectedListener) - { - foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) { - $actualListener = (new ReflectionFunction($listenerClosure)) - ->getStaticVariables()['listener']; - - $normalizedListener = $expectedListener; - - if (is_string($actualListener) && Str::contains($actualListener, '@')) { - $actualListener = Str::parseCallback($actualListener); - - if (is_string($expectedListener)) { - if (Str::contains($expectedListener, '@')) { - $normalizedListener = Str::parseCallback($expectedListener); - } else { - $normalizedListener = [ - $expectedListener, - method_exists($expectedListener, 'handle') ? 'handle' : '__invoke', - ]; - } - } - } - - if ($actualListener === $normalizedListener || - ($actualListener instanceof Closure && - $normalizedListener === Closure::class)) { - PHPUnit::assertTrue(true); - - return; - } - } - - PHPUnit::assertTrue( - false, - sprintf( - 'Event [%s] does not have the [%s] listener attached to it', - $expectedEvent, - print_r($expectedListener, true) - ) - ); - } - /** * Assert if an event was dispatched based on a truth-test callback. * - * @param string|\Closure $event - * @param callable|int|null $callback + * @param string $event + * @param callable|null $callback * @return void */ public function assertDispatched($event, $callback = null) { - if ($event instanceof Closure) { - [$event, $callback] = [$this->firstClosureParameterType($event), $event]; - } - - if (is_int($callback)) { - return $this->assertDispatchedTimes($event, $callback); - } - PHPUnit::assertTrue( $this->dispatched($event, $callback)->count() > 0, "The expected [{$event}] event was not dispatched." ); } - /** - * Assert if an event was dispatched a number of times. - * - * @param string $event - * @param int $times - * @return void - */ - public function assertDispatchedTimes($event, $times = 1) - { - $count = $this->dispatched($event)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$event}] event was dispatched {$count} times instead of {$times} times." - ); - } - /** * Determine if an event was dispatched based on a truth-test callback. * - * @param string|\Closure $event + * @param string $event * @param callable|null $callback * @return void */ public function assertNotDispatched($event, $callback = null) { - if ($event instanceof Closure) { - [$event, $callback] = [$this->firstClosureParameterType($event), $event]; - } - - PHPUnit::assertCount( - 0, $this->dispatched($event, $callback), + PHPUnit::assertTrue( + $this->dispatched($event, $callback)->count() === 0, "The unexpected [{$event}] event was dispatched." ); } - /** - * Assert that no events were dispatched. - * - * @return void - */ - public function assertNothingDispatched() - { - $count = count(Arr::flatten($this->events)); - - PHPUnit::assertSame( - 0, $count, - "{$count} unexpected events were dispatched." - ); - } - /** * Get all of the events matching a truth-test callback. * @@ -211,11 +57,13 @@ class EventFake implements Dispatcher, Fake return collect(); } - $callback = $callback ?: fn () => true; + $callback = $callback ?: function () { + return true; + }; - return collect($this->events[$event])->filter( - fn ($arguments) => $callback(...$arguments) - ); + return collect($this->events[$event])->filter(function ($arguments) use ($callback) { + return $callback(...$arguments); + }); } /** @@ -232,13 +80,13 @@ class EventFake implements Dispatcher, Fake /** * Register an event listener with the dispatcher. * - * @param \Closure|string|array $events + * @param string|array $events * @param mixed $listener * @return void */ - public function listen($events, $listener = null) + public function listen($events, $listener) { - $this->dispatcher->listen($events, $listener); + // } /** @@ -249,7 +97,7 @@ class EventFake implements Dispatcher, Fake */ public function hasListeners($eventName) { - return $this->dispatcher->hasListeners($eventName); + // } /** @@ -272,7 +120,7 @@ class EventFake implements Dispatcher, Fake */ public function subscribe($subscriber) { - $this->dispatcher->subscribe($subscriber); + // } /** @@ -286,6 +134,19 @@ class EventFake implements Dispatcher, Fake // } + /** + * Fire an event and call the listeners. + * + * @param string|object $event + * @param mixed $payload + * @param bool $halt + * @return array|null + */ + public function fire($event, $payload = [], $halt = false) + { + return $this->dispatch($event, $payload, $halt); + } + /** * Fire an event and call the listeners. * @@ -298,77 +159,7 @@ class EventFake implements Dispatcher, Fake { $name = is_object($event) ? get_class($event) : (string) $event; - if ($this->shouldFakeEvent($name, $payload)) { - $this->fakeEvent($event, $name, func_get_args()); - } else { - return $this->dispatcher->dispatch($event, $payload, $halt); - } - } - - /** - * Determine if an event should be faked or actually dispatched. - * - * @param string $eventName - * @param mixed $payload - * @return bool - */ - protected function shouldFakeEvent($eventName, $payload) - { - if ($this->shouldDispatchEvent($eventName, $payload)) { - return false; - } - - if (empty($this->eventsToFake)) { - return true; - } - - return collect($this->eventsToFake) - ->filter(function ($event) use ($eventName, $payload) { - return $event instanceof Closure - ? $event($eventName, $payload) - : $event === $eventName; - }) - ->isNotEmpty(); - } - - /** - * Push the event onto the fake events array immediately or after the next database transaction. - * - * @param string|object $event - * @param string $name - * @param array $arguments - * @return void - */ - protected function fakeEvent($event, $name, $arguments) - { - if ($event instanceof ShouldDispatchAfterCommit && Container::getInstance()->bound('db.transactions')) { - return Container::getInstance()->make('db.transactions') - ->addCallback(fn () => $this->events[$name][] = $arguments); - } - - $this->events[$name][] = $arguments; - } - - /** - * Determine whether an event should be dispatched or not. - * - * @param string $eventName - * @param mixed $payload - * @return bool - */ - protected function shouldDispatchEvent($eventName, $payload) - { - if (empty($this->eventsToDispatch)) { - return false; - } - - return collect($this->eventsToDispatch) - ->filter(function ($event) use ($eventName, $payload) { - return $event instanceof Closure - ? $event($eventName, $payload) - : $event === $eventName; - }) - ->isNotEmpty(); + $this->events[$name][] = func_get_args(); } /** @@ -395,24 +186,12 @@ class EventFake implements Dispatcher, Fake /** * Dispatch an event and call the listeners. * - * @param string|object $event - * @param mixed $payload - * @return mixed + * @param string|object $event + * @param mixed $payload + * @return void */ public function until($event, $payload = []) { return $this->dispatch($event, $payload, true); } - - /** - * Handle dynamic method calls to the dispatcher. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->forwardCallTo($this->dispatcher, $method, $parameters); - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/Fake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/Fake.php deleted file mode 100644 index 4a243c4e8..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/Fake.php +++ /dev/null @@ -1,8 +0,0 @@ -manager = $manager; - } - /** * Assert if a mailable was sent based on a truth-test callback. * - * @param string|\Closure $mailable - * @param callable|int|null $callback + * @param string $mailable + * @param callable|null $callback * @return void */ public function assertSent($mailable, $callback = null) { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - - if (is_numeric($callback)) { - return $this->assertSentTimes($mailable, $callback); - } - - $message = "The expected [{$mailable}] mailable was not sent."; - - if (count($this->queuedMailables) > 0) { - $message .= ' Did you mean to use assertQueued() instead?'; - } - PHPUnit::assertTrue( $this->sent($mailable, $callback)->count() > 0, - $message + "The expected [{$mailable}] mailable was not sent." ); } - /** - * Assert if a mailable was sent a number of times. - * - * @param string $mailable - * @param int $times - * @return void - */ - protected function assertSentTimes($mailable, $times = 1) - { - $count = $this->sent($mailable)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$mailable}] mailable was sent {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a mailable was not sent or queued to be sent based on a truth-test callback. - * - * @param string|\Closure $mailable - * @param callable|null $callback - * @return void - */ - public function assertNotOutgoing($mailable, $callback = null) - { - $this->assertNotSent($mailable, $callback); - $this->assertNotQueued($mailable, $callback); - } - /** * Determine if a mailable was not sent based on a truth-test callback. * - * @param string|\Closure $mailable + * @param string $mailable * @param callable|null $callback * @return void */ public function assertNotSent($mailable, $callback = null) { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - - PHPUnit::assertCount( - 0, $this->sent($mailable, $callback), + PHPUnit::assertTrue( + $this->sent($mailable, $callback)->count() === 0, "The unexpected [{$mailable}] mailable was sent." ); } - /** - * Assert that no mailables were sent or queued to be sent. - * - * @return void - */ - public function assertNothingOutgoing() - { - $this->assertNothingSent(); - $this->assertNothingQueued(); - } - /** * Assert that no mailables were sent. * @@ -148,150 +52,29 @@ class MailFake implements Factory, Fake, Mailer, MailQueue */ public function assertNothingSent() { - $mailableNames = collect($this->mailables)->map( - fn ($mailable) => get_class($mailable) - )->join(', '); - - PHPUnit::assertEmpty($this->mailables, 'The following mailables were sent unexpectedly: '.$mailableNames); - } - - /** - * Assert if a mailable was queued based on a truth-test callback. - * - * @param string|\Closure $mailable - * @param callable|int|null $callback - * @return void - */ - public function assertQueued($mailable, $callback = null) - { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - - if (is_numeric($callback)) { - return $this->assertQueuedTimes($mailable, $callback); - } - - PHPUnit::assertTrue( - $this->queued($mailable, $callback)->count() > 0, - "The expected [{$mailable}] mailable was not queued." - ); - } - - /** - * Assert if a mailable was queued a number of times. - * - * @param string $mailable - * @param int $times - * @return void - */ - protected function assertQueuedTimes($mailable, $times = 1) - { - $count = $this->queued($mailable)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$mailable}] mailable was queued {$count} times instead of {$times} times." - ); - } - - /** - * Determine if a mailable was not queued based on a truth-test callback. - * - * @param string|\Closure $mailable - * @param callable|null $callback - * @return void - */ - public function assertNotQueued($mailable, $callback = null) - { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - - PHPUnit::assertCount( - 0, $this->queued($mailable, $callback), - "The unexpected [{$mailable}] mailable was queued." - ); - } - - /** - * Assert that no mailables were queued. - * - * @return void - */ - public function assertNothingQueued() - { - $mailableNames = collect($this->queuedMailables)->map( - fn ($mailable) => get_class($mailable) - )->join(', '); - - PHPUnit::assertEmpty($this->queuedMailables, 'The following mailables were queued unexpectedly: '.$mailableNames); - } - - /** - * Assert the total number of mailables that were sent. - * - * @param int $count - * @return void - */ - public function assertSentCount($count) - { - $total = collect($this->mailables)->count(); - - PHPUnit::assertSame( - $count, $total, - "The total number of mailables sent was {$total} instead of {$count}." - ); - } - - /** - * Assert the total number of mailables that were queued. - * - * @param int $count - * @return void - */ - public function assertQueuedCount($count) - { - $total = collect($this->queuedMailables)->count(); - - PHPUnit::assertSame( - $count, $total, - "The total number of mailables queued was {$total} instead of {$count}." - ); - } - - /** - * Assert the total number of mailables that were sent or queued. - * - * @param int $count - * @return void - */ - public function assertOutgoingCount($count) - { - $total = collect($this->mailables) - ->concat($this->queuedMailables) - ->count(); - - PHPUnit::assertSame( - $count, $total, - "The total number of outgoing mailables was {$total} instead of {$count}." - ); + PHPUnit::assertEmpty($this->mailables, 'Mailables were sent unexpectedly.'); } /** * Get all of the mailables matching a truth-test callback. * - * @param string|\Closure $mailable + * @param string $mailable * @param callable|null $callback * @return \Illuminate\Support\Collection */ public function sent($mailable, $callback = null) { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - if (! $this->hasSent($mailable)) { return collect(); } - $callback = $callback ?: fn () => true; + $callback = $callback ?: function () { + return true; + }; - return $this->mailablesOf($mailable)->filter(fn ($mailable) => $callback($mailable)); + return $this->mailablesOf($mailable)->filter(function ($mailable) use ($callback) { + return $callback($mailable); + }); } /** @@ -305,37 +88,6 @@ class MailFake implements Factory, Fake, Mailer, MailQueue return $this->mailablesOf($mailable)->count() > 0; } - /** - * Get all of the queued mailables matching a truth-test callback. - * - * @param string|\Closure $mailable - * @param callable|null $callback - * @return \Illuminate\Support\Collection - */ - public function queued($mailable, $callback = null) - { - [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback); - - if (! $this->hasQueued($mailable)) { - return collect(); - } - - $callback = $callback ?: fn () => true; - - return $this->queuedMailablesOf($mailable)->filter(fn ($mailable) => $callback($mailable)); - } - - /** - * Determine if the given mailable has been queued. - * - * @param string $mailable - * @return bool - */ - public function hasQueued($mailable) - { - return $this->queuedMailablesOf($mailable)->count() > 0; - } - /** * Get all of the mailed mailables for a given type. * @@ -344,31 +96,9 @@ class MailFake implements Factory, Fake, Mailer, MailQueue */ protected function mailablesOf($type) { - return collect($this->mailables)->filter(fn ($mailable) => $mailable instanceof $type); - } - - /** - * Get all of the mailed mailables for a given type. - * - * @param string $type - * @return \Illuminate\Support\Collection - */ - protected function queuedMailablesOf($type) - { - return collect($this->queuedMailables)->filter(fn ($mailable) => $mailable instanceof $type); - } - - /** - * Get a mailer instance by name. - * - * @param string|null $name - * @return \Illuminate\Contracts\Mail\Mailer - */ - public function mailer($name = null) - { - $this->currentMailer = $name; - - return $this; + return collect($this->mailables)->filter(function ($mailable) use ($type) { + return $mailable instanceof $type; + }); } /** @@ -382,17 +112,6 @@ class MailFake implements Factory, Fake, Mailer, MailQueue return (new PendingMailFake($this))->to($users); } - /** - * Begin the process of mailing a mailable class instance. - * - * @param mixed $users - * @return \Illuminate\Mail\PendingMail - */ - public function cc($users) - { - return (new PendingMailFake($this))->cc($users); - } - /** * Begin the process of mailing a mailable class instance. * @@ -405,11 +124,11 @@ class MailFake implements Factory, Fake, Mailer, MailQueue } /** - * Send a new message with only a raw text part. + * Send a new message when only a raw text part. * * @param string $text * @param \Closure|string $callback - * @return void + * @return int */ public function raw($text, $callback) { @@ -419,9 +138,9 @@ class MailFake implements Factory, Fake, Mailer, MailQueue /** * Send a new message using a view. * - * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|array $view * @param array $data - * @param \Closure|string|null $callback + * @param \Closure|string $callback * @return void */ public function send($view, array $data = [], $callback = null) @@ -430,87 +149,30 @@ class MailFake implements Factory, Fake, Mailer, MailQueue return; } - $view->mailer($this->currentMailer); - - if ($view instanceof ShouldQueue) { - return $this->queue($view, $data); - } - - $this->currentMailer = null; - $this->mailables[] = $view; } /** * Queue a new e-mail message for sending. * - * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|array $view + * @param array $data + * @param \Closure|string $callback * @param string|null $queue * @return mixed */ - public function queue($view, $queue = null) + public function queue($view, array $data = [], $callback = null, $queue = null) { - if (! $view instanceof Mailable) { - return; - } - - $view->mailer($this->currentMailer); - - $this->currentMailer = null; - - $this->queuedMailables[] = $view; + $this->send($view); } /** - * Queue a new e-mail message for sending after (n) seconds. + * Get the array of failed recipients. * - * @param \DateTimeInterface|\DateInterval|int $delay - * @param \Illuminate\Contracts\Mail\Mailable|string|array $view - * @param string|null $queue - * @return mixed - */ - public function later($delay, $view, $queue = null) - { - $this->queue($view, $queue); - } - - /** - * Infer mailable class using reflection if a typehinted closure is passed to assertion. - * - * @param string|\Closure $mailable - * @param callable|null $callback * @return array */ - protected function prepareMailableAndCallback($mailable, $callback) + public function failures() { - if ($mailable instanceof Closure) { - return [$this->firstClosureParameterType($mailable), $mailable]; - } - - return [$mailable, $callback]; - } - - /** - * Forget all of the resolved mailer instances. - * - * @return $this - */ - public function forgetMailers() - { - $this->currentMailer = null; - - return $this; - } - - /** - * Handle dynamic method calls to the mailer. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public function __call($method, $parameters) - { - return $this->forwardCallTo($this->manager, $method, $parameters); + // } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/NotificationFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/NotificationFake.php index 526c111c3..63050c582 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/NotificationFake.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/NotificationFake.php @@ -2,23 +2,13 @@ namespace Illuminate\Support\Testing\Fakes; -use Closure; -use Exception; -use Illuminate\Contracts\Notifications\Dispatcher as NotificationDispatcher; -use Illuminate\Contracts\Notifications\Factory as NotificationFactory; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Contracts\Translation\HasLocalePreference; -use Illuminate\Notifications\AnonymousNotifiable; +use Ramsey\Uuid\Uuid; use Illuminate\Support\Collection; -use Illuminate\Support\Str; -use Illuminate\Support\Traits\Macroable; -use Illuminate\Support\Traits\ReflectsClosures; use PHPUnit\Framework\Assert as PHPUnit; +use Illuminate\Contracts\Notifications\Factory as NotificationFactory; -class NotificationFake implements Fake, NotificationDispatcher, NotificationFactory +class NotificationFake implements NotificationFactory { - use Macroable, ReflectsClosures; - /** * All of the notifications that have been sent. * @@ -26,51 +16,17 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact */ protected $notifications = []; - /** - * Locale used when sending notifications. - * - * @var string|null - */ - public $locale; - - /** - * Indicates if notifications should be serialized and restored when pushed to the queue. - * - * @var bool - */ - protected $serializeAndRestore = false; - - /** - * Assert if a notification was sent on-demand based on a truth-test callback. - * - * @param string|\Closure $notification - * @param callable|null $callback - * @return void - * - * @throws \Exception - */ - public function assertSentOnDemand($notification, $callback = null) - { - $this->assertSentTo(new AnonymousNotifiable, $notification, $callback); - } - /** * Assert if a notification was sent based on a truth-test callback. * * @param mixed $notifiable - * @param string|\Closure $notification + * @param string $notification * @param callable|null $callback * @return void - * - * @throws \Exception */ public function assertSentTo($notifiable, $notification, $callback = null) { if (is_array($notifiable) || $notifiable instanceof Collection) { - if (count($notifiable) === 0) { - throw new Exception('No notifiable given.'); - } - foreach ($notifiable as $singleNotifiable) { $this->assertSentTo($singleNotifiable, $notification, $callback); } @@ -78,67 +34,23 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact return; } - if ($notification instanceof Closure) { - [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification]; - } - - if (is_numeric($callback)) { - return $this->assertSentToTimes($notifiable, $notification, $callback); - } - PHPUnit::assertTrue( $this->sent($notifiable, $notification, $callback)->count() > 0, "The expected [{$notification}] notification was not sent." ); } - /** - * Assert if a notification was sent on-demand a number of times. - * - * @param string $notification - * @param int $times - * @return void - */ - public function assertSentOnDemandTimes($notification, $times = 1) - { - return $this->assertSentToTimes(new AnonymousNotifiable, $notification, $times); - } - - /** - * Assert if a notification was sent a number of times. - * - * @param mixed $notifiable - * @param string $notification - * @param int $times - * @return void - */ - public function assertSentToTimes($notifiable, $notification, $times = 1) - { - $count = $this->sent($notifiable, $notification)->count(); - - PHPUnit::assertSame( - $times, $count, - "Expected [{$notification}] to be sent {$times} times, but was sent {$count} times." - ); - } - /** * Determine if a notification was sent based on a truth-test callback. * * @param mixed $notifiable - * @param string|\Closure $notification + * @param string $notification * @param callable|null $callback * @return void - * - * @throws \Exception */ public function assertNotSentTo($notifiable, $notification, $callback = null) { if (is_array($notifiable) || $notifiable instanceof Collection) { - if (count($notifiable) === 0) { - throw new Exception('No notifiable given.'); - } - foreach ($notifiable as $singleNotifiable) { $this->assertNotSentTo($singleNotifiable, $notification, $callback); } @@ -146,89 +58,12 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact return; } - if ($notification instanceof Closure) { - [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification]; - } - - PHPUnit::assertCount( - 0, $this->sent($notifiable, $notification, $callback), + PHPUnit::assertTrue( + $this->sent($notifiable, $notification, $callback)->count() === 0, "The unexpected [{$notification}] notification was sent." ); } - /** - * Assert that no notifications were sent. - * - * @return void - */ - public function assertNothingSent() - { - PHPUnit::assertEmpty($this->notifications, 'Notifications were sent unexpectedly.'); - } - - /** - * Assert that no notifications were sent to the given notifiable. - * - * @param mixed $notifiable - * @return void - * - * @throws \Exception - */ - public function assertNothingSentTo($notifiable) - { - if (is_array($notifiable) || $notifiable instanceof Collection) { - if (count($notifiable) === 0) { - throw new Exception('No notifiable given.'); - } - - foreach ($notifiable as $singleNotifiable) { - $this->assertNothingSentTo($singleNotifiable); - } - - return; - } - - PHPUnit::assertEmpty( - $this->notifications[get_class($notifiable)][$notifiable->getKey()] ?? [], - 'Notifications were sent unexpectedly.', - ); - } - - /** - * Assert the total amount of times a notification was sent. - * - * @param string $notification - * @param int $expectedCount - * @return void - */ - public function assertSentTimes($notification, $expectedCount) - { - $actualCount = collect($this->notifications) - ->flatten(1) - ->reduce(fn ($count, $sent) => $count + count($sent[$notification] ?? []), 0); - - PHPUnit::assertSame( - $expectedCount, $actualCount, - "Expected [{$notification}] to be sent {$expectedCount} times, but was sent {$actualCount} times." - ); - } - - /** - * Assert the total count of notification that were sent. - * - * @param int $expectedCount - * @return void - */ - public function assertCount($expectedCount) - { - $actualCount = collect($this->notifications)->flatten(3)->count(); - - PHPUnit::assertSame( - $expectedCount, $actualCount, - "Expected {$expectedCount} notifications to be sent, but {$actualCount} were sent." - ); - } - /** * Get all of the notifications matching a truth-test callback. * @@ -243,13 +78,15 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact return collect(); } - $callback = $callback ?: fn () => true; + $callback = $callback ?: function () { + return true; + }; $notifications = collect($this->notificationsFor($notifiable, $notification)); - return $notifications->filter( - fn ($arguments) => $callback(...array_values($arguments)) - )->pluck('notification'); + return $notifications->filter(function ($arguments) use ($callback) { + return $callback(...array_values($arguments)); + })->pluck('notification'); } /** @@ -273,7 +110,11 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact */ protected function notificationsFor($notifiable, $notification) { - return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? []; + if (isset($this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification])) { + return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification]; + } + + return []; } /** @@ -285,7 +126,7 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact */ public function send($notifiables, $notification) { - $this->sendNow($notifiables, $notification); + return $this->sendNow($notifiables, $notification); } /** @@ -293,44 +134,20 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification - * @param array|null $channels * @return void */ - public function sendNow($notifiables, $notification, ?array $channels = null) + public function sendNow($notifiables, $notification) { if (! $notifiables instanceof Collection && ! is_array($notifiables)) { $notifiables = [$notifiables]; } foreach ($notifiables as $notifiable) { - if (! $notification->id) { - $notification->id = Str::uuid()->toString(); - } - - $notifiableChannels = $channels ?: $notification->via($notifiable); - - if (method_exists($notification, 'shouldSend')) { - $notifiableChannels = array_filter( - $notifiableChannels, - fn ($channel) => $notification->shouldSend($notifiable, $channel) !== false - ); - } - - if (empty($notifiableChannels)) { - continue; - } + $notification->id = Uuid::uuid4()->toString(); $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [ - 'notification' => $this->serializeAndRestore && $notification instanceof ShouldQueue - ? $this->serializeAndRestoreNotification($notification) - : $notification, - 'channels' => $notifiableChannels, - 'notifiable' => $notifiable, - 'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) { - if ($notifiable instanceof HasLocalePreference) { - return $notifiable->preferredLocale(); - } - }), + 'notification' => $notification, + 'channels' => $notification->via($notifiable), ]; } } @@ -345,51 +162,4 @@ class NotificationFake implements Fake, NotificationDispatcher, NotificationFact { // } - - /** - * Set the locale of notifications. - * - * @param string $locale - * @return $this - */ - public function locale($locale) - { - $this->locale = $locale; - - return $this; - } - - /** - * Specify if notification should be serialized and restored when being "pushed" to the queue. - * - * @param bool $serializeAndRestore - * @return $this - */ - public function serializeAndRestore(bool $serializeAndRestore = true) - { - $this->serializeAndRestore = $serializeAndRestore; - - return $this; - } - - /** - * Serialize and unserialize the notification to simulate the queueing process. - * - * @param mixed $notification - * @return mixed - */ - protected function serializeAndRestoreNotification($notification) - { - return unserialize(serialize($notification)); - } - - /** - * Get the notifications that have been sent. - * - * @return array - */ - public function sentNotifications() - { - return $this->notifications; - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingBatchFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingBatchFake.php deleted file mode 100644 index 3d0f49929..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingBatchFake.php +++ /dev/null @@ -1,49 +0,0 @@ -bus = $bus; - $this->jobs = $jobs; - } - - /** - * Dispatch the batch. - * - * @return \Illuminate\Bus\Batch - */ - public function dispatch() - { - return $this->bus->recordPendingBatch($this); - } - - /** - * Dispatch the batch after the response is sent to the browser. - * - * @return \Illuminate\Bus\Batch - */ - public function dispatchAfterResponse() - { - return $this->bus->recordPendingBatch($this); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingChainFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingChainFake.php deleted file mode 100644 index 533c6498b..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingChainFake.php +++ /dev/null @@ -1,56 +0,0 @@ -bus = $bus; - $this->job = $job; - $this->chain = $chain; - } - - /** - * Dispatch the job with the given arguments. - * - * @return \Illuminate\Foundation\Bus\PendingDispatch - */ - public function dispatch() - { - if (is_string($this->job)) { - $firstJob = new $this->job(...func_get_args()); - } elseif ($this->job instanceof Closure) { - $firstJob = CallQueuedClosure::create($this->job); - } else { - $firstJob = $this->job; - } - - $firstJob->allOnConnection($this->connection); - $firstJob->allOnQueue($this->queue); - $firstJob->chain($this->chain); - $firstJob->delay($this->delay); - $firstJob->chainCatchCallbacks = $this->catchCallbacks(); - - return $this->bus->dispatch($firstJob); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingMailFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingMailFake.php index 52251301c..0baa9d2a2 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingMailFake.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/PendingMailFake.php @@ -2,7 +2,7 @@ namespace Illuminate\Support\Testing\Fakes; -use Illuminate\Contracts\Mail\Mailable; +use Illuminate\Mail\Mailable; use Illuminate\Mail\PendingMail; class PendingMailFake extends PendingMail @@ -21,10 +21,21 @@ class PendingMailFake extends PendingMail /** * Send a new mailable message instance. * - * @param \Illuminate\Contracts\Mail\Mailable $mailable - * @return void + * @param Mailable $mailable + * @return mixed */ public function send(Mailable $mailable) + { + return $this->sendNow($mailable); + } + + /** + * Send a mailable message immediately. + * + * @param Mailable $mailable + * @return mixed + */ + public function sendNow(Mailable $mailable) { $this->mailer->send($this->fill($mailable)); } @@ -32,11 +43,11 @@ class PendingMailFake extends PendingMail /** * Push the given mailable onto the queue. * - * @param \Illuminate\Contracts\Mail\Mailable $mailable + * @param Mailable $mailable * @return mixed */ public function queue(Mailable $mailable) { - return $this->mailer->queue($this->fill($mailable)); + return $this->sendNow($mailable); } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/QueueFake.php b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/QueueFake.php index d0da55de1..4da24c8e5 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/QueueFake.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Testing/Fakes/QueueFake.php @@ -2,40 +2,12 @@ namespace Illuminate\Support\Testing\Fakes; -use BadMethodCallException; -use Closure; -use Illuminate\Contracts\Queue\Queue; -use Illuminate\Queue\CallQueuedClosure; use Illuminate\Queue\QueueManager; -use Illuminate\Support\Collection; -use Illuminate\Support\Traits\ReflectsClosures; +use Illuminate\Contracts\Queue\Queue; use PHPUnit\Framework\Assert as PHPUnit; -class QueueFake extends QueueManager implements Fake, Queue +class QueueFake extends QueueManager implements Queue { - use ReflectsClosures; - - /** - * The original queue manager. - * - * @var \Illuminate\Contracts\Queue\Queue - */ - public $queue; - - /** - * The job types that should be intercepted instead of pushed to the queue. - * - * @var \Illuminate\Support\Collection - */ - protected $jobsToFake; - - /** - * The job types that should be pushed to the queue and not intercepted. - * - * @var \Illuminate\Support\Collection - */ - protected $jobsToBeQueued; - /** * All of the jobs that have been pushed. * @@ -43,98 +15,32 @@ class QueueFake extends QueueManager implements Fake, Queue */ protected $jobs = []; - /** - * Indicates if items should be serialized and restored when pushed to the queue. - * - * @var bool - */ - protected bool $serializeAndRestore = false; - - /** - * Create a new fake queue instance. - * - * @param \Illuminate\Contracts\Foundation\Application $app - * @param array $jobsToFake - * @param \Illuminate\Queue\QueueManager|null $queue - * @return void - */ - public function __construct($app, $jobsToFake = [], $queue = null) - { - parent::__construct($app); - - $this->jobsToFake = Collection::wrap($jobsToFake); - $this->jobsToBeQueued = Collection::make(); - $this->queue = $queue; - } - - /** - * Specify the jobs that should be queued instead of faked. - * - * @param array|string $jobsToBeQueued - * @return $this - */ - public function except($jobsToBeQueued) - { - $this->jobsToBeQueued = Collection::wrap($jobsToBeQueued)->merge($this->jobsToBeQueued); - - return $this; - } - /** * Assert if a job was pushed based on a truth-test callback. * - * @param string|\Closure $job - * @param callable|int|null $callback + * @param string $job + * @param callable|null $callback * @return void */ public function assertPushed($job, $callback = null) { - if ($job instanceof Closure) { - [$job, $callback] = [$this->firstClosureParameterType($job), $job]; - } - - if (is_numeric($callback)) { - return $this->assertPushedTimes($job, $callback); - } - PHPUnit::assertTrue( $this->pushed($job, $callback)->count() > 0, "The expected [{$job}] job was not pushed." ); } - /** - * Assert if a job was pushed a number of times. - * - * @param string $job - * @param int $times - * @return void - */ - protected function assertPushedTimes($job, $times = 1) - { - $count = $this->pushed($job)->count(); - - PHPUnit::assertSame( - $times, $count, - "The expected [{$job}] job was pushed {$count} times instead of {$times} times." - ); - } - /** * Assert if a job was pushed based on a truth-test callback. * * @param string $queue - * @param string|\Closure $job + * @param string $job * @param callable|null $callback * @return void */ public function assertPushedOn($queue, $job, $callback = null) { - if ($job instanceof Closure) { - [$job, $callback] = [$this->firstClosureParameterType($job), $job]; - } - - $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { + return $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) { if ($pushedQueue !== $queue) { return false; } @@ -143,167 +49,21 @@ class QueueFake extends QueueManager implements Fake, Queue }); } - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - public function assertPushedWithChain($job, $expectedChain = [], $callback = null) - { - PHPUnit::assertTrue( - $this->pushed($job, $callback)->isNotEmpty(), - "The expected [{$job}] job was not pushed." - ); - - PHPUnit::assertTrue( - collect($expectedChain)->isNotEmpty(), - 'The expected chain can not be empty.' - ); - - $this->isChainOfObjects($expectedChain) - ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback) - : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback); - } - - /** - * Assert if a job was pushed with an empty chain based on a truth-test callback. - * - * @param string $job - * @param callable|null $callback - * @return void - */ - public function assertPushedWithoutChain($job, $callback = null) - { - PHPUnit::assertTrue( - $this->pushed($job, $callback)->isNotEmpty(), - "The expected [{$job}] job was not pushed." - ); - - $this->assertPushedWithChainOfClasses($job, [], $callback); - } - - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - protected function assertPushedWithChainOfObjects($job, $expectedChain, $callback) - { - $chain = collect($expectedChain)->map(fn ($job) => serialize($job))->all(); - - PHPUnit::assertTrue( - $this->pushed($job, $callback)->filter(fn ($job) => $job->chained == $chain)->isNotEmpty(), - 'The expected chain was not pushed.' - ); - } - - /** - * Assert if a job was pushed with chained jobs based on a truth-test callback. - * - * @param string $job - * @param array $expectedChain - * @param callable|null $callback - * @return void - */ - protected function assertPushedWithChainOfClasses($job, $expectedChain, $callback) - { - $matching = $this->pushed($job, $callback)->map->chained->map(function ($chain) { - return collect($chain)->map(function ($job) { - return get_class(unserialize($job)); - }); - })->filter(function ($chain) use ($expectedChain) { - return $chain->all() === $expectedChain; - }); - - PHPUnit::assertTrue( - $matching->isNotEmpty(), 'The expected chain was not pushed.' - ); - } - - /** - * Assert if a closure was pushed based on a truth-test callback. - * - * @param callable|int|null $callback - * @return void - */ - public function assertClosurePushed($callback = null) - { - $this->assertPushed(CallQueuedClosure::class, $callback); - } - - /** - * Assert that a closure was not pushed based on a truth-test callback. - * - * @param callable|null $callback - * @return void - */ - public function assertClosureNotPushed($callback = null) - { - $this->assertNotPushed(CallQueuedClosure::class, $callback); - } - - /** - * Determine if the given chain is entirely composed of objects. - * - * @param array $chain - * @return bool - */ - protected function isChainOfObjects($chain) - { - return ! collect($chain)->contains(fn ($job) => ! is_object($job)); - } - /** * Determine if a job was pushed based on a truth-test callback. * - * @param string|\Closure $job + * @param string $job * @param callable|null $callback * @return void */ public function assertNotPushed($job, $callback = null) { - if ($job instanceof Closure) { - [$job, $callback] = [$this->firstClosureParameterType($job), $job]; - } - - PHPUnit::assertCount( - 0, $this->pushed($job, $callback), + PHPUnit::assertTrue( + $this->pushed($job, $callback)->count() === 0, "The unexpected [{$job}] job was pushed." ); } - /** - * Assert the total count of jobs that were pushed. - * - * @param int $expectedCount - * @return void - */ - public function assertCount($expectedCount) - { - $actualCount = collect($this->jobs)->flatten(1)->count(); - - PHPUnit::assertSame( - $expectedCount, $actualCount, - "Expected {$expectedCount} jobs to be pushed, but found {$actualCount} instead." - ); - } - - /** - * Assert that no jobs were pushed. - * - * @return void - */ - public function assertNothingPushed() - { - PHPUnit::assertEmpty($this->jobs, 'Jobs were pushed unexpectedly.'); - } - /** * Get all of the jobs matching a truth-test callback. * @@ -317,11 +77,13 @@ class QueueFake extends QueueManager implements Fake, Queue return collect(); } - $callback = $callback ?: fn () => true; + $callback = $callback ?: function () { + return true; + }; - return collect($this->jobs[$job])->filter( - fn ($data) => $callback($data['job'], $data['queue'], $data['data']) - )->pluck('job'); + return collect($this->jobs[$job])->filter(function ($data) use ($callback) { + return $callback($data['job'], $data['queue']); + })->pluck('job'); } /** @@ -349,87 +111,36 @@ class QueueFake extends QueueManager implements Fake, Queue /** * Get the size of the queue. * - * @param string|null $queue + * @param string $queue * @return int */ public function size($queue = null) { - return collect($this->jobs)->flatten(1)->filter( - fn ($job) => $job['queue'] === $queue - )->count(); + return 0; } /** * Push a new job onto the queue. * - * @param string|object $job - * @param mixed $data - * @param string|null $queue + * @param string $job + * @param mixed $data + * @param string $queue * @return mixed */ public function push($job, $data = '', $queue = null) { - if ($this->shouldFakeJob($job)) { - if ($job instanceof Closure) { - $job = CallQueuedClosure::create($job); - } - - $this->jobs[is_object($job) ? get_class($job) : $job][] = [ - 'job' => $this->serializeAndRestore ? $this->serializeAndRestoreJob($job) : $job, - 'queue' => $queue, - 'data' => $data, - ]; - } else { - is_object($job) && isset($job->connection) - ? $this->queue->connection($job->connection)->push($job, $data, $queue) - : $this->queue->push($job, $data, $queue); - } - } - - /** - * Determine if a job should be faked or actually dispatched. - * - * @param object $job - * @return bool - */ - public function shouldFakeJob($job) - { - if ($this->shouldDispatchJob($job)) { - return false; - } - - if ($this->jobsToFake->isEmpty()) { - return true; - } - - return $this->jobsToFake->contains( - fn ($jobToFake) => $job instanceof ((string) $jobToFake) || $job === (string) $jobToFake - ); - } - - /** - * Determine if a job should be pushed to the queue instead of faked. - * - * @param object $job - * @return bool - */ - protected function shouldDispatchJob($job) - { - if ($this->jobsToBeQueued->isEmpty()) { - return false; - } - - return $this->jobsToBeQueued->contains( - fn ($jobToQueue) => $job instanceof ((string) $jobToQueue) - ); + $this->jobs[is_object($job) ? get_class($job) : $job][] = [ + 'job' => $job, + 'queue' => $queue, + ]; } /** * Push a raw payload onto the queue. * * @param string $payload - * @param string|null $queue - * @param array $options + * @param string $queue + * @param array $options * @return mixed */ public function pushRaw($payload, $queue = null, array $options = []) @@ -438,12 +149,12 @@ class QueueFake extends QueueManager implements Fake, Queue } /** - * Push a new job onto the queue after (n) seconds. + * Push a new job onto the queue after a delay. * - * @param \DateTimeInterface|\DateInterval|int $delay - * @param string|object $job - * @param mixed $data - * @param string|null $queue + * @param \DateTime|int $delay + * @param string $job + * @param mixed $data + * @param string $queue * @return mixed */ public function later($delay, $job, $data = '', $queue = null) @@ -455,8 +166,8 @@ class QueueFake extends QueueManager implements Fake, Queue * Push a new job onto the queue. * * @param string $queue - * @param string|object $job - * @param mixed $data + * @param string $job + * @param mixed $data * @return mixed */ public function pushOn($queue, $job, $data = '') @@ -465,12 +176,12 @@ class QueueFake extends QueueManager implements Fake, Queue } /** - * Push a new job onto a specific queue after (n) seconds. + * Push a new job onto the queue after a delay. * * @param string $queue - * @param \DateTimeInterface|\DateInterval|int $delay - * @param string|object $job - * @param mixed $data + * @param \DateTime|int $delay + * @param string $job + * @param mixed $data * @return mixed */ public function laterOn($queue, $delay, $job, $data = '') @@ -481,7 +192,7 @@ class QueueFake extends QueueManager implements Fake, Queue /** * Pop the next job off of the queue. * - * @param string|null $queue + * @param string $queue * @return \Illuminate\Contracts\Queue\Job|null */ public function pop($queue = null) @@ -492,52 +203,18 @@ class QueueFake extends QueueManager implements Fake, Queue /** * Push an array of jobs onto the queue. * - * @param array $jobs - * @param mixed $data - * @param string|null $queue + * @param array $jobs + * @param mixed $data + * @param string $queue * @return mixed */ public function bulk($jobs, $data = '', $queue = null) { - foreach ($jobs as $job) { - $this->push($job, $data, $queue); + foreach ($this->jobs as $job) { + $this->push($job); } } - /** - * Get the jobs that have been pushed. - * - * @return array - */ - public function pushedJobs() - { - return $this->jobs; - } - - /** - * Specify if jobs should be serialized and restored when being "pushed" to the queue. - * - * @param bool $serializeAndRestore - * @return $this - */ - public function serializeAndRestore(bool $serializeAndRestore = true) - { - $this->serializeAndRestore = $serializeAndRestore; - - return $this; - } - - /** - * Serialize and unserialize the job to simulate the queueing process. - * - * @param mixed $job - * @return mixed - */ - protected function serializeAndRestoreJob($job) - { - return unserialize(serialize($job)); - } - /** * Get the connection name for the queue. * @@ -551,27 +228,11 @@ class QueueFake extends QueueManager implements Fake, Queue /** * Set the connection name for the queue. * - * @param string $name + * @param string $name * @return $this */ public function setConnectionName($name) { return $this; } - - /** - * Override the QueueManager to prevent circular dependency. - * - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - public function __call($method, $parameters) - { - throw new BadMethodCallException(sprintf( - 'Call to undefined method %s::%s()', static::class, $method - )); - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/Timebox.php b/lam/lib/3rdParty/composer/illuminate/support/Timebox.php deleted file mode 100644 index cb99a4a84..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Timebox.php +++ /dev/null @@ -1,84 +0,0 @@ -earlyReturn && $remainder > 0) { - $this->usleep($remainder); - } - - if ($exception) { - throw $exception; - } - - return $result; - } - - /** - * Indicate that the timebox can return early. - * - * @return $this - */ - public function returnEarly() - { - $this->earlyReturn = true; - - return $this; - } - - /** - * Indicate that the timebox cannot return early. - * - * @return $this - */ - public function dontReturnEarly() - { - $this->earlyReturn = false; - - return $this; - } - - /** - * Sleep for the specified number of microseconds. - * - * @param int $microseconds - * @return void - */ - protected function usleep(int $microseconds) - { - Sleep::usleep($microseconds); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/CapsuleManagerTrait.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/CapsuleManagerTrait.php index 053275522..08089ef66 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/Traits/CapsuleManagerTrait.php +++ b/lam/lib/3rdParty/composer/illuminate/support/Traits/CapsuleManagerTrait.php @@ -2,8 +2,8 @@ namespace Illuminate\Support\Traits; -use Illuminate\Contracts\Container\Container; use Illuminate\Support\Fluent; +use Illuminate\Contracts\Container\Container; trait CapsuleManagerTrait { diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/ForwardsCalls.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/ForwardsCalls.php deleted file mode 100644 index 4c6b610aa..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Traits/ForwardsCalls.php +++ /dev/null @@ -1,71 +0,0 @@ -{$method}(...$parameters); - } catch (Error|BadMethodCallException $e) { - $pattern = '~^Call to undefined method (?P[^:]+)::(?P[^\(]+)\(\)$~'; - - if (! preg_match($pattern, $e->getMessage(), $matches)) { - throw $e; - } - - if ($matches['class'] != get_class($object) || - $matches['method'] != $method) { - throw $e; - } - - static::throwBadMethodCallException($method); - } - } - - /** - * Forward a method call to the given object, returning $this if the forwarded call returned itself. - * - * @param mixed $object - * @param string $method - * @param array $parameters - * @return mixed - * - * @throws \BadMethodCallException - */ - protected function forwardDecoratedCallTo($object, $method, $parameters) - { - $result = $this->forwardCallTo($object, $method, $parameters); - - return $result === $object ? $this : $result; - } - - /** - * Throw a bad method call exception for the given method. - * - * @param string $method - * @return void - * - * @throws \BadMethodCallException - */ - protected static function throwBadMethodCallException($method) - { - throw new BadMethodCallException(sprintf( - 'Call to undefined method %s::%s()', static::class, $method - )); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/Localizable.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/Localizable.php deleted file mode 100644 index 1e9fa58c9..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Traits/Localizable.php +++ /dev/null @@ -1,34 +0,0 @@ -getLocale(); - - try { - $app->setLocale($locale); - - return $callback(); - } finally { - $app->setLocale($original); - } - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/Macroable.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/Macroable.php new file mode 100644 index 000000000..2c103d4fc --- /dev/null +++ b/lam/lib/3rdParty/composer/illuminate/support/Traits/Macroable.php @@ -0,0 +1,83 @@ +bindTo($this, static::class), $parameters); + } + + return call_user_func_array(static::$macros[$method], $parameters); + } +} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/ReflectsClosures.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/ReflectsClosures.php deleted file mode 100644 index bf47d7ec2..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Traits/ReflectsClosures.php +++ /dev/null @@ -1,88 +0,0 @@ -closureParameterTypes($closure)); - - if (! $types) { - throw new RuntimeException('The given Closure has no parameters.'); - } - - if ($types[0] === null) { - throw new RuntimeException('The first parameter of the given Closure is missing a type hint.'); - } - - return $types[0]; - } - - /** - * Get the class names of the first parameter of the given Closure, including union types. - * - * @param \Closure $closure - * @return array - * - * @throws \ReflectionException - * @throws \RuntimeException - */ - protected function firstClosureParameterTypes(Closure $closure) - { - $reflection = new ReflectionFunction($closure); - - $types = collect($reflection->getParameters())->mapWithKeys(function ($parameter) { - if ($parameter->isVariadic()) { - return [$parameter->getName() => null]; - } - - return [$parameter->getName() => Reflector::getParameterClassNames($parameter)]; - })->filter()->values()->all(); - - if (empty($types)) { - throw new RuntimeException('The given Closure has no parameters.'); - } - - if (isset($types[0]) && empty($types[0])) { - throw new RuntimeException('The first parameter of the given Closure is missing a type hint.'); - } - - return $types[0]; - } - - /** - * Get the class names / types of the parameters of the given Closure. - * - * @param \Closure $closure - * @return array - * - * @throws \ReflectionException - */ - protected function closureParameterTypes(Closure $closure) - { - $reflection = new ReflectionFunction($closure); - - return collect($reflection->getParameters())->mapWithKeys(function ($parameter) { - if ($parameter->isVariadic()) { - return [$parameter->getName() => null]; - } - - return [$parameter->getName() => Reflector::getParameterClassName($parameter)]; - })->all(); - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/Traits/Tappable.php b/lam/lib/3rdParty/composer/illuminate/support/Traits/Tappable.php deleted file mode 100644 index 9353451ad..000000000 --- a/lam/lib/3rdParty/composer/illuminate/support/Traits/Tappable.php +++ /dev/null @@ -1,17 +0,0 @@ -input = $input; - } - - /** - * Determine if the validated input has one or more keys. - * - * @param mixed $keys - * @return bool - */ - public function has($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - foreach ($keys as $key) { - if (! Arr::has($this->all(), $key)) { - return false; - } - } - - return true; - } - - /** - * Determine if the validated input is missing one or more keys. - * - * @param mixed $keys - * @return bool - */ - public function missing($keys) - { - return ! $this->has($keys); - } - - /** - * Get a subset containing the provided keys with values from the input data. - * - * @param mixed $keys - * @return array - */ - public function only($keys) - { - $results = []; - - $input = $this->all(); - - $placeholder = new stdClass; - - foreach (is_array($keys) ? $keys : func_get_args() as $key) { - $value = data_get($input, $key, $placeholder); - - if ($value !== $placeholder) { - Arr::set($results, $key, $value); - } - } - - return $results; - } - - /** - * Get all of the input except for a specified array of items. - * - * @param mixed $keys - * @return array - */ - public function except($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - $results = $this->all(); - - Arr::forget($results, $keys); - - return $results; - } - - /** - * Merge the validated input with the given array of additional data. - * - * @param array $items - * @return static - */ - public function merge(array $items) - { - return new static(array_merge($this->all(), $items)); - } - - /** - * Get the input as a collection. - * - * @param array|string|null $key - * @return \Illuminate\Support\Collection - */ - public function collect($key = null) - { - return collect(is_array($key) ? $this->only($key) : $this->input($key)); - } - - /** - * Get the raw, underlying input array. - * - * @return array - */ - public function all() - { - return $this->input; - } - - /** - * Get the instance as an array. - * - * @return array - */ - public function toArray() - { - return $this->all(); - } - - /** - * Dynamically access input data. - * - * @param string $name - * @return mixed - */ - public function __get($name) - { - return $this->input($name); - } - - /** - * Dynamically set input data. - * - * @param string $name - * @param mixed $value - * @return mixed - */ - public function __set($name, $value) - { - $this->input[$name] = $value; - } - - /** - * Determine if an input key is set. - * - * @return bool - */ - public function __isset($name) - { - return $this->exists($name); - } - - /** - * Remove an input key. - * - * @param string $name - * @return void - */ - public function __unset($name) - { - unset($this->input[$name]); - } - - /** - * Determine if an item exists at an offset. - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key): bool - { - return $this->exists($key); - } - - /** - * Get an item at a given offset. - * - * @param mixed $key - * @return mixed - */ - public function offsetGet($key): mixed - { - return $this->input($key); - } - - /** - * Set the item at a given offset. - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value): void - { - if (is_null($key)) { - $this->input[] = $value; - } else { - $this->input[$key] = $value; - } - } - - /** - * Unset the item at a given offset. - * - * @param string $key - * @return void - */ - public function offsetUnset($key): void - { - unset($this->input[$key]); - } - - /** - * Get an iterator for the input. - * - * @return \ArrayIterator - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->input); - } - - /** - * Determine if the validated inputs contains a given input item key. - * - * @param string|array $key - * @return bool - */ - public function exists($key) - { - return $this->has($key); - } - - /** - * Determine if the validated inputs contains any of the given inputs. - * - * @param string|array $keys - * @return bool - */ - public function hasAny($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - $input = $this->all(); - - return Arr::hasAny($input, $keys); - } - - /** - * Apply the callback if the validated inputs contains the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenHas($key, callable $callback, ?callable $default = null) - { - if ($this->has($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Determine if the validated inputs contains a non-empty value for an input item. - * - * @param string|array $key - * @return bool - */ - public function filled($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if ($this->isEmptyString($value)) { - return false; - } - } - - return true; - } - - /** - * Determine if the validated inputs contains an empty value for an input item. - * - * @param string|array $key - * @return bool - */ - public function isNotFilled($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if (! $this->isEmptyString($value)) { - return false; - } - } - - return true; - } - - /** - * Determine if the validated inputs contains a non-empty value for any of the given inputs. - * - * @param string|array $keys - * @return bool - */ - public function anyFilled($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - foreach ($keys as $key) { - if ($this->filled($key)) { - return true; - } - } - - return false; - } - - /** - * Apply the callback if the validated inputs contains a non-empty value for the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenFilled($key, callable $callback, ?callable $default = null) - { - if ($this->filled($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Apply the callback if the validated inputs is missing the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenMissing($key, callable $callback, ?callable $default = null) - { - if ($this->missing($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Determine if the given input key is an empty string for "filled". - * - * @param string $key - * @return bool - */ - protected function isEmptyString($key) - { - $value = $this->input($key); - - return ! is_bool($value) && ! is_array($value) && trim((string) $value) === ''; - } - - /** - * Get the keys for all of the input. - * - * @return array - */ - public function keys() - { - return array_keys($this->input()); - } - - /** - * Retrieve an input item from the validated inputs. - * - * @param string|null $key - * @param mixed $default - * @return mixed - */ - public function input($key = null, $default = null) - { - return data_get( - $this->all(), $key, $default - ); - } - - /** - * Retrieve input from the validated inputs as a Stringable instance. - * - * @param string $key - * @param mixed $default - * @return \Illuminate\Support\Stringable - */ - public function str($key, $default = null) - { - return $this->string($key, $default); - } - - /** - * Retrieve input from the validated inputs as a Stringable instance. - * - * @param string $key - * @param mixed $default - * @return \Illuminate\Support\Stringable - */ - public function string($key, $default = null) - { - return str($this->input($key, $default)); - } - - /** - * Retrieve input as a boolean value. - * - * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. - * - * @param string|null $key - * @param bool $default - * @return bool - */ - public function boolean($key = null, $default = false) - { - return filter_var($this->input($key, $default), FILTER_VALIDATE_BOOLEAN); - } - - /** - * Retrieve input as an integer value. - * - * @param string $key - * @param int $default - * @return int - */ - public function integer($key, $default = 0) - { - return intval($this->input($key, $default)); - } - - /** - * Retrieve input as a float value. - * - * @param string $key - * @param float $default - * @return float - */ - public function float($key, $default = 0.0) - { - return floatval($this->input($key, $default)); - } - - /** - * Retrieve input from the validated inputs as a Carbon instance. - * - * @param string $key - * @param string|null $format - * @param string|null $tz - * @return \Illuminate\Support\Carbon|null - * - * @throws \Carbon\Exceptions\InvalidFormatException - */ - public function date($key, $format = null, $tz = null) - { - if ($this->isNotFilled($key)) { - return null; - } - - if (is_null($format)) { - return Date::parse($this->input($key), $tz); - } - - return Date::createFromFormat($format, $this->input($key), $tz); - } - - /** - * Retrieve input from the validated inputs as an enum. - * - * @template TEnum - * - * @param string $key - * @param class-string $enumClass - * @return TEnum|null - */ - public function enum($key, $enumClass) - { - if ($this->isNotFilled($key) || - ! enum_exists($enumClass) || - ! method_exists($enumClass, 'tryFrom')) { - return null; - } - - return $enumClass::tryFrom($this->input($key)); - } - - /** - * Dump the validated inputs items and end the script. - * - * @param mixed ...$keys - * @return never - */ - public function dd(...$keys) - { - $this->dump(...$keys); - - exit(1); - } - - /** - * Dump the items. - * - * @param mixed $keys - * @return $this - */ - public function dump($keys = []) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - VarDumper::dump(count($keys) > 0 ? $this->only($keys) : $this->all()); - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/illuminate/support/ViewErrorBag.php b/lam/lib/3rdParty/composer/illuminate/support/ViewErrorBag.php index ff9da4fc5..89e6a0527 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/ViewErrorBag.php +++ b/lam/lib/3rdParty/composer/illuminate/support/ViewErrorBag.php @@ -78,7 +78,7 @@ class ViewErrorBag implements Countable * * @return int */ - public function count(): int + public function count() { return $this->getBag('default')->count(); } @@ -117,14 +117,4 @@ class ViewErrorBag implements Countable { $this->put($key, $value); } - - /** - * Convert the default bag to its string representation. - * - * @return string - */ - public function __toString() - { - return (string) $this->getBag('default'); - } } diff --git a/lam/lib/3rdParty/composer/illuminate/support/composer.json b/lam/lib/3rdParty/composer/illuminate/support/composer.json index 57c92e366..0aac0b49c 100644 --- a/lam/lib/3rdParty/composer/illuminate/support/composer.json +++ b/lam/lib/3rdParty/composer/illuminate/support/composer.json @@ -14,20 +14,14 @@ } ], "require": { - "php": "^8.1", - "ext-ctype": "*", - "ext-filter": "*", + "php": ">=5.6.4", "ext-mbstring": "*", - "doctrine/inflector": "^2.0", - "illuminate/collections": "^10.0", - "illuminate/conditionable": "^10.0", - "illuminate/contracts": "^10.0", - "illuminate/macroable": "^10.0", - "nesbot/carbon": "^2.67", - "voku/portable-ascii": "^2.0" + "doctrine/inflector": "~1.1", + "illuminate/contracts": "5.4.*", + "paragonie/random_compat": "~1.4|~2.0" }, - "conflict": { - "tightenco/collect": "<5.5.33" + "replace": { + "tightenco/collect": "self.version" }, "autoload": { "psr-4": { @@ -39,17 +33,13 @@ }, "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "5.4-dev" } }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (^10.0).", - "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", - "ramsey/uuid": "Required to use Str::uuid() (^4.7).", - "symfony/process": "Required to use the composer class (^6.2).", - "symfony/uid": "Required to use Str::ulid() (^6.2).", - "symfony/var-dumper": "Required to use the dd function (^6.2).", - "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." + "illuminate/filesystem": "Required to use the composer class (5.2.*).", + "symfony/process": "Required to use the composer class (~3.2).", + "symfony/var-dumper": "Required to use the dd function (~3.2)." }, "config": { "sort-packages": true diff --git a/lam/lib/3rdParty/composer/illuminate/support/helpers.php b/lam/lib/3rdParty/composer/illuminate/support/helpers.php index cdcf52f15..018937f1e 100755 --- a/lam/lib/3rdParty/composer/illuminate/support/helpers.php +++ b/lam/lib/3rdParty/composer/illuminate/support/helpers.php @@ -1,13 +1,11 @@ $class] as $class) { + foreach (array_merge([$class => $class], class_parents($class)) as $class) { $results += trait_uses_recursive($class); } @@ -99,29 +381,184 @@ if (! function_exists('class_uses_recursive')) { } } -if (! function_exists('e')) { +if (! function_exists('collect')) { /** - * Encode HTML special characters in a string. + * Create a collection from the given value. * - * @param \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|\BackedEnum|string|null $value - * @param bool $doubleEncode - * @return string + * @param mixed $value + * @return \Illuminate\Support\Collection */ - function e($value, $doubleEncode = true) + function collect($value = null) { - if ($value instanceof DeferringDisplayableValue) { - $value = $value->resolveDisplayableValue(); + return new Collection($value); + } +} + +if (! function_exists('data_fill')) { + /** + * Fill in data where it's missing. + * + * @param mixed $target + * @param string|array $key + * @param mixed $value + * @return mixed + */ + function data_fill(&$target, $key, $value) + { + return data_set($target, $key, $value, false); + } +} + +if (! function_exists('data_get')) { + /** + * Get an item from an array or object using "dot" notation. + * + * @param mixed $target + * @param string|array $key + * @param mixed $default + * @return mixed + */ + function data_get($target, $key, $default = null) + { + if (is_null($key)) { + return $target; } + $key = is_array($key) ? $key : explode('.', $key); + + while (! is_null($segment = array_shift($key))) { + if ($segment === '*') { + if ($target instanceof Collection) { + $target = $target->all(); + } elseif (! is_array($target)) { + return value($default); + } + + $result = Arr::pluck($target, $key); + + return in_array('*', $key) ? Arr::collapse($result) : $result; + } + + if (Arr::accessible($target) && Arr::exists($target, $segment)) { + $target = $target[$segment]; + } elseif (is_object($target) && isset($target->{$segment})) { + $target = $target->{$segment}; + } else { + return value($default); + } + } + + return $target; + } +} + +if (! function_exists('data_set')) { + /** + * Set an item on an array or object using dot notation. + * + * @param mixed $target + * @param string|array $key + * @param mixed $value + * @param bool $overwrite + * @return mixed + */ + function data_set(&$target, $key, $value, $overwrite = true) + { + $segments = is_array($key) ? $key : explode('.', $key); + + if (($segment = array_shift($segments)) === '*') { + if (! Arr::accessible($target)) { + $target = []; + } + + if ($segments) { + foreach ($target as &$inner) { + data_set($inner, $segments, $value, $overwrite); + } + } elseif ($overwrite) { + foreach ($target as &$inner) { + $inner = $value; + } + } + } elseif (Arr::accessible($target)) { + if ($segments) { + if (! Arr::exists($target, $segment)) { + $target[$segment] = []; + } + + data_set($target[$segment], $segments, $value, $overwrite); + } elseif ($overwrite || ! Arr::exists($target, $segment)) { + $target[$segment] = $value; + } + } elseif (is_object($target)) { + if ($segments) { + if (! isset($target->{$segment})) { + $target->{$segment} = []; + } + + data_set($target->{$segment}, $segments, $value, $overwrite); + } elseif ($overwrite || ! isset($target->{$segment})) { + $target->{$segment} = $value; + } + } else { + $target = []; + + if ($segments) { + data_set($target[$segment], $segments, $value, $overwrite); + } elseif ($overwrite) { + $target[$segment] = $value; + } + } + + return $target; + } +} + +if (! function_exists('dd')) { + /** + * Dump the passed variables and end the script. + * + * @param mixed + * @return void + */ + function dd(...$args) + { + foreach ($args as $x) { + (new Dumper)->dump($x); + } + + die(1); + } +} + +if (! function_exists('e')) { + /** + * Escape HTML special characters in a string. + * + * @param \Illuminate\Contracts\Support\Htmlable|string $value + * @return string + */ + function e($value) + { if ($value instanceof Htmlable) { return $value->toHtml(); } - if ($value instanceof BackedEnum) { - $value = $value->value; - } + return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false); + } +} - return htmlspecialchars($value ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', $doubleEncode); +if (! function_exists('ends_with')) { + /** + * Determine if a given string ends with a given substring. + * + * @param string $haystack + * @param string|array $needles + * @return bool + */ + function ends_with($haystack, $needles) + { + return Str::endsWith($haystack, $needles); } } @@ -130,25 +567,76 @@ if (! function_exists('env')) { * Gets the value of an environment variable. * * @param string $key - * @param mixed $default + * @param mixed $default * @return mixed */ function env($key, $default = null) { - return Env::get($key, $default); + $value = getenv($key); + + if ($value === false) { + return value($default); + } + + switch (strtolower($value)) { + case 'true': + case '(true)': + return true; + case 'false': + case '(false)': + return false; + case 'empty': + case '(empty)': + return ''; + case 'null': + case '(null)': + return; + } + + if (strlen($value) > 1 && Str::startsWith($value, '"') && Str::endsWith($value, '"')) { + return substr($value, 1, -1); + } + + return $value; } } -if (! function_exists('filled')) { +if (! function_exists('head')) { /** - * Determine if a value is "filled". + * Get the first element of an array. Useful for method chaining. * - * @param mixed $value - * @return bool + * @param array $array + * @return mixed */ - function filled($value) + function head($array) { - return ! blank($value); + return reset($array); + } +} + +if (! function_exists('kebab_case')) { + /** + * Convert a string to kebab case. + * + * @param string $value + * @return string + */ + function kebab_case($value) + { + return Str::kebab($value); + } +} + +if (! function_exists('last')) { + /** + * Get the last element from an array. + * + * @param array $array + * @return mixed + */ + function last($array) + { + return end($array); } } @@ -157,13 +645,13 @@ if (! function_exists('object_get')) { * Get an item from an object using "dot" notation. * * @param object $object - * @param string|null $key - * @param mixed $default + * @param string $key + * @param mixed $default * @return mixed */ function object_get($object, $key, $default = null) { - if (is_null($key) || trim($key) === '') { + if (is_null($key) || trim($key) == '') { return $object; } @@ -179,37 +667,19 @@ if (! function_exists('object_get')) { } } -if (! function_exists('optional')) { - /** - * Provide access to optional objects. - * - * @param mixed $value - * @param callable|null $callback - * @return mixed - */ - function optional($value = null, ?callable $callback = null) - { - if (is_null($callback)) { - return new Optional($value); - } elseif (! is_null($value)) { - return $callback($value); - } - } -} - if (! function_exists('preg_replace_array')) { /** * Replace a given pattern with each value in the array in sequentially. * * @param string $pattern - * @param array $replacements + * @param array $replacements * @param string $subject * @return string */ function preg_replace_array($pattern, array $replacements, $subject) { return preg_replace_callback($pattern, function () use (&$replacements) { - foreach ($replacements as $value) { + foreach ($replacements as $key => $value) { return array_shift($replacements); } }, $subject); @@ -220,41 +690,29 @@ if (! function_exists('retry')) { /** * Retry an operation a given number of times. * - * @param int|array $times + * @param int $times * @param callable $callback - * @param int|\Closure $sleepMilliseconds - * @param callable|null $when + * @param int $sleep * @return mixed * * @throws \Exception */ - function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null) + function retry($times, callable $callback, $sleep = 0) { - $attempts = 0; - - $backoff = []; - - if (is_array($times)) { - $backoff = $times; - - $times = count($times) + 1; - } - - beginning: - $attempts++; $times--; + beginning: try { - return $callback($attempts); + return $callback(); } catch (Exception $e) { - if ($times < 1 || ($when && ! $when($e))) { + if (! $times) { throw $e; } - $sleepMilliseconds = $backoff[$attempts - 1] ?? $sleepMilliseconds; + $times--; - if ($sleepMilliseconds) { - Sleep::usleep(value($sleepMilliseconds, $attempts, $e) * 1000); + if ($sleep) { + usleep($sleep * 1000); } goto beginning; @@ -262,31 +720,230 @@ if (! function_exists('retry')) { } } -if (! function_exists('str')) { +if (! function_exists('snake_case')) { /** - * Get a new stringable object from the given string. + * Convert a string to snake case. * - * @param string|null $string - * @return \Illuminate\Support\Stringable|mixed + * @param string $value + * @param string $delimiter + * @return string */ - function str($string = null) + function snake_case($value, $delimiter = '_') { - if (func_num_args() === 0) { - return new class - { - public function __call($method, $parameters) - { - return Str::$method(...$parameters); - } + return Str::snake($value, $delimiter); + } +} - public function __toString() - { - return ''; - } - }; - } +if (! function_exists('starts_with')) { + /** + * Determine if a given string starts with a given substring. + * + * @param string $haystack + * @param string|array $needles + * @return bool + */ + function starts_with($haystack, $needles) + { + return Str::startsWith($haystack, $needles); + } +} - return Str::of($string); +if (! function_exists('str_after')) { + /** + * Return the remainder of a string after a given value. + * + * @param string $subject + * @param string $search + * @return string + */ + function str_after($subject, $search) + { + return Str::after($subject, $search); + } +} + +if (! function_exists('str_contains')) { + /** + * Determine if a given string contains a given substring. + * + * @param string $haystack + * @param string|array $needles + * @return bool + */ + function str_contains($haystack, $needles) + { + return Str::contains($haystack, $needles); + } +} + +if (! function_exists('str_finish')) { + /** + * Cap a string with a single instance of a given value. + * + * @param string $value + * @param string $cap + * @return string + */ + function str_finish($value, $cap) + { + return Str::finish($value, $cap); + } +} + +if (! function_exists('str_is')) { + /** + * Determine if a given string matches a given pattern. + * + * @param string $pattern + * @param string $value + * @return bool + */ + function str_is($pattern, $value) + { + return Str::is($pattern, $value); + } +} + +if (! function_exists('str_limit')) { + /** + * Limit the number of characters in a string. + * + * @param string $value + * @param int $limit + * @param string $end + * @return string + */ + function str_limit($value, $limit = 100, $end = '...') + { + return Str::limit($value, $limit, $end); + } +} + +if (! function_exists('str_plural')) { + /** + * Get the plural form of an English word. + * + * @param string $value + * @param int $count + * @return string + */ + function str_plural($value, $count = 2) + { + return Str::plural($value, $count); + } +} + +if (! function_exists('str_random')) { + /** + * Generate a more truly "random" alpha-numeric string. + * + * @param int $length + * @return string + * + * @throws \RuntimeException + */ + function str_random($length = 16) + { + return Str::random($length); + } +} + +if (! function_exists('str_replace_array')) { + /** + * Replace a given value in the string sequentially with an array. + * + * @param string $search + * @param array $replace + * @param string $subject + * @return string + */ + function str_replace_array($search, array $replace, $subject) + { + return Str::replaceArray($search, $replace, $subject); + } +} + +if (! function_exists('str_replace_first')) { + /** + * Replace the first occurrence of a given value in the string. + * + * @param string $search + * @param string $replace + * @param string $subject + * @return string + */ + function str_replace_first($search, $replace, $subject) + { + return Str::replaceFirst($search, $replace, $subject); + } +} + +if (! function_exists('str_replace_last')) { + /** + * Replace the last occurrence of a given value in the string. + * + * @param string $search + * @param string $replace + * @param string $subject + * @return string + */ + function str_replace_last($search, $replace, $subject) + { + return Str::replaceLast($search, $replace, $subject); + } +} + +if (! function_exists('str_singular')) { + /** + * Get the singular form of an English word. + * + * @param string $value + * @return string + */ + function str_singular($value) + { + return Str::singular($value); + } +} + +if (! function_exists('str_slug')) { + /** + * Generate a URL friendly "slug" from a given string. + * + * @param string $title + * @param string $separator + * @return string + */ + function str_slug($title, $separator = '-') + { + return Str::slug($title, $separator); + } +} + +if (! function_exists('str_start')) { + /** + * Begin a string with a single instance of a given value. + * + * @param string $value + * @param string $prefix + * @return string + */ + function str_start($value, $prefix) + { + return Str::start($value, $prefix); + } +} + +if (! function_exists('studly_case')) { + /** + * Convert a value to studly caps case. + * + * @param string $value + * @return string + */ + function studly_case($value) + { + return Str::studly($value); } } @@ -310,51 +967,16 @@ if (! function_exists('tap')) { } } -if (! function_exists('throw_if')) { +if (! function_exists('title_case')) { /** - * Throw the given exception if the given condition is true. + * Convert a value to title case. * - * @template TException of \Throwable - * - * @param mixed $condition - * @param TException|class-string|string $exception - * @param mixed ...$parameters - * @return mixed - * - * @throws TException + * @param string $value + * @return string */ - function throw_if($condition, $exception = 'RuntimeException', ...$parameters) + function title_case($value) { - if ($condition) { - if (is_string($exception) && class_exists($exception)) { - $exception = new $exception(...$parameters); - } - - throw is_string($exception) ? new RuntimeException($exception) : $exception; - } - - return $condition; - } -} - -if (! function_exists('throw_unless')) { - /** - * Throw the given exception unless the given condition is true. - * - * @template TException of \Throwable - * - * @param mixed $condition - * @param TException|class-string|string $exception - * @param mixed ...$parameters - * @return mixed - * - * @throws TException - */ - function throw_unless($condition, $exception = 'RuntimeException', ...$parameters) - { - throw_if(! $condition, $exception, ...$parameters); - - return $condition; + return Str::title($value); } } @@ -362,12 +984,12 @@ if (! function_exists('trait_uses_recursive')) { /** * Returns all traits used by a trait and its traits. * - * @param object|string $trait + * @param string $trait * @return array */ function trait_uses_recursive($trait) { - $traits = class_uses($trait) ?: []; + $traits = class_uses($trait); foreach ($traits as $trait) { $traits += trait_uses_recursive($trait); @@ -377,30 +999,16 @@ if (! function_exists('trait_uses_recursive')) { } } -if (! function_exists('transform')) { +if (! function_exists('value')) { /** - * Transform the given value if it is present. + * Return the default value of the given value. * - * @template TValue of mixed - * @template TReturn of mixed - * @template TDefault of mixed - * - * @param TValue $value - * @param callable(TValue): TReturn $callback - * @param TDefault|callable(TValue): TDefault|null $default - * @return ($value is empty ? ($default is null ? null : TDefault) : TReturn) + * @param mixed $value + * @return mixed */ - function transform($value, callable $callback, $default = null) + function value($value) { - if (filled($value)) { - return $callback($value); - } - - if (is_callable($default)) { - return $default($value); - } - - return $default; + return $value instanceof Closure ? $value() : $value; } } @@ -412,23 +1020,19 @@ if (! function_exists('windows_os')) { */ function windows_os() { - return PHP_OS_FAMILY === 'Windows'; + return strtolower(substr(PHP_OS, 0, 3)) === 'win'; } } if (! function_exists('with')) { /** - * Return the given value, optionally passed through the given callback. + * Return the given object. Useful for chaining. * - * @template TValue - * @template TReturn - * - * @param TValue $value - * @param (callable(TValue): (TReturn))|null $callback - * @return ($callback is null ? TValue : TReturn) + * @param mixed $object + * @return mixed */ - function with($value, ?callable $callback = null) + function with($object) { - return is_null($callback) ? $value : $callback($value); + return $object; } } diff --git a/lam/lib/3rdParty/composer/lcobucci/clock/LICENSE b/lam/lib/3rdParty/composer/lcobucci/clock/LICENSE new file mode 100644 index 000000000..58ea9440e --- /dev/null +++ b/lam/lib/3rdParty/composer/lcobucci/clock/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Luís Cobucci + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lam/lib/3rdParty/composer/lcobucci/clock/composer.json b/lam/lib/3rdParty/composer/lcobucci/clock/composer.json new file mode 100644 index 000000000..4a3ec5723 --- /dev/null +++ b/lam/lib/3rdParty/composer/lcobucci/clock/composer.json @@ -0,0 +1,48 @@ +{ + "name": "lcobucci/clock", + "description": "Yet another clock abstraction", + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "require": { + "php": "~8.1.0 || ~8.2.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.26", + "lcobucci/coding-standard": "^9.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-deprecation-rules": "^1.1.1", + "phpstan/phpstan-phpunit": "^1.3.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.27" + }, + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Lcobucci\\Clock\\": "test" + } + }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "infection/extension-installer": true, + "phpstan/extension-installer": true + } + }, + "provide": { + "psr/clock-implementation": "1.0" + } +} diff --git a/lam/lib/3rdParty/composer/lcobucci/clock/renovate.json b/lam/lib/3rdParty/composer/lcobucci/clock/renovate.json new file mode 100644 index 000000000..6eb57ea62 --- /dev/null +++ b/lam/lib/3rdParty/composer/lcobucci/clock/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>lcobucci/.github:renovate-config" + ] +} diff --git a/lam/lib/3rdParty/composer/lcobucci/clock/src/Clock.php b/lam/lib/3rdParty/composer/lcobucci/clock/src/Clock.php new file mode 100644 index 000000000..45a033b87 --- /dev/null +++ b/lam/lib/3rdParty/composer/lcobucci/clock/src/Clock.php @@ -0,0 +1,12 @@ +now = $now; + } + + public function now(): DateTimeImmutable + { + return $this->now; + } +} diff --git a/lam/lib/3rdParty/composer/lcobucci/clock/src/SystemClock.php b/lam/lib/3rdParty/composer/lcobucci/clock/src/SystemClock.php new file mode 100644 index 000000000..69de81f81 --- /dev/null +++ b/lam/lib/3rdParty/composer/lcobucci/clock/src/SystemClock.php @@ -0,0 +1,31 @@ +timezone); + } +} diff --git a/lam/lib/3rdParty/composer/monolog/monolog/CHANGELOG.md b/lam/lib/3rdParty/composer/monolog/monolog/CHANGELOG.md index ce16eecbd..4cd4c6b9b 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/CHANGELOG.md +++ b/lam/lib/3rdParty/composer/monolog/monolog/CHANGELOG.md @@ -1,3 +1,18 @@ +### 3.9.0 (2025-03-24) + + * BC Warning: Fixed SendGridHandler to use the V3 API as V2 is now shut down, but this requires a new API key (#1952) + * Deprecated Monolog\Test\TestCase in favor of Monolog\Test\MonologTestCase (#1953) + * Added extension point for NativeMailerHandler::mail (#1948) + * Added setHandler method to BufferHandler to modify the nested handler at runtime (#1946) + * Fixed date format in ElasticsearchFormatter to use +00:00 vs +0000 tz identifiers (#1942) + * Fixed GelfMessageFormatter handling numeric context/extra keys (#1932) + +### 3.8.1 (2024-12-05) + + * Deprecated Monolog\DateTimeImmutable in favor of Monolog\JsonSerializableDateTimeImmutable (#1928) + * Fixed gelf keys not being valid when context/extra data keys have spaces in them (#1927) + * Fixed empty lines appearing in the stack traces when a custom formatter returned null (#1925) + ### 3.8.0 (2024-11-12) * Added `$fileOpenMode` param to `StreamHandler` to define a custom fopen mode to open the log file (#1913) diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/DateTimeImmutable.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/DateTimeImmutable.php index 3d9477f40..3cb7086d7 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/DateTimeImmutable.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/DateTimeImmutable.php @@ -11,38 +11,14 @@ namespace Monolog; -use DateTimeZone; +class_alias(JsonSerializableDateTimeImmutable::class, 'Monolog\DateTimeImmutable'); -/** - * Overrides default json encoding of date time objects - * - * @author Menno Holtkamp - * @author Jordi Boggiano - */ -class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable -{ - private bool $useMicroseconds; - - public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null) +// @phpstan-ignore-next-line +if (false) { + /** + * @deprecated Use \Monolog\JsonSerializableDateTimeImmutable instead. + */ + class DateTimeImmutable extends JsonSerializableDateTimeImmutable { - $this->useMicroseconds = $useMicroseconds; - - // if you like to use a custom time to pass to Logger::addRecord directly, - // call modify() or setTimestamp() on this instance to change the date after creating it - parent::__construct('now', $timezone); - } - - public function jsonSerialize(): string - { - if ($this->useMicroseconds) { - return $this->format('Y-m-d\TH:i:s.uP'); - } - - return $this->format('Y-m-d\TH:i:sP'); - } - - public function __toString(): string - { - return $this->jsonSerialize(); } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php index 160510ad8..a0fa4a9e1 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php @@ -77,9 +77,6 @@ class ElasticaFormatter extends NormalizerFormatter { $document = new Document(); $document->setData($record); - if (method_exists($document, 'setType')) { - $document->setType($this->type); - } $document->setIndex($this->index); return $document; diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php index 6c3eb9b2a..6326cf5d7 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -38,7 +38,7 @@ class ElasticsearchFormatter extends NormalizerFormatter public function __construct(string $index, string $type) { // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. - parent::__construct(DateTimeInterface::ISO8601); + parent::__construct(DateTimeInterface::ATOM); $this->index = $index; $this->type = $type; diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php index 9b0861948..12a3b0a32 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php @@ -115,6 +115,7 @@ class GelfMessageFormatter extends NormalizerFormatter } foreach ($extra as $key => $val) { + $key = (string) preg_replace('#[^\w.-]#', '-', (string) $key); $val = \is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = \strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { @@ -126,6 +127,7 @@ class GelfMessageFormatter extends NormalizerFormatter } foreach ($context as $key => $val) { + $key = (string) preg_replace('#[^\w.-]#', '-', (string) $key); $val = \is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = \strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php index 2f4305409..b59639e17 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php @@ -216,7 +216,7 @@ class JsonFormatter extends NormalizerFormatter * Normalizes given exception with or without its own stack trace based on * `includeStacktraces` property. * - * @return array>>|string + * @return array>> */ protected function normalizeException(Throwable $e, int $depth = 0): array { diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/LineFormatter.php index e563503f0..fd9dc5bbd 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/LineFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/LineFormatter.php @@ -204,16 +204,15 @@ class LineFormatter extends NormalizerFormatter { $str = $this->formatException($e); - if (($previous = $e->getPrevious()) instanceof \Throwable) { - do { - $depth++; - if ($depth > $this->maxNormalizeDepth) { - $str .= "\n[previous exception] Over " . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; - break; - } - - $str .= "\n[previous exception] " . $this->formatException($previous); - } while ($previous = $previous->getPrevious()); + $previous = $e->getPrevious(); + while ($previous instanceof \Throwable) { + $depth++; + if ($depth > $this->maxNormalizeDepth) { + $str .= "\n[previous exception] Over " . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; + break; + } + $str .= "\n[previous exception] " . $this->formatException($previous); + $previous = $previous->getPrevious(); } return $str; @@ -309,6 +308,6 @@ class LineFormatter extends NormalizerFormatter private function stacktracesParserCustom(string $trace): string { - return implode("\n", array_filter(array_map($this->stacktracesParser, explode("\n", $trace)), fn ($line) => $line !== false && $line !== '')); + return implode("\n", array_filter(array_map($this->stacktracesParser, explode("\n", $trace)), fn ($line) => is_string($line) && trim($line) !== '')); } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php index 261967f1a..60da29cf7 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\DateTimeImmutable; +use Monolog\JsonSerializableDateTimeImmutable; use Monolog\Utils; use Throwable; use Monolog\LogRecord; @@ -248,7 +248,7 @@ class NormalizerFormatter implements FormatterInterface } /** - * @return array>>|string + * @return array>> */ protected function normalizeException(Throwable $e, int $depth = 0) { @@ -322,9 +322,9 @@ class NormalizerFormatter implements FormatterInterface protected function formatDate(\DateTimeInterface $date): string { - // in case the date format isn't custom then we defer to the custom DateTimeImmutable + // in case the date format isn't custom then we defer to the custom JsonSerializableDateTimeImmutable // formatting logic, which will pick the right format based on whether useMicroseconds is on - if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof DateTimeImmutable) { + if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof JsonSerializableDateTimeImmutable) { return (string) $date; } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/BufferHandler.php index c241c32f2..c799b6b9c 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/BufferHandler.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/BufferHandler.php @@ -162,4 +162,9 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa throw new \UnexpectedValueException('The nested handler of type '.\get_class($this->handler).' does not support formatters.'); } + + public function setHandler(HandlerInterface $handler): void + { + $this->handler = $handler; + } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php index 61c9e83f9..6598e822c 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php @@ -16,7 +16,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; -use Monolog\DateTimeImmutable; +use Monolog\JsonSerializableDateTimeImmutable; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -150,7 +150,7 @@ class ChromePHPHandler extends AbstractProcessingHandler message: 'Incomplete logs, chrome header size limit reached', level: Level::Warning, channel: 'monolog', - datetime: new DateTimeImmutable(true), + datetime: new JsonSerializableDateTimeImmutable(true), ); self::$json['rows'][\count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/Curl/Util.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/Curl/Util.php index f10281144..6d78cb154 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/Curl/Util.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/Curl/Util.php @@ -37,9 +37,10 @@ final class Util * @param CurlHandle $ch curl handler * @return bool|string @see curl_exec */ - public static function execute(CurlHandle $ch, int $retries = 5, bool $closeAfterDone = true) + public static function execute(CurlHandle $ch, int $retries = 5, bool $closeAfterDone = true): bool|string { - while ($retries--) { + while ($retries > 0) { + $retries--; $curlResponse = curl_exec($ch); if ($curlResponse === false) { $curlErrno = curl_errno($ch); @@ -53,7 +54,6 @@ final class Util throw new \RuntimeException(sprintf('Curl error (code %d): %s', $curlErrno, $curlError)); } - continue; } @@ -63,7 +63,6 @@ final class Util return $curlResponse; } - return false; } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php index a38c3f5e0..cd28ff6ac 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php @@ -27,12 +27,12 @@ class ErrorLogHandler extends AbstractProcessingHandler public const OPERATING_SYSTEM = 0; public const SAPI = 4; - /** @var 0|1|3|4 */ + /** @var 0|4 */ protected int $messageType; protected bool $expandNewlines; /** - * @param 0|1|3|4 $messageType Says where the error should go. + * @param 0|4 $messageType Says where the error should go. * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries * * @throws \InvalidArgumentException If an unsupported message type is set diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php index c68b1ddd0..a5d1a9771 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php @@ -128,7 +128,7 @@ class NativeMailerHandler extends MailHandler $parameters = implode(' ', $this->parameters); foreach ($this->to as $to) { - mail($to, $subject, $content, $headers, $parameters); + $this->mail($to, $subject, $content, $headers, $parameters); } } @@ -170,4 +170,10 @@ class NativeMailerHandler extends MailHandler return $this; } + + + protected function mail(string $to, string $subject, string $content, string $headers, string $parameters): void + { + mail($to, $subject, $content, $headers, $parameters); + } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/SendGridHandler.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/SendGridHandler.php index 9c3b8e6af..5847a585c 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/SendGridHandler.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Handler/SendGridHandler.php @@ -12,9 +12,10 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\Utils; /** - * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html + * SendGridHandler uses the SendGrid API v3 function to send Log emails, more information in https://www.twilio.com/docs/sendgrid/for-developers/sending-email/api-getting-started * * @author Ricardo Fontanelli */ @@ -22,19 +23,9 @@ class SendGridHandler extends MailHandler { /** * The SendGrid API User + * @deprecated this is not used anymore as of SendGrid API v3 */ protected string $apiUser; - - /** - * The SendGrid API Key - */ - protected string $apiKey; - - /** - * The email addresses to which the message will be sent - */ - protected string $from; - /** * The email addresses to which the message will be sent * @var string[] @@ -42,59 +33,63 @@ class SendGridHandler extends MailHandler protected array $to; /** - * The subject of the email - */ - protected string $subject; - - /** - * @param string $apiUser The SendGrid API User - * @param string $apiKey The SendGrid API Key - * @param string $from The sender of the email - * @param string|string[] $to The recipients of the email - * @param string $subject The subject of the mail - * + * @param string|null $apiUser Unused user as of SendGrid API v3, you can pass null or any string + * @param list|string $to + * @param non-empty-string $apiHost Allows you to use another endpoint (e.g. api.eu.sendgrid.com) * @throws MissingExtensionException If the curl extension is missing */ - public function __construct(string $apiUser, string $apiKey, string $from, string|array $to, string $subject, int|string|Level $level = Level::Error, bool $bubble = true) - { + public function __construct( + string|null $apiUser, + protected string $apiKey, + protected string $from, + array|string $to, + protected string $subject, + int|string|Level $level = Level::Error, + bool $bubble = true, + /** @var non-empty-string */ + private readonly string $apiHost = 'api.sendgrid.com', + ) { if (!\extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler'); } - parent::__construct($level, $bubble); - $this->apiUser = $apiUser; - $this->apiKey = $apiKey; - $this->from = $from; $this->to = (array) $to; - $this->subject = $subject; + // @phpstan-ignore property.deprecated + $this->apiUser = $apiUser ?? ''; + parent::__construct($level, $bubble); } - /** - * @inheritDoc - */ protected function send(string $content, array $records): void { - $message = []; - $message['api_user'] = $this->apiUser; - $message['api_key'] = $this->apiKey; - $message['from'] = $this->from; + $body = []; + $body['personalizations'] = []; + $body['from']['email'] = $this->from; foreach ($this->to as $recipient) { - $message['to[]'] = $recipient; + $body['personalizations'][]['to'][]['email'] = $recipient; } - $message['subject'] = $this->subject; - $message['date'] = date('r'); + $body['subject'] = $this->subject; if ($this->isHtmlBody($content)) { - $message['html'] = $content; + $body['content'][] = [ + 'type' => 'text/html', + 'value' => $content, + ]; } else { - $message['text'] = $content; + $body['content'][] = [ + 'type' => 'text/plain', + 'value' => $content, + ]; } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, 'https://api.sendgrid.com/api/mail.send.json'); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Authorization: Bearer '.$this->apiKey, + ]); + curl_setopt($ch, CURLOPT_URL, 'https://'.$this->apiHost.'/v3/mail/send'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($message)); + curl_setopt($ch, CURLOPT_POSTFIELDS, Utils::jsonEncode($body)); + Curl\Util::execute($ch, 2); } } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/JsonSerializableDateTimeImmutable.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/JsonSerializableDateTimeImmutable.php new file mode 100644 index 000000000..de2cc5e96 --- /dev/null +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/JsonSerializableDateTimeImmutable.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use DateTimeZone; + +/** + * Overrides default json encoding of date time objects + * + * @author Menno Holtkamp + * @author Jordi Boggiano + */ +class JsonSerializableDateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable +{ + private bool $useMicroseconds; + + public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null) + { + $this->useMicroseconds = $useMicroseconds; + + // if you like to use a custom time to pass to Logger::addRecord directly, + // call modify() or setTimestamp() on this instance to change the date after creating it + parent::__construct('now', $timezone); + } + + public function jsonSerialize(): string + { + if ($this->useMicroseconds) { + return $this->format('Y-m-d\TH:i:s.uP'); + } + + return $this->format('Y-m-d\TH:i:sP'); + } + + public function __toString(): string + { + return $this->jsonSerialize(); + } +} diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Level.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Level.php index 5620bc4de..38a74fb8f 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Level.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Level.php @@ -87,15 +87,15 @@ enum Level: int */ public static function fromName(string $name): self { - return match ($name) { - 'debug', 'Debug', 'DEBUG' => self::Debug, - 'info', 'Info', 'INFO' => self::Info, - 'notice', 'Notice', 'NOTICE' => self::Notice, - 'warning', 'Warning', 'WARNING' => self::Warning, - 'error', 'Error', 'ERROR' => self::Error, - 'critical', 'Critical', 'CRITICAL' => self::Critical, - 'alert', 'Alert', 'ALERT' => self::Alert, - 'emergency', 'Emergency', 'EMERGENCY' => self::Emergency, + return match (strtolower($name)) { + 'debug' => self::Debug, + 'info' => self::Info, + 'notice' => self::Notice, + 'warning' => self::Warning, + 'error' => self::Error, + 'critical' => self::Critical, + 'alert' => self::Alert, + 'emergency' => self::Emergency, }; } diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Logger.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Logger.php index f57fe332e..e545c4487 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Logger.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Logger.php @@ -323,12 +323,13 @@ class Logger implements LoggerInterface, ResettableInterface * @param int $level The logging level (a Monolog or RFC 5424 level) * @param string $message The log message * @param mixed[] $context The log context - * @param DateTimeImmutable|null $datetime Optional log date to log into the past or future + * @param JsonSerializableDateTimeImmutable|null $datetime Optional log date to log into the past or future + * * @return bool Whether the record has been processed * * @phpstan-param value-of|Level $level */ - public function addRecord(int|Level $level, string $message, array $context = [], DateTimeImmutable|null $datetime = null): bool + public function addRecord(int|Level $level, string $message, array $context = [], JsonSerializableDateTimeImmutable|null $datetime = null): bool { if (\is_int($level) && isset(self::RFC_5424_LEVELS[$level])) { $level = self::RFC_5424_LEVELS[$level]; @@ -356,7 +357,7 @@ class Logger implements LoggerInterface, ResettableInterface $recordInitialized = \count($this->processors) === 0; $record = new LogRecord( - datetime: $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + datetime: $datetime ?? new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone), channel: $this->name, level: self::toMonologLevel($level), message: $message, @@ -518,7 +519,7 @@ class Logger implements LoggerInterface, ResettableInterface public function isHandling(int|string|Level $level): bool { $record = new LogRecord( - datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + datetime: new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone), channel: $this->name, message: '', level: self::toMonologLevel($level), diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php index 76adf258f..291361d2f 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -60,7 +60,7 @@ class PsrLogMessageProcessor implements ProcessorInterface if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, "__toString"))) { $replacements[$placeholder] = $val; } elseif ($val instanceof \DateTimeInterface) { - if (null === $this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) { + if (null === $this->dateFormat && $val instanceof \Monolog\JsonSerializableDateTimeImmutable) { // handle monolog dates using __toString if no specific dateFormat was asked for // so that it follows the useMicroseconds flag $replacements[$placeholder] = (string) $val; diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/MonologTestCase.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/MonologTestCase.php new file mode 100644 index 000000000..34c7724ea --- /dev/null +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/MonologTestCase.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Test; + +use Monolog\Level; +use Monolog\Logger; +use Monolog\LogRecord; +use Monolog\JsonSerializableDateTimeImmutable; +use Monolog\Formatter\FormatterInterface; +use Psr\Log\LogLevel; + +/** + * Lets you easily generate log records and a dummy formatter for testing purposes + * + * @author Jordi Boggiano + */ +class MonologTestCase extends \PHPUnit\Framework\TestCase +{ + /** + * @param array $context + * @param array $extra + * + * @phpstan-param value-of|value-of|Level|LogLevel::* $level + */ + protected function getRecord(int|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new JsonSerializableDateTimeImmutable(true), array $extra = []): LogRecord + { + return new LogRecord( + message: (string) $message, + context: $context, + level: Logger::toMonologLevel($level), + channel: $channel, + datetime: $datetime, + extra: $extra, + ); + } + + /** + * @phpstan-return list + */ + protected function getMultipleRecords(): array + { + return [ + $this->getRecord(Level::Debug, 'debug message 1'), + $this->getRecord(Level::Debug, 'debug message 2'), + $this->getRecord(Level::Info, 'information'), + $this->getRecord(Level::Warning, 'warning'), + $this->getRecord(Level::Error, 'error'), + ]; + } + + protected function getIdentityFormatter(): FormatterInterface + { + $formatter = $this->createMock(FormatterInterface::class); + $formatter->expects(self::any()) + ->method('format') + ->willReturnCallback(function ($record) { + return $record->message; + }); + + return $formatter; + } +} diff --git a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/TestCase.php b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/TestCase.php index a2ff3f7ad..bf40b31fc 100644 --- a/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/TestCase.php +++ b/lam/lib/3rdParty/composer/monolog/monolog/src/Monolog/Test/TestCase.php @@ -11,64 +11,13 @@ namespace Monolog\Test; -use Monolog\Level; -use Monolog\Logger; -use Monolog\LogRecord; -use Monolog\DateTimeImmutable; -use Monolog\Formatter\FormatterInterface; -use Psr\Log\LogLevel; -use ReflectionProperty; - /** * Lets you easily generate log records and a dummy formatter for testing purposes * * @author Jordi Boggiano * - * @internal feel free to reuse this to test your own handlers, this is marked internal to avoid issues with PHPStorm https://github.com/Seldaek/monolog/issues/1677 + * @deprecated use MonologTestCase instead. */ -class TestCase extends \PHPUnit\Framework\TestCase +class TestCase extends MonologTestCase { - /** - * @param array $context - * @param array $extra - * - * @phpstan-param value-of|value-of|Level|LogLevel::* $level - */ - protected function getRecord(int|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord - { - return new LogRecord( - message: (string) $message, - context: $context, - level: Logger::toMonologLevel($level), - channel: $channel, - datetime: $datetime, - extra: $extra, - ); - } - - /** - * @phpstan-return list - */ - protected function getMultipleRecords(): array - { - return [ - $this->getRecord(Level::Debug, 'debug message 1'), - $this->getRecord(Level::Debug, 'debug message 2'), - $this->getRecord(Level::Info, 'information'), - $this->getRecord(Level::Warning, 'warning'), - $this->getRecord(Level::Error, 'error'), - ]; - } - - protected function getIdentityFormatter(): FormatterInterface - { - $formatter = $this->createMock(FormatterInterface::class); - $formatter->expects(self::any()) - ->method('format') - ->willReturnCallback(function ($record) { - return $record->message; - }); - - return $formatter; - } } diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/CHANGELOG.md b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/CHANGELOG.md new file mode 100644 index 000000000..4eedf742d --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/CHANGELOG.md @@ -0,0 +1,72 @@ +# CHANGELOG + +## 2.8.0 - 2024-09-04 + +* Add support for PHP 8.4. + +## 2.7.0 - 2023-08-15 + +* Fixed flattening in arrays starting with null. +* Drop support for HHVM and PHP earlier than 7.2.5. +* Add support for PHP 8.1, 8.2, and 8.3. + +## 2.6.0 - 2020-07-31 + +* Support for PHP 8.0. + +## 2.5.0 - 2019-12-30 + +* Full support for PHP 7.0-7.4. +* Fixed autoloading when run from within vendor folder. +* Full multibyte (UTF-8) string support. + +## 2.4.0 - 2016-12-03 + +* Added support for floats when interpreting data. +* Added a function_exists check to work around redeclaration issues. + +## 2.3.0 - 2016-01-05 + +* Added support for [JEP-9](https://github.com/jmespath/jmespath.site/blob/master/docs/proposals/improved-filters.rst), + including unary filter expressions, and `&&` filter expressions. +* Fixed various parsing issues, including not removing escaped single quotes + from raw string literals. +* Added support for the `map` function. +* Fixed several issues with code generation. + +## 2.2.0 - 2015-05-27 + +* Added support for [JEP-12](https://github.com/jmespath/jmespath.site/blob/master/docs/proposals/raw-string-literals.rst) + and raw string literals (e.g., `'foo'`). + +## 2.1.0 - 2014-01-13 + +* Added `JmesPath\Env::cleanCompileDir()` to delete any previously compiled + JMESPath expressions. + +## 2.0.0 - 2014-01-11 + +* Moving to a flattened namespace structure. +* Runtimes are now only PHP callables. +* Fixed an error in the way empty JSON literals are parsed so that they now + return an empty string to match the Python and JavaScript implementations. +* Removed functions from runtimes. Instead there is now a function dispatcher + class, FnDispatcher, that provides function implementations behind a single + dispatch function. +* Removed ExprNode in lieu of just using a PHP callable with bound variables. +* Removed debug methods from runtimes and instead into a new Debugger class. +* Heavily cleaned up function argument validation. +* Slice syntax is now properly validated (i.e., colons are followed by the + appropriate value). +* Lots of code cleanup and performance improvements. +* Added a convenient `JmesPath\search()` function. +* **IMPORTANT**: Relocating the project to https://github.com/jmespath/jmespath.php + +## 1.1.1 - 2014-10-08 + +* Added support for using ArrayAccess and Countable as arrays and objects. + +## 1.1.0 - 2014-08-06 + +* Added the ability to search data returned from json_decode() where JSON + objects are returned as stdClass objects. diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/LICENSE b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/LICENSE new file mode 100644 index 000000000..5c970a421 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/README.rst b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/README.rst new file mode 100644 index 000000000..bef8db483 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/README.rst @@ -0,0 +1,123 @@ +============ +jmespath.php +============ + +JMESPath (pronounced "jaymz path") allows you to declaratively specify how to +extract elements from a JSON document. *jmespath.php* allows you to use +JMESPath in PHP applications with PHP data structures. It requires PHP 7.2.5 or +greater and can be installed through `Composer `_ +using the ``mtdowling/jmespath.php`` package. + +.. code-block:: php + + require 'vendor/autoload.php'; + + $expression = 'foo.*.baz'; + + $data = [ + 'foo' => [ + 'bar' => ['baz' => 1], + 'bam' => ['baz' => 2], + 'boo' => ['baz' => 3] + ] + ]; + + JmesPath\search($expression, $data); + // Returns: [1, 2, 3] + +- `JMESPath Tutorial `_ +- `JMESPath Grammar `_ +- `JMESPath Python library `_ + +PHP Usage +========= + +The ``JmesPath\search`` function can be used in most cases when using the +library. This function utilizes a JMESPath runtime based on your environment. +The runtime utilized can be configured using environment variables and may at +some point in the future automatically utilize a C extension if available. + +.. code-block:: php + + $result = JmesPath\search($expression, $data); + + // or, if you require PSR-4 compliance. + $result = JmesPath\Env::search($expression, $data); + +Runtimes +-------- + +jmespath.php utilizes *runtimes*. There are currently two runtimes: +AstRuntime and CompilerRuntime. + +AstRuntime is utilized by ``JmesPath\search()`` and ``JmesPath\Env::search()`` +by default. + +AstRuntime +~~~~~~~~~~ + +The AstRuntime will parse an expression, cache the resulting AST in memory, +and interpret the AST using an external tree visitor. AstRuntime provides a +good general approach for interpreting JMESPath expressions that have a low to +moderate level of reuse. + +.. code-block:: php + + $runtime = new JmesPath\AstRuntime(); + $runtime('foo.bar', ['foo' => ['bar' => 'baz']]); + // > 'baz' + +CompilerRuntime +~~~~~~~~~~~~~~~ + +``JmesPath\CompilerRuntime`` provides the most performance for +applications that have a moderate to high level of reuse of JMESPath +expressions. The CompilerRuntime will walk a JMESPath AST and emit PHP source +code, resulting in anywhere from 7x to 60x speed improvements. + +Compiling JMESPath expressions to source code is a slower process than just +walking and interpreting a JMESPath AST (via the AstRuntime). However, +running the compiled JMESPath code results in much better performance than +walking an AST. This essentially means that there is a warm-up period when +using the ``CompilerRuntime``, but after the warm-up period, it will provide +much better performance. + +Use the CompilerRuntime if you know that you will be executing JMESPath +expressions more than once or if you can pre-compile JMESPath expressions +before executing them (for example, server-side applications). + +.. code-block:: php + + // Note: The cache directory argument is optional. + $runtime = new JmesPath\CompilerRuntime('/path/to/compile/folder'); + $runtime('foo.bar', ['foo' => ['bar' => 'baz']]); + // > 'baz' + +Environment Variables +^^^^^^^^^^^^^^^^^^^^^ + +You can utilize the CompilerRuntime in ``JmesPath\search()`` by setting +the ``JP_PHP_COMPILE`` environment variable to "on" or to a directory +on disk used to store cached expressions. + +Testing +======= + +A comprehensive list of test cases can be found at +https://github.com/jmespath/jmespath.php/tree/master/tests/compliance. +These compliance tests are utilized by jmespath.php to ensure consistency with +other implementations, and can serve as examples of the language. + +jmespath.php is tested using PHPUnit. In order to run the tests, you need to +first install the dependencies using Composer as described in the *Installation* +section. Next you just need to run the tests via make: + +.. code-block:: bash + + make test + +You can run a suite of performance tests as well: + +.. code-block:: bash + + make perf diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/bin/jp.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/bin/jp.php new file mode 100755 index 000000000..c8433b589 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/bin/jp.php @@ -0,0 +1,74 @@ +#!/usr/bin/env php +check(); +unset($xdebug); + +$dir = isset($argv[1]) ? $argv[1] : __DIR__ . '/../tests/compliance/perf'; +is_dir($dir) or die('Dir not found: ' . $dir); +// Warm up the runner +\JmesPath\Env::search('foo', []); + +$total = 0; +foreach (glob($dir . '/*.json') as $file) { + $total += runSuite($file); +} +echo "\nTotal time: {$total}\n"; + +function runSuite($file) +{ + $contents = file_get_contents($file); + $json = json_decode($contents, true); + $total = 0; + foreach ($json as $suite) { + foreach ($suite['cases'] as $case) { + $total += runCase( + $suite['given'], + $case['expression'], + $case['name'] + ); + } + } + return $total; +} + +function runCase($given, $expression, $name) +{ + $best = 99999; + $runtime = \JmesPath\Env::createRuntime(); + + for ($i = 0; $i < 100; $i++) { + $t = microtime(true); + $runtime($expression, $given); + $tryTime = (microtime(true) - $t) * 1000; + if ($tryTime < $best) { + $best = $tryTime; + } + if (!getenv('CACHE')) { + $runtime = \JmesPath\Env::createRuntime(); + // Delete compiled scripts if not caching. + if ($runtime instanceof \JmesPath\CompilerRuntime) { + array_map('unlink', glob(sys_get_temp_dir() . '/jmespath_*.php')); + } + } + } + + printf("time: %07.4fms name: %s\n", $best, $name); + + return $best; +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/composer.json b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/composer.json new file mode 100644 index 000000000..819db12e9 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/composer.json @@ -0,0 +1,38 @@ +{ + "name": "mtdowling/jmespath.php", + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": ["json", "jsonpath"], + "license": "MIT", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": ["src/JmesPath.php"] + }, + "bin": ["bin/jp.php"], + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/AstRuntime.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/AstRuntime.php new file mode 100644 index 000000000..f5620be0b --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/AstRuntime.php @@ -0,0 +1,47 @@ +interpreter = new TreeInterpreter($fnDispatcher); + $this->parser = $parser ?: new Parser(); + } + + /** + * Returns data from the provided input that matches a given JMESPath + * expression. + * + * @param string $expression JMESPath expression to evaluate + * @param mixed $data Data to search. This data should be data that + * is similar to data returned from json_decode + * using associative arrays rather than objects. + * + * @return mixed Returns the matching data or null + */ + public function __invoke($expression, $data) + { + if (!isset($this->cache[$expression])) { + // Clear the AST cache when it hits 1024 entries + if (++$this->cachedCount > 1024) { + $this->cache = []; + $this->cachedCount = 0; + } + $this->cache[$expression] = $this->parser->parse($expression); + } + + return $this->interpreter->visit($this->cache[$expression], $data); + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/CompilerRuntime.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/CompilerRuntime.php new file mode 100644 index 000000000..b85f68e78 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/CompilerRuntime.php @@ -0,0 +1,83 @@ +parser = $parser ?: new Parser(); + $this->compiler = new TreeCompiler(); + $dir = $dir ?: sys_get_temp_dir(); + + if (!is_dir($dir) && !mkdir($dir, 0755, true)) { + throw new \RuntimeException("Unable to create cache directory: $dir"); + } + + $this->cacheDir = realpath($dir); + $this->interpreter = new TreeInterpreter(); + } + + /** + * Returns data from the provided input that matches a given JMESPath + * expression. + * + * @param string $expression JMESPath expression to evaluate + * @param mixed $data Data to search. This data should be data that + * is similar to data returned from json_decode + * using associative arrays rather than objects. + * + * @return mixed Returns the matching data or null + * @throws \RuntimeException + */ + public function __invoke($expression, $data) + { + $functionName = 'jmespath_' . md5($expression); + + if (!function_exists($functionName)) { + $filename = "{$this->cacheDir}/{$functionName}.php"; + if (!file_exists($filename)) { + $this->compile($filename, $expression, $functionName); + } + require $filename; + } + + return $functionName($this->interpreter, $data); + } + + private function compile($filename, $expression, $functionName) + { + $code = $this->compiler->visit( + $this->parser->parse($expression), + $functionName, + $expression + ); + + if (!file_put_contents($filename, $code)) { + throw new \RuntimeException(sprintf( + 'Unable to write the compiled PHP code to: %s (%s)', + $filename, + var_export(error_get_last(), true) + )); + } + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/DebugRuntime.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/DebugRuntime.php new file mode 100644 index 000000000..405256172 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/DebugRuntime.php @@ -0,0 +1,109 @@ +runtime = $runtime; + $this->out = $output ?: STDOUT; + $this->lexer = new Lexer(); + $this->parser = new Parser($this->lexer); + } + + public function __invoke($expression, $data) + { + if ($this->runtime instanceof CompilerRuntime) { + return $this->debugCompiled($expression, $data); + } + + return $this->debugInterpreted($expression, $data); + } + + private function debugInterpreted($expression, $data) + { + return $this->debugCallback( + function () use ($expression, $data) { + $runtime = $this->runtime; + return $runtime($expression, $data); + }, + $expression, + $data + ); + } + + private function debugCompiled($expression, $data) + { + $result = $this->debugCallback( + function () use ($expression, $data) { + $runtime = $this->runtime; + return $runtime($expression, $data); + }, + $expression, + $data + ); + $this->dumpCompiledCode($expression); + + return $result; + } + + private function dumpTokens($expression) + { + $lexer = new Lexer(); + fwrite($this->out, "Tokens\n======\n\n"); + $tokens = $lexer->tokenize($expression); + + foreach ($tokens as $t) { + fprintf( + $this->out, + "%3d %-13s %s\n", $t['pos'], $t['type'], + json_encode($t['value']) + ); + } + + fwrite($this->out, "\n"); + } + + private function dumpAst($expression) + { + $parser = new Parser(); + $ast = $parser->parse($expression); + fwrite($this->out, "AST\n========\n\n"); + fwrite($this->out, json_encode($ast, JSON_PRETTY_PRINT) . "\n"); + } + + private function dumpCompiledCode($expression) + { + fwrite($this->out, "Code\n========\n\n"); + $dir = sys_get_temp_dir(); + $hash = md5($expression); + $functionName = "jmespath_{$hash}"; + $filename = "{$dir}/{$functionName}.php"; + fwrite($this->out, "File: {$filename}\n\n"); + fprintf($this->out, file_get_contents($filename)); + } + + private function debugCallback(callable $debugFn, $expression, $data) + { + fprintf($this->out, "Expression\n==========\n\n%s\n\n", $expression); + $this->dumpTokens($expression); + $this->dumpAst($expression); + fprintf($this->out, "\nData\n====\n\n%s\n\n", json_encode($data, JSON_PRETTY_PRINT)); + $startTime = microtime(true); + $result = $debugFn(); + $total = microtime(true) - $startTime; + fprintf($this->out, "\nResult\n======\n\n%s\n\n", json_encode($result, JSON_PRETTY_PRINT)); + fwrite($this->out, "Time\n====\n\n"); + fprintf($this->out, "Total time: %f ms\n\n", $total); + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Env.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Env.php new file mode 100644 index 000000000..b22cf25f9 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Env.php @@ -0,0 +1,91 @@ +{'fn_' . $fn}($args); + } + + private function fn_abs(array $args) + { + $this->validate('abs', $args, [['number']]); + return abs($args[0]); + } + + private function fn_avg(array $args) + { + $this->validate('avg', $args, [['array']]); + $sum = $this->reduce('avg:0', $args[0], ['number'], function ($a, $b) { + return Utils::add($a, $b); + }); + return $args[0] ? ($sum / count($args[0])) : null; + } + + private function fn_ceil(array $args) + { + $this->validate('ceil', $args, [['number']]); + return ceil($args[0]); + } + + private function fn_contains(array $args) + { + $this->validate('contains', $args, [['string', 'array'], ['any']]); + if (is_array($args[0])) { + return in_array($args[1], $args[0]); + } elseif (is_string($args[1])) { + return mb_strpos($args[0], $args[1], 0, 'UTF-8') !== false; + } else { + return null; + } + } + + private function fn_ends_with(array $args) + { + $this->validate('ends_with', $args, [['string'], ['string']]); + list($search, $suffix) = $args; + return $suffix === '' || mb_substr($search, -mb_strlen($suffix, 'UTF-8'), null, 'UTF-8') === $suffix; + } + + private function fn_floor(array $args) + { + $this->validate('floor', $args, [['number']]); + return floor($args[0]); + } + + private function fn_not_null(array $args) + { + if (!$args) { + throw new \RuntimeException( + "not_null() expects 1 or more arguments, 0 were provided" + ); + } + + return array_reduce($args, function ($carry, $item) { + return $carry !== null ? $carry : $item; + }); + } + + private function fn_join(array $args) + { + $this->validate('join', $args, [['string'], ['array']]); + $fn = function ($a, $b, $i) use ($args) { + return $i ? ($a . $args[0] . $b) : $b; + }; + return $this->reduce('join:0', $args[1], ['string'], $fn); + } + + private function fn_keys(array $args) + { + $this->validate('keys', $args, [['object']]); + return array_keys((array) $args[0]); + } + + private function fn_length(array $args) + { + $this->validate('length', $args, [['string', 'array', 'object']]); + return is_string($args[0]) ? mb_strlen($args[0], 'UTF-8') : count((array) $args[0]); + } + + private function fn_max(array $args) + { + $this->validate('max', $args, [['array']]); + $fn = function ($a, $b) { + return $a >= $b ? $a : $b; + }; + return $this->reduce('max:0', $args[0], ['number', 'string'], $fn); + } + + private function fn_max_by(array $args) + { + $this->validate('max_by', $args, [['array'], ['expression']]); + $expr = $this->wrapExpression('max_by:1', $args[1], ['number', 'string']); + $fn = function ($carry, $item, $index) use ($expr) { + return $index + ? ($expr($carry) >= $expr($item) ? $carry : $item) + : $item; + }; + return $this->reduce('max_by:1', $args[0], ['any'], $fn); + } + + private function fn_min(array $args) + { + $this->validate('min', $args, [['array']]); + $fn = function ($a, $b, $i) { + return $i && $a <= $b ? $a : $b; + }; + return $this->reduce('min:0', $args[0], ['number', 'string'], $fn); + } + + private function fn_min_by(array $args) + { + $this->validate('min_by', $args, [['array'], ['expression']]); + $expr = $this->wrapExpression('min_by:1', $args[1], ['number', 'string']); + $i = -1; + $fn = function ($a, $b) use ($expr, &$i) { + return ++$i ? ($expr($a) <= $expr($b) ? $a : $b) : $b; + }; + return $this->reduce('min_by:1', $args[0], ['any'], $fn); + } + + private function fn_reverse(array $args) + { + $this->validate('reverse', $args, [['array', 'string']]); + if (is_array($args[0])) { + return array_reverse($args[0]); + } elseif (is_string($args[0])) { + return strrev($args[0]); + } else { + throw new \RuntimeException('Cannot reverse provided argument'); + } + } + + private function fn_sum(array $args) + { + $this->validate('sum', $args, [['array']]); + $fn = function ($a, $b) { + return Utils::add($a, $b); + }; + return $this->reduce('sum:0', $args[0], ['number'], $fn); + } + + private function fn_sort(array $args) + { + $this->validate('sort', $args, [['array']]); + $valid = ['string', 'number']; + return Utils::stableSort($args[0], function ($a, $b) use ($valid) { + $this->validateSeq('sort:0', $valid, $a, $b); + return strnatcmp($a, $b); + }); + } + + private function fn_sort_by(array $args) + { + $this->validate('sort_by', $args, [['array'], ['expression']]); + $expr = $args[1]; + $valid = ['string', 'number']; + return Utils::stableSort( + $args[0], + function ($a, $b) use ($expr, $valid) { + $va = $expr($a); + $vb = $expr($b); + $this->validateSeq('sort_by:0', $valid, $va, $vb); + return strnatcmp($va, $vb); + } + ); + } + + private function fn_starts_with(array $args) + { + $this->validate('starts_with', $args, [['string'], ['string']]); + list($search, $prefix) = $args; + return $prefix === '' || mb_strpos($search, $prefix, 0, 'UTF-8') === 0; + } + + private function fn_type(array $args) + { + $this->validateArity('type', count($args), 1); + return Utils::type($args[0]); + } + + private function fn_to_string(array $args) + { + $this->validateArity('to_string', count($args), 1); + $v = $args[0]; + if (is_string($v)) { + return $v; + } elseif (is_object($v) + && !($v instanceof \JsonSerializable) + && method_exists($v, '__toString') + ) { + return (string) $v; + } + + return json_encode($v); + } + + private function fn_to_number(array $args) + { + $this->validateArity('to_number', count($args), 1); + $value = $args[0]; + $type = Utils::type($value); + if ($type == 'number') { + return $value; + } elseif ($type == 'string' && is_numeric($value)) { + return mb_strpos($value, '.', 0, 'UTF-8') ? (float) $value : (int) $value; + } else { + return null; + } + } + + private function fn_values(array $args) + { + $this->validate('values', $args, [['array', 'object']]); + return array_values((array) $args[0]); + } + + private function fn_merge(array $args) + { + if (!$args) { + throw new \RuntimeException( + "merge() expects 1 or more arguments, 0 were provided" + ); + } + + return call_user_func_array('array_replace', $args); + } + + private function fn_to_array(array $args) + { + $this->validate('to_array', $args, [['any']]); + + return Utils::isArray($args[0]) ? $args[0] : [$args[0]]; + } + + private function fn_map(array $args) + { + $this->validate('map', $args, [['expression'], ['any']]); + $result = []; + foreach ($args[1] as $a) { + $result[] = $args[0]($a); + } + return $result; + } + + private function typeError($from, $msg) + { + if (mb_strpos($from, ':', 0, 'UTF-8')) { + list($fn, $pos) = explode(':', $from); + throw new \RuntimeException( + sprintf('Argument %d of %s %s', $pos, $fn, $msg) + ); + } else { + throw new \RuntimeException( + sprintf('Type error: %s %s', $from, $msg) + ); + } + } + + private function validateArity($from, $given, $expected) + { + if ($given != $expected) { + $err = "%s() expects {$expected} arguments, {$given} were provided"; + throw new \RuntimeException(sprintf($err, $from)); + } + } + + private function validate($from, $args, $types = []) + { + $this->validateArity($from, count($args), count($types)); + foreach ($args as $index => $value) { + if (!isset($types[$index]) || !$types[$index]) { + continue; + } + $this->validateType("{$from}:{$index}", $value, $types[$index]); + } + } + + private function validateType($from, $value, array $types) + { + if ($types[0] == 'any' + || in_array(Utils::type($value), $types) + || ($value === [] && in_array('object', $types)) + ) { + return; + } + $msg = 'must be one of the following types: ' . implode(', ', $types) + . '. ' . Utils::type($value) . ' found'; + $this->typeError($from, $msg); + } + + /** + * Validates value A and B, ensures they both are correctly typed, and of + * the same type. + * + * @param string $from String of function:argument_position + * @param array $types Array of valid value types. + * @param mixed $a Value A + * @param mixed $b Value B + */ + private function validateSeq($from, array $types, $a, $b) + { + $ta = Utils::type($a); + $tb = Utils::type($b); + + if ($ta !== $tb) { + $msg = "encountered a type mismatch in sequence: {$ta}, {$tb}"; + $this->typeError($from, $msg); + } + + $typeMatch = ($types && $types[0] == 'any') || in_array($ta, $types); + if (!$typeMatch) { + $msg = 'encountered a type error in sequence. The argument must be ' + . 'an array of ' . implode('|', $types) . ' types. ' + . "Found {$ta}, {$tb}."; + $this->typeError($from, $msg); + } + } + + /** + * Reduces and validates an array of values to a single value using a fn. + * + * @param string $from String of function:argument_position + * @param array $values Values to reduce. + * @param array $types Array of valid value types. + * @param callable $reduce Reduce function that accepts ($carry, $item). + * + * @return mixed + */ + private function reduce($from, array $values, array $types, callable $reduce) + { + $i = -1; + return array_reduce( + $values, + function ($carry, $item) use ($from, $types, $reduce, &$i) { + if (++$i > 0) { + $this->validateSeq($from, $types, $carry, $item); + } + return $reduce($carry, $item, $i); + } + ); + } + + /** + * Validates the return values of expressions as they are applied. + * + * @param string $from Function name : position + * @param callable $expr Expression function to validate. + * @param array $types Array of acceptable return type values. + * + * @return callable Returns a wrapped function + */ + private function wrapExpression($from, callable $expr, array $types) + { + list($fn, $pos) = explode(':', $from); + $from = "The expression return value of argument {$pos} of {$fn}"; + return function ($value) use ($from, $expr, $types) { + $value = $expr($value); + $this->validateType($from, $value, $types); + return $value; + }; + } + + /** @internal Pass function name validation off to runtime */ + public function __call($name, $args) + { + $name = str_replace('fn_', '', $name); + throw new \RuntimeException("Call to undefined function {$name}"); + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/JmesPath.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/JmesPath.php new file mode 100644 index 000000000..d24e5160d --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/JmesPath.php @@ -0,0 +1,17 @@ + self::STATE_LT, + '>' => self::STATE_GT, + '=' => self::STATE_EQ, + '!' => self::STATE_NOT, + '[' => self::STATE_LBRACKET, + '|' => self::STATE_PIPE, + '&' => self::STATE_AND, + '`' => self::STATE_JSON_LITERAL, + '"' => self::STATE_QUOTED_STRING, + "'" => self::STATE_STRING_LITERAL, + '-' => self::STATE_NUMBER, + '0' => self::STATE_NUMBER, + '1' => self::STATE_NUMBER, + '2' => self::STATE_NUMBER, + '3' => self::STATE_NUMBER, + '4' => self::STATE_NUMBER, + '5' => self::STATE_NUMBER, + '6' => self::STATE_NUMBER, + '7' => self::STATE_NUMBER, + '8' => self::STATE_NUMBER, + '9' => self::STATE_NUMBER, + ' ' => self::STATE_WHITESPACE, + "\t" => self::STATE_WHITESPACE, + "\n" => self::STATE_WHITESPACE, + "\r" => self::STATE_WHITESPACE, + '.' => self::STATE_SINGLE_CHAR, + '*' => self::STATE_SINGLE_CHAR, + ']' => self::STATE_SINGLE_CHAR, + ',' => self::STATE_SINGLE_CHAR, + ':' => self::STATE_SINGLE_CHAR, + '@' => self::STATE_SINGLE_CHAR, + '(' => self::STATE_SINGLE_CHAR, + ')' => self::STATE_SINGLE_CHAR, + '{' => self::STATE_SINGLE_CHAR, + '}' => self::STATE_SINGLE_CHAR, + '_' => self::STATE_IDENTIFIER, + 'A' => self::STATE_IDENTIFIER, + 'B' => self::STATE_IDENTIFIER, + 'C' => self::STATE_IDENTIFIER, + 'D' => self::STATE_IDENTIFIER, + 'E' => self::STATE_IDENTIFIER, + 'F' => self::STATE_IDENTIFIER, + 'G' => self::STATE_IDENTIFIER, + 'H' => self::STATE_IDENTIFIER, + 'I' => self::STATE_IDENTIFIER, + 'J' => self::STATE_IDENTIFIER, + 'K' => self::STATE_IDENTIFIER, + 'L' => self::STATE_IDENTIFIER, + 'M' => self::STATE_IDENTIFIER, + 'N' => self::STATE_IDENTIFIER, + 'O' => self::STATE_IDENTIFIER, + 'P' => self::STATE_IDENTIFIER, + 'Q' => self::STATE_IDENTIFIER, + 'R' => self::STATE_IDENTIFIER, + 'S' => self::STATE_IDENTIFIER, + 'T' => self::STATE_IDENTIFIER, + 'U' => self::STATE_IDENTIFIER, + 'V' => self::STATE_IDENTIFIER, + 'W' => self::STATE_IDENTIFIER, + 'X' => self::STATE_IDENTIFIER, + 'Y' => self::STATE_IDENTIFIER, + 'Z' => self::STATE_IDENTIFIER, + 'a' => self::STATE_IDENTIFIER, + 'b' => self::STATE_IDENTIFIER, + 'c' => self::STATE_IDENTIFIER, + 'd' => self::STATE_IDENTIFIER, + 'e' => self::STATE_IDENTIFIER, + 'f' => self::STATE_IDENTIFIER, + 'g' => self::STATE_IDENTIFIER, + 'h' => self::STATE_IDENTIFIER, + 'i' => self::STATE_IDENTIFIER, + 'j' => self::STATE_IDENTIFIER, + 'k' => self::STATE_IDENTIFIER, + 'l' => self::STATE_IDENTIFIER, + 'm' => self::STATE_IDENTIFIER, + 'n' => self::STATE_IDENTIFIER, + 'o' => self::STATE_IDENTIFIER, + 'p' => self::STATE_IDENTIFIER, + 'q' => self::STATE_IDENTIFIER, + 'r' => self::STATE_IDENTIFIER, + 's' => self::STATE_IDENTIFIER, + 't' => self::STATE_IDENTIFIER, + 'u' => self::STATE_IDENTIFIER, + 'v' => self::STATE_IDENTIFIER, + 'w' => self::STATE_IDENTIFIER, + 'x' => self::STATE_IDENTIFIER, + 'y' => self::STATE_IDENTIFIER, + 'z' => self::STATE_IDENTIFIER, + ]; + + /** @var array Valid identifier characters after first character */ + private $validIdentifier = [ + 'A' => true, 'B' => true, 'C' => true, 'D' => true, 'E' => true, + 'F' => true, 'G' => true, 'H' => true, 'I' => true, 'J' => true, + 'K' => true, 'L' => true, 'M' => true, 'N' => true, 'O' => true, + 'P' => true, 'Q' => true, 'R' => true, 'S' => true, 'T' => true, + 'U' => true, 'V' => true, 'W' => true, 'X' => true, 'Y' => true, + 'Z' => true, 'a' => true, 'b' => true, 'c' => true, 'd' => true, + 'e' => true, 'f' => true, 'g' => true, 'h' => true, 'i' => true, + 'j' => true, 'k' => true, 'l' => true, 'm' => true, 'n' => true, + 'o' => true, 'p' => true, 'q' => true, 'r' => true, 's' => true, + 't' => true, 'u' => true, 'v' => true, 'w' => true, 'x' => true, + 'y' => true, 'z' => true, '_' => true, '0' => true, '1' => true, + '2' => true, '3' => true, '4' => true, '5' => true, '6' => true, + '7' => true, '8' => true, '9' => true, + ]; + + /** @var array Valid number characters after the first character */ + private $numbers = [ + '0' => true, '1' => true, '2' => true, '3' => true, '4' => true, + '5' => true, '6' => true, '7' => true, '8' => true, '9' => true + ]; + + /** @var array Map of simple single character tokens */ + private $simpleTokens = [ + '.' => self::T_DOT, + '*' => self::T_STAR, + ']' => self::T_RBRACKET, + ',' => self::T_COMMA, + ':' => self::T_COLON, + '@' => self::T_CURRENT, + '(' => self::T_LPAREN, + ')' => self::T_RPAREN, + '{' => self::T_LBRACE, + '}' => self::T_RBRACE, + ]; + + /** + * Tokenize the JMESPath expression into an array of tokens hashes that + * contain a 'type', 'value', and 'key'. + * + * @param string $input JMESPath input + * + * @return array + * @throws SyntaxErrorException + */ + public function tokenize($input) + { + $tokens = []; + + if ($input === '') { + goto eof; + } + + $chars = str_split($input); + + while (false !== ($current = current($chars))) { + + // Every character must be in the transition character table. + if (!isset(self::$transitionTable[$current])) { + $tokens[] = [ + 'type' => self::T_UNKNOWN, + 'pos' => key($chars), + 'value' => $current + ]; + next($chars); + continue; + } + + $state = self::$transitionTable[$current]; + + if ($state === self::STATE_SINGLE_CHAR) { + + // Consume simple tokens like ".", ",", "@", etc. + $tokens[] = [ + 'type' => $this->simpleTokens[$current], + 'pos' => key($chars), + 'value' => $current + ]; + next($chars); + + } elseif ($state === self::STATE_IDENTIFIER) { + + // Consume identifiers + $start = key($chars); + $buffer = ''; + do { + $buffer .= $current; + $current = next($chars); + } while ($current !== false && isset($this->validIdentifier[$current])); + $tokens[] = [ + 'type' => self::T_IDENTIFIER, + 'value' => $buffer, + 'pos' => $start + ]; + + } elseif ($state === self::STATE_WHITESPACE) { + + // Skip whitespace + next($chars); + + } elseif ($state === self::STATE_LBRACKET) { + + // Consume "[", "[?", and "[]" + $position = key($chars); + $actual = next($chars); + if ($actual === ']') { + next($chars); + $tokens[] = [ + 'type' => self::T_FLATTEN, + 'pos' => $position, + 'value' => '[]' + ]; + } elseif ($actual === '?') { + next($chars); + $tokens[] = [ + 'type' => self::T_FILTER, + 'pos' => $position, + 'value' => '[?' + ]; + } else { + $tokens[] = [ + 'type' => self::T_LBRACKET, + 'pos' => $position, + 'value' => '[' + ]; + } + + } elseif ($state === self::STATE_STRING_LITERAL) { + + // Consume raw string literals + $t = $this->inside($chars, "'", self::T_LITERAL); + $t['value'] = str_replace("\\'", "'", $t['value']); + $tokens[] = $t; + + } elseif ($state === self::STATE_PIPE) { + + // Consume pipe and OR + $tokens[] = $this->matchOr($chars, '|', '|', self::T_OR, self::T_PIPE); + + } elseif ($state == self::STATE_JSON_LITERAL) { + + // Consume JSON literals + $token = $this->inside($chars, '`', self::T_LITERAL); + if ($token['type'] === self::T_LITERAL) { + $token['value'] = str_replace('\\`', '`', $token['value']); + $token = $this->parseJson($token); + } + $tokens[] = $token; + + } elseif ($state == self::STATE_NUMBER) { + + // Consume numbers + $start = key($chars); + $buffer = ''; + do { + $buffer .= $current; + $current = next($chars); + } while ($current !== false && isset($this->numbers[$current])); + $tokens[] = [ + 'type' => self::T_NUMBER, + 'value' => (int)$buffer, + 'pos' => $start + ]; + + } elseif ($state === self::STATE_QUOTED_STRING) { + + // Consume quoted identifiers + $token = $this->inside($chars, '"', self::T_QUOTED_IDENTIFIER); + if ($token['type'] === self::T_QUOTED_IDENTIFIER) { + $token['value'] = '"' . $token['value'] . '"'; + $token = $this->parseJson($token); + } + $tokens[] = $token; + + } elseif ($state === self::STATE_EQ) { + + // Consume equals + $tokens[] = $this->matchOr($chars, '=', '=', self::T_COMPARATOR, self::T_UNKNOWN); + + } elseif ($state == self::STATE_AND) { + + $tokens[] = $this->matchOr($chars, '&', '&', self::T_AND, self::T_EXPREF); + + } elseif ($state === self::STATE_NOT) { + + // Consume not equal + $tokens[] = $this->matchOr($chars, '!', '=', self::T_COMPARATOR, self::T_NOT); + + } else { + + // either '<' or '>' + // Consume less than and greater than + $tokens[] = $this->matchOr($chars, $current, '=', self::T_COMPARATOR, self::T_COMPARATOR); + + } + } + + eof: + $tokens[] = [ + 'type' => self::T_EOF, + 'pos' => mb_strlen($input, 'UTF-8'), + 'value' => null + ]; + + return $tokens; + } + + /** + * Returns a token based on whether or not the next token matches the + * expected value. If it does, a token of "$type" is returned. Otherwise, + * a token of "$orElse" type is returned. + * + * @param array $chars Array of characters by reference. + * @param string $current The current character. + * @param string $expected Expected character. + * @param string $type Expected result type. + * @param string $orElse Otherwise return a token of this type. + * + * @return array Returns a conditional token. + */ + private function matchOr(array &$chars, $current, $expected, $type, $orElse) + { + if (next($chars) === $expected) { + next($chars); + return [ + 'type' => $type, + 'pos' => key($chars) - 1, + 'value' => $current . $expected + ]; + } + + return [ + 'type' => $orElse, + 'pos' => key($chars) - 1, + 'value' => $current + ]; + } + + /** + * Returns a token the is the result of consuming inside of delimiter + * characters. Escaped delimiters will be adjusted before returning a + * value. If the token is not closed, "unknown" is returned. + * + * @param array $chars Array of characters by reference. + * @param string $delim The delimiter character. + * @param string $type Token type. + * + * @return array Returns the consumed token. + */ + private function inside(array &$chars, $delim, $type) + { + $position = key($chars); + $current = next($chars); + $buffer = ''; + + while ($current !== $delim) { + if ($current === '\\') { + $buffer .= '\\'; + $current = next($chars); + } + if ($current === false) { + // Unclosed delimiter + return [ + 'type' => self::T_UNKNOWN, + 'value' => $buffer, + 'pos' => $position + ]; + } + $buffer .= $current; + $current = next($chars); + } + + next($chars); + + return ['type' => $type, 'value' => $buffer, 'pos' => $position]; + } + + /** + * Parses a JSON token or sets the token type to "unknown" on error. + * + * @param array $token Token that needs parsing. + * + * @return array Returns a token with a parsed value. + */ + private function parseJson(array $token) + { + $value = json_decode($token['value'], true); + + if ($error = json_last_error()) { + // Legacy support for elided quotes. Try to parse again by adding + // quotes around the bad input value. + $value = json_decode('"' . $token['value'] . '"', true); + if ($error = json_last_error()) { + $token['type'] = self::T_UNKNOWN; + return $token; + } + } + + $token['value'] = $value; + return $token; + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Parser.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Parser.php new file mode 100644 index 000000000..d126de56b --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Parser.php @@ -0,0 +1,519 @@ + T::T_EOF]; + private static $currentNode = ['type' => T::T_CURRENT]; + + private static $bp = [ + T::T_EOF => 0, + T::T_QUOTED_IDENTIFIER => 0, + T::T_IDENTIFIER => 0, + T::T_RBRACKET => 0, + T::T_RPAREN => 0, + T::T_COMMA => 0, + T::T_RBRACE => 0, + T::T_NUMBER => 0, + T::T_CURRENT => 0, + T::T_EXPREF => 0, + T::T_COLON => 0, + T::T_PIPE => 1, + T::T_OR => 2, + T::T_AND => 3, + T::T_COMPARATOR => 5, + T::T_FLATTEN => 9, + T::T_STAR => 20, + T::T_FILTER => 21, + T::T_DOT => 40, + T::T_NOT => 45, + T::T_LBRACE => 50, + T::T_LBRACKET => 55, + T::T_LPAREN => 60, + ]; + + /** @var array Acceptable tokens after a dot token */ + private static $afterDot = [ + T::T_IDENTIFIER => true, // foo.bar + T::T_QUOTED_IDENTIFIER => true, // foo."bar" + T::T_STAR => true, // foo.* + T::T_LBRACE => true, // foo[1] + T::T_LBRACKET => true, // foo{a: 0} + T::T_FILTER => true, // foo.[?bar==10] + ]; + + /** + * @param Lexer|null $lexer Lexer used to tokenize expressions + */ + public function __construct(?Lexer $lexer = null) + { + $this->lexer = $lexer ?: new Lexer(); + } + + /** + * Parses a JMESPath expression into an AST + * + * @param string $expression JMESPath expression to compile + * + * @return array Returns an array based AST + * @throws SyntaxErrorException + */ + public function parse($expression) + { + $this->expression = $expression; + $this->tokens = $this->lexer->tokenize($expression); + $this->tpos = -1; + $this->next(); + $result = $this->expr(); + + if ($this->token['type'] === T::T_EOF) { + return $result; + } + + throw $this->syntax('Did not reach the end of the token stream'); + } + + /** + * Parses an expression while rbp < lbp. + * + * @param int $rbp Right bound precedence + * + * @return array + */ + private function expr($rbp = 0) + { + $left = $this->{"nud_{$this->token['type']}"}(); + while ($rbp < self::$bp[$this->token['type']]) { + $left = $this->{"led_{$this->token['type']}"}($left); + } + + return $left; + } + + private function nud_identifier() + { + $token = $this->token; + $this->next(); + return ['type' => 'field', 'value' => $token['value']]; + } + + private function nud_quoted_identifier() + { + $token = $this->token; + $this->next(); + $this->assertNotToken(T::T_LPAREN); + return ['type' => 'field', 'value' => $token['value']]; + } + + private function nud_current() + { + $this->next(); + return self::$currentNode; + } + + private function nud_literal() + { + $token = $this->token; + $this->next(); + return ['type' => 'literal', 'value' => $token['value']]; + } + + private function nud_expref() + { + $this->next(); + return ['type' => T::T_EXPREF, 'children' => [$this->expr(self::$bp[T::T_EXPREF])]]; + } + + private function nud_not() + { + $this->next(); + return ['type' => T::T_NOT, 'children' => [$this->expr(self::$bp[T::T_NOT])]]; + } + + private function nud_lparen() + { + $this->next(); + $result = $this->expr(0); + if ($this->token['type'] !== T::T_RPAREN) { + throw $this->syntax('Unclosed `(`'); + } + $this->next(); + return $result; + } + + private function nud_lbrace() + { + static $validKeys = [T::T_QUOTED_IDENTIFIER => true, T::T_IDENTIFIER => true]; + $this->next($validKeys); + $pairs = []; + + do { + $pairs[] = $this->parseKeyValuePair(); + if ($this->token['type'] == T::T_COMMA) { + $this->next($validKeys); + } + } while ($this->token['type'] !== T::T_RBRACE); + + $this->next(); + + return['type' => 'multi_select_hash', 'children' => $pairs]; + } + + private function nud_flatten() + { + return $this->led_flatten(self::$currentNode); + } + + private function nud_filter() + { + return $this->led_filter(self::$currentNode); + } + + private function nud_star() + { + return $this->parseWildcardObject(self::$currentNode); + } + + private function nud_lbracket() + { + $this->next(); + $type = $this->token['type']; + if ($type == T::T_NUMBER || $type == T::T_COLON) { + return $this->parseArrayIndexExpression(); + } elseif ($type == T::T_STAR && $this->lookahead() == T::T_RBRACKET) { + return $this->parseWildcardArray(); + } else { + return $this->parseMultiSelectList(); + } + } + + private function led_lbracket(array $left) + { + static $nextTypes = [T::T_NUMBER => true, T::T_COLON => true, T::T_STAR => true]; + $this->next($nextTypes); + switch ($this->token['type']) { + case T::T_NUMBER: + case T::T_COLON: + return [ + 'type' => 'subexpression', + 'children' => [$left, $this->parseArrayIndexExpression()] + ]; + default: + return $this->parseWildcardArray($left); + } + } + + private function led_flatten(array $left) + { + $this->next(); + + return [ + 'type' => 'projection', + 'from' => 'array', + 'children' => [ + ['type' => T::T_FLATTEN, 'children' => [$left]], + $this->parseProjection(self::$bp[T::T_FLATTEN]) + ] + ]; + } + + private function led_dot(array $left) + { + $this->next(self::$afterDot); + + if ($this->token['type'] == T::T_STAR) { + return $this->parseWildcardObject($left); + } + + return [ + 'type' => 'subexpression', + 'children' => [$left, $this->parseDot(self::$bp[T::T_DOT])] + ]; + } + + private function led_or(array $left) + { + $this->next(); + return [ + 'type' => T::T_OR, + 'children' => [$left, $this->expr(self::$bp[T::T_OR])] + ]; + } + + private function led_and(array $left) + { + $this->next(); + return [ + 'type' => T::T_AND, + 'children' => [$left, $this->expr(self::$bp[T::T_AND])] + ]; + } + + private function led_pipe(array $left) + { + $this->next(); + return [ + 'type' => T::T_PIPE, + 'children' => [$left, $this->expr(self::$bp[T::T_PIPE])] + ]; + } + + private function led_lparen(array $left) + { + $args = []; + $this->next(); + + while ($this->token['type'] != T::T_RPAREN) { + $args[] = $this->expr(0); + if ($this->token['type'] == T::T_COMMA) { + $this->next(); + } + } + + $this->next(); + + return [ + 'type' => 'function', + 'value' => $left['value'], + 'children' => $args + ]; + } + + private function led_filter(array $left) + { + $this->next(); + $expression = $this->expr(); + if ($this->token['type'] != T::T_RBRACKET) { + throw $this->syntax('Expected a closing rbracket for the filter'); + } + + $this->next(); + $rhs = $this->parseProjection(self::$bp[T::T_FILTER]); + + return [ + 'type' => 'projection', + 'from' => 'array', + 'children' => [ + $left ?: self::$currentNode, + [ + 'type' => 'condition', + 'children' => [$expression, $rhs] + ] + ] + ]; + } + + private function led_comparator(array $left) + { + $token = $this->token; + $this->next(); + + return [ + 'type' => T::T_COMPARATOR, + 'value' => $token['value'], + 'children' => [$left, $this->expr(self::$bp[T::T_COMPARATOR])] + ]; + } + + private function parseProjection($bp) + { + $type = $this->token['type']; + if (self::$bp[$type] < 10) { + return self::$currentNode; + } elseif ($type == T::T_DOT) { + $this->next(self::$afterDot); + return $this->parseDot($bp); + } elseif ($type == T::T_LBRACKET || $type == T::T_FILTER) { + return $this->expr($bp); + } + + throw $this->syntax('Syntax error after projection'); + } + + private function parseDot($bp) + { + if ($this->token['type'] == T::T_LBRACKET) { + $this->next(); + return $this->parseMultiSelectList(); + } + + return $this->expr($bp); + } + + private function parseKeyValuePair() + { + static $validColon = [T::T_COLON => true]; + $key = $this->token['value']; + $this->next($validColon); + $this->next(); + + return [ + 'type' => 'key_val_pair', + 'value' => $key, + 'children' => [$this->expr()] + ]; + } + + private function parseWildcardObject(?array $left = null) + { + $this->next(); + + return [ + 'type' => 'projection', + 'from' => 'object', + 'children' => [ + $left ?: self::$currentNode, + $this->parseProjection(self::$bp[T::T_STAR]) + ] + ]; + } + + private function parseWildcardArray(?array $left = null) + { + static $getRbracket = [T::T_RBRACKET => true]; + $this->next($getRbracket); + $this->next(); + + return [ + 'type' => 'projection', + 'from' => 'array', + 'children' => [ + $left ?: self::$currentNode, + $this->parseProjection(self::$bp[T::T_STAR]) + ] + ]; + } + + /** + * Parses an array index expression (e.g., [0], [1:2:3] + */ + private function parseArrayIndexExpression() + { + static $matchNext = [ + T::T_NUMBER => true, + T::T_COLON => true, + T::T_RBRACKET => true + ]; + + $pos = 0; + $parts = [null, null, null]; + $expected = $matchNext; + + do { + if ($this->token['type'] == T::T_COLON) { + $pos++; + $expected = $matchNext; + } elseif ($this->token['type'] == T::T_NUMBER) { + $parts[$pos] = $this->token['value']; + $expected = [T::T_COLON => true, T::T_RBRACKET => true]; + } + $this->next($expected); + } while ($this->token['type'] != T::T_RBRACKET); + + // Consume the closing bracket + $this->next(); + + if ($pos === 0) { + // No colons were found so this is a simple index extraction + return ['type' => 'index', 'value' => $parts[0]]; + } + + if ($pos > 2) { + throw $this->syntax('Invalid array slice syntax: too many colons'); + } + + // Sliced array from start (e.g., [2:]) + return [ + 'type' => 'projection', + 'from' => 'array', + 'children' => [ + ['type' => 'slice', 'value' => $parts], + $this->parseProjection(self::$bp[T::T_STAR]) + ] + ]; + } + + private function parseMultiSelectList() + { + $nodes = []; + + do { + $nodes[] = $this->expr(); + if ($this->token['type'] == T::T_COMMA) { + $this->next(); + $this->assertNotToken(T::T_RBRACKET); + } + } while ($this->token['type'] !== T::T_RBRACKET); + $this->next(); + + return ['type' => 'multi_select_list', 'children' => $nodes]; + } + + private function syntax($msg) + { + return new SyntaxErrorException($msg, $this->token, $this->expression); + } + + private function lookahead() + { + return (!isset($this->tokens[$this->tpos + 1])) + ? T::T_EOF + : $this->tokens[$this->tpos + 1]['type']; + } + + private function next(?array $match = null) + { + if (!isset($this->tokens[$this->tpos + 1])) { + $this->token = self::$nullToken; + } else { + $this->token = $this->tokens[++$this->tpos]; + } + + if ($match && !isset($match[$this->token['type']])) { + throw $this->syntax($match); + } + } + + private function assertNotToken($type) + { + if ($this->token['type'] == $type) { + throw $this->syntax("Token {$this->tpos} not allowed to be $type"); + } + } + + /** + * @internal Handles undefined tokens without paying the cost of validation + */ + public function __call($method, $args) + { + $prefix = substr($method, 0, 4); + if ($prefix == 'nud_' || $prefix == 'led_') { + $token = substr($method, 4); + $message = "Unexpected \"$token\" token ($method). Expected one of" + . " the following tokens: " + . implode(', ', array_map(function ($i) { + return '"' . substr($i, 4) . '"'; + }, array_filter( + get_class_methods($this), + function ($i) use ($prefix) { + return strpos($i, $prefix) === 0; + } + ))); + throw $this->syntax($message); + } + + throw new \BadMethodCallException("Call to undefined method $method"); + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/SyntaxErrorException.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/SyntaxErrorException.php new file mode 100644 index 000000000..b9e376e12 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/SyntaxErrorException.php @@ -0,0 +1,36 @@ +createTokenMessage($token, $expectedTypesOrMessage); + parent::__construct($message); + } + + private function createTokenMessage(array $token, array $valid) + { + return sprintf( + 'Expected one of the following: %s; found %s "%s"', + implode(', ', array_keys($valid)), + $token['type'], + $token['value'] + ); + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeCompiler.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeCompiler.php new file mode 100644 index 000000000..b5f065894 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeCompiler.php @@ -0,0 +1,419 @@ +vars = []; + $this->source = $this->indentation = ''; + $this->write("write('use JmesPath\\TreeInterpreter as Ti;') + ->write('use JmesPath\\FnDispatcher as Fd;') + ->write('use JmesPath\\Utils;') + ->write('') + ->write('function %s(Ti $interpreter, $value) {', $fnName) + ->indent() + ->dispatch($ast) + ->write('') + ->write('return $value;') + ->outdent() + ->write('}'); + + return $this->source; + } + + /** + * @param array $node + * @return mixed + */ + private function dispatch(array $node) + { + return $this->{"visit_{$node['type']}"}($node); + } + + /** + * Creates a monotonically incrementing unique variable name by prefix. + * + * @param string $prefix Variable name prefix + * + * @return string + */ + private function makeVar($prefix) + { + if (!isset($this->vars[$prefix])) { + $this->vars[$prefix] = 0; + return '$' . $prefix; + } + + return '$' . $prefix . ++$this->vars[$prefix]; + } + + /** + * Writes the given line of source code. Pass positional arguments to write + * that match the format of sprintf. + * + * @param string $str String to write + * @return $this + */ + private function write($str) + { + $this->source .= $this->indentation; + if (func_num_args() == 1) { + $this->source .= $str . "\n"; + return $this; + } + $this->source .= vsprintf($str, array_slice(func_get_args(), 1)) . "\n"; + return $this; + } + + /** + * Decreases the indentation level of code being written + * @return $this + */ + private function outdent() + { + $this->indentation = substr($this->indentation, 0, -4); + return $this; + } + + /** + * Increases the indentation level of code being written + * @return $this + */ + private function indent() + { + $this->indentation .= ' '; + return $this; + } + + private function visit_or(array $node) + { + $a = $this->makeVar('beforeOr'); + return $this + ->write('%s = $value;', $a) + ->dispatch($node['children'][0]) + ->write('if (!$value && $value !== "0" && $value !== 0) {') + ->indent() + ->write('$value = %s;', $a) + ->dispatch($node['children'][1]) + ->outdent() + ->write('}'); + } + + private function visit_and(array $node) + { + $a = $this->makeVar('beforeAnd'); + return $this + ->write('%s = $value;', $a) + ->dispatch($node['children'][0]) + ->write('if ($value || $value === "0" || $value === 0) {') + ->indent() + ->write('$value = %s;', $a) + ->dispatch($node['children'][1]) + ->outdent() + ->write('}'); + } + + private function visit_not(array $node) + { + return $this + ->write('// Visiting not node') + ->dispatch($node['children'][0]) + ->write('// Applying boolean not to result of not node') + ->write('$value = !Utils::isTruthy($value);'); + } + + private function visit_subexpression(array $node) + { + return $this + ->dispatch($node['children'][0]) + ->write('if ($value !== null) {') + ->indent() + ->dispatch($node['children'][1]) + ->outdent() + ->write('}'); + } + + private function visit_field(array $node) + { + $arr = '$value[' . var_export($node['value'], true) . ']'; + $obj = '$value->{' . var_export($node['value'], true) . '}'; + $this->write('if (is_array($value) || $value instanceof \\ArrayAccess) {') + ->indent() + ->write('$value = isset(%s) ? %s : null;', $arr, $arr) + ->outdent() + ->write('} elseif ($value instanceof \\stdClass) {') + ->indent() + ->write('$value = isset(%s) ? %s : null;', $obj, $obj) + ->outdent() + ->write("} else {") + ->indent() + ->write('$value = null;') + ->outdent() + ->write("}"); + + return $this; + } + + private function visit_index(array $node) + { + if ($node['value'] >= 0) { + $check = '$value[' . $node['value'] . ']'; + return $this->write( + '$value = (is_array($value) || $value instanceof \\ArrayAccess)' + . ' && isset(%s) ? %s : null;', + $check, $check + ); + } + + $a = $this->makeVar('count'); + return $this + ->write('if (is_array($value) || ($value instanceof \\ArrayAccess && $value instanceof \\Countable)) {') + ->indent() + ->write('%s = count($value) + %s;', $a, $node['value']) + ->write('$value = isset($value[%s]) ? $value[%s] : null;', $a, $a) + ->outdent() + ->write('} else {') + ->indent() + ->write('$value = null;') + ->outdent() + ->write('}'); + } + + private function visit_literal(array $node) + { + return $this->write('$value = %s;', var_export($node['value'], true)); + } + + private function visit_pipe(array $node) + { + return $this + ->dispatch($node['children'][0]) + ->dispatch($node['children'][1]); + } + + private function visit_multi_select_list(array $node) + { + return $this->visit_multi_select_hash($node); + } + + private function visit_multi_select_hash(array $node) + { + $listVal = $this->makeVar('list'); + $value = $this->makeVar('prev'); + $this->write('if ($value !== null) {') + ->indent() + ->write('%s = [];', $listVal) + ->write('%s = $value;', $value); + + $first = true; + foreach ($node['children'] as $child) { + if (!$first) { + $this->write('$value = %s;', $value); + } + $first = false; + if ($node['type'] == 'multi_select_hash') { + $this->dispatch($child['children'][0]); + $key = var_export($child['value'], true); + $this->write('%s[%s] = $value;', $listVal, $key); + } else { + $this->dispatch($child); + $this->write('%s[] = $value;', $listVal); + } + } + + return $this + ->write('$value = %s;', $listVal) + ->outdent() + ->write('}'); + } + + private function visit_function(array $node) + { + $value = $this->makeVar('val'); + $args = $this->makeVar('args'); + $this->write('%s = $value;', $value) + ->write('%s = [];', $args); + + foreach ($node['children'] as $arg) { + $this->dispatch($arg); + $this->write('%s[] = $value;', $args) + ->write('$value = %s;', $value); + } + + return $this->write( + '$value = Fd::getInstance()->__invoke("%s", %s);', + $node['value'], $args + ); + } + + private function visit_slice(array $node) + { + return $this + ->write('$value = !is_string($value) && !Utils::isArray($value)') + ->write(' ? null : Utils::slice($value, %s, %s, %s);', + var_export($node['value'][0], true), + var_export($node['value'][1], true), + var_export($node['value'][2], true) + ); + } + + private function visit_current(array $node) + { + return $this->write('// Visiting current node (no-op)'); + } + + private function visit_expref(array $node) + { + $child = var_export($node['children'][0], true); + return $this->write('$value = function ($value) use ($interpreter) {') + ->indent() + ->write('return $interpreter->visit(%s, $value);', $child) + ->outdent() + ->write('};'); + } + + private function visit_flatten(array $node) + { + $this->dispatch($node['children'][0]); + $merged = $this->makeVar('merged'); + $val = $this->makeVar('val'); + + $this + ->write('// Visiting merge node') + ->write('if (!Utils::isArray($value)) {') + ->indent() + ->write('$value = null;') + ->outdent() + ->write('} else {') + ->indent() + ->write('%s = [];', $merged) + ->write('foreach ($value as %s) {', $val) + ->indent() + ->write('if (is_array(%s) && array_key_exists(0, %s)) {', $val, $val) + ->indent() + ->write('%s = array_merge(%s, %s);', $merged, $merged, $val) + ->outdent() + ->write('} elseif (%s !== []) {', $val) + ->indent() + ->write('%s[] = %s;', $merged, $val) + ->outdent() + ->write('}') + ->outdent() + ->write('}') + ->write('$value = %s;', $merged) + ->outdent() + ->write('}'); + + return $this; + } + + private function visit_projection(array $node) + { + $val = $this->makeVar('val'); + $collected = $this->makeVar('collected'); + $this->write('// Visiting projection node') + ->dispatch($node['children'][0]) + ->write(''); + + if (!isset($node['from'])) { + $this->write('if (!is_array($value) || !($value instanceof \stdClass)) { $value = null; }'); + } elseif ($node['from'] == 'object') { + $this->write('if (!Utils::isObject($value)) { $value = null; }'); + } elseif ($node['from'] == 'array') { + $this->write('if (!Utils::isArray($value)) { $value = null; }'); + } + + $this->write('if ($value !== null) {') + ->indent() + ->write('%s = [];', $collected) + ->write('foreach ((array) $value as %s) {', $val) + ->indent() + ->write('$value = %s;', $val) + ->dispatch($node['children'][1]) + ->write('if ($value !== null) {') + ->indent() + ->write('%s[] = $value;', $collected) + ->outdent() + ->write('}') + ->outdent() + ->write('}') + ->write('$value = %s;', $collected) + ->outdent() + ->write('}'); + + return $this; + } + + private function visit_condition(array $node) + { + $value = $this->makeVar('beforeCondition'); + return $this + ->write('%s = $value;', $value) + ->write('// Visiting condition node') + ->dispatch($node['children'][0]) + ->write('// Checking result of condition node') + ->write('if (Utils::isTruthy($value)) {') + ->indent() + ->write('$value = %s;', $value) + ->dispatch($node['children'][1]) + ->outdent() + ->write('} else {') + ->indent() + ->write('$value = null;') + ->outdent() + ->write('}'); + } + + private function visit_comparator(array $node) + { + $value = $this->makeVar('val'); + $a = $this->makeVar('left'); + $b = $this->makeVar('right'); + + $this + ->write('// Visiting comparator node') + ->write('%s = $value;', $value) + ->dispatch($node['children'][0]) + ->write('%s = $value;', $a) + ->write('$value = %s;', $value) + ->dispatch($node['children'][1]) + ->write('%s = $value;', $b); + + if ($node['value'] == '==') { + $this->write('$value = Utils::isEqual(%s, %s);', $a, $b); + } elseif ($node['value'] == '!=') { + $this->write('$value = !Utils::isEqual(%s, %s);', $a, $b); + } else { + $this->write( + '$value = (is_int(%s) || is_float(%s)) && (is_int(%s) || is_float(%s)) && %s %s %s;', + $a, $a, $b, $b, $a, $node['value'], $b + ); + } + + return $this; + } + + /** @internal */ + public function __call($method, $args) + { + throw new \RuntimeException( + sprintf('Invalid node encountered: %s', json_encode($args[0])) + ); + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeInterpreter.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeInterpreter.php new file mode 100644 index 000000000..f4a8aeca7 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/TreeInterpreter.php @@ -0,0 +1,235 @@ +fnDispatcher = $fnDispatcher ?: FnDispatcher::getInstance(); + } + + /** + * Visits each node in a JMESPath AST and returns the evaluated result. + * + * @param array $node JMESPath AST node + * @param mixed $data Data to evaluate + * + * @return mixed + */ + public function visit(array $node, $data) + { + return $this->dispatch($node, $data); + } + + /** + * Recursively traverses an AST using depth-first, pre-order traversal. + * The evaluation logic for each node type is embedded into a large switch + * statement to avoid the cost of "double dispatch". + * @return mixed + */ + private function dispatch(array $node, $value) + { + $dispatcher = $this->fnDispatcher; + + switch ($node['type']) { + + case 'field': + if (is_array($value) || $value instanceof \ArrayAccess) { + return isset($value[$node['value']]) ? $value[$node['value']] : null; + } elseif ($value instanceof \stdClass) { + return isset($value->{$node['value']}) ? $value->{$node['value']} : null; + } + return null; + + case 'subexpression': + return $this->dispatch( + $node['children'][1], + $this->dispatch($node['children'][0], $value) + ); + + case 'index': + if (!Utils::isArray($value)) { + return null; + } + $idx = $node['value'] >= 0 + ? $node['value'] + : $node['value'] + count($value); + return isset($value[$idx]) ? $value[$idx] : null; + + case 'projection': + $left = $this->dispatch($node['children'][0], $value); + switch ($node['from']) { + case 'object': + if (!Utils::isObject($left)) { + return null; + } + break; + case 'array': + if (!Utils::isArray($left)) { + return null; + } + break; + default: + if (!is_array($left) || !($left instanceof \stdClass)) { + return null; + } + } + + $collected = []; + foreach ((array) $left as $val) { + $result = $this->dispatch($node['children'][1], $val); + if ($result !== null) { + $collected[] = $result; + } + } + + return $collected; + + case 'flatten': + static $skipElement = []; + $value = $this->dispatch($node['children'][0], $value); + + if (!Utils::isArray($value)) { + return null; + } + + $merged = []; + foreach ($value as $values) { + // Only merge up arrays lists and not hashes + if (is_array($values) && array_key_exists(0, $values)) { + $merged = array_merge($merged, $values); + } elseif ($values !== $skipElement) { + $merged[] = $values; + } + } + + return $merged; + + case 'literal': + return $node['value']; + + case 'current': + return $value; + + case 'or': + $result = $this->dispatch($node['children'][0], $value); + return Utils::isTruthy($result) + ? $result + : $this->dispatch($node['children'][1], $value); + + case 'and': + $result = $this->dispatch($node['children'][0], $value); + return Utils::isTruthy($result) + ? $this->dispatch($node['children'][1], $value) + : $result; + + case 'not': + return !Utils::isTruthy( + $this->dispatch($node['children'][0], $value) + ); + + case 'pipe': + return $this->dispatch( + $node['children'][1], + $this->dispatch($node['children'][0], $value) + ); + + case 'multi_select_list': + if ($value === null) { + return null; + } + + $collected = []; + foreach ($node['children'] as $node) { + $collected[] = $this->dispatch($node, $value); + } + + return $collected; + + case 'multi_select_hash': + if ($value === null) { + return null; + } + + $collected = []; + foreach ($node['children'] as $node) { + $collected[$node['value']] = $this->dispatch( + $node['children'][0], + $value + ); + } + + return $collected; + + case 'comparator': + $left = $this->dispatch($node['children'][0], $value); + $right = $this->dispatch($node['children'][1], $value); + if ($node['value'] == '==') { + return Utils::isEqual($left, $right); + } elseif ($node['value'] == '!=') { + return !Utils::isEqual($left, $right); + } else { + return self::relativeCmp($left, $right, $node['value']); + } + + case 'condition': + return Utils::isTruthy($this->dispatch($node['children'][0], $value)) + ? $this->dispatch($node['children'][1], $value) + : null; + + case 'function': + $args = []; + foreach ($node['children'] as $arg) { + $args[] = $this->dispatch($arg, $value); + } + return $dispatcher($node['value'], $args); + + case 'slice': + return is_string($value) || Utils::isArray($value) + ? Utils::slice( + $value, + $node['value'][0], + $node['value'][1], + $node['value'][2] + ) : null; + + case 'expref': + $apply = $node['children'][0]; + return function ($value) use ($apply) { + return $this->visit($apply, $value); + }; + + default: + throw new \RuntimeException("Unknown node type: {$node['type']}"); + } + } + + /** + * @return bool + */ + private static function relativeCmp($left, $right, $cmp) + { + if (!(is_int($left) || is_float($left)) || !(is_int($right) || is_float($right))) { + return false; + } + + switch ($cmp) { + case '>': return $left > $right; + case '>=': return $left >= $right; + case '<': return $left < $right; + case '<=': return $left <= $right; + default: throw new \RuntimeException("Invalid comparison: $cmp"); + } + } +} diff --git a/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Utils.php b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Utils.php new file mode 100644 index 000000000..9e69fef06 --- /dev/null +++ b/lam/lib/3rdParty/composer/mtdowling/jmespath.php/src/Utils.php @@ -0,0 +1,258 @@ + 'boolean', + 'string' => 'string', + 'NULL' => 'null', + 'double' => 'number', + 'float' => 'number', + 'integer' => 'number' + ]; + + /** + * Returns true if the value is truthy + * + * @param mixed $value Value to check + * + * @return bool + */ + public static function isTruthy($value) + { + if (!$value) { + return $value === 0 || $value === '0'; + } elseif ($value instanceof \stdClass) { + return (bool) get_object_vars($value); + } else { + return true; + } + } + + /** + * Gets the JMESPath type equivalent of a PHP variable. + * + * @param mixed $arg PHP variable + * @return string Returns the JSON data type + * @throws \InvalidArgumentException when an unknown type is given. + */ + public static function type($arg) + { + $type = gettype($arg); + if (isset(self::$typeMap[$type])) { + return self::$typeMap[$type]; + } elseif ($type === 'array') { + if (empty($arg)) { + return 'array'; + } + reset($arg); + return key($arg) === 0 ? 'array' : 'object'; + } elseif ($arg instanceof \stdClass) { + return 'object'; + } elseif ($arg instanceof \Closure) { + return 'expression'; + } elseif ($arg instanceof \ArrayAccess + && $arg instanceof \Countable + ) { + return count($arg) == 0 || $arg->offsetExists(0) + ? 'array' + : 'object'; + } elseif (method_exists($arg, '__toString')) { + return 'string'; + } + + throw new \InvalidArgumentException( + 'Unable to determine JMESPath type from ' . get_class($arg) + ); + } + + /** + * Determine if the provided value is a JMESPath compatible object. + * + * @param mixed $value + * + * @return bool + */ + public static function isObject($value) + { + if (is_array($value)) { + return !$value || array_keys($value)[0] !== 0; + } + + // Handle array-like values. Must be empty or offset 0 does not exist + return $value instanceof \Countable && $value instanceof \ArrayAccess + ? count($value) == 0 || !$value->offsetExists(0) + : $value instanceof \stdClass; + } + + /** + * Determine if the provided value is a JMESPath compatible array. + * + * @param mixed $value + * + * @return bool + */ + public static function isArray($value) + { + if (is_array($value)) { + return !$value || array_keys($value)[0] === 0; + } + + // Handle array-like values. Must be empty or offset 0 exists. + return $value instanceof \Countable && $value instanceof \ArrayAccess + ? count($value) == 0 || $value->offsetExists(0) + : false; + } + + /** + * JSON aware value comparison function. + * + * @param mixed $a First value to compare + * @param mixed $b Second value to compare + * + * @return bool + */ + public static function isEqual($a, $b) + { + if ($a === $b) { + return true; + } elseif ($a instanceof \stdClass) { + return self::isEqual((array) $a, $b); + } elseif ($b instanceof \stdClass) { + return self::isEqual($a, (array) $b); + } else { + return false; + } + } + + /** + * Safely add together two values. + * + * @param mixed $a First value to add + * @param mixed $b Second value to add + * + * @return int|float + */ + public static function add($a, $b) + { + if (is_numeric($a)) { + if (is_numeric($b)) { + return $a + $b; + } else { + return $a; + } + } else { + if (is_numeric($b)) { + return $b; + } else { + return 0; + } + } + } + + /** + * JMESPath requires a stable sorting algorithm, so here we'll implement + * a simple Schwartzian transform that uses array index positions as tie + * breakers. + * + * @param array $data List or map of data to sort + * @param callable $sortFn Callable used to sort values + * + * @return array Returns the sorted array + * @link http://en.wikipedia.org/wiki/Schwartzian_transform + */ + public static function stableSort(array $data, callable $sortFn) + { + // Decorate each item by creating an array of [value, index] + array_walk($data, function (&$v, $k) { + $v = [$v, $k]; + }); + // Sort by the sort function and use the index as a tie-breaker + uasort($data, function ($a, $b) use ($sortFn) { + return $sortFn($a[0], $b[0]) ?: ($a[1] < $b[1] ? -1 : 1); + }); + + // Undecorate each item and return the resulting sorted array + return array_map(function ($v) { + return $v[0]; + }, array_values($data)); + } + + /** + * Creates a Python-style slice of a string or array. + * + * @param array|string $value Value to slice + * @param int|null $start Starting position + * @param int|null $stop Stop position + * @param int $step Step (1, 2, -1, -2, etc.) + * + * @return array|string + * @throws \InvalidArgumentException + */ + public static function slice($value, $start = null, $stop = null, $step = 1) + { + if (!is_array($value) && !is_string($value)) { + throw new \InvalidArgumentException('Expects string or array'); + } + + return self::sliceIndices($value, $start, $stop, $step); + } + + private static function adjustEndpoint($length, $endpoint, $step) + { + if ($endpoint < 0) { + $endpoint += $length; + if ($endpoint < 0) { + $endpoint = $step < 0 ? -1 : 0; + } + } elseif ($endpoint >= $length) { + $endpoint = $step < 0 ? $length - 1 : $length; + } + + return $endpoint; + } + + private static function adjustSlice($length, $start, $stop, $step) + { + if ($step === null) { + $step = 1; + } elseif ($step === 0) { + throw new \RuntimeException('step cannot be 0'); + } + + if ($start === null) { + $start = $step < 0 ? $length - 1 : 0; + } else { + $start = self::adjustEndpoint($length, $start, $step); + } + + if ($stop === null) { + $stop = $step < 0 ? -1 : $length; + } else { + $stop = self::adjustEndpoint($length, $stop, $step); + } + + return [$start, $stop, $step]; + } + + private static function sliceIndices($subject, $start, $stop, $step) + { + $type = gettype($subject); + $len = $type == 'string' ? mb_strlen($subject, 'UTF-8') : count($subject); + list($start, $stop, $step) = self::adjustSlice($len, $start, $stop, $step); + + $result = []; + if ($step > 0) { + for ($i = $start; $i < $stop; $i += $step) { + $result[] = $subject[$i]; + } + } else { + for ($i = $start; $i > $stop; $i += $step) { + $result[] = $subject[$i]; + } + } + + return $type == 'string' ? implode('', $result) : $result; + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/composer.json b/lam/lib/3rdParty/composer/nesbot/carbon/composer.json index 0014434ea..f1a56552b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/composer.json +++ b/lam/lib/3rdParty/composer/nesbot/carbon/composer.json @@ -21,8 +21,8 @@ ], "homepage": "https://carbon.nesbot.com", "support": { - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon", "docs": "https://carbon.nesbot.com/docs" }, "funding": [ @@ -40,26 +40,24 @@ } ], "require": { - "php": "^7.1.8 || ^8.0", + "php": "^8.1", "ext-json": "*", - "carbonphp/carbon-doctrine-types": "*", + "carbonphp/carbon-doctrine-types": "<100.0", "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "require-dev": { - "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", - "doctrine/orm": "^2.7 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.0", - "kylekatarnls/multi-tester": "^2.0", - "ondrejmirtes/better-reflection": "*", - "phpmd/phpmd": "^2.9", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.99 || ^1.7.14", - "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", - "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", - "squizlabs/php_codesniffer": "^3.4" + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.75.0", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, "provide": { "psr/clock-implementation": "1.0" diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroBuiltin.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroBuiltin.php deleted file mode 100644 index ba7cf6320..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroBuiltin.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -use PHPStan\BetterReflection\Reflection; -use ReflectionMethod; - -if (!class_exists(AbstractReflectionMacro::class, false)) { - abstract class AbstractReflectionMacro extends AbstractMacro - { - /** - * {@inheritdoc} - */ - public function getReflection(): ?ReflectionMethod - { - if ($this->reflectionFunction instanceof Reflection\ReflectionMethod) { - return new Reflection\Adapter\ReflectionMethod($this->reflectionFunction); - } - - return $this->reflectionFunction instanceof ReflectionMethod - ? $this->reflectionFunction - : null; - } - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroStatic.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroStatic.php deleted file mode 100644 index bd4c8e804..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroStatic.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -use PHPStan\BetterReflection\Reflection; -use ReflectionMethod; - -if (!class_exists(AbstractReflectionMacro::class, false)) { - abstract class AbstractReflectionMacro extends AbstractMacro - { - /** - * {@inheritdoc} - */ - public function getReflection(): ?Reflection\Adapter\ReflectionMethod - { - if ($this->reflectionFunction instanceof Reflection\Adapter\ReflectionMethod) { - return $this->reflectionFunction; - } - - if ($this->reflectionFunction instanceof Reflection\ReflectionMethod) { - return new Reflection\Adapter\ReflectionMethod($this->reflectionFunction); - } - - return $this->reflectionFunction instanceof ReflectionMethod - ? new Reflection\Adapter\ReflectionMethod( - Reflection\ReflectionMethod::createFromName( - $this->reflectionFunction->getDeclaringClass()->getName(), - $this->reflectionFunction->getName() - ) - ) - : null; - } - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroStrongType.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroStrongType.php deleted file mode 100644 index f615b3a64..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroStrongType.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -if (!class_exists(LazyMacro::class, false)) { - abstract class LazyMacro extends AbstractReflectionMacro - { - /** - * {@inheritdoc} - */ - public function getFileName(): ?string - { - $file = $this->reflectionFunction->getFileName(); - - return (($file ? realpath($file) : null) ?: $file) ?: null; - } - - /** - * {@inheritdoc} - */ - public function getStartLine(): ?int - { - return $this->reflectionFunction->getStartLine(); - } - - /** - * {@inheritdoc} - */ - public function getEndLine(): ?int - { - return $this->reflectionFunction->getEndLine(); - } - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroWeakType.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroWeakType.php deleted file mode 100644 index bf64c1dd9..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/PHPStan/MacroWeakType.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -if (!class_exists(LazyMacro::class, false)) { - abstract class LazyMacro extends AbstractReflectionMacro - { - /** - * {@inheritdoc} - * - * @return string|false - */ - public function getFileName() - { - $file = $this->reflectionFunction->getFileName(); - - return (($file ? realpath($file) : null) ?: $file) ?: null; - } - - /** - * {@inheritdoc} - * - * @return int|false - */ - public function getStartLine() - { - return $this->reflectionFunction->getStartLine(); - } - - /** - * {@inheritdoc} - * - * @return int|false - */ - public function getEndLine() - { - return $this->reflectionFunction->getEndLine(); - } - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/ProtectedDatePeriod.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/ProtectedDatePeriod.php new file mode 100644 index 000000000..927e48d21 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/ProtectedDatePeriod.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use DatePeriod; + +if (!class_exists(DatePeriodBase::class, false)) { + class DatePeriodBase extends DatePeriod + { + /** + * Period start in PHP < 8.2. + * + * @var CarbonInterface + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period start. + */ + protected $start; + + /** + * Period end in PHP < 8.2. + * + * @var CarbonInterface|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period end. + */ + protected $end; + + /** + * Period current iterated date in PHP < 8.2. + * + * @var CarbonInterface|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period current iterated date. + */ + protected $current; + + /** + * Period interval in PHP < 8.2. + * + * @var CarbonInterval|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period interval. + */ + protected $interval; + + /** + * Period recurrences in PHP < 8.2. + * + * @var int|float|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period recurrences. + */ + protected $recurrences; + + /** + * Period start included option in PHP < 8.2. + * + * @var bool + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period start included option. + */ + protected $include_start_date; + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/UnprotectedDatePeriod.php b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/UnprotectedDatePeriod.php new file mode 100644 index 000000000..2341be715 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/lazy/Carbon/UnprotectedDatePeriod.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use DatePeriod; + +if (!class_exists(DatePeriodBase::class, false)) { + class DatePeriodBase extends DatePeriod + { + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/readme.md b/lam/lib/3rdParty/composer/nesbot/carbon/readme.md index 97ec8ce08..76bc5c7d8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/readme.md +++ b/lam/lib/3rdParty/composer/nesbot/carbon/readme.md @@ -2,12 +2,15 @@ [![Latest Stable Version](https://img.shields.io/packagist/v/nesbot/carbon.svg?style=flat-square)](https://packagist.org/packages/nesbot/carbon) [![Total Downloads](https://img.shields.io/packagist/dt/nesbot/carbon.svg?style=flat-square)](https://packagist.org/packages/nesbot/carbon) -[![GitHub Actions](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fbriannesbitt%2FCarbon%2Fbadge&style=flat-square&label=Build&logo=none)](https://github.com/briannesbitt/Carbon/actions) -[![codecov.io](https://img.shields.io/codecov/c/github/briannesbitt/Carbon.svg?style=flat-square)](https://codecov.io/github/briannesbitt/Carbon?branch=master) -[![Tidelift](https://tidelift.com/badges/github/briannesbitt/Carbon)](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme) +[![GitHub Actions](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FCarbonPHP%2Fcarbon%2Fbadge&style=flat-square&label=Build&logo=none)](https://github.com/CarbonPHP/carbon/actions) +[![codecov.io](https://img.shields.io/codecov/c/github/CarbonPHP/carbon.svg?style=flat-square)](https://codecov.io/github/CarbonPHP/carbon/actions?branch=master) An international PHP extension for DateTime. [https://carbon.nesbot.com](https://carbon.nesbot.com) +> [!NOTE] +> We're migrating the repository from [briannesbitt/Carbon](https://github.com/briannesbitt/Carbon) to [CarbonPHP/carbon](https://github.com/CarbonPHP/carbon), +> which means if you're looking specific issues/pull-requests, you may have to search both. No other impact as code on both will be kept up to date. + ```php toDateTimeString()); printf("Right now in Vancouver is %s", Carbon::now('America/Vancouver')); //implicit __toString() $tomorrow = Carbon::now()->addDay(); $lastWeek = Carbon::now()->subWeek(); -$nextSummerOlympics = Carbon::createFromDate(2016)->addYears(4); $officialDate = Carbon::now()->toRfc2822String(); @@ -50,10 +52,15 @@ echo Carbon::parse('2019-07-23 14:51')->locale('fr_FR')->isoFormat('LLLL'); // ' // ... but also does 'from now', 'after' and 'before' // rolling up to seconds, minutes, hours, days, months, years -$daysSinceEpoch = Carbon::createFromTimestamp(0)->diffInDays(); -``` +$daysSinceEpoch = Carbon::createFromTimestamp(0)->diffInDays(); // something such as: + // 19817.6771 +$daysUntilInternetBlowUp = $internetWillBlowUpOn->diffInDays(); // Negative value since it's in the future: + // -5037.4560 -[Get supported nesbot/carbon with the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme) +// Without parameter, difference is calculated from now, but doing $a->diff($b) +// it will count time from $a to $b. +Carbon::createFromTimestamp(0)->diffInDays($internetWillBlowUpOn); // 24855.1348 +``` ## Installation @@ -66,7 +73,7 @@ $ composer require nesbot/carbon ```json { "require": { - "nesbot/carbon": "^2.16" + "nesbot/carbon": "^3" } } ``` @@ -82,7 +89,7 @@ printf("Now: %s", Carbon::now()); ### Without Composer -Why are you not using [composer](https://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need. +Why are you not using [composer](https://getcomposer.org/)? Download the Carbon [latest release](https://github.com/CarbonPHP/carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need. ```php + ### Translators @@ -119,47 +126,55 @@ This project exists thanks to all the people who contribute. Support this project by becoming a sponsor. Your logo will show up here with a link to your website. - -Онлайн казино -CasinoHex Canada -Probukmacher -Casino-portugal.pt -Игровые автоматы -Slots City -inkedin -Онлайн казино України + +Online Kasyno Polis +Онлайн казино 777 +Best non Gamstop sites in the UK +Non GamStop Bookies UK +Route4Me Route Planner +gaia-wines.gr +Букмекер +best non Gamstop casinos +CasinoHex Canada +Real Money Pokies +Betking казино +WestNews онлайн казино Украины +UK casinos not on GamStop
    See more OnlineCasinosSpelen -Best non Gamstop sites in the UK -Real Money Pokies -Non GamStop Bookies UK -Онлайн Казино Украины -SSSTwitter -Non-GamStop Bets UK -Chudovo -UK Casino Gap -NZ Casino Deps -NonStopCasino.org -Migliori Siti Non AAMS -UK NonGamStopCasinos -SnapTik -Proxidize -IG Downloader -Blastup -Organic Social Boost -AzuraCast -Triplebyte -GitHub Sponsors -Salesforce - +Guidebook.BetWinner +Онлайн казино casino.ua +PayIDGambler +Legal Casino +Playfortune.net.br +https://play-fortune.pl/kasyno/z-minimalnym-depozytem/ +Best Betting +Slots not on GamStop +Sportsbook Reviews Online +Ставки на спорт Favbet +inkedin +Casino-portugal.pt +Probukmacher +Tidelift +Онлайн казино України +Sites not on GamStop +Лучшие онлайн казино Украины на Sportarena +Онлайн казино та їхні бонуси y-k.com.ua +Slots City +WildWinz Casino +Ігрові автомати +Non Gamstop Casinos +Slotozilla +casino non aams +Credit Zaim +ssddanbrown
    -[[Become a sponsor via OpenCollective](https://opencollective.com/Carbon#sponsor)] +[[See all](https://carbon.nesbot.com/#sponsors)] - - - - +[[Become a sponsor via OpenCollective*](https://opencollective.com/Carbon#sponsor)] -[[Become a sponsor via GitHub](https://github.com/sponsors/kylekatarnls)] +[[Become a sponsor via GitHub*](https://github.com/sponsors/kylekatarnls)] + +* This is a donation. No goods or services are expected in return. Any requests for refunds for those purposes will be rejected. ### Backers diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/sponsors.php b/lam/lib/3rdParty/composer/nesbot/carbon/sponsors.php index 67b217161..05a6a919b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/sponsors.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/sponsors.php @@ -37,27 +37,87 @@ function getHtmlAttribute($rawValue): string function getOpenCollectiveSponsors(): string { - $customSponsorImages = [ + $customSponsorOverride = [ // For consistency and equity among sponsors, as of now, we kindly ask our sponsors // to provide an image having a width/height ratio between 1/1 and 2/1. // By default, we'll show the member picture from OpenCollective, and will resize it if bigger - // int(OpenCollective.MemberId) => ImageURL + 662698 => [ + // alt attribute + 'name' => 'Non Gamstop Casinos', + // title attribute + 'description' => 'Casinos not on Gamstop', + // src attribute + 'image' => 'https://lgcnews.com/wp-content/uploads/2018/01/LGC-logo-v8-temp.png', + // href attribute + 'website' => 'https://lgcnews.com/', + ], + 663069 => [ + // alt attribute + 'name' => 'Ставки на спорт Favbet', + // href attribute + 'website' => 'https://www.favbet.ua/uk/', + ], + 676798 => [ + // alt attribute + 'name' => 'Top Casinos Canada', + // title attribute + 'description' => 'Top Casinos Canada', + // src attribute + 'image' => 'https://topcasino.net/img/topcasino-logo-cover.png', + // href attribute + 'website' => 'https://topcasino.net/', + ], ]; $members = json_decode(file_get_contents('https://opencollective.com/carbon/members/all.json'), true); - $list = array_filter($members, static function ($member): bool { - return ($member['lastTransactionAmount'] > 3 || $member['isActive']) && - $member['role'] === 'BACKER' && - $member['type'] !== 'USER' && - ( - $member['totalAmountDonated'] > 100 || - $member['lastTransactionAt'] > CarbonImmutable::now() - ->subMonthsNoOverflow(getMaxHistoryMonthsByAmount($member['lastTransactionAmount'])) - ->format('Y-m-d h:i') || - $member['isActive'] && $member['lastTransactionAmount'] >= 30 - ); - }); + foreach ($members as &$member) { + $member = array_merge($member, $customSponsorOverride[$member['MemberId']] ?? []); + } + + // Adding sponsors paying via other payment methods + $members[] = [ + 'MemberId' => 1, + 'createdAt' => '2019-01-01 02:00', + 'type' => 'ORGANIZATION', + 'role' => 'BACKER', + 'tier' => 'backer+', + 'isActive' => true, + 'totalAmountDonated' => 1000, + 'currency' => 'USD', + 'lastTransactionAt' => CarbonImmutable::now()->format('Y-m-d').' 02:00', + 'lastTransactionAmount' => 25, + 'profile' => 'https://tidelift.com/', + 'name' => 'Tidelift', + 'description' => 'Get professional support for Carbon', + 'image' => 'https://carbon.nesbot.com/docs/sponsors/tidelift-brand.png', + 'website' => 'https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=docs', + ]; + $members[] = [ + 'MemberId' => 2, + 'createdAt' => '2024-11-14 02:00', + 'type' => 'ORGANIZATION', + 'role' => 'BACKER', + 'tier' => 'backer+ yearly', + 'isActive' => true, + 'totalAmountDonated' => 170, + 'currency' => 'USD', + 'lastTransactionAt' => '2024-11-14 02:00', + 'lastTransactionAmount' => 170, + 'profile' => 'https://www.slotozilla.com/nz/free-spins', + 'name' => 'Slotozilla', + 'description' => 'Slotozilla website', + 'image' => 'https://carbon.nesbot.com/docs/sponsors/slotozilla.png', + 'website' => 'https://www.slotozilla.com/nz/free-spins', + ]; + + $list = array_filter($members, static fn (array $member): bool => $member['totalAmountDonated'] > 3 && $member['role'] !== 'HOST' && ( + $member['totalAmountDonated'] > 100 || + $member['lastTransactionAt'] > CarbonImmutable::now() + ->subMonthsNoOverflow(getMaxHistoryMonthsByAmount($member['lastTransactionAmount'])) + ->format('Y-m-d h:i') || + $member['isActive'] && $member['lastTransactionAmount'] >= 30 + )); $list = array_map(static function (array $member): array { $createdAt = CarbonImmutable::parse($member['createdAt']); @@ -69,55 +129,134 @@ function getOpenCollectiveSponsors(): string ->modify($lastTransactionAt->format('H:i:s.u')); } - $monthlyContribution = (float) ($member['totalAmountDonated'] / ceil($createdAt->floatDiffInMonths())); + $isYearly = str_contains(strtolower($member['tier'] ?? ''), 'yearly'); + $monthlyContribution = (float) ( + ($isYearly && $lastTransactionAt > CarbonImmutable::parse('-1 year')) + ? ($member['lastTransactionAmount'] / 11.2) // 11.2 instead of 12 to include the discount for yearly subscription + : ($member['totalAmountDonated'] / ceil($createdAt->floatDiffInMonths())) + ); - if ( - $lastTransactionAt->isAfter('last month') && - $member['lastTransactionAmount'] > $monthlyContribution - ) { - $monthlyContribution = (float) $member['lastTransactionAmount']; + if (!$isYearly) { + if ( + $lastTransactionAt->isAfter('last month') && + $member['lastTransactionAmount'] > $monthlyContribution + ) { + $monthlyContribution = (float) $member['lastTransactionAmount']; + } + + if ($lastTransactionAt->isBefore('-75 days')) { + $days = min(120, $lastTransactionAt->diffInDays('now') - 70); + $monthlyContribution *= 1 - $days / 240; + } } - $yearlyContribution = (float) ($member['totalAmountDonated'] / max(1, $createdAt->floatDiffInYears())); + $yearlyContribution = (float) ( + $isYearly + ? (12 * $monthlyContribution) + : ($member['totalAmountDonated'] / max(1, $createdAt->floatDiffInYears())) + ); $status = null; + $rank = 0; - if ($monthlyContribution > 29) { + if ($monthlyContribution > 50 || $yearlyContribution > 900) { $status = 'sponsor'; - } elseif ($monthlyContribution > 4.5 || $yearlyContribution > 29) { + $rank = 5; + } elseif ($monthlyContribution > 29 || $yearlyContribution > 700) { + $status = 'sponsor'; + $rank = 4; + } elseif ($monthlyContribution > 14.5 || $yearlyContribution > 500) { + $status = 'backerPlus'; + $rank = 3; + } elseif ($monthlyContribution > 4.5 || $yearlyContribution > 80) { $status = 'backer'; + $rank = 2; } elseif ($member['totalAmountDonated'] > 0) { $status = 'helper'; + $rank = 1; } return array_merge($member, [ - 'star' => ($monthlyContribution > 98 || $yearlyContribution > 500), + 'star' => ($monthlyContribution > 98 || $yearlyContribution > 800), 'status' => $status, + 'rank' => $rank, 'monthlyContribution' => $monthlyContribution, 'yearlyContribution' => $yearlyContribution, ]); }, $list); usort($list, static function (array $a, array $b): int { - return ($b['monthlyContribution'] <=> $a['monthlyContribution']) + return ($b['star'] <=> $a['star']) + ?: ($b['rank'] <=> $a['rank']) + ?: ($b['monthlyContribution'] <=> $a['monthlyContribution']) ?: ($b['totalAmountDonated'] <=> $a['totalAmountDonated']); }); - return implode('', array_map(static function (array $member) use ($customSponsorImages): string { - $href = htmlspecialchars($member['website'] ?? $member['profile']); + $membersByUrl = []; + $output = ''; + $extra = ''; + + foreach ($list as $member) { + $url = $member['website'] ?? $member['profile']; + + if (isset($membersByUrl[$url]) || !\in_array($member['status'], ['sponsor', 'backerPlus'], true)) { + continue; + } + + $membersByUrl[$url] = $member; + $href = htmlspecialchars($url); $src = $customSponsorImages[$member['MemberId'] ?? ''] ?? $member['image'] ?? (strtr($member['profile'], ['https://opencollective.com/' => 'https://images.opencollective.com/']).'/avatar/256.png'); [$x, $y] = @getimagesize($src) ?: [0, 0]; $validImage = ($x && $y); $src = $validImage ? htmlspecialchars($src) : 'https://opencollective.com/static/images/default-guest-logo.svg'; - $height = $member['status'] === 'sponsor' ? 64 : 42; + $height = match ($member['status']) { + 'sponsor' => 64, + 'backerPlus' => 42, + 'backer' => 32, + default => 24, + }; + $rel = match ($member['status']) { + 'sponsor', 'backerPlus' => '', + default => ' rel="sponsored"', + }; + $width = min($height * 2, $validImage ? round($x * $height / $y) : $height); - $href .= (strpos($href, '?') === false ? '?' : '&').'utm_source=opencollective&utm_medium=github&utm_campaign=Carbon'; + + if (!str_contains($href, 'utm_source') && !preg_match('/^https?:\/\/(?:www\.)?(?:onlinekasyno-polis\.pl|zonaminecraft\.net|slotozilla\.com)(\/.*)?/', $href)) { + $href .= (!str_contains($href, '?') ? '?' : '&').'utm_source=opencollective&utm_medium=github&utm_campaign=Carbon'; + } + $title = getHtmlAttribute(($member['description'] ?? null) ?: $member['name']); $alt = getHtmlAttribute($member['name']); - return "\n".''. + if ($member['star']) { + $width *= 1.5; + $height *= 1.5; + } + + $link = "\n".''. ''.$alt.''. ''; - }, $list))."\n"; + + if ($member['rank'] >= 5) { + $output .= $link; + + continue; + } + + $extra .= $link; + } + + $github = [ + 8343178 => 'ssddanbrown', + ]; + + foreach ($github as $avatar => $user) { + $extra .= "\n".''. + ''.$user.''. + ''; + } + + return $output.'
    See more'.$extra.'
    '; } file_put_contents('readme.md', preg_replace_callback( @@ -125,5 +264,5 @@ file_put_contents('readme.md', preg_replace_callback( static function (array $match): string { return $match[1].getOpenCollectiveSponsors().$match[2]; }, - file_get_contents('readme.md') + file_get_contents('readme.md'), )); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/AbstractTranslator.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/AbstractTranslator.php index 8b8fe089e..8dd47aeed 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/AbstractTranslator.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/AbstractTranslator.php @@ -1,5 +1,7 @@ */ - protected $aliases = [ + protected array $aliases = [ 'me' => 'sr_Latn_ME', 'scr' => 'sh', ]; @@ -66,32 +68,31 @@ abstract class AbstractTranslator extends Translation\Translator * * @return static */ - public static function get($locale = null) + public static function get(?string $locale = null): static { $locale = $locale ?: 'en'; $key = static::class === Translator::class ? $locale : static::class.'|'.$locale; + $count = \count(static::$singletons); - if (!isset(static::$singletons[$key])) { - static::$singletons[$key] = new static($locale); + // Remember only the last 10 translators created + if ($count > 10) { + foreach (\array_slice(array_keys(static::$singletons), 0, $count - 10) as $index) { + unset(static::$singletons[$index]); + } } + static::$singletons[$key] ??= new static($locale); + return static::$singletons[$key]; } - public function __construct($locale, MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) + public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false) { - parent::setLocale($locale); - $this->initializing = true; - $this->directories = [__DIR__.'/Lang']; - $this->addLoader('array', new ArrayLoader()); - parent::__construct($locale, new MessageFormatterMapper($formatter), $cacheDir, $debug); - $this->initializing = false; + $this->initialize($locale, $formatter, $cacheDir, $debug); } /** * Returns the list of directories translation files are searched in. - * - * @return array */ public function getDirectories(): array { @@ -105,7 +106,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return $this */ - public function setDirectories(array $directories) + public function setDirectories(array $directories): static { $this->directories = $directories; @@ -119,7 +120,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return $this */ - public function addDirectory(string $directory) + public function addDirectory(string $directory): static { $this->directories[] = $directory; @@ -133,25 +134,22 @@ abstract class AbstractTranslator extends Translation\Translator * * @return $this */ - public function removeDirectory(string $directory) + public function removeDirectory(string $directory): static { $search = rtrim(strtr($directory, '\\', '/'), '/'); - return $this->setDirectories(array_filter($this->getDirectories(), function ($item) use ($search) { - return rtrim(strtr($item, '\\', '/'), '/') !== $search; - })); + return $this->setDirectories(array_filter( + $this->getDirectories(), + static fn ($item) => rtrim(strtr($item, '\\', '/'), '/') !== $search, + )); } /** * Reset messages of a locale (all locale if no locale passed). * Remove custom messages and reload initial messages from matching * file in Lang directory. - * - * @param string|null $locale - * - * @return bool */ - public function resetMessages($locale = null) + public function resetMessages(?string $locale = null): bool { if ($locale === null) { $this->messages = []; @@ -159,8 +157,10 @@ abstract class AbstractTranslator extends Translation\Translator return true; } + $this->assertValidLocale($locale); + foreach ($this->getDirectories() as $directory) { - $data = @include sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale); + $data = @include \sprintf('%s/%s.php', rtrim($directory, '\\/'), $locale); if ($data !== false) { $this->messages[$locale] = $data; @@ -180,7 +180,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return array */ - public function getLocalesFiles($prefix = '') + public function getLocalesFiles(string $prefix = ''): array { $files = []; @@ -203,7 +203,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return array */ - public function getAvailableLocales($prefix = '') + public function getAvailableLocales(string $prefix = ''): array { $locales = []; foreach ($this->getLocalesFiles($prefix) as $file) { @@ -228,7 +228,7 @@ abstract class AbstractTranslator extends Translation\Translator // @codeCoverageIgnoreStart try { $count = (new ReflectionFunction($format))->getNumberOfRequiredParameters(); - } catch (ReflectionException $exception) { + } catch (ReflectionException) { $count = 0; } // @codeCoverageIgnoreEnd @@ -249,7 +249,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return bool */ - protected function loadMessagesFromFile($locale) + protected function loadMessagesFromFile(string $locale): bool { return isset($this->messages[$locale]) || $this->resetMessages($locale); } @@ -262,7 +262,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return $this */ - public function setMessages($locale, $messages) + public function setMessages(string $locale, array $messages): static { $this->loadMessagesFromFile($locale); $this->addResource('array', $messages, $locale); @@ -281,7 +281,7 @@ abstract class AbstractTranslator extends Translation\Translator * * @return $this */ - public function setTranslations($messages) + public function setTranslations(array $messages): static { return $this->setMessages($this->getLocale(), $messages); } @@ -289,12 +289,8 @@ abstract class AbstractTranslator extends Translation\Translator /** * Get messages of a locale, if none given, return all the * languages. - * - * @param string|null $locale - * - * @return array */ - public function getMessages($locale = null) + public function getMessages(?string $locale = null): array { return $locale === null ? $this->messages : $this->messages[$locale]; } @@ -303,16 +299,14 @@ abstract class AbstractTranslator extends Translation\Translator * Set the current translator locale and indicate if the source locale file exists * * @param string $locale locale ex. en - * - * @return bool */ - public function setLocale($locale) + public function setLocale($locale): void { $locale = preg_replace_callback('/[-_]([a-z]{2,}|\d{2,})/', function ($matches) { // _2-letters or YUE is a region, _3+-letters is a variant $upper = strtoupper($matches[1]); - if ($upper === 'YUE' || $upper === 'ISO' || \strlen($upper) < 3) { + if ($upper === 'YUE' || $upper === 'ISO' || \strlen($upper) <= static::REGION_CODE_LENGTH) { return "_$upper"; } @@ -322,7 +316,7 @@ abstract class AbstractTranslator extends Translation\Translator $previousLocale = $this->getLocale(); if ($previousLocale === $locale && isset($this->messages[$locale])) { - return true; + return; } unset(static::$singletons[$previousLocale]); @@ -334,13 +328,12 @@ abstract class AbstractTranslator extends Translation\Translator $completeLocaleChunks = preg_split('/[_.-]+/', $completeLocale); - $getScore = function ($language) use ($completeLocaleChunks) { - return self::compareChunkLists($completeLocaleChunks, preg_split('/[_.-]+/', $language)); - }; + $getScore = static fn ($language) => self::compareChunkLists( + $completeLocaleChunks, + preg_split('/[_.-]+/', $language), + ); - usort($locales, function ($first, $second) use ($getScore) { - return $getScore($second) <=> $getScore($first); - }); + usort($locales, static fn ($first, $second) => $getScore($second) <=> $getScore($first)); $locale = $locales[0]; } @@ -357,12 +350,10 @@ abstract class AbstractTranslator extends Translation\Translator } if (!$this->loadMessagesFromFile($locale) && !$this->initializing) { - return false; + return; } parent::setLocale($locale); - - return true; } /** @@ -377,6 +368,28 @@ abstract class AbstractTranslator extends Translation\Translator ]; } + public function __serialize(): array + { + return [ + 'locale' => $this->getLocale(), + ]; + } + + public function __unserialize(array $data): void + { + $this->initialize($data['locale'] ?? 'en'); + } + + private function initialize($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false): void + { + parent::setLocale($locale); + $this->initializing = true; + $this->directories = [__DIR__.'/Lang']; + $this->addLoader('array', new ArrayLoader()); + parent::__construct($locale, new MessageFormatterMapper($formatter), $cacheDir, $debug); + $this->initializing = false; + } + private static function compareChunkLists($referenceChunks, $chunks) { $score = 0; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Callback.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Callback.php new file mode 100644 index 000000000..c7456f1eb --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Callback.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use Closure; +use DateInterval; +use DatePeriod; +use DateTime; +use DateTimeInterface; +use DateTimeZone; +use ReflectionFunction; +use ReflectionNamedType; +use ReflectionType; + +final class Callback +{ + private ?ReflectionFunction $function; + + private function __construct(private readonly Closure $closure) + { + } + + public static function fromClosure(Closure $closure): self + { + return new self($closure); + } + + public static function parameter(mixed $closure, mixed $value, string|int $index = 0): mixed + { + if ($closure instanceof Closure) { + return self::fromClosure($closure)->prepareParameter($value, $index); + } + + return $value; + } + + public function getReflectionFunction(): ReflectionFunction + { + return $this->function ??= new ReflectionFunction($this->closure); + } + + public function prepareParameter(mixed $value, string|int $index = 0): mixed + { + $type = $this->getParameterType($index); + + if (!($type instanceof ReflectionNamedType)) { + return $value; + } + + $name = $type->getName(); + + if ($name === CarbonInterface::class) { + $name = $value instanceof DateTime ? Carbon::class : CarbonImmutable::class; + } + + if (!class_exists($name) || is_a($value, $name)) { + return $value; + } + + $class = $this->getPromotedClass($value); + + if ($class && is_a($name, $class, true)) { + return $name::instance($value); + } + + return $value; + } + + public function call(mixed ...$arguments): mixed + { + foreach ($arguments as $index => &$value) { + if ($this->getPromotedClass($value)) { + $value = $this->prepareParameter($value, $index); + } + } + + return ($this->closure)(...$arguments); + } + + private function getParameterType(string|int $index): ?ReflectionType + { + $parameters = $this->getReflectionFunction()->getParameters(); + + if (\is_int($index)) { + return ($parameters[$index] ?? null)?->getType(); + } + + foreach ($parameters as $parameter) { + if ($parameter->getName() === $index) { + return $parameter->getType(); + } + } + + return null; + } + + /** @return class-string|null */ + private function getPromotedClass(mixed $value): ?string + { + if ($value instanceof DateTimeInterface) { + return CarbonInterface::class; + } + + if ($value instanceof DateInterval) { + return CarbonInterval::class; + } + + if ($value instanceof DatePeriod) { + return CarbonPeriod::class; + } + + if ($value instanceof DateTimeZone) { + return CarbonTimeZone::class; + } + + return null; + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Carbon.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Carbon.php index e32569ae3..8364e8412 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Carbon.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Carbon.php @@ -1,5 +1,7 @@ * - * @property int $year - * @property int $yearIso - * @property int $month - * @property int $day - * @property int $hour - * @property int $minute - * @property int $second - * @property int $micro - * @property int $microsecond - * @property int|float|string $timestamp seconds since the Unix Epoch - * @property string $englishDayOfWeek the day of week in English - * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the month in English - * @property string $shortEnglishMonth the abbreviated month in English - * @property int $milliseconds - * @property int $millisecond - * @property int $milli - * @property int $week 1 through 53 - * @property int $isoWeek 1 through 53 - * @property int $weekYear year according to week format - * @property int $isoWeekYear year according to ISO week format - * @property int $dayOfYear 1 through 366 - * @property int $age does a diffInYears() with default parameters - * @property int $offset the timezone offset in seconds from UTC - * @property int $offsetMinutes the timezone offset in minutes from UTC - * @property int $offsetHours the timezone offset in hours from UTC - * @property CarbonTimeZone $timezone the current timezone - * @property CarbonTimeZone $tz alias of $timezone - * @property-read int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) - * @property-read int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month - * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) - * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) - * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name - * @property-read string $tzAbbrName alias of $timezoneAbbreviatedName - * @property-read string $dayName long name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $shortDayName short name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $minDayName very short name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $monthName long name of month translated according to Carbon locale, in english if no translation available for current language - * @property-read string $shortMonthName short name of month translated according to Carbon locale, in english if no translation available for current language - * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language - * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language - * @property-read int $noZeroHour current hour from 1 to 24 - * @property-read int $weeksInYear 51 through 53 - * @property-read int $isoWeeksInYear 51 through 53 - * @property-read int $weekOfMonth 1 through 5 - * @property-read int $weekNumberInMonth 1 through 5 - * @property-read int $firstWeekDay 0 through 6 - * @property-read int $lastWeekDay 0 through 6 - * @property-read int $daysInYear 365 or 366 - * @property-read int $quarter the quarter of this instance, 1 - 4 - * @property-read int $decade the decade of this instance - * @property-read int $century the century of this instance - * @property-read int $millennium the millennium of this instance - * @property-read bool $dst daylight savings time indicator, true if DST, false otherwise - * @property-read bool $local checks if the timezone is local, true if local, false otherwise - * @property-read bool $utc checks if the timezone is UTC, true if UTC, false otherwise - * @property-read string $timezoneName the current timezone name - * @property-read string $tzName alias of $timezoneName - * @property-read string $locale locale of the current instance + * @property string $localeDayOfWeek the day of week in current locale + * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale + * @property string $localeMonth the month in current locale + * @property string $shortLocaleMonth the abbreviated month in current locale + * @property int $year + * @property int $yearIso + * @property int $month + * @property int $day + * @property int $hour + * @property int $minute + * @property int $second + * @property int $micro + * @property int $microsecond + * @property int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) + * @property int|float|string $timestamp seconds since the Unix Epoch + * @property string $englishDayOfWeek the day of week in English + * @property string $shortEnglishDayOfWeek the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English + * @property int $milliseconds + * @property int $millisecond + * @property int $milli + * @property int $week 1 through 53 + * @property int $isoWeek 1 through 53 + * @property int $weekYear year according to week format + * @property int $isoWeekYear year according to ISO week format + * @property int $age does a diffInYears() with default parameters + * @property int $offset the timezone offset in seconds from UTC + * @property int $offsetMinutes the timezone offset in minutes from UTC + * @property int $offsetHours the timezone offset in hours from UTC + * @property CarbonTimeZone $timezone the current timezone + * @property CarbonTimeZone $tz alias of $timezone + * @property int $centuryOfMillennium The value of the century starting from the beginning of the current millennium + * @property int $dayOfCentury The value of the day starting from the beginning of the current century + * @property int $dayOfDecade The value of the day starting from the beginning of the current decade + * @property int $dayOfMillennium The value of the day starting from the beginning of the current millennium + * @property int $dayOfMonth The value of the day starting from the beginning of the current month + * @property int $dayOfQuarter The value of the day starting from the beginning of the current quarter + * @property int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) + * @property int $dayOfYear 1 through 366 + * @property int $decadeOfCentury The value of the decade starting from the beginning of the current century + * @property int $decadeOfMillennium The value of the decade starting from the beginning of the current millennium + * @property int $hourOfCentury The value of the hour starting from the beginning of the current century + * @property int $hourOfDay The value of the hour starting from the beginning of the current day + * @property int $hourOfDecade The value of the hour starting from the beginning of the current decade + * @property int $hourOfMillennium The value of the hour starting from the beginning of the current millennium + * @property int $hourOfMonth The value of the hour starting from the beginning of the current month + * @property int $hourOfQuarter The value of the hour starting from the beginning of the current quarter + * @property int $hourOfWeek The value of the hour starting from the beginning of the current week + * @property int $hourOfYear The value of the hour starting from the beginning of the current year + * @property int $microsecondOfCentury The value of the microsecond starting from the beginning of the current century + * @property int $microsecondOfDay The value of the microsecond starting from the beginning of the current day + * @property int $microsecondOfDecade The value of the microsecond starting from the beginning of the current decade + * @property int $microsecondOfHour The value of the microsecond starting from the beginning of the current hour + * @property int $microsecondOfMillennium The value of the microsecond starting from the beginning of the current millennium + * @property int $microsecondOfMillisecond The value of the microsecond starting from the beginning of the current millisecond + * @property int $microsecondOfMinute The value of the microsecond starting from the beginning of the current minute + * @property int $microsecondOfMonth The value of the microsecond starting from the beginning of the current month + * @property int $microsecondOfQuarter The value of the microsecond starting from the beginning of the current quarter + * @property int $microsecondOfSecond The value of the microsecond starting from the beginning of the current second + * @property int $microsecondOfWeek The value of the microsecond starting from the beginning of the current week + * @property int $microsecondOfYear The value of the microsecond starting from the beginning of the current year + * @property int $millisecondOfCentury The value of the millisecond starting from the beginning of the current century + * @property int $millisecondOfDay The value of the millisecond starting from the beginning of the current day + * @property int $millisecondOfDecade The value of the millisecond starting from the beginning of the current decade + * @property int $millisecondOfHour The value of the millisecond starting from the beginning of the current hour + * @property int $millisecondOfMillennium The value of the millisecond starting from the beginning of the current millennium + * @property int $millisecondOfMinute The value of the millisecond starting from the beginning of the current minute + * @property int $millisecondOfMonth The value of the millisecond starting from the beginning of the current month + * @property int $millisecondOfQuarter The value of the millisecond starting from the beginning of the current quarter + * @property int $millisecondOfSecond The value of the millisecond starting from the beginning of the current second + * @property int $millisecondOfWeek The value of the millisecond starting from the beginning of the current week + * @property int $millisecondOfYear The value of the millisecond starting from the beginning of the current year + * @property int $minuteOfCentury The value of the minute starting from the beginning of the current century + * @property int $minuteOfDay The value of the minute starting from the beginning of the current day + * @property int $minuteOfDecade The value of the minute starting from the beginning of the current decade + * @property int $minuteOfHour The value of the minute starting from the beginning of the current hour + * @property int $minuteOfMillennium The value of the minute starting from the beginning of the current millennium + * @property int $minuteOfMonth The value of the minute starting from the beginning of the current month + * @property int $minuteOfQuarter The value of the minute starting from the beginning of the current quarter + * @property int $minuteOfWeek The value of the minute starting from the beginning of the current week + * @property int $minuteOfYear The value of the minute starting from the beginning of the current year + * @property int $monthOfCentury The value of the month starting from the beginning of the current century + * @property int $monthOfDecade The value of the month starting from the beginning of the current decade + * @property int $monthOfMillennium The value of the month starting from the beginning of the current millennium + * @property int $monthOfQuarter The value of the month starting from the beginning of the current quarter + * @property int $monthOfYear The value of the month starting from the beginning of the current year + * @property int $quarterOfCentury The value of the quarter starting from the beginning of the current century + * @property int $quarterOfDecade The value of the quarter starting from the beginning of the current decade + * @property int $quarterOfMillennium The value of the quarter starting from the beginning of the current millennium + * @property int $quarterOfYear The value of the quarter starting from the beginning of the current year + * @property int $secondOfCentury The value of the second starting from the beginning of the current century + * @property int $secondOfDay The value of the second starting from the beginning of the current day + * @property int $secondOfDecade The value of the second starting from the beginning of the current decade + * @property int $secondOfHour The value of the second starting from the beginning of the current hour + * @property int $secondOfMillennium The value of the second starting from the beginning of the current millennium + * @property int $secondOfMinute The value of the second starting from the beginning of the current minute + * @property int $secondOfMonth The value of the second starting from the beginning of the current month + * @property int $secondOfQuarter The value of the second starting from the beginning of the current quarter + * @property int $secondOfWeek The value of the second starting from the beginning of the current week + * @property int $secondOfYear The value of the second starting from the beginning of the current year + * @property int $weekOfCentury The value of the week starting from the beginning of the current century + * @property int $weekOfDecade The value of the week starting from the beginning of the current decade + * @property int $weekOfMillennium The value of the week starting from the beginning of the current millennium + * @property int $weekOfMonth 1 through 5 + * @property int $weekOfQuarter The value of the week starting from the beginning of the current quarter + * @property int $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property int $yearOfCentury The value of the year starting from the beginning of the current century + * @property int $yearOfDecade The value of the year starting from the beginning of the current decade + * @property int $yearOfMillennium The value of the year starting from the beginning of the current millennium + * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) + * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) + * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name + * @property-read string $tzAbbrName alias of $timezoneAbbreviatedName + * @property-read string $dayName long name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $shortDayName short name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $minDayName very short name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $monthName long name of month translated according to Carbon locale, in english if no translation available for current language + * @property-read string $shortMonthName short name of month translated according to Carbon locale, in english if no translation available for current language + * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language + * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language + * @property-read int $noZeroHour current hour from 1 to 24 + * @property-read int $isoWeeksInYear 51 through 53 + * @property-read int $weekNumberInMonth 1 through 5 + * @property-read int $firstWeekDay 0 through 6 + * @property-read int $lastWeekDay 0 through 6 + * @property-read int $quarter the quarter of this instance, 1 - 4 + * @property-read int $decade the decade of this instance + * @property-read int $century the century of this instance + * @property-read int $millennium the millennium of this instance + * @property-read bool $dst daylight savings time indicator, true if DST, false otherwise + * @property-read bool $local checks if the timezone is local, true if local, false otherwise + * @property-read bool $utc checks if the timezone is UTC, true if UTC, false otherwise + * @property-read string $timezoneName the current timezone name + * @property-read string $tzName alias of $timezoneName + * @property-read string $locale locale of the current instance + * @property-read int $centuriesInMillennium The number of centuries contained in the current millennium + * @property-read int $daysInCentury The number of days contained in the current century + * @property-read int $daysInDecade The number of days contained in the current decade + * @property-read int $daysInMillennium The number of days contained in the current millennium + * @property-read int $daysInMonth number of days in the given month + * @property-read int $daysInQuarter The number of days contained in the current quarter + * @property-read int $daysInWeek The number of days contained in the current week + * @property-read int $daysInYear 365 or 366 + * @property-read int $decadesInCentury The number of decades contained in the current century + * @property-read int $decadesInMillennium The number of decades contained in the current millennium + * @property-read int $hoursInCentury The number of hours contained in the current century + * @property-read int $hoursInDay The number of hours contained in the current day + * @property-read int $hoursInDecade The number of hours contained in the current decade + * @property-read int $hoursInMillennium The number of hours contained in the current millennium + * @property-read int $hoursInMonth The number of hours contained in the current month + * @property-read int $hoursInQuarter The number of hours contained in the current quarter + * @property-read int $hoursInWeek The number of hours contained in the current week + * @property-read int $hoursInYear The number of hours contained in the current year + * @property-read int $microsecondsInCentury The number of microseconds contained in the current century + * @property-read int $microsecondsInDay The number of microseconds contained in the current day + * @property-read int $microsecondsInDecade The number of microseconds contained in the current decade + * @property-read int $microsecondsInHour The number of microseconds contained in the current hour + * @property-read int $microsecondsInMillennium The number of microseconds contained in the current millennium + * @property-read int $microsecondsInMillisecond The number of microseconds contained in the current millisecond + * @property-read int $microsecondsInMinute The number of microseconds contained in the current minute + * @property-read int $microsecondsInMonth The number of microseconds contained in the current month + * @property-read int $microsecondsInQuarter The number of microseconds contained in the current quarter + * @property-read int $microsecondsInSecond The number of microseconds contained in the current second + * @property-read int $microsecondsInWeek The number of microseconds contained in the current week + * @property-read int $microsecondsInYear The number of microseconds contained in the current year + * @property-read int $millisecondsInCentury The number of milliseconds contained in the current century + * @property-read int $millisecondsInDay The number of milliseconds contained in the current day + * @property-read int $millisecondsInDecade The number of milliseconds contained in the current decade + * @property-read int $millisecondsInHour The number of milliseconds contained in the current hour + * @property-read int $millisecondsInMillennium The number of milliseconds contained in the current millennium + * @property-read int $millisecondsInMinute The number of milliseconds contained in the current minute + * @property-read int $millisecondsInMonth The number of milliseconds contained in the current month + * @property-read int $millisecondsInQuarter The number of milliseconds contained in the current quarter + * @property-read int $millisecondsInSecond The number of milliseconds contained in the current second + * @property-read int $millisecondsInWeek The number of milliseconds contained in the current week + * @property-read int $millisecondsInYear The number of milliseconds contained in the current year + * @property-read int $minutesInCentury The number of minutes contained in the current century + * @property-read int $minutesInDay The number of minutes contained in the current day + * @property-read int $minutesInDecade The number of minutes contained in the current decade + * @property-read int $minutesInHour The number of minutes contained in the current hour + * @property-read int $minutesInMillennium The number of minutes contained in the current millennium + * @property-read int $minutesInMonth The number of minutes contained in the current month + * @property-read int $minutesInQuarter The number of minutes contained in the current quarter + * @property-read int $minutesInWeek The number of minutes contained in the current week + * @property-read int $minutesInYear The number of minutes contained in the current year + * @property-read int $monthsInCentury The number of months contained in the current century + * @property-read int $monthsInDecade The number of months contained in the current decade + * @property-read int $monthsInMillennium The number of months contained in the current millennium + * @property-read int $monthsInQuarter The number of months contained in the current quarter + * @property-read int $monthsInYear The number of months contained in the current year + * @property-read int $quartersInCentury The number of quarters contained in the current century + * @property-read int $quartersInDecade The number of quarters contained in the current decade + * @property-read int $quartersInMillennium The number of quarters contained in the current millennium + * @property-read int $quartersInYear The number of quarters contained in the current year + * @property-read int $secondsInCentury The number of seconds contained in the current century + * @property-read int $secondsInDay The number of seconds contained in the current day + * @property-read int $secondsInDecade The number of seconds contained in the current decade + * @property-read int $secondsInHour The number of seconds contained in the current hour + * @property-read int $secondsInMillennium The number of seconds contained in the current millennium + * @property-read int $secondsInMinute The number of seconds contained in the current minute + * @property-read int $secondsInMonth The number of seconds contained in the current month + * @property-read int $secondsInQuarter The number of seconds contained in the current quarter + * @property-read int $secondsInWeek The number of seconds contained in the current week + * @property-read int $secondsInYear The number of seconds contained in the current year + * @property-read int $weeksInCentury The number of weeks contained in the current century + * @property-read int $weeksInDecade The number of weeks contained in the current decade + * @property-read int $weeksInMillennium The number of weeks contained in the current millennium + * @property-read int $weeksInMonth The number of weeks contained in the current month + * @property-read int $weeksInQuarter The number of weeks contained in the current quarter + * @property-read int $weeksInYear 51 through 53 + * @property-read int $yearsInCentury The number of years contained in the current century + * @property-read int $yearsInDecade The number of years contained in the current decade + * @property-read int $yearsInMillennium The number of years contained in the current millennium * - * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) - * @method bool isLocal() Check if the current instance has non-UTC timezone. - * @method bool isValid() Check if the current instance is a valid date. - * @method bool isDST() Check if the current instance is in a daylight saving time. - * @method bool isSunday() Checks if the instance day is sunday. - * @method bool isMonday() Checks if the instance day is monday. - * @method bool isTuesday() Checks if the instance day is tuesday. - * @method bool isWednesday() Checks if the instance day is wednesday. - * @method bool isThursday() Checks if the instance day is thursday. - * @method bool isFriday() Checks if the instance day is friday. - * @method bool isSaturday() Checks if the instance day is saturday. - * @method bool isSameYear(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. - * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. - * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. - * @method bool isSameWeek(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. - * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. - * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. - * @method bool isSameDay(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. - * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. - * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. - * @method bool isSameHour(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. - * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. - * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. - * @method bool isSameMinute(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. - * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. - * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. - * @method bool isSameSecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. - * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. - * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. - * @method bool isSameMicro(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. - * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. - * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. - * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. - * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. - * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. - * @method bool isSameDecade(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. - * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. - * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. - * @method bool isSameCentury(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. - * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. - * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. - * @method bool isSameMillennium(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. - * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. - * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. - * @method $this years(int $value) Set current instance year to the given value. - * @method $this year(int $value) Set current instance year to the given value. - * @method $this setYears(int $value) Set current instance year to the given value. - * @method $this setYear(int $value) Set current instance year to the given value. - * @method $this months(int $value) Set current instance month to the given value. - * @method $this month(int $value) Set current instance month to the given value. - * @method $this setMonths(int $value) Set current instance month to the given value. - * @method $this setMonth(int $value) Set current instance month to the given value. - * @method $this days(int $value) Set current instance day to the given value. - * @method $this day(int $value) Set current instance day to the given value. - * @method $this setDays(int $value) Set current instance day to the given value. - * @method $this setDay(int $value) Set current instance day to the given value. - * @method $this hours(int $value) Set current instance hour to the given value. - * @method $this hour(int $value) Set current instance hour to the given value. - * @method $this setHours(int $value) Set current instance hour to the given value. - * @method $this setHour(int $value) Set current instance hour to the given value. - * @method $this minutes(int $value) Set current instance minute to the given value. - * @method $this minute(int $value) Set current instance minute to the given value. - * @method $this setMinutes(int $value) Set current instance minute to the given value. - * @method $this setMinute(int $value) Set current instance minute to the given value. - * @method $this seconds(int $value) Set current instance second to the given value. - * @method $this second(int $value) Set current instance second to the given value. - * @method $this setSeconds(int $value) Set current instance second to the given value. - * @method $this setSecond(int $value) Set current instance second to the given value. - * @method $this millis(int $value) Set current instance millisecond to the given value. - * @method $this milli(int $value) Set current instance millisecond to the given value. - * @method $this setMillis(int $value) Set current instance millisecond to the given value. - * @method $this setMilli(int $value) Set current instance millisecond to the given value. - * @method $this milliseconds(int $value) Set current instance millisecond to the given value. - * @method $this millisecond(int $value) Set current instance millisecond to the given value. - * @method $this setMilliseconds(int $value) Set current instance millisecond to the given value. - * @method $this setMillisecond(int $value) Set current instance millisecond to the given value. - * @method $this micros(int $value) Set current instance microsecond to the given value. - * @method $this micro(int $value) Set current instance microsecond to the given value. - * @method $this setMicros(int $value) Set current instance microsecond to the given value. - * @method $this setMicro(int $value) Set current instance microsecond to the given value. - * @method $this microseconds(int $value) Set current instance microsecond to the given value. - * @method $this microsecond(int $value) Set current instance microsecond to the given value. - * @method $this setMicroseconds(int $value) Set current instance microsecond to the given value. - * @method $this setMicrosecond(int $value) Set current instance microsecond to the given value. - * @method $this addYears(int $value = 1) Add years (the $value count passed in) to the instance (using date interval). - * @method $this addYear() Add one year to the instance (using date interval). - * @method $this subYears(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval). - * @method $this subYear() Sub one year to the instance (using date interval). - * @method $this addYearsWithOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. - * @method $this subYearsWithOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. - * @method $this addYearsWithoutOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearsWithoutOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addYearsWithNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearsWithNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addYearsNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearsNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonths(int $value = 1) Add months (the $value count passed in) to the instance (using date interval). - * @method $this addMonth() Add one month to the instance (using date interval). - * @method $this subMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval). - * @method $this subMonth() Sub one month to the instance (using date interval). - * @method $this addMonthsWithOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. - * @method $this subMonthsWithOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. - * @method $this addMonthsWithoutOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthsWithoutOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonthsWithNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthsWithNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonthsNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthsNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDays(int $value = 1) Add days (the $value count passed in) to the instance (using date interval). - * @method $this addDay() Add one day to the instance (using date interval). - * @method $this subDays(int $value = 1) Sub days (the $value count passed in) to the instance (using date interval). - * @method $this subDay() Sub one day to the instance (using date interval). - * @method $this addHours(int $value = 1) Add hours (the $value count passed in) to the instance (using date interval). - * @method $this addHour() Add one hour to the instance (using date interval). - * @method $this subHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). - * @method $this subHour() Sub one hour to the instance (using date interval). - * @method $this addMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). - * @method $this addMinute() Add one minute to the instance (using date interval). - * @method $this subMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). - * @method $this subMinute() Sub one minute to the instance (using date interval). - * @method $this addSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). - * @method $this addSecond() Add one second to the instance (using date interval). - * @method $this subSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). - * @method $this subSecond() Sub one second to the instance (using date interval). - * @method $this addMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). - * @method $this addMilli() Add one millisecond to the instance (using date interval). - * @method $this subMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). - * @method $this subMilli() Sub one millisecond to the instance (using date interval). - * @method $this addMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). - * @method $this addMillisecond() Add one millisecond to the instance (using date interval). - * @method $this subMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). - * @method $this subMillisecond() Sub one millisecond to the instance (using date interval). - * @method $this addMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). - * @method $this addMicro() Add one microsecond to the instance (using date interval). - * @method $this subMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). - * @method $this subMicro() Sub one microsecond to the instance (using date interval). - * @method $this addMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). - * @method $this addMicrosecond() Add one microsecond to the instance (using date interval). - * @method $this subMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). - * @method $this subMicrosecond() Sub one microsecond to the instance (using date interval). - * @method $this addMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). - * @method $this addMillennium() Add one millennium to the instance (using date interval). - * @method $this subMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). - * @method $this subMillennium() Sub one millennium to the instance (using date interval). - * @method $this addMillenniaWithOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method $this subMillenniaWithOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method $this addMillenniaWithoutOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniaWithoutOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMillenniaWithNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniaWithNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMillenniaNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniaNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). - * @method $this addCentury() Add one century to the instance (using date interval). - * @method $this subCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). - * @method $this subCentury() Sub one century to the instance (using date interval). - * @method $this addCenturiesWithOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. - * @method $this subCenturiesWithOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. - * @method $this addCenturiesWithoutOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturiesWithoutOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturiesWithNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturiesWithNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturiesNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturiesNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval). - * @method $this addDecade() Add one decade to the instance (using date interval). - * @method $this subDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). - * @method $this subDecade() Sub one decade to the instance (using date interval). - * @method $this addDecadesWithOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. - * @method $this subDecadesWithOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. - * @method $this addDecadesWithoutOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadesWithoutOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecadesWithNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadesWithNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecadesNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadesNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). - * @method $this addQuarter() Add one quarter to the instance (using date interval). - * @method $this subQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). - * @method $this subQuarter() Sub one quarter to the instance (using date interval). - * @method $this addQuartersWithOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method $this subQuartersWithOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method $this subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method $this addQuartersWithoutOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuartersWithoutOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuartersWithNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuartersWithNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuartersNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuartersNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method $this subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method $this addWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). - * @method $this addWeek() Add one week to the instance (using date interval). - * @method $this subWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). - * @method $this subWeek() Sub one week to the instance (using date interval). - * @method $this addWeekdays(int $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). - * @method $this addWeekday() Add one weekday to the instance (using date interval). - * @method $this subWeekdays(int $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). - * @method $this subWeekday() Sub one weekday to the instance (using date interval). - * @method $this addRealMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMicro() Add one microsecond to the instance (using timestamp). - * @method $this subRealMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMicro() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method $this addRealMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMicrosecond() Add one microsecond to the instance (using timestamp). - * @method $this subRealMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMicrosecond() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method $this addRealMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMilli() Add one millisecond to the instance (using timestamp). - * @method $this subRealMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMilli() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method $this addRealMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMillisecond() Add one millisecond to the instance (using timestamp). - * @method $this subRealMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMillisecond() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method $this addRealSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). - * @method $this addRealSecond() Add one second to the instance (using timestamp). - * @method $this subRealSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). - * @method $this subRealSecond() Sub one second to the instance (using timestamp). - * @method CarbonPeriod secondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. - * @method $this addRealMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMinute() Add one minute to the instance (using timestamp). - * @method $this subRealMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMinute() Sub one minute to the instance (using timestamp). - * @method CarbonPeriod minutesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. - * @method $this addRealHours(int $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). - * @method $this addRealHour() Add one hour to the instance (using timestamp). - * @method $this subRealHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). - * @method $this subRealHour() Sub one hour to the instance (using timestamp). - * @method CarbonPeriod hoursUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. - * @method $this addRealDays(int $value = 1) Add days (the $value count passed in) to the instance (using timestamp). - * @method $this addRealDay() Add one day to the instance (using timestamp). - * @method $this subRealDays(int $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). - * @method $this subRealDay() Sub one day to the instance (using timestamp). - * @method CarbonPeriod daysUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. - * @method $this addRealWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). - * @method $this addRealWeek() Add one week to the instance (using timestamp). - * @method $this subRealWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). - * @method $this subRealWeek() Sub one week to the instance (using timestamp). - * @method CarbonPeriod weeksUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. - * @method $this addRealMonths(int $value = 1) Add months (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMonth() Add one month to the instance (using timestamp). - * @method $this subRealMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMonth() Sub one month to the instance (using timestamp). - * @method CarbonPeriod monthsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. - * @method $this addRealQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). - * @method $this addRealQuarter() Add one quarter to the instance (using timestamp). - * @method $this subRealQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). - * @method $this subRealQuarter() Sub one quarter to the instance (using timestamp). - * @method CarbonPeriod quartersUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. - * @method $this addRealYears(int $value = 1) Add years (the $value count passed in) to the instance (using timestamp). - * @method $this addRealYear() Add one year to the instance (using timestamp). - * @method $this subRealYears(int $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). - * @method $this subRealYear() Sub one year to the instance (using timestamp). - * @method CarbonPeriod yearsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. - * @method $this addRealDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). - * @method $this addRealDecade() Add one decade to the instance (using timestamp). - * @method $this subRealDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). - * @method $this subRealDecade() Sub one decade to the instance (using timestamp). - * @method CarbonPeriod decadesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. - * @method $this addRealCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). - * @method $this addRealCentury() Add one century to the instance (using timestamp). - * @method $this subRealCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). - * @method $this subRealCentury() Sub one century to the instance (using timestamp). - * @method CarbonPeriod centuriesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. - * @method $this addRealMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). - * @method $this addRealMillennium() Add one millennium to the instance (using timestamp). - * @method $this subRealMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). - * @method $this subRealMillennium() Sub one millennium to the instance (using timestamp). - * @method CarbonPeriod millenniaUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. - * @method $this roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. - * @method $this roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. - * @method $this floorYear(float $precision = 1) Truncate the current instance year with given precision. - * @method $this floorYears(float $precision = 1) Truncate the current instance year with given precision. - * @method $this ceilYear(float $precision = 1) Ceil the current instance year with given precision. - * @method $this ceilYears(float $precision = 1) Ceil the current instance year with given precision. - * @method $this roundMonth(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. - * @method $this roundMonths(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. - * @method $this floorMonth(float $precision = 1) Truncate the current instance month with given precision. - * @method $this floorMonths(float $precision = 1) Truncate the current instance month with given precision. - * @method $this ceilMonth(float $precision = 1) Ceil the current instance month with given precision. - * @method $this ceilMonths(float $precision = 1) Ceil the current instance month with given precision. - * @method $this roundDay(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. - * @method $this roundDays(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. - * @method $this floorDay(float $precision = 1) Truncate the current instance day with given precision. - * @method $this floorDays(float $precision = 1) Truncate the current instance day with given precision. - * @method $this ceilDay(float $precision = 1) Ceil the current instance day with given precision. - * @method $this ceilDays(float $precision = 1) Ceil the current instance day with given precision. - * @method $this roundHour(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. - * @method $this roundHours(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. - * @method $this floorHour(float $precision = 1) Truncate the current instance hour with given precision. - * @method $this floorHours(float $precision = 1) Truncate the current instance hour with given precision. - * @method $this ceilHour(float $precision = 1) Ceil the current instance hour with given precision. - * @method $this ceilHours(float $precision = 1) Ceil the current instance hour with given precision. - * @method $this roundMinute(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. - * @method $this roundMinutes(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. - * @method $this floorMinute(float $precision = 1) Truncate the current instance minute with given precision. - * @method $this floorMinutes(float $precision = 1) Truncate the current instance minute with given precision. - * @method $this ceilMinute(float $precision = 1) Ceil the current instance minute with given precision. - * @method $this ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision. - * @method $this roundSecond(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. - * @method $this roundSeconds(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. - * @method $this floorSecond(float $precision = 1) Truncate the current instance second with given precision. - * @method $this floorSeconds(float $precision = 1) Truncate the current instance second with given precision. - * @method $this ceilSecond(float $precision = 1) Ceil the current instance second with given precision. - * @method $this ceilSeconds(float $precision = 1) Ceil the current instance second with given precision. - * @method $this roundMillennium(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. - * @method $this roundMillennia(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. - * @method $this floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision. - * @method $this floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision. - * @method $this ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision. - * @method $this ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision. - * @method $this roundCentury(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. - * @method $this roundCenturies(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. - * @method $this floorCentury(float $precision = 1) Truncate the current instance century with given precision. - * @method $this floorCenturies(float $precision = 1) Truncate the current instance century with given precision. - * @method $this ceilCentury(float $precision = 1) Ceil the current instance century with given precision. - * @method $this ceilCenturies(float $precision = 1) Ceil the current instance century with given precision. - * @method $this roundDecade(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. - * @method $this roundDecades(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. - * @method $this floorDecade(float $precision = 1) Truncate the current instance decade with given precision. - * @method $this floorDecades(float $precision = 1) Truncate the current instance decade with given precision. - * @method $this ceilDecade(float $precision = 1) Ceil the current instance decade with given precision. - * @method $this ceilDecades(float $precision = 1) Ceil the current instance decade with given precision. - * @method $this roundQuarter(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. - * @method $this roundQuarters(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. - * @method $this floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision. - * @method $this floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision. - * @method $this ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision. - * @method $this ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision. - * @method $this roundMillisecond(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. - * @method $this roundMilliseconds(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. - * @method $this floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision. - * @method $this floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision. - * @method $this ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision. - * @method $this ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision. - * @method $this roundMicrosecond(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. - * @method $this roundMicroseconds(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. - * @method $this floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision. - * @method $this floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision. - * @method $this ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision. - * @method $this ceilMicroseconds(float $precision = 1) Ceil the current instance microsecond with given precision. - * @method string shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method static static|false createFromFormat(string $format, string $time, DateTimeZone|string|false|null $timezone = null) Parse a string into a new Carbon object according to the specified format. - * @method static static __set_state(array $array) https://php.net/manual/en/datetime.set-state.php + * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) + * @method bool isLocal() Check if the current instance has non-UTC timezone. + * @method bool isValid() Check if the current instance is a valid date. + * @method bool isDST() Check if the current instance is in a daylight saving time. + * @method bool isSunday() Checks if the instance day is sunday. + * @method bool isMonday() Checks if the instance day is monday. + * @method bool isTuesday() Checks if the instance day is tuesday. + * @method bool isWednesday() Checks if the instance day is wednesday. + * @method bool isThursday() Checks if the instance day is thursday. + * @method bool isFriday() Checks if the instance day is friday. + * @method bool isSaturday() Checks if the instance day is saturday. + * @method bool isSameYear(DateTimeInterface|string $date) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. + * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. + * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. + * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. + * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. + * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. + * @method bool isSameWeek(DateTimeInterface|string $date) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. + * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. + * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. + * @method bool isSameDay(DateTimeInterface|string $date) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. + * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. + * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. + * @method bool isSameHour(DateTimeInterface|string $date) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. + * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. + * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. + * @method bool isSameMinute(DateTimeInterface|string $date) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. + * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. + * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. + * @method bool isSameSecond(DateTimeInterface|string $date) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. + * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. + * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. + * @method bool isSameMilli(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMilli() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMilli() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMilli() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMillisecond(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillisecond() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMillisecond() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMillisecond() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMicro(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameMicrosecond(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameDecade(DateTimeInterface|string $date) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. + * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. + * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. + * @method bool isSameCentury(DateTimeInterface|string $date) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. + * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. + * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. + * @method bool isSameMillennium(DateTimeInterface|string $date) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. + * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. + * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. + * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. + * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. + * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. + * @method $this years(int $value) Set current instance year to the given value. + * @method $this year(int $value) Set current instance year to the given value. + * @method $this setYears(int $value) Set current instance year to the given value. + * @method $this setYear(int $value) Set current instance year to the given value. + * @method $this months(Month|int $value) Set current instance month to the given value. + * @method $this month(Month|int $value) Set current instance month to the given value. + * @method $this setMonths(Month|int $value) Set current instance month to the given value. + * @method $this setMonth(Month|int $value) Set current instance month to the given value. + * @method $this days(int $value) Set current instance day to the given value. + * @method $this day(int $value) Set current instance day to the given value. + * @method $this setDays(int $value) Set current instance day to the given value. + * @method $this setDay(int $value) Set current instance day to the given value. + * @method $this hours(int $value) Set current instance hour to the given value. + * @method $this hour(int $value) Set current instance hour to the given value. + * @method $this setHours(int $value) Set current instance hour to the given value. + * @method $this setHour(int $value) Set current instance hour to the given value. + * @method $this minutes(int $value) Set current instance minute to the given value. + * @method $this minute(int $value) Set current instance minute to the given value. + * @method $this setMinutes(int $value) Set current instance minute to the given value. + * @method $this setMinute(int $value) Set current instance minute to the given value. + * @method $this seconds(int $value) Set current instance second to the given value. + * @method $this second(int $value) Set current instance second to the given value. + * @method $this setSeconds(int $value) Set current instance second to the given value. + * @method $this setSecond(int $value) Set current instance second to the given value. + * @method $this millis(int $value) Set current instance millisecond to the given value. + * @method $this milli(int $value) Set current instance millisecond to the given value. + * @method $this setMillis(int $value) Set current instance millisecond to the given value. + * @method $this setMilli(int $value) Set current instance millisecond to the given value. + * @method $this milliseconds(int $value) Set current instance millisecond to the given value. + * @method $this millisecond(int $value) Set current instance millisecond to the given value. + * @method $this setMilliseconds(int $value) Set current instance millisecond to the given value. + * @method $this setMillisecond(int $value) Set current instance millisecond to the given value. + * @method $this micros(int $value) Set current instance microsecond to the given value. + * @method $this micro(int $value) Set current instance microsecond to the given value. + * @method $this setMicros(int $value) Set current instance microsecond to the given value. + * @method $this setMicro(int $value) Set current instance microsecond to the given value. + * @method $this microseconds(int $value) Set current instance microsecond to the given value. + * @method $this microsecond(int $value) Set current instance microsecond to the given value. + * @method $this setMicroseconds(int $value) Set current instance microsecond to the given value. + * @method $this setMicrosecond(int $value) Set current instance microsecond to the given value. + * @method $this addYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval). + * @method $this addYear() Add one year to the instance (using date interval). + * @method $this subYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval). + * @method $this subYear() Sub one year to the instance (using date interval). + * @method $this addYearsWithOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. + * @method $this subYearsWithOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. + * @method $this addYearsWithoutOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearsWithoutOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addYearsWithNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearsWithNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addYearsNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearsNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval). + * @method $this addMonth() Add one month to the instance (using date interval). + * @method $this subMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval). + * @method $this subMonth() Sub one month to the instance (using date interval). + * @method $this addMonthsWithOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. + * @method $this subMonthsWithOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. + * @method $this addMonthsWithoutOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthsWithoutOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonthsWithNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthsWithNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonthsNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthsNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval). + * @method $this addDay() Add one day to the instance (using date interval). + * @method $this subDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using date interval). + * @method $this subDay() Sub one day to the instance (using date interval). + * @method $this addHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using date interval). + * @method $this addHour() Add one hour to the instance (using date interval). + * @method $this subHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). + * @method $this subHour() Sub one hour to the instance (using date interval). + * @method $this addMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). + * @method $this addMinute() Add one minute to the instance (using date interval). + * @method $this subMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). + * @method $this subMinute() Sub one minute to the instance (using date interval). + * @method $this addSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). + * @method $this addSecond() Add one second to the instance (using date interval). + * @method $this subSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). + * @method $this subSecond() Sub one second to the instance (using date interval). + * @method $this addMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method $this addMilli() Add one millisecond to the instance (using date interval). + * @method $this subMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method $this subMilli() Sub one millisecond to the instance (using date interval). + * @method $this addMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method $this addMillisecond() Add one millisecond to the instance (using date interval). + * @method $this subMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method $this subMillisecond() Sub one millisecond to the instance (using date interval). + * @method $this addMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method $this addMicro() Add one microsecond to the instance (using date interval). + * @method $this subMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method $this subMicro() Sub one microsecond to the instance (using date interval). + * @method $this addMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method $this addMicrosecond() Add one microsecond to the instance (using date interval). + * @method $this subMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method $this subMicrosecond() Sub one microsecond to the instance (using date interval). + * @method $this addMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). + * @method $this addMillennium() Add one millennium to the instance (using date interval). + * @method $this subMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). + * @method $this subMillennium() Sub one millennium to the instance (using date interval). + * @method $this addMillenniaWithOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method $this subMillenniaWithOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method $this addMillenniaWithoutOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniaWithoutOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMillenniaWithNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniaWithNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMillenniaNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniaNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). + * @method $this addCentury() Add one century to the instance (using date interval). + * @method $this subCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). + * @method $this subCentury() Sub one century to the instance (using date interval). + * @method $this addCenturiesWithOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. + * @method $this subCenturiesWithOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. + * @method $this addCenturiesWithoutOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturiesWithoutOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturiesWithNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturiesWithNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturiesNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturiesNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval). + * @method $this addDecade() Add one decade to the instance (using date interval). + * @method $this subDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). + * @method $this subDecade() Sub one decade to the instance (using date interval). + * @method $this addDecadesWithOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. + * @method $this subDecadesWithOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. + * @method $this addDecadesWithoutOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadesWithoutOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecadesWithNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadesWithNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecadesNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadesNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). + * @method $this addQuarter() Add one quarter to the instance (using date interval). + * @method $this subQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). + * @method $this subQuarter() Sub one quarter to the instance (using date interval). + * @method $this addQuartersWithOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method $this subQuartersWithOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method $this subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method $this addQuartersWithoutOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuartersWithoutOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuartersWithNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuartersWithNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuartersNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuartersNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method $this subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method $this addWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). + * @method $this addWeek() Add one week to the instance (using date interval). + * @method $this subWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). + * @method $this subWeek() Sub one week to the instance (using date interval). + * @method $this addWeekdays(int|float $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). + * @method $this addWeekday() Add one weekday to the instance (using date interval). + * @method $this subWeekdays(int|float $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). + * @method $this subWeekday() Sub one weekday to the instance (using date interval). + * @method $this addUTCMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMicro() Add one microsecond to the instance (using timestamp). + * @method $this subUTCMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMicro() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicros(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method $this addUTCMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMicrosecond() Add one microsecond to the instance (using timestamp). + * @method $this subUTCMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMicrosecond() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicroseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method $this addUTCMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMilli() Add one millisecond to the instance (using timestamp). + * @method $this subUTCMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMilli() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMillis(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method $this addUTCMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMillisecond() Add one millisecond to the instance (using timestamp). + * @method $this subUTCMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMillisecond() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMilliseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method $this addUTCSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCSecond() Add one second to the instance (using timestamp). + * @method $this subUTCSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCSecond() Sub one second to the instance (using timestamp). + * @method CarbonPeriod secondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. + * @method float diffInUTCSeconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of seconds. + * @method $this addUTCMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMinute() Add one minute to the instance (using timestamp). + * @method $this subUTCMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMinute() Sub one minute to the instance (using timestamp). + * @method CarbonPeriod minutesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. + * @method float diffInUTCMinutes(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of minutes. + * @method $this addUTCHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCHour() Add one hour to the instance (using timestamp). + * @method $this subUTCHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCHour() Sub one hour to the instance (using timestamp). + * @method CarbonPeriod hoursUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. + * @method float diffInUTCHours(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of hours. + * @method $this addUTCDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCDay() Add one day to the instance (using timestamp). + * @method $this subUTCDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCDay() Sub one day to the instance (using timestamp). + * @method CarbonPeriod daysUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. + * @method float diffInUTCDays(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of days. + * @method $this addUTCWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCWeek() Add one week to the instance (using timestamp). + * @method $this subUTCWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCWeek() Sub one week to the instance (using timestamp). + * @method CarbonPeriod weeksUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. + * @method float diffInUTCWeeks(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of weeks. + * @method $this addUTCMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMonth() Add one month to the instance (using timestamp). + * @method $this subUTCMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMonth() Sub one month to the instance (using timestamp). + * @method CarbonPeriod monthsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. + * @method float diffInUTCMonths(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of months. + * @method $this addUTCQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCQuarter() Add one quarter to the instance (using timestamp). + * @method $this subUTCQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCQuarter() Sub one quarter to the instance (using timestamp). + * @method CarbonPeriod quartersUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. + * @method float diffInUTCQuarters(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of quarters. + * @method $this addUTCYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCYear() Add one year to the instance (using timestamp). + * @method $this subUTCYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCYear() Sub one year to the instance (using timestamp). + * @method CarbonPeriod yearsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. + * @method float diffInUTCYears(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of years. + * @method $this addUTCDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCDecade() Add one decade to the instance (using timestamp). + * @method $this subUTCDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCDecade() Sub one decade to the instance (using timestamp). + * @method CarbonPeriod decadesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. + * @method float diffInUTCDecades(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of decades. + * @method $this addUTCCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCCentury() Add one century to the instance (using timestamp). + * @method $this subUTCCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCCentury() Sub one century to the instance (using timestamp). + * @method CarbonPeriod centuriesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. + * @method float diffInUTCCenturies(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of centuries. + * @method $this addUTCMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). + * @method $this addUTCMillennium() Add one millennium to the instance (using timestamp). + * @method $this subUTCMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). + * @method $this subUTCMillennium() Sub one millennium to the instance (using timestamp). + * @method CarbonPeriod millenniaUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method float diffInUTCMillennia(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of millennia. + * @method $this roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method $this roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method $this floorYear(float $precision = 1) Truncate the current instance year with given precision. + * @method $this floorYears(float $precision = 1) Truncate the current instance year with given precision. + * @method $this ceilYear(float $precision = 1) Ceil the current instance year with given precision. + * @method $this ceilYears(float $precision = 1) Ceil the current instance year with given precision. + * @method $this roundMonth(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method $this roundMonths(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method $this floorMonth(float $precision = 1) Truncate the current instance month with given precision. + * @method $this floorMonths(float $precision = 1) Truncate the current instance month with given precision. + * @method $this ceilMonth(float $precision = 1) Ceil the current instance month with given precision. + * @method $this ceilMonths(float $precision = 1) Ceil the current instance month with given precision. + * @method $this roundDay(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method $this roundDays(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method $this floorDay(float $precision = 1) Truncate the current instance day with given precision. + * @method $this floorDays(float $precision = 1) Truncate the current instance day with given precision. + * @method $this ceilDay(float $precision = 1) Ceil the current instance day with given precision. + * @method $this ceilDays(float $precision = 1) Ceil the current instance day with given precision. + * @method $this roundHour(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method $this roundHours(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method $this floorHour(float $precision = 1) Truncate the current instance hour with given precision. + * @method $this floorHours(float $precision = 1) Truncate the current instance hour with given precision. + * @method $this ceilHour(float $precision = 1) Ceil the current instance hour with given precision. + * @method $this ceilHours(float $precision = 1) Ceil the current instance hour with given precision. + * @method $this roundMinute(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method $this roundMinutes(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method $this floorMinute(float $precision = 1) Truncate the current instance minute with given precision. + * @method $this floorMinutes(float $precision = 1) Truncate the current instance minute with given precision. + * @method $this ceilMinute(float $precision = 1) Ceil the current instance minute with given precision. + * @method $this ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision. + * @method $this roundSecond(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method $this roundSeconds(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method $this floorSecond(float $precision = 1) Truncate the current instance second with given precision. + * @method $this floorSeconds(float $precision = 1) Truncate the current instance second with given precision. + * @method $this ceilSecond(float $precision = 1) Ceil the current instance second with given precision. + * @method $this ceilSeconds(float $precision = 1) Ceil the current instance second with given precision. + * @method $this roundMillennium(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method $this roundMillennia(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method $this floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision. + * @method $this floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision. + * @method $this ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision. + * @method $this ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision. + * @method $this roundCentury(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method $this roundCenturies(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method $this floorCentury(float $precision = 1) Truncate the current instance century with given precision. + * @method $this floorCenturies(float $precision = 1) Truncate the current instance century with given precision. + * @method $this ceilCentury(float $precision = 1) Ceil the current instance century with given precision. + * @method $this ceilCenturies(float $precision = 1) Ceil the current instance century with given precision. + * @method $this roundDecade(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method $this roundDecades(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method $this floorDecade(float $precision = 1) Truncate the current instance decade with given precision. + * @method $this floorDecades(float $precision = 1) Truncate the current instance decade with given precision. + * @method $this ceilDecade(float $precision = 1) Ceil the current instance decade with given precision. + * @method $this ceilDecades(float $precision = 1) Ceil the current instance decade with given precision. + * @method $this roundQuarter(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method $this roundQuarters(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method $this floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision. + * @method $this floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision. + * @method $this ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision. + * @method $this ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision. + * @method $this roundMillisecond(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method $this roundMilliseconds(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method $this floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method $this floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method $this ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method $this ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method $this roundMicrosecond(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method $this roundMicroseconds(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method $this floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method $this floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method $this ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision. + * @method $this ceilMicroseconds(float $precision = 1) Ceil the current instance microsecond with given precision. + * @method string shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method int centuriesInMillennium() Return the number of centuries contained in the current millennium + * @method int|static centuryOfMillennium(?int $century = null) Return the value of the century starting from the beginning of the current millennium when called with no parameters, change the current century when called with an integer value + * @method int|static dayOfCentury(?int $day = null) Return the value of the day starting from the beginning of the current century when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfDecade(?int $day = null) Return the value of the day starting from the beginning of the current decade when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMillennium(?int $day = null) Return the value of the day starting from the beginning of the current millennium when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMonth(?int $day = null) Return the value of the day starting from the beginning of the current month when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfQuarter(?int $day = null) Return the value of the day starting from the beginning of the current quarter when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfWeek(?int $day = null) Return the value of the day starting from the beginning of the current week when called with no parameters, change the current day when called with an integer value + * @method int daysInCentury() Return the number of days contained in the current century + * @method int daysInDecade() Return the number of days contained in the current decade + * @method int daysInMillennium() Return the number of days contained in the current millennium + * @method int daysInMonth() Return the number of days contained in the current month + * @method int daysInQuarter() Return the number of days contained in the current quarter + * @method int daysInWeek() Return the number of days contained in the current week + * @method int daysInYear() Return the number of days contained in the current year + * @method int|static decadeOfCentury(?int $decade = null) Return the value of the decade starting from the beginning of the current century when called with no parameters, change the current decade when called with an integer value + * @method int|static decadeOfMillennium(?int $decade = null) Return the value of the decade starting from the beginning of the current millennium when called with no parameters, change the current decade when called with an integer value + * @method int decadesInCentury() Return the number of decades contained in the current century + * @method int decadesInMillennium() Return the number of decades contained in the current millennium + * @method int|static hourOfCentury(?int $hour = null) Return the value of the hour starting from the beginning of the current century when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDay(?int $hour = null) Return the value of the hour starting from the beginning of the current day when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDecade(?int $hour = null) Return the value of the hour starting from the beginning of the current decade when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMillennium(?int $hour = null) Return the value of the hour starting from the beginning of the current millennium when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMonth(?int $hour = null) Return the value of the hour starting from the beginning of the current month when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfQuarter(?int $hour = null) Return the value of the hour starting from the beginning of the current quarter when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfWeek(?int $hour = null) Return the value of the hour starting from the beginning of the current week when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfYear(?int $hour = null) Return the value of the hour starting from the beginning of the current year when called with no parameters, change the current hour when called with an integer value + * @method int hoursInCentury() Return the number of hours contained in the current century + * @method int hoursInDay() Return the number of hours contained in the current day + * @method int hoursInDecade() Return the number of hours contained in the current decade + * @method int hoursInMillennium() Return the number of hours contained in the current millennium + * @method int hoursInMonth() Return the number of hours contained in the current month + * @method int hoursInQuarter() Return the number of hours contained in the current quarter + * @method int hoursInWeek() Return the number of hours contained in the current week + * @method int hoursInYear() Return the number of hours contained in the current year + * @method int|static microsecondOfCentury(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current century when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDay(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current day when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDecade(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current decade when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfHour(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current hour when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillennium(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millennium when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillisecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millisecond when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMinute(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current minute when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMonth(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current month when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfQuarter(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current quarter when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfSecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current second when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfWeek(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current week when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfYear(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current year when called with no parameters, change the current microsecond when called with an integer value + * @method int microsecondsInCentury() Return the number of microseconds contained in the current century + * @method int microsecondsInDay() Return the number of microseconds contained in the current day + * @method int microsecondsInDecade() Return the number of microseconds contained in the current decade + * @method int microsecondsInHour() Return the number of microseconds contained in the current hour + * @method int microsecondsInMillennium() Return the number of microseconds contained in the current millennium + * @method int microsecondsInMillisecond() Return the number of microseconds contained in the current millisecond + * @method int microsecondsInMinute() Return the number of microseconds contained in the current minute + * @method int microsecondsInMonth() Return the number of microseconds contained in the current month + * @method int microsecondsInQuarter() Return the number of microseconds contained in the current quarter + * @method int microsecondsInSecond() Return the number of microseconds contained in the current second + * @method int microsecondsInWeek() Return the number of microseconds contained in the current week + * @method int microsecondsInYear() Return the number of microseconds contained in the current year + * @method int|static millisecondOfCentury(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current century when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDay(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current day when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDecade(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current decade when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfHour(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current hour when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMillennium(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current millennium when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMinute(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current minute when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMonth(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current month when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfQuarter(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current quarter when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfSecond(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current second when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfWeek(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current week when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfYear(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current year when called with no parameters, change the current millisecond when called with an integer value + * @method int millisecondsInCentury() Return the number of milliseconds contained in the current century + * @method int millisecondsInDay() Return the number of milliseconds contained in the current day + * @method int millisecondsInDecade() Return the number of milliseconds contained in the current decade + * @method int millisecondsInHour() Return the number of milliseconds contained in the current hour + * @method int millisecondsInMillennium() Return the number of milliseconds contained in the current millennium + * @method int millisecondsInMinute() Return the number of milliseconds contained in the current minute + * @method int millisecondsInMonth() Return the number of milliseconds contained in the current month + * @method int millisecondsInQuarter() Return the number of milliseconds contained in the current quarter + * @method int millisecondsInSecond() Return the number of milliseconds contained in the current second + * @method int millisecondsInWeek() Return the number of milliseconds contained in the current week + * @method int millisecondsInYear() Return the number of milliseconds contained in the current year + * @method int|static minuteOfCentury(?int $minute = null) Return the value of the minute starting from the beginning of the current century when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDay(?int $minute = null) Return the value of the minute starting from the beginning of the current day when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDecade(?int $minute = null) Return the value of the minute starting from the beginning of the current decade when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfHour(?int $minute = null) Return the value of the minute starting from the beginning of the current hour when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMillennium(?int $minute = null) Return the value of the minute starting from the beginning of the current millennium when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMonth(?int $minute = null) Return the value of the minute starting from the beginning of the current month when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfQuarter(?int $minute = null) Return the value of the minute starting from the beginning of the current quarter when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfWeek(?int $minute = null) Return the value of the minute starting from the beginning of the current week when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfYear(?int $minute = null) Return the value of the minute starting from the beginning of the current year when called with no parameters, change the current minute when called with an integer value + * @method int minutesInCentury() Return the number of minutes contained in the current century + * @method int minutesInDay() Return the number of minutes contained in the current day + * @method int minutesInDecade() Return the number of minutes contained in the current decade + * @method int minutesInHour() Return the number of minutes contained in the current hour + * @method int minutesInMillennium() Return the number of minutes contained in the current millennium + * @method int minutesInMonth() Return the number of minutes contained in the current month + * @method int minutesInQuarter() Return the number of minutes contained in the current quarter + * @method int minutesInWeek() Return the number of minutes contained in the current week + * @method int minutesInYear() Return the number of minutes contained in the current year + * @method int|static monthOfCentury(?int $month = null) Return the value of the month starting from the beginning of the current century when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfDecade(?int $month = null) Return the value of the month starting from the beginning of the current decade when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfMillennium(?int $month = null) Return the value of the month starting from the beginning of the current millennium when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfQuarter(?int $month = null) Return the value of the month starting from the beginning of the current quarter when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfYear(?int $month = null) Return the value of the month starting from the beginning of the current year when called with no parameters, change the current month when called with an integer value + * @method int monthsInCentury() Return the number of months contained in the current century + * @method int monthsInDecade() Return the number of months contained in the current decade + * @method int monthsInMillennium() Return the number of months contained in the current millennium + * @method int monthsInQuarter() Return the number of months contained in the current quarter + * @method int monthsInYear() Return the number of months contained in the current year + * @method int|static quarterOfCentury(?int $quarter = null) Return the value of the quarter starting from the beginning of the current century when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfDecade(?int $quarter = null) Return the value of the quarter starting from the beginning of the current decade when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfMillennium(?int $quarter = null) Return the value of the quarter starting from the beginning of the current millennium when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfYear(?int $quarter = null) Return the value of the quarter starting from the beginning of the current year when called with no parameters, change the current quarter when called with an integer value + * @method int quartersInCentury() Return the number of quarters contained in the current century + * @method int quartersInDecade() Return the number of quarters contained in the current decade + * @method int quartersInMillennium() Return the number of quarters contained in the current millennium + * @method int quartersInYear() Return the number of quarters contained in the current year + * @method int|static secondOfCentury(?int $second = null) Return the value of the second starting from the beginning of the current century when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDay(?int $second = null) Return the value of the second starting from the beginning of the current day when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDecade(?int $second = null) Return the value of the second starting from the beginning of the current decade when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfHour(?int $second = null) Return the value of the second starting from the beginning of the current hour when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMillennium(?int $second = null) Return the value of the second starting from the beginning of the current millennium when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMinute(?int $second = null) Return the value of the second starting from the beginning of the current minute when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMonth(?int $second = null) Return the value of the second starting from the beginning of the current month when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfQuarter(?int $second = null) Return the value of the second starting from the beginning of the current quarter when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfWeek(?int $second = null) Return the value of the second starting from the beginning of the current week when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfYear(?int $second = null) Return the value of the second starting from the beginning of the current year when called with no parameters, change the current second when called with an integer value + * @method int secondsInCentury() Return the number of seconds contained in the current century + * @method int secondsInDay() Return the number of seconds contained in the current day + * @method int secondsInDecade() Return the number of seconds contained in the current decade + * @method int secondsInHour() Return the number of seconds contained in the current hour + * @method int secondsInMillennium() Return the number of seconds contained in the current millennium + * @method int secondsInMinute() Return the number of seconds contained in the current minute + * @method int secondsInMonth() Return the number of seconds contained in the current month + * @method int secondsInQuarter() Return the number of seconds contained in the current quarter + * @method int secondsInWeek() Return the number of seconds contained in the current week + * @method int secondsInYear() Return the number of seconds contained in the current year + * @method int|static weekOfCentury(?int $week = null) Return the value of the week starting from the beginning of the current century when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfDecade(?int $week = null) Return the value of the week starting from the beginning of the current decade when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMillennium(?int $week = null) Return the value of the week starting from the beginning of the current millennium when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMonth(?int $week = null) Return the value of the week starting from the beginning of the current month when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfQuarter(?int $week = null) Return the value of the week starting from the beginning of the current quarter when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfYear(?int $week = null) Return the value of the week starting from the beginning of the current year when called with no parameters, change the current week when called with an integer value + * @method int weeksInCentury() Return the number of weeks contained in the current century + * @method int weeksInDecade() Return the number of weeks contained in the current decade + * @method int weeksInMillennium() Return the number of weeks contained in the current millennium + * @method int weeksInMonth() Return the number of weeks contained in the current month + * @method int weeksInQuarter() Return the number of weeks contained in the current quarter + * @method int|static yearOfCentury(?int $year = null) Return the value of the year starting from the beginning of the current century when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfDecade(?int $year = null) Return the value of the year starting from the beginning of the current decade when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfMillennium(?int $year = null) Return the value of the year starting from the beginning of the current millennium when called with no parameters, change the current year when called with an integer value + * @method int yearsInCentury() Return the number of years contained in the current century + * @method int yearsInDecade() Return the number of years contained in the current decade + * @method int yearsInMillennium() Return the number of years contained in the current millennium * * */ @@ -513,10 +839,8 @@ class Carbon extends DateTime implements CarbonInterface /** * Returns true if the current class/instance is mutable. - * - * @return bool */ - public static function isMutable() + public static function isMutable(): bool { return true; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonConverterInterface.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonConverterInterface.php index 1ce967b25..fd89bd776 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonConverterInterface.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonConverterInterface.php @@ -1,5 +1,7 @@ * - * @property int $year - * @property int $yearIso - * @property int $month - * @property int $day - * @property int $hour - * @property int $minute - * @property int $second - * @property int $micro - * @property int $microsecond - * @property int|float|string $timestamp seconds since the Unix Epoch - * @property string $englishDayOfWeek the day of week in English - * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the month in English - * @property string $shortEnglishMonth the abbreviated month in English - * @property int $milliseconds - * @property int $millisecond - * @property int $milli - * @property int $week 1 through 53 - * @property int $isoWeek 1 through 53 - * @property int $weekYear year according to week format - * @property int $isoWeekYear year according to ISO week format - * @property int $dayOfYear 1 through 366 - * @property int $age does a diffInYears() with default parameters - * @property int $offset the timezone offset in seconds from UTC - * @property int $offsetMinutes the timezone offset in minutes from UTC - * @property int $offsetHours the timezone offset in hours from UTC - * @property CarbonTimeZone $timezone the current timezone - * @property CarbonTimeZone $tz alias of $timezone - * @property-read int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) - * @property-read int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month - * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) - * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) - * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name - * @property-read string $tzAbbrName alias of $timezoneAbbreviatedName - * @property-read string $dayName long name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $shortDayName short name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $minDayName very short name of weekday translated according to Carbon locale, in english if no translation available for current language - * @property-read string $monthName long name of month translated according to Carbon locale, in english if no translation available for current language - * @property-read string $shortMonthName short name of month translated according to Carbon locale, in english if no translation available for current language - * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language - * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language - * @property-read int $noZeroHour current hour from 1 to 24 - * @property-read int $weeksInYear 51 through 53 - * @property-read int $isoWeeksInYear 51 through 53 - * @property-read int $weekOfMonth 1 through 5 - * @property-read int $weekNumberInMonth 1 through 5 - * @property-read int $firstWeekDay 0 through 6 - * @property-read int $lastWeekDay 0 through 6 - * @property-read int $daysInYear 365 or 366 - * @property-read int $quarter the quarter of this instance, 1 - 4 - * @property-read int $decade the decade of this instance - * @property-read int $century the century of this instance - * @property-read int $millennium the millennium of this instance - * @property-read bool $dst daylight savings time indicator, true if DST, false otherwise - * @property-read bool $local checks if the timezone is local, true if local, false otherwise - * @property-read bool $utc checks if the timezone is UTC, true if UTC, false otherwise - * @property-read string $timezoneName the current timezone name - * @property-read string $tzName alias of $timezoneName - * @property-read string $locale locale of the current instance + * @property string $localeDayOfWeek the day of week in current locale + * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale + * @property string $localeMonth the month in current locale + * @property string $shortLocaleMonth the abbreviated month in current locale + * @property int $year + * @property int $yearIso + * @property int $month + * @property int $day + * @property int $hour + * @property int $minute + * @property int $second + * @property int $micro + * @property int $microsecond + * @property int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) + * @property int|float|string $timestamp seconds since the Unix Epoch + * @property string $englishDayOfWeek the day of week in English + * @property string $shortEnglishDayOfWeek the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English + * @property int $milliseconds + * @property int $millisecond + * @property int $milli + * @property int $week 1 through 53 + * @property int $isoWeek 1 through 53 + * @property int $weekYear year according to week format + * @property int $isoWeekYear year according to ISO week format + * @property int $age does a diffInYears() with default parameters + * @property int $offset the timezone offset in seconds from UTC + * @property int $offsetMinutes the timezone offset in minutes from UTC + * @property int $offsetHours the timezone offset in hours from UTC + * @property CarbonTimeZone $timezone the current timezone + * @property CarbonTimeZone $tz alias of $timezone + * @property int $centuryOfMillennium The value of the century starting from the beginning of the current millennium + * @property int $dayOfCentury The value of the day starting from the beginning of the current century + * @property int $dayOfDecade The value of the day starting from the beginning of the current decade + * @property int $dayOfMillennium The value of the day starting from the beginning of the current millennium + * @property int $dayOfMonth The value of the day starting from the beginning of the current month + * @property int $dayOfQuarter The value of the day starting from the beginning of the current quarter + * @property int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) + * @property int $dayOfYear 1 through 366 + * @property int $decadeOfCentury The value of the decade starting from the beginning of the current century + * @property int $decadeOfMillennium The value of the decade starting from the beginning of the current millennium + * @property int $hourOfCentury The value of the hour starting from the beginning of the current century + * @property int $hourOfDay The value of the hour starting from the beginning of the current day + * @property int $hourOfDecade The value of the hour starting from the beginning of the current decade + * @property int $hourOfMillennium The value of the hour starting from the beginning of the current millennium + * @property int $hourOfMonth The value of the hour starting from the beginning of the current month + * @property int $hourOfQuarter The value of the hour starting from the beginning of the current quarter + * @property int $hourOfWeek The value of the hour starting from the beginning of the current week + * @property int $hourOfYear The value of the hour starting from the beginning of the current year + * @property int $microsecondOfCentury The value of the microsecond starting from the beginning of the current century + * @property int $microsecondOfDay The value of the microsecond starting from the beginning of the current day + * @property int $microsecondOfDecade The value of the microsecond starting from the beginning of the current decade + * @property int $microsecondOfHour The value of the microsecond starting from the beginning of the current hour + * @property int $microsecondOfMillennium The value of the microsecond starting from the beginning of the current millennium + * @property int $microsecondOfMillisecond The value of the microsecond starting from the beginning of the current millisecond + * @property int $microsecondOfMinute The value of the microsecond starting from the beginning of the current minute + * @property int $microsecondOfMonth The value of the microsecond starting from the beginning of the current month + * @property int $microsecondOfQuarter The value of the microsecond starting from the beginning of the current quarter + * @property int $microsecondOfSecond The value of the microsecond starting from the beginning of the current second + * @property int $microsecondOfWeek The value of the microsecond starting from the beginning of the current week + * @property int $microsecondOfYear The value of the microsecond starting from the beginning of the current year + * @property int $millisecondOfCentury The value of the millisecond starting from the beginning of the current century + * @property int $millisecondOfDay The value of the millisecond starting from the beginning of the current day + * @property int $millisecondOfDecade The value of the millisecond starting from the beginning of the current decade + * @property int $millisecondOfHour The value of the millisecond starting from the beginning of the current hour + * @property int $millisecondOfMillennium The value of the millisecond starting from the beginning of the current millennium + * @property int $millisecondOfMinute The value of the millisecond starting from the beginning of the current minute + * @property int $millisecondOfMonth The value of the millisecond starting from the beginning of the current month + * @property int $millisecondOfQuarter The value of the millisecond starting from the beginning of the current quarter + * @property int $millisecondOfSecond The value of the millisecond starting from the beginning of the current second + * @property int $millisecondOfWeek The value of the millisecond starting from the beginning of the current week + * @property int $millisecondOfYear The value of the millisecond starting from the beginning of the current year + * @property int $minuteOfCentury The value of the minute starting from the beginning of the current century + * @property int $minuteOfDay The value of the minute starting from the beginning of the current day + * @property int $minuteOfDecade The value of the minute starting from the beginning of the current decade + * @property int $minuteOfHour The value of the minute starting from the beginning of the current hour + * @property int $minuteOfMillennium The value of the minute starting from the beginning of the current millennium + * @property int $minuteOfMonth The value of the minute starting from the beginning of the current month + * @property int $minuteOfQuarter The value of the minute starting from the beginning of the current quarter + * @property int $minuteOfWeek The value of the minute starting from the beginning of the current week + * @property int $minuteOfYear The value of the minute starting from the beginning of the current year + * @property int $monthOfCentury The value of the month starting from the beginning of the current century + * @property int $monthOfDecade The value of the month starting from the beginning of the current decade + * @property int $monthOfMillennium The value of the month starting from the beginning of the current millennium + * @property int $monthOfQuarter The value of the month starting from the beginning of the current quarter + * @property int $monthOfYear The value of the month starting from the beginning of the current year + * @property int $quarterOfCentury The value of the quarter starting from the beginning of the current century + * @property int $quarterOfDecade The value of the quarter starting from the beginning of the current decade + * @property int $quarterOfMillennium The value of the quarter starting from the beginning of the current millennium + * @property int $quarterOfYear The value of the quarter starting from the beginning of the current year + * @property int $secondOfCentury The value of the second starting from the beginning of the current century + * @property int $secondOfDay The value of the second starting from the beginning of the current day + * @property int $secondOfDecade The value of the second starting from the beginning of the current decade + * @property int $secondOfHour The value of the second starting from the beginning of the current hour + * @property int $secondOfMillennium The value of the second starting from the beginning of the current millennium + * @property int $secondOfMinute The value of the second starting from the beginning of the current minute + * @property int $secondOfMonth The value of the second starting from the beginning of the current month + * @property int $secondOfQuarter The value of the second starting from the beginning of the current quarter + * @property int $secondOfWeek The value of the second starting from the beginning of the current week + * @property int $secondOfYear The value of the second starting from the beginning of the current year + * @property int $weekOfCentury The value of the week starting from the beginning of the current century + * @property int $weekOfDecade The value of the week starting from the beginning of the current decade + * @property int $weekOfMillennium The value of the week starting from the beginning of the current millennium + * @property int $weekOfMonth 1 through 5 + * @property int $weekOfQuarter The value of the week starting from the beginning of the current quarter + * @property int $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property int $yearOfCentury The value of the year starting from the beginning of the current century + * @property int $yearOfDecade The value of the year starting from the beginning of the current decade + * @property int $yearOfMillennium The value of the year starting from the beginning of the current millennium + * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) + * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) + * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name + * @property-read string $tzAbbrName alias of $timezoneAbbreviatedName + * @property-read string $dayName long name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $shortDayName short name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $minDayName very short name of weekday translated according to Carbon locale, in english if no translation available for current language + * @property-read string $monthName long name of month translated according to Carbon locale, in english if no translation available for current language + * @property-read string $shortMonthName short name of month translated according to Carbon locale, in english if no translation available for current language + * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language + * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language + * @property-read int $noZeroHour current hour from 1 to 24 + * @property-read int $isoWeeksInYear 51 through 53 + * @property-read int $weekNumberInMonth 1 through 5 + * @property-read int $firstWeekDay 0 through 6 + * @property-read int $lastWeekDay 0 through 6 + * @property-read int $quarter the quarter of this instance, 1 - 4 + * @property-read int $decade the decade of this instance + * @property-read int $century the century of this instance + * @property-read int $millennium the millennium of this instance + * @property-read bool $dst daylight savings time indicator, true if DST, false otherwise + * @property-read bool $local checks if the timezone is local, true if local, false otherwise + * @property-read bool $utc checks if the timezone is UTC, true if UTC, false otherwise + * @property-read string $timezoneName the current timezone name + * @property-read string $tzName alias of $timezoneName + * @property-read string $locale locale of the current instance + * @property-read int $centuriesInMillennium The number of centuries contained in the current millennium + * @property-read int $daysInCentury The number of days contained in the current century + * @property-read int $daysInDecade The number of days contained in the current decade + * @property-read int $daysInMillennium The number of days contained in the current millennium + * @property-read int $daysInMonth number of days in the given month + * @property-read int $daysInQuarter The number of days contained in the current quarter + * @property-read int $daysInWeek The number of days contained in the current week + * @property-read int $daysInYear 365 or 366 + * @property-read int $decadesInCentury The number of decades contained in the current century + * @property-read int $decadesInMillennium The number of decades contained in the current millennium + * @property-read int $hoursInCentury The number of hours contained in the current century + * @property-read int $hoursInDay The number of hours contained in the current day + * @property-read int $hoursInDecade The number of hours contained in the current decade + * @property-read int $hoursInMillennium The number of hours contained in the current millennium + * @property-read int $hoursInMonth The number of hours contained in the current month + * @property-read int $hoursInQuarter The number of hours contained in the current quarter + * @property-read int $hoursInWeek The number of hours contained in the current week + * @property-read int $hoursInYear The number of hours contained in the current year + * @property-read int $microsecondsInCentury The number of microseconds contained in the current century + * @property-read int $microsecondsInDay The number of microseconds contained in the current day + * @property-read int $microsecondsInDecade The number of microseconds contained in the current decade + * @property-read int $microsecondsInHour The number of microseconds contained in the current hour + * @property-read int $microsecondsInMillennium The number of microseconds contained in the current millennium + * @property-read int $microsecondsInMillisecond The number of microseconds contained in the current millisecond + * @property-read int $microsecondsInMinute The number of microseconds contained in the current minute + * @property-read int $microsecondsInMonth The number of microseconds contained in the current month + * @property-read int $microsecondsInQuarter The number of microseconds contained in the current quarter + * @property-read int $microsecondsInSecond The number of microseconds contained in the current second + * @property-read int $microsecondsInWeek The number of microseconds contained in the current week + * @property-read int $microsecondsInYear The number of microseconds contained in the current year + * @property-read int $millisecondsInCentury The number of milliseconds contained in the current century + * @property-read int $millisecondsInDay The number of milliseconds contained in the current day + * @property-read int $millisecondsInDecade The number of milliseconds contained in the current decade + * @property-read int $millisecondsInHour The number of milliseconds contained in the current hour + * @property-read int $millisecondsInMillennium The number of milliseconds contained in the current millennium + * @property-read int $millisecondsInMinute The number of milliseconds contained in the current minute + * @property-read int $millisecondsInMonth The number of milliseconds contained in the current month + * @property-read int $millisecondsInQuarter The number of milliseconds contained in the current quarter + * @property-read int $millisecondsInSecond The number of milliseconds contained in the current second + * @property-read int $millisecondsInWeek The number of milliseconds contained in the current week + * @property-read int $millisecondsInYear The number of milliseconds contained in the current year + * @property-read int $minutesInCentury The number of minutes contained in the current century + * @property-read int $minutesInDay The number of minutes contained in the current day + * @property-read int $minutesInDecade The number of minutes contained in the current decade + * @property-read int $minutesInHour The number of minutes contained in the current hour + * @property-read int $minutesInMillennium The number of minutes contained in the current millennium + * @property-read int $minutesInMonth The number of minutes contained in the current month + * @property-read int $minutesInQuarter The number of minutes contained in the current quarter + * @property-read int $minutesInWeek The number of minutes contained in the current week + * @property-read int $minutesInYear The number of minutes contained in the current year + * @property-read int $monthsInCentury The number of months contained in the current century + * @property-read int $monthsInDecade The number of months contained in the current decade + * @property-read int $monthsInMillennium The number of months contained in the current millennium + * @property-read int $monthsInQuarter The number of months contained in the current quarter + * @property-read int $monthsInYear The number of months contained in the current year + * @property-read int $quartersInCentury The number of quarters contained in the current century + * @property-read int $quartersInDecade The number of quarters contained in the current decade + * @property-read int $quartersInMillennium The number of quarters contained in the current millennium + * @property-read int $quartersInYear The number of quarters contained in the current year + * @property-read int $secondsInCentury The number of seconds contained in the current century + * @property-read int $secondsInDay The number of seconds contained in the current day + * @property-read int $secondsInDecade The number of seconds contained in the current decade + * @property-read int $secondsInHour The number of seconds contained in the current hour + * @property-read int $secondsInMillennium The number of seconds contained in the current millennium + * @property-read int $secondsInMinute The number of seconds contained in the current minute + * @property-read int $secondsInMonth The number of seconds contained in the current month + * @property-read int $secondsInQuarter The number of seconds contained in the current quarter + * @property-read int $secondsInWeek The number of seconds contained in the current week + * @property-read int $secondsInYear The number of seconds contained in the current year + * @property-read int $weeksInCentury The number of weeks contained in the current century + * @property-read int $weeksInDecade The number of weeks contained in the current decade + * @property-read int $weeksInMillennium The number of weeks contained in the current millennium + * @property-read int $weeksInMonth The number of weeks contained in the current month + * @property-read int $weeksInQuarter The number of weeks contained in the current quarter + * @property-read int $weeksInYear 51 through 53 + * @property-read int $yearsInCentury The number of years contained in the current century + * @property-read int $yearsInDecade The number of years contained in the current decade + * @property-read int $yearsInMillennium The number of years contained in the current millennium * - * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) - * @method bool isLocal() Check if the current instance has non-UTC timezone. - * @method bool isValid() Check if the current instance is a valid date. - * @method bool isDST() Check if the current instance is in a daylight saving time. - * @method bool isSunday() Checks if the instance day is sunday. - * @method bool isMonday() Checks if the instance day is monday. - * @method bool isTuesday() Checks if the instance day is tuesday. - * @method bool isWednesday() Checks if the instance day is wednesday. - * @method bool isThursday() Checks if the instance day is thursday. - * @method bool isFriday() Checks if the instance day is friday. - * @method bool isSaturday() Checks if the instance day is saturday. - * @method bool isSameYear(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. - * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. - * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. - * @method bool isSameWeek(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. - * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. - * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. - * @method bool isSameDay(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. - * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. - * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. - * @method bool isSameHour(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. - * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. - * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. - * @method bool isSameMinute(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. - * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. - * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. - * @method bool isSameSecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. - * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. - * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. - * @method bool isSameMicro(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. - * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. - * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. - * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. - * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. - * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. - * @method bool isSameDecade(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. - * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. - * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. - * @method bool isSameCentury(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. - * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. - * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. - * @method bool isSameMillennium(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. - * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. - * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. - * @method CarbonImmutable years(int $value) Set current instance year to the given value. - * @method CarbonImmutable year(int $value) Set current instance year to the given value. - * @method CarbonImmutable setYears(int $value) Set current instance year to the given value. - * @method CarbonImmutable setYear(int $value) Set current instance year to the given value. - * @method CarbonImmutable months(int $value) Set current instance month to the given value. - * @method CarbonImmutable month(int $value) Set current instance month to the given value. - * @method CarbonImmutable setMonths(int $value) Set current instance month to the given value. - * @method CarbonImmutable setMonth(int $value) Set current instance month to the given value. - * @method CarbonImmutable days(int $value) Set current instance day to the given value. - * @method CarbonImmutable day(int $value) Set current instance day to the given value. - * @method CarbonImmutable setDays(int $value) Set current instance day to the given value. - * @method CarbonImmutable setDay(int $value) Set current instance day to the given value. - * @method CarbonImmutable hours(int $value) Set current instance hour to the given value. - * @method CarbonImmutable hour(int $value) Set current instance hour to the given value. - * @method CarbonImmutable setHours(int $value) Set current instance hour to the given value. - * @method CarbonImmutable setHour(int $value) Set current instance hour to the given value. - * @method CarbonImmutable minutes(int $value) Set current instance minute to the given value. - * @method CarbonImmutable minute(int $value) Set current instance minute to the given value. - * @method CarbonImmutable setMinutes(int $value) Set current instance minute to the given value. - * @method CarbonImmutable setMinute(int $value) Set current instance minute to the given value. - * @method CarbonImmutable seconds(int $value) Set current instance second to the given value. - * @method CarbonImmutable second(int $value) Set current instance second to the given value. - * @method CarbonImmutable setSeconds(int $value) Set current instance second to the given value. - * @method CarbonImmutable setSecond(int $value) Set current instance second to the given value. - * @method CarbonImmutable millis(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable milli(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable setMillis(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable setMilli(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable milliseconds(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable millisecond(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable setMilliseconds(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable setMillisecond(int $value) Set current instance millisecond to the given value. - * @method CarbonImmutable micros(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable micro(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable setMicros(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable setMicro(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable microseconds(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable microsecond(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable setMicroseconds(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable setMicrosecond(int $value) Set current instance microsecond to the given value. - * @method CarbonImmutable addYears(int $value = 1) Add years (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addYear() Add one year to the instance (using date interval). - * @method CarbonImmutable subYears(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subYear() Sub one year to the instance (using date interval). - * @method CarbonImmutable addYearsWithOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subYearsWithOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addYearsWithoutOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearsWithoutOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addYearsWithNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearsWithNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addYearsNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearsNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonths(int $value = 1) Add months (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMonth() Add one month to the instance (using date interval). - * @method CarbonImmutable subMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMonth() Sub one month to the instance (using date interval). - * @method CarbonImmutable addMonthsWithOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subMonthsWithOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addMonthsWithoutOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthsWithoutOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonthsWithNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthsWithNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonthsNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthsNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDays(int $value = 1) Add days (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addDay() Add one day to the instance (using date interval). - * @method CarbonImmutable subDays(int $value = 1) Sub days (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subDay() Sub one day to the instance (using date interval). - * @method CarbonImmutable addHours(int $value = 1) Add hours (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addHour() Add one hour to the instance (using date interval). - * @method CarbonImmutable subHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subHour() Sub one hour to the instance (using date interval). - * @method CarbonImmutable addMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMinute() Add one minute to the instance (using date interval). - * @method CarbonImmutable subMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMinute() Sub one minute to the instance (using date interval). - * @method CarbonImmutable addSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addSecond() Add one second to the instance (using date interval). - * @method CarbonImmutable subSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subSecond() Sub one second to the instance (using date interval). - * @method CarbonImmutable addMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMilli() Add one millisecond to the instance (using date interval). - * @method CarbonImmutable subMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMilli() Sub one millisecond to the instance (using date interval). - * @method CarbonImmutable addMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMillisecond() Add one millisecond to the instance (using date interval). - * @method CarbonImmutable subMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMillisecond() Sub one millisecond to the instance (using date interval). - * @method CarbonImmutable addMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMicro() Add one microsecond to the instance (using date interval). - * @method CarbonImmutable subMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMicro() Sub one microsecond to the instance (using date interval). - * @method CarbonImmutable addMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMicrosecond() Add one microsecond to the instance (using date interval). - * @method CarbonImmutable subMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMicrosecond() Sub one microsecond to the instance (using date interval). - * @method CarbonImmutable addMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addMillennium() Add one millennium to the instance (using date interval). - * @method CarbonImmutable subMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subMillennium() Sub one millennium to the instance (using date interval). - * @method CarbonImmutable addMillenniaWithOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subMillenniaWithOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addMillenniaWithoutOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniaWithoutOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMillenniaWithNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniaWithNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMillenniaNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniaNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addCentury() Add one century to the instance (using date interval). - * @method CarbonImmutable subCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subCentury() Sub one century to the instance (using date interval). - * @method CarbonImmutable addCenturiesWithOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subCenturiesWithOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addCenturiesWithoutOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturiesWithoutOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturiesWithNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturiesWithNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturiesNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturiesNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addDecade() Add one decade to the instance (using date interval). - * @method CarbonImmutable subDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subDecade() Sub one decade to the instance (using date interval). - * @method CarbonImmutable addDecadesWithOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subDecadesWithOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addDecadesWithoutOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadesWithoutOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecadesWithNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadesWithNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecadesNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadesNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addQuarter() Add one quarter to the instance (using date interval). - * @method CarbonImmutable subQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subQuarter() Sub one quarter to the instance (using date interval). - * @method CarbonImmutable addQuartersWithOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subQuartersWithOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonImmutable addQuartersWithoutOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuartersWithoutOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuartersWithNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuartersWithNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuartersNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuartersNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonImmutable addWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addWeek() Add one week to the instance (using date interval). - * @method CarbonImmutable subWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subWeek() Sub one week to the instance (using date interval). - * @method CarbonImmutable addWeekdays(int $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable addWeekday() Add one weekday to the instance (using date interval). - * @method CarbonImmutable subWeekdays(int $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). - * @method CarbonImmutable subWeekday() Sub one weekday to the instance (using date interval). - * @method CarbonImmutable addRealMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMicro() Add one microsecond to the instance (using timestamp). - * @method CarbonImmutable subRealMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMicro() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonImmutable addRealMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMicrosecond() Add one microsecond to the instance (using timestamp). - * @method CarbonImmutable subRealMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMicrosecond() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonImmutable addRealMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMilli() Add one millisecond to the instance (using timestamp). - * @method CarbonImmutable subRealMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMilli() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonImmutable addRealMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMillisecond() Add one millisecond to the instance (using timestamp). - * @method CarbonImmutable subRealMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMillisecond() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonImmutable addRealSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealSecond() Add one second to the instance (using timestamp). - * @method CarbonImmutable subRealSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealSecond() Sub one second to the instance (using timestamp). - * @method CarbonPeriod secondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. - * @method CarbonImmutable addRealMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMinute() Add one minute to the instance (using timestamp). - * @method CarbonImmutable subRealMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMinute() Sub one minute to the instance (using timestamp). - * @method CarbonPeriod minutesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. - * @method CarbonImmutable addRealHours(int $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealHour() Add one hour to the instance (using timestamp). - * @method CarbonImmutable subRealHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealHour() Sub one hour to the instance (using timestamp). - * @method CarbonPeriod hoursUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. - * @method CarbonImmutable addRealDays(int $value = 1) Add days (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealDay() Add one day to the instance (using timestamp). - * @method CarbonImmutable subRealDays(int $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealDay() Sub one day to the instance (using timestamp). - * @method CarbonPeriod daysUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. - * @method CarbonImmutable addRealWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealWeek() Add one week to the instance (using timestamp). - * @method CarbonImmutable subRealWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealWeek() Sub one week to the instance (using timestamp). - * @method CarbonPeriod weeksUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. - * @method CarbonImmutable addRealMonths(int $value = 1) Add months (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMonth() Add one month to the instance (using timestamp). - * @method CarbonImmutable subRealMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMonth() Sub one month to the instance (using timestamp). - * @method CarbonPeriod monthsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. - * @method CarbonImmutable addRealQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealQuarter() Add one quarter to the instance (using timestamp). - * @method CarbonImmutable subRealQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealQuarter() Sub one quarter to the instance (using timestamp). - * @method CarbonPeriod quartersUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. - * @method CarbonImmutable addRealYears(int $value = 1) Add years (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealYear() Add one year to the instance (using timestamp). - * @method CarbonImmutable subRealYears(int $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealYear() Sub one year to the instance (using timestamp). - * @method CarbonPeriod yearsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. - * @method CarbonImmutable addRealDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealDecade() Add one decade to the instance (using timestamp). - * @method CarbonImmutable subRealDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealDecade() Sub one decade to the instance (using timestamp). - * @method CarbonPeriod decadesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. - * @method CarbonImmutable addRealCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealCentury() Add one century to the instance (using timestamp). - * @method CarbonImmutable subRealCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealCentury() Sub one century to the instance (using timestamp). - * @method CarbonPeriod centuriesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. - * @method CarbonImmutable addRealMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable addRealMillennium() Add one millennium to the instance (using timestamp). - * @method CarbonImmutable subRealMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonImmutable subRealMillennium() Sub one millennium to the instance (using timestamp). - * @method CarbonPeriod millenniaUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. - * @method CarbonImmutable roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. - * @method CarbonImmutable roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. - * @method CarbonImmutable floorYear(float $precision = 1) Truncate the current instance year with given precision. - * @method CarbonImmutable floorYears(float $precision = 1) Truncate the current instance year with given precision. - * @method CarbonImmutable ceilYear(float $precision = 1) Ceil the current instance year with given precision. - * @method CarbonImmutable ceilYears(float $precision = 1) Ceil the current instance year with given precision. - * @method CarbonImmutable roundMonth(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. - * @method CarbonImmutable roundMonths(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. - * @method CarbonImmutable floorMonth(float $precision = 1) Truncate the current instance month with given precision. - * @method CarbonImmutable floorMonths(float $precision = 1) Truncate the current instance month with given precision. - * @method CarbonImmutable ceilMonth(float $precision = 1) Ceil the current instance month with given precision. - * @method CarbonImmutable ceilMonths(float $precision = 1) Ceil the current instance month with given precision. - * @method CarbonImmutable roundDay(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. - * @method CarbonImmutable roundDays(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. - * @method CarbonImmutable floorDay(float $precision = 1) Truncate the current instance day with given precision. - * @method CarbonImmutable floorDays(float $precision = 1) Truncate the current instance day with given precision. - * @method CarbonImmutable ceilDay(float $precision = 1) Ceil the current instance day with given precision. - * @method CarbonImmutable ceilDays(float $precision = 1) Ceil the current instance day with given precision. - * @method CarbonImmutable roundHour(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. - * @method CarbonImmutable roundHours(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. - * @method CarbonImmutable floorHour(float $precision = 1) Truncate the current instance hour with given precision. - * @method CarbonImmutable floorHours(float $precision = 1) Truncate the current instance hour with given precision. - * @method CarbonImmutable ceilHour(float $precision = 1) Ceil the current instance hour with given precision. - * @method CarbonImmutable ceilHours(float $precision = 1) Ceil the current instance hour with given precision. - * @method CarbonImmutable roundMinute(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. - * @method CarbonImmutable roundMinutes(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. - * @method CarbonImmutable floorMinute(float $precision = 1) Truncate the current instance minute with given precision. - * @method CarbonImmutable floorMinutes(float $precision = 1) Truncate the current instance minute with given precision. - * @method CarbonImmutable ceilMinute(float $precision = 1) Ceil the current instance minute with given precision. - * @method CarbonImmutable ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision. - * @method CarbonImmutable roundSecond(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. - * @method CarbonImmutable roundSeconds(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. - * @method CarbonImmutable floorSecond(float $precision = 1) Truncate the current instance second with given precision. - * @method CarbonImmutable floorSeconds(float $precision = 1) Truncate the current instance second with given precision. - * @method CarbonImmutable ceilSecond(float $precision = 1) Ceil the current instance second with given precision. - * @method CarbonImmutable ceilSeconds(float $precision = 1) Ceil the current instance second with given precision. - * @method CarbonImmutable roundMillennium(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. - * @method CarbonImmutable roundMillennia(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. - * @method CarbonImmutable floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision. - * @method CarbonImmutable floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision. - * @method CarbonImmutable ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision. - * @method CarbonImmutable ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision. - * @method CarbonImmutable roundCentury(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. - * @method CarbonImmutable roundCenturies(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. - * @method CarbonImmutable floorCentury(float $precision = 1) Truncate the current instance century with given precision. - * @method CarbonImmutable floorCenturies(float $precision = 1) Truncate the current instance century with given precision. - * @method CarbonImmutable ceilCentury(float $precision = 1) Ceil the current instance century with given precision. - * @method CarbonImmutable ceilCenturies(float $precision = 1) Ceil the current instance century with given precision. - * @method CarbonImmutable roundDecade(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. - * @method CarbonImmutable roundDecades(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. - * @method CarbonImmutable floorDecade(float $precision = 1) Truncate the current instance decade with given precision. - * @method CarbonImmutable floorDecades(float $precision = 1) Truncate the current instance decade with given precision. - * @method CarbonImmutable ceilDecade(float $precision = 1) Ceil the current instance decade with given precision. - * @method CarbonImmutable ceilDecades(float $precision = 1) Ceil the current instance decade with given precision. - * @method CarbonImmutable roundQuarter(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. - * @method CarbonImmutable roundQuarters(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. - * @method CarbonImmutable floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision. - * @method CarbonImmutable floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision. - * @method CarbonImmutable ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision. - * @method CarbonImmutable ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision. - * @method CarbonImmutable roundMillisecond(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. - * @method CarbonImmutable roundMilliseconds(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. - * @method CarbonImmutable floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision. - * @method CarbonImmutable floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision. - * @method CarbonImmutable ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision. - * @method CarbonImmutable ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision. - * @method CarbonImmutable roundMicrosecond(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. - * @method CarbonImmutable roundMicroseconds(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. - * @method CarbonImmutable floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision. - * @method CarbonImmutable floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision. - * @method CarbonImmutable ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision. - * @method CarbonImmutable ceilMicroseconds(float $precision = 1) Ceil the current instance microsecond with given precision. - * @method string shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) - * @method static static|false createFromFormat(string $format, string $time, DateTimeZone|string|false|null $timezone = null) Parse a string into a new CarbonImmutable object according to the specified format. - * @method static static __set_state(array $array) https://php.net/manual/en/datetime.set-state.php + * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) + * @method bool isLocal() Check if the current instance has non-UTC timezone. + * @method bool isValid() Check if the current instance is a valid date. + * @method bool isDST() Check if the current instance is in a daylight saving time. + * @method bool isSunday() Checks if the instance day is sunday. + * @method bool isMonday() Checks if the instance day is monday. + * @method bool isTuesday() Checks if the instance day is tuesday. + * @method bool isWednesday() Checks if the instance day is wednesday. + * @method bool isThursday() Checks if the instance day is thursday. + * @method bool isFriday() Checks if the instance day is friday. + * @method bool isSaturday() Checks if the instance day is saturday. + * @method bool isSameYear(DateTimeInterface|string $date) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. + * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. + * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. + * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. + * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. + * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. + * @method bool isSameWeek(DateTimeInterface|string $date) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. + * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. + * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. + * @method bool isSameDay(DateTimeInterface|string $date) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. + * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. + * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. + * @method bool isSameHour(DateTimeInterface|string $date) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. + * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. + * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. + * @method bool isSameMinute(DateTimeInterface|string $date) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. + * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. + * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. + * @method bool isSameSecond(DateTimeInterface|string $date) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. + * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. + * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. + * @method bool isSameMilli(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMilli() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMilli() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMilli() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMillisecond(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillisecond() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMillisecond() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMillisecond() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMicro(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameMicrosecond(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameDecade(DateTimeInterface|string $date) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. + * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. + * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. + * @method bool isSameCentury(DateTimeInterface|string $date) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. + * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. + * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. + * @method bool isSameMillennium(DateTimeInterface|string $date) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. + * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. + * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. + * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. + * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. + * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. + * @method CarbonImmutable years(int $value) Set current instance year to the given value. + * @method CarbonImmutable year(int $value) Set current instance year to the given value. + * @method CarbonImmutable setYears(int $value) Set current instance year to the given value. + * @method CarbonImmutable setYear(int $value) Set current instance year to the given value. + * @method CarbonImmutable months(Month|int $value) Set current instance month to the given value. + * @method CarbonImmutable month(Month|int $value) Set current instance month to the given value. + * @method CarbonImmutable setMonths(Month|int $value) Set current instance month to the given value. + * @method CarbonImmutable setMonth(Month|int $value) Set current instance month to the given value. + * @method CarbonImmutable days(int $value) Set current instance day to the given value. + * @method CarbonImmutable day(int $value) Set current instance day to the given value. + * @method CarbonImmutable setDays(int $value) Set current instance day to the given value. + * @method CarbonImmutable setDay(int $value) Set current instance day to the given value. + * @method CarbonImmutable hours(int $value) Set current instance hour to the given value. + * @method CarbonImmutable hour(int $value) Set current instance hour to the given value. + * @method CarbonImmutable setHours(int $value) Set current instance hour to the given value. + * @method CarbonImmutable setHour(int $value) Set current instance hour to the given value. + * @method CarbonImmutable minutes(int $value) Set current instance minute to the given value. + * @method CarbonImmutable minute(int $value) Set current instance minute to the given value. + * @method CarbonImmutable setMinutes(int $value) Set current instance minute to the given value. + * @method CarbonImmutable setMinute(int $value) Set current instance minute to the given value. + * @method CarbonImmutable seconds(int $value) Set current instance second to the given value. + * @method CarbonImmutable second(int $value) Set current instance second to the given value. + * @method CarbonImmutable setSeconds(int $value) Set current instance second to the given value. + * @method CarbonImmutable setSecond(int $value) Set current instance second to the given value. + * @method CarbonImmutable millis(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable milli(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMillis(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMilli(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable milliseconds(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable millisecond(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMilliseconds(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMillisecond(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable micros(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable micro(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicros(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicro(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable microseconds(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable microsecond(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicroseconds(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicrosecond(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable addYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addYear() Add one year to the instance (using date interval). + * @method CarbonImmutable subYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subYear() Sub one year to the instance (using date interval). + * @method CarbonImmutable addYearsWithOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subYearsWithOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addYearsWithoutOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsWithoutOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearsWithNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsWithNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearsNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMonth() Add one month to the instance (using date interval). + * @method CarbonImmutable subMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMonth() Sub one month to the instance (using date interval). + * @method CarbonImmutable addMonthsWithOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMonthsWithOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMonthsWithoutOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsWithoutOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthsWithNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsWithNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthsNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addDay() Add one day to the instance (using date interval). + * @method CarbonImmutable subDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subDay() Sub one day to the instance (using date interval). + * @method CarbonImmutable addHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addHour() Add one hour to the instance (using date interval). + * @method CarbonImmutable subHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subHour() Sub one hour to the instance (using date interval). + * @method CarbonImmutable addMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMinute() Add one minute to the instance (using date interval). + * @method CarbonImmutable subMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMinute() Sub one minute to the instance (using date interval). + * @method CarbonImmutable addSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addSecond() Add one second to the instance (using date interval). + * @method CarbonImmutable subSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subSecond() Sub one second to the instance (using date interval). + * @method CarbonImmutable addMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMilli() Add one millisecond to the instance (using date interval). + * @method CarbonImmutable subMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMilli() Sub one millisecond to the instance (using date interval). + * @method CarbonImmutable addMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMillisecond() Add one millisecond to the instance (using date interval). + * @method CarbonImmutable subMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMillisecond() Sub one millisecond to the instance (using date interval). + * @method CarbonImmutable addMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMicro() Add one microsecond to the instance (using date interval). + * @method CarbonImmutable subMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMicro() Sub one microsecond to the instance (using date interval). + * @method CarbonImmutable addMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMicrosecond() Add one microsecond to the instance (using date interval). + * @method CarbonImmutable subMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMicrosecond() Sub one microsecond to the instance (using date interval). + * @method CarbonImmutable addMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMillennium() Add one millennium to the instance (using date interval). + * @method CarbonImmutable subMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMillennium() Sub one millennium to the instance (using date interval). + * @method CarbonImmutable addMillenniaWithOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMillenniaWithOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMillenniaWithoutOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaWithoutOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniaWithNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaWithNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniaNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addCentury() Add one century to the instance (using date interval). + * @method CarbonImmutable subCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subCentury() Sub one century to the instance (using date interval). + * @method CarbonImmutable addCenturiesWithOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subCenturiesWithOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addCenturiesWithoutOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesWithoutOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturiesWithNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesWithNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturiesNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addDecade() Add one decade to the instance (using date interval). + * @method CarbonImmutable subDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subDecade() Sub one decade to the instance (using date interval). + * @method CarbonImmutable addDecadesWithOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subDecadesWithOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addDecadesWithoutOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesWithoutOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadesWithNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesWithNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadesNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addQuarter() Add one quarter to the instance (using date interval). + * @method CarbonImmutable subQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subQuarter() Sub one quarter to the instance (using date interval). + * @method CarbonImmutable addQuartersWithOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subQuartersWithOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addQuartersWithoutOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersWithoutOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuartersWithNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersWithNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuartersNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addWeek() Add one week to the instance (using date interval). + * @method CarbonImmutable subWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subWeek() Sub one week to the instance (using date interval). + * @method CarbonImmutable addWeekdays(int|float $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addWeekday() Add one weekday to the instance (using date interval). + * @method CarbonImmutable subWeekdays(int|float $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subWeekday() Sub one weekday to the instance (using date interval). + * @method CarbonImmutable addUTCMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMicro() Add one microsecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMicro() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicros(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonImmutable addUTCMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMicrosecond() Add one microsecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMicrosecond() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicroseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonImmutable addUTCMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMilli() Add one millisecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMilli() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMillis(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonImmutable addUTCMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMillisecond() Add one millisecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMillisecond() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMilliseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonImmutable addUTCSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCSecond() Add one second to the instance (using timestamp). + * @method CarbonImmutable subUTCSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCSecond() Sub one second to the instance (using timestamp). + * @method CarbonPeriod secondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. + * @method float diffInUTCSeconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of seconds. + * @method CarbonImmutable addUTCMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMinute() Add one minute to the instance (using timestamp). + * @method CarbonImmutable subUTCMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMinute() Sub one minute to the instance (using timestamp). + * @method CarbonPeriod minutesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. + * @method float diffInUTCMinutes(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of minutes. + * @method CarbonImmutable addUTCHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCHour() Add one hour to the instance (using timestamp). + * @method CarbonImmutable subUTCHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCHour() Sub one hour to the instance (using timestamp). + * @method CarbonPeriod hoursUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. + * @method float diffInUTCHours(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of hours. + * @method CarbonImmutable addUTCDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCDay() Add one day to the instance (using timestamp). + * @method CarbonImmutable subUTCDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCDay() Sub one day to the instance (using timestamp). + * @method CarbonPeriod daysUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. + * @method float diffInUTCDays(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of days. + * @method CarbonImmutable addUTCWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCWeek() Add one week to the instance (using timestamp). + * @method CarbonImmutable subUTCWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCWeek() Sub one week to the instance (using timestamp). + * @method CarbonPeriod weeksUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. + * @method float diffInUTCWeeks(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of weeks. + * @method CarbonImmutable addUTCMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMonth() Add one month to the instance (using timestamp). + * @method CarbonImmutable subUTCMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMonth() Sub one month to the instance (using timestamp). + * @method CarbonPeriod monthsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. + * @method float diffInUTCMonths(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of months. + * @method CarbonImmutable addUTCQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCQuarter() Add one quarter to the instance (using timestamp). + * @method CarbonImmutable subUTCQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCQuarter() Sub one quarter to the instance (using timestamp). + * @method CarbonPeriod quartersUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. + * @method float diffInUTCQuarters(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of quarters. + * @method CarbonImmutable addUTCYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCYear() Add one year to the instance (using timestamp). + * @method CarbonImmutable subUTCYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCYear() Sub one year to the instance (using timestamp). + * @method CarbonPeriod yearsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. + * @method float diffInUTCYears(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of years. + * @method CarbonImmutable addUTCDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCDecade() Add one decade to the instance (using timestamp). + * @method CarbonImmutable subUTCDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCDecade() Sub one decade to the instance (using timestamp). + * @method CarbonPeriod decadesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. + * @method float diffInUTCDecades(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of decades. + * @method CarbonImmutable addUTCCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCCentury() Add one century to the instance (using timestamp). + * @method CarbonImmutable subUTCCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCCentury() Sub one century to the instance (using timestamp). + * @method CarbonPeriod centuriesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. + * @method float diffInUTCCenturies(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of centuries. + * @method CarbonImmutable addUTCMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMillennium() Add one millennium to the instance (using timestamp). + * @method CarbonImmutable subUTCMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMillennium() Sub one millennium to the instance (using timestamp). + * @method CarbonPeriod millenniaUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method float diffInUTCMillennia(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of millennia. + * @method CarbonImmutable roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method CarbonImmutable roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method CarbonImmutable floorYear(float $precision = 1) Truncate the current instance year with given precision. + * @method CarbonImmutable floorYears(float $precision = 1) Truncate the current instance year with given precision. + * @method CarbonImmutable ceilYear(float $precision = 1) Ceil the current instance year with given precision. + * @method CarbonImmutable ceilYears(float $precision = 1) Ceil the current instance year with given precision. + * @method CarbonImmutable roundMonth(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method CarbonImmutable roundMonths(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method CarbonImmutable floorMonth(float $precision = 1) Truncate the current instance month with given precision. + * @method CarbonImmutable floorMonths(float $precision = 1) Truncate the current instance month with given precision. + * @method CarbonImmutable ceilMonth(float $precision = 1) Ceil the current instance month with given precision. + * @method CarbonImmutable ceilMonths(float $precision = 1) Ceil the current instance month with given precision. + * @method CarbonImmutable roundDay(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method CarbonImmutable roundDays(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method CarbonImmutable floorDay(float $precision = 1) Truncate the current instance day with given precision. + * @method CarbonImmutable floorDays(float $precision = 1) Truncate the current instance day with given precision. + * @method CarbonImmutable ceilDay(float $precision = 1) Ceil the current instance day with given precision. + * @method CarbonImmutable ceilDays(float $precision = 1) Ceil the current instance day with given precision. + * @method CarbonImmutable roundHour(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method CarbonImmutable roundHours(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method CarbonImmutable floorHour(float $precision = 1) Truncate the current instance hour with given precision. + * @method CarbonImmutable floorHours(float $precision = 1) Truncate the current instance hour with given precision. + * @method CarbonImmutable ceilHour(float $precision = 1) Ceil the current instance hour with given precision. + * @method CarbonImmutable ceilHours(float $precision = 1) Ceil the current instance hour with given precision. + * @method CarbonImmutable roundMinute(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method CarbonImmutable roundMinutes(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method CarbonImmutable floorMinute(float $precision = 1) Truncate the current instance minute with given precision. + * @method CarbonImmutable floorMinutes(float $precision = 1) Truncate the current instance minute with given precision. + * @method CarbonImmutable ceilMinute(float $precision = 1) Ceil the current instance minute with given precision. + * @method CarbonImmutable ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision. + * @method CarbonImmutable roundSecond(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method CarbonImmutable roundSeconds(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method CarbonImmutable floorSecond(float $precision = 1) Truncate the current instance second with given precision. + * @method CarbonImmutable floorSeconds(float $precision = 1) Truncate the current instance second with given precision. + * @method CarbonImmutable ceilSecond(float $precision = 1) Ceil the current instance second with given precision. + * @method CarbonImmutable ceilSeconds(float $precision = 1) Ceil the current instance second with given precision. + * @method CarbonImmutable roundMillennium(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method CarbonImmutable roundMillennia(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method CarbonImmutable floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision. + * @method CarbonImmutable floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision. + * @method CarbonImmutable ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision. + * @method CarbonImmutable ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision. + * @method CarbonImmutable roundCentury(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method CarbonImmutable roundCenturies(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method CarbonImmutable floorCentury(float $precision = 1) Truncate the current instance century with given precision. + * @method CarbonImmutable floorCenturies(float $precision = 1) Truncate the current instance century with given precision. + * @method CarbonImmutable ceilCentury(float $precision = 1) Ceil the current instance century with given precision. + * @method CarbonImmutable ceilCenturies(float $precision = 1) Ceil the current instance century with given precision. + * @method CarbonImmutable roundDecade(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method CarbonImmutable roundDecades(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method CarbonImmutable floorDecade(float $precision = 1) Truncate the current instance decade with given precision. + * @method CarbonImmutable floorDecades(float $precision = 1) Truncate the current instance decade with given precision. + * @method CarbonImmutable ceilDecade(float $precision = 1) Ceil the current instance decade with given precision. + * @method CarbonImmutable ceilDecades(float $precision = 1) Ceil the current instance decade with given precision. + * @method CarbonImmutable roundQuarter(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method CarbonImmutable roundQuarters(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method CarbonImmutable floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision. + * @method CarbonImmutable floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision. + * @method CarbonImmutable ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision. + * @method CarbonImmutable ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision. + * @method CarbonImmutable roundMillisecond(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method CarbonImmutable roundMilliseconds(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method CarbonImmutable floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method CarbonImmutable floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method CarbonImmutable ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method CarbonImmutable ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method CarbonImmutable roundMicrosecond(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method CarbonImmutable roundMicroseconds(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method CarbonImmutable floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method CarbonImmutable floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method CarbonImmutable ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision. + * @method CarbonImmutable ceilMicroseconds(float $precision = 1) Ceil the current instance microsecond with given precision. + * @method string shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method int centuriesInMillennium() Return the number of centuries contained in the current millennium + * @method int|static centuryOfMillennium(?int $century = null) Return the value of the century starting from the beginning of the current millennium when called with no parameters, change the current century when called with an integer value + * @method int|static dayOfCentury(?int $day = null) Return the value of the day starting from the beginning of the current century when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfDecade(?int $day = null) Return the value of the day starting from the beginning of the current decade when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMillennium(?int $day = null) Return the value of the day starting from the beginning of the current millennium when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMonth(?int $day = null) Return the value of the day starting from the beginning of the current month when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfQuarter(?int $day = null) Return the value of the day starting from the beginning of the current quarter when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfWeek(?int $day = null) Return the value of the day starting from the beginning of the current week when called with no parameters, change the current day when called with an integer value + * @method int daysInCentury() Return the number of days contained in the current century + * @method int daysInDecade() Return the number of days contained in the current decade + * @method int daysInMillennium() Return the number of days contained in the current millennium + * @method int daysInMonth() Return the number of days contained in the current month + * @method int daysInQuarter() Return the number of days contained in the current quarter + * @method int daysInWeek() Return the number of days contained in the current week + * @method int daysInYear() Return the number of days contained in the current year + * @method int|static decadeOfCentury(?int $decade = null) Return the value of the decade starting from the beginning of the current century when called with no parameters, change the current decade when called with an integer value + * @method int|static decadeOfMillennium(?int $decade = null) Return the value of the decade starting from the beginning of the current millennium when called with no parameters, change the current decade when called with an integer value + * @method int decadesInCentury() Return the number of decades contained in the current century + * @method int decadesInMillennium() Return the number of decades contained in the current millennium + * @method int|static hourOfCentury(?int $hour = null) Return the value of the hour starting from the beginning of the current century when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDay(?int $hour = null) Return the value of the hour starting from the beginning of the current day when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDecade(?int $hour = null) Return the value of the hour starting from the beginning of the current decade when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMillennium(?int $hour = null) Return the value of the hour starting from the beginning of the current millennium when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMonth(?int $hour = null) Return the value of the hour starting from the beginning of the current month when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfQuarter(?int $hour = null) Return the value of the hour starting from the beginning of the current quarter when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfWeek(?int $hour = null) Return the value of the hour starting from the beginning of the current week when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfYear(?int $hour = null) Return the value of the hour starting from the beginning of the current year when called with no parameters, change the current hour when called with an integer value + * @method int hoursInCentury() Return the number of hours contained in the current century + * @method int hoursInDay() Return the number of hours contained in the current day + * @method int hoursInDecade() Return the number of hours contained in the current decade + * @method int hoursInMillennium() Return the number of hours contained in the current millennium + * @method int hoursInMonth() Return the number of hours contained in the current month + * @method int hoursInQuarter() Return the number of hours contained in the current quarter + * @method int hoursInWeek() Return the number of hours contained in the current week + * @method int hoursInYear() Return the number of hours contained in the current year + * @method int|static microsecondOfCentury(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current century when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDay(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current day when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDecade(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current decade when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfHour(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current hour when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillennium(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millennium when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillisecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millisecond when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMinute(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current minute when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMonth(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current month when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfQuarter(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current quarter when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfSecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current second when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfWeek(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current week when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfYear(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current year when called with no parameters, change the current microsecond when called with an integer value + * @method int microsecondsInCentury() Return the number of microseconds contained in the current century + * @method int microsecondsInDay() Return the number of microseconds contained in the current day + * @method int microsecondsInDecade() Return the number of microseconds contained in the current decade + * @method int microsecondsInHour() Return the number of microseconds contained in the current hour + * @method int microsecondsInMillennium() Return the number of microseconds contained in the current millennium + * @method int microsecondsInMillisecond() Return the number of microseconds contained in the current millisecond + * @method int microsecondsInMinute() Return the number of microseconds contained in the current minute + * @method int microsecondsInMonth() Return the number of microseconds contained in the current month + * @method int microsecondsInQuarter() Return the number of microseconds contained in the current quarter + * @method int microsecondsInSecond() Return the number of microseconds contained in the current second + * @method int microsecondsInWeek() Return the number of microseconds contained in the current week + * @method int microsecondsInYear() Return the number of microseconds contained in the current year + * @method int|static millisecondOfCentury(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current century when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDay(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current day when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDecade(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current decade when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfHour(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current hour when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMillennium(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current millennium when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMinute(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current minute when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMonth(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current month when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfQuarter(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current quarter when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfSecond(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current second when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfWeek(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current week when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfYear(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current year when called with no parameters, change the current millisecond when called with an integer value + * @method int millisecondsInCentury() Return the number of milliseconds contained in the current century + * @method int millisecondsInDay() Return the number of milliseconds contained in the current day + * @method int millisecondsInDecade() Return the number of milliseconds contained in the current decade + * @method int millisecondsInHour() Return the number of milliseconds contained in the current hour + * @method int millisecondsInMillennium() Return the number of milliseconds contained in the current millennium + * @method int millisecondsInMinute() Return the number of milliseconds contained in the current minute + * @method int millisecondsInMonth() Return the number of milliseconds contained in the current month + * @method int millisecondsInQuarter() Return the number of milliseconds contained in the current quarter + * @method int millisecondsInSecond() Return the number of milliseconds contained in the current second + * @method int millisecondsInWeek() Return the number of milliseconds contained in the current week + * @method int millisecondsInYear() Return the number of milliseconds contained in the current year + * @method int|static minuteOfCentury(?int $minute = null) Return the value of the minute starting from the beginning of the current century when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDay(?int $minute = null) Return the value of the minute starting from the beginning of the current day when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDecade(?int $minute = null) Return the value of the minute starting from the beginning of the current decade when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfHour(?int $minute = null) Return the value of the minute starting from the beginning of the current hour when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMillennium(?int $minute = null) Return the value of the minute starting from the beginning of the current millennium when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMonth(?int $minute = null) Return the value of the minute starting from the beginning of the current month when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfQuarter(?int $minute = null) Return the value of the minute starting from the beginning of the current quarter when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfWeek(?int $minute = null) Return the value of the minute starting from the beginning of the current week when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfYear(?int $minute = null) Return the value of the minute starting from the beginning of the current year when called with no parameters, change the current minute when called with an integer value + * @method int minutesInCentury() Return the number of minutes contained in the current century + * @method int minutesInDay() Return the number of minutes contained in the current day + * @method int minutesInDecade() Return the number of minutes contained in the current decade + * @method int minutesInHour() Return the number of minutes contained in the current hour + * @method int minutesInMillennium() Return the number of minutes contained in the current millennium + * @method int minutesInMonth() Return the number of minutes contained in the current month + * @method int minutesInQuarter() Return the number of minutes contained in the current quarter + * @method int minutesInWeek() Return the number of minutes contained in the current week + * @method int minutesInYear() Return the number of minutes contained in the current year + * @method int|static monthOfCentury(?int $month = null) Return the value of the month starting from the beginning of the current century when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfDecade(?int $month = null) Return the value of the month starting from the beginning of the current decade when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfMillennium(?int $month = null) Return the value of the month starting from the beginning of the current millennium when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfQuarter(?int $month = null) Return the value of the month starting from the beginning of the current quarter when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfYear(?int $month = null) Return the value of the month starting from the beginning of the current year when called with no parameters, change the current month when called with an integer value + * @method int monthsInCentury() Return the number of months contained in the current century + * @method int monthsInDecade() Return the number of months contained in the current decade + * @method int monthsInMillennium() Return the number of months contained in the current millennium + * @method int monthsInQuarter() Return the number of months contained in the current quarter + * @method int monthsInYear() Return the number of months contained in the current year + * @method int|static quarterOfCentury(?int $quarter = null) Return the value of the quarter starting from the beginning of the current century when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfDecade(?int $quarter = null) Return the value of the quarter starting from the beginning of the current decade when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfMillennium(?int $quarter = null) Return the value of the quarter starting from the beginning of the current millennium when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfYear(?int $quarter = null) Return the value of the quarter starting from the beginning of the current year when called with no parameters, change the current quarter when called with an integer value + * @method int quartersInCentury() Return the number of quarters contained in the current century + * @method int quartersInDecade() Return the number of quarters contained in the current decade + * @method int quartersInMillennium() Return the number of quarters contained in the current millennium + * @method int quartersInYear() Return the number of quarters contained in the current year + * @method int|static secondOfCentury(?int $second = null) Return the value of the second starting from the beginning of the current century when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDay(?int $second = null) Return the value of the second starting from the beginning of the current day when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDecade(?int $second = null) Return the value of the second starting from the beginning of the current decade when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfHour(?int $second = null) Return the value of the second starting from the beginning of the current hour when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMillennium(?int $second = null) Return the value of the second starting from the beginning of the current millennium when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMinute(?int $second = null) Return the value of the second starting from the beginning of the current minute when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMonth(?int $second = null) Return the value of the second starting from the beginning of the current month when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfQuarter(?int $second = null) Return the value of the second starting from the beginning of the current quarter when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfWeek(?int $second = null) Return the value of the second starting from the beginning of the current week when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfYear(?int $second = null) Return the value of the second starting from the beginning of the current year when called with no parameters, change the current second when called with an integer value + * @method int secondsInCentury() Return the number of seconds contained in the current century + * @method int secondsInDay() Return the number of seconds contained in the current day + * @method int secondsInDecade() Return the number of seconds contained in the current decade + * @method int secondsInHour() Return the number of seconds contained in the current hour + * @method int secondsInMillennium() Return the number of seconds contained in the current millennium + * @method int secondsInMinute() Return the number of seconds contained in the current minute + * @method int secondsInMonth() Return the number of seconds contained in the current month + * @method int secondsInQuarter() Return the number of seconds contained in the current quarter + * @method int secondsInWeek() Return the number of seconds contained in the current week + * @method int secondsInYear() Return the number of seconds contained in the current year + * @method int|static weekOfCentury(?int $week = null) Return the value of the week starting from the beginning of the current century when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfDecade(?int $week = null) Return the value of the week starting from the beginning of the current decade when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMillennium(?int $week = null) Return the value of the week starting from the beginning of the current millennium when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMonth(?int $week = null) Return the value of the week starting from the beginning of the current month when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfQuarter(?int $week = null) Return the value of the week starting from the beginning of the current quarter when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfYear(?int $week = null) Return the value of the week starting from the beginning of the current year when called with no parameters, change the current week when called with an integer value + * @method int weeksInCentury() Return the number of weeks contained in the current century + * @method int weeksInDecade() Return the number of weeks contained in the current decade + * @method int weeksInMillennium() Return the number of weeks contained in the current millennium + * @method int weeksInMonth() Return the number of weeks contained in the current month + * @method int weeksInQuarter() Return the number of weeks contained in the current quarter + * @method int|static yearOfCentury(?int $year = null) Return the value of the year starting from the beginning of the current century when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfDecade(?int $year = null) Return the value of the year starting from the beginning of the current decade when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfMillennium(?int $year = null) Return the value of the year starting from the beginning of the current millennium when called with no parameters, change the current year when called with an integer value + * @method int yearsInCentury() Return the number of years contained in the current century + * @method int yearsInDecade() Return the number of years contained in the current decade + * @method int yearsInMillennium() Return the number of years contained in the current millennium * * */ @@ -513,7 +839,7 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface __clone as dateTraitClone; } - public function __clone() + public function __clone(): void { $this->dateTraitClone(); $this->endOfTime = false; @@ -525,7 +851,7 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface * * @return static */ - public static function startOfTime(): self + public static function startOfTime(): static { $date = static::parse('0001-01-01')->years(self::getStartOfTimeYear()); $date->startOfTime = true; @@ -538,7 +864,7 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface * * @return static */ - public static function endOfTime(): self + public static function endOfTime(): static { $date = static::parse('9999-12-31 23:59:59.999999')->years(self::getEndOfTimeYear()); $date->endOfTime = true; @@ -551,16 +877,7 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface */ private static function getEndOfTimeYear(): int { - if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) { - return 145261681241552; - } - - // Remove if https://bugs.php.net/bug.php?id=81107 is fixed - if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) { - return 1118290769066902787; - } - - return PHP_INT_MAX; + return 1118290769066902787; // PHP_INT_MAX no longer work since PHP 8.1 } /** @@ -568,15 +885,6 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface */ private static function getStartOfTimeYear(): int { - if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) { - return -135908816449551; - } - - // Remove if https://bugs.php.net/bug.php?id=81107 is fixed - if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) { - return -1118290769066898816; - } - - return max(PHP_INT_MIN, -9223372036854773760); + return -1118290769066898816; // PHP_INT_MIN no longer work since PHP 8.1 } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterface.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterface.php index b90e29817..1779246e5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterface.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterface.php @@ -1,5 +1,7 @@ * + * @property string $localeDayOfWeek the day of week in current locale + * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale + * @property string $localeMonth the month in current locale + * @property string $shortLocaleMonth the abbreviated month in current locale * @property int $year * @property int $yearIso * @property int $month @@ -45,6 +51,7 @@ use Throwable; * @property int $second * @property int $micro * @property int $microsecond + * @property int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) * @property int|float|string $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English @@ -57,17 +64,90 @@ use Throwable; * @property int $isoWeek 1 through 53 * @property int $weekYear year according to week format * @property int $isoWeekYear year according to ISO week format - * @property int $dayOfYear 1 through 366 * @property int $age does a diffInYears() with default parameters * @property int $offset the timezone offset in seconds from UTC * @property int $offsetMinutes the timezone offset in minutes from UTC * @property int $offsetHours the timezone offset in hours from UTC * @property CarbonTimeZone $timezone the current timezone * @property CarbonTimeZone $tz alias of $timezone - * @property-read int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) - * @property-read int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month + * @property int $centuryOfMillennium The value of the century starting from the beginning of the current millennium + * @property int $dayOfCentury The value of the day starting from the beginning of the current century + * @property int $dayOfDecade The value of the day starting from the beginning of the current decade + * @property int $dayOfMillennium The value of the day starting from the beginning of the current millennium + * @property int $dayOfMonth The value of the day starting from the beginning of the current month + * @property int $dayOfQuarter The value of the day starting from the beginning of the current quarter + * @property int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) + * @property int $dayOfYear 1 through 366 + * @property int $decadeOfCentury The value of the decade starting from the beginning of the current century + * @property int $decadeOfMillennium The value of the decade starting from the beginning of the current millennium + * @property int $hourOfCentury The value of the hour starting from the beginning of the current century + * @property int $hourOfDay The value of the hour starting from the beginning of the current day + * @property int $hourOfDecade The value of the hour starting from the beginning of the current decade + * @property int $hourOfMillennium The value of the hour starting from the beginning of the current millennium + * @property int $hourOfMonth The value of the hour starting from the beginning of the current month + * @property int $hourOfQuarter The value of the hour starting from the beginning of the current quarter + * @property int $hourOfWeek The value of the hour starting from the beginning of the current week + * @property int $hourOfYear The value of the hour starting from the beginning of the current year + * @property int $microsecondOfCentury The value of the microsecond starting from the beginning of the current century + * @property int $microsecondOfDay The value of the microsecond starting from the beginning of the current day + * @property int $microsecondOfDecade The value of the microsecond starting from the beginning of the current decade + * @property int $microsecondOfHour The value of the microsecond starting from the beginning of the current hour + * @property int $microsecondOfMillennium The value of the microsecond starting from the beginning of the current millennium + * @property int $microsecondOfMillisecond The value of the microsecond starting from the beginning of the current millisecond + * @property int $microsecondOfMinute The value of the microsecond starting from the beginning of the current minute + * @property int $microsecondOfMonth The value of the microsecond starting from the beginning of the current month + * @property int $microsecondOfQuarter The value of the microsecond starting from the beginning of the current quarter + * @property int $microsecondOfSecond The value of the microsecond starting from the beginning of the current second + * @property int $microsecondOfWeek The value of the microsecond starting from the beginning of the current week + * @property int $microsecondOfYear The value of the microsecond starting from the beginning of the current year + * @property int $millisecondOfCentury The value of the millisecond starting from the beginning of the current century + * @property int $millisecondOfDay The value of the millisecond starting from the beginning of the current day + * @property int $millisecondOfDecade The value of the millisecond starting from the beginning of the current decade + * @property int $millisecondOfHour The value of the millisecond starting from the beginning of the current hour + * @property int $millisecondOfMillennium The value of the millisecond starting from the beginning of the current millennium + * @property int $millisecondOfMinute The value of the millisecond starting from the beginning of the current minute + * @property int $millisecondOfMonth The value of the millisecond starting from the beginning of the current month + * @property int $millisecondOfQuarter The value of the millisecond starting from the beginning of the current quarter + * @property int $millisecondOfSecond The value of the millisecond starting from the beginning of the current second + * @property int $millisecondOfWeek The value of the millisecond starting from the beginning of the current week + * @property int $millisecondOfYear The value of the millisecond starting from the beginning of the current year + * @property int $minuteOfCentury The value of the minute starting from the beginning of the current century + * @property int $minuteOfDay The value of the minute starting from the beginning of the current day + * @property int $minuteOfDecade The value of the minute starting from the beginning of the current decade + * @property int $minuteOfHour The value of the minute starting from the beginning of the current hour + * @property int $minuteOfMillennium The value of the minute starting from the beginning of the current millennium + * @property int $minuteOfMonth The value of the minute starting from the beginning of the current month + * @property int $minuteOfQuarter The value of the minute starting from the beginning of the current quarter + * @property int $minuteOfWeek The value of the minute starting from the beginning of the current week + * @property int $minuteOfYear The value of the minute starting from the beginning of the current year + * @property int $monthOfCentury The value of the month starting from the beginning of the current century + * @property int $monthOfDecade The value of the month starting from the beginning of the current decade + * @property int $monthOfMillennium The value of the month starting from the beginning of the current millennium + * @property int $monthOfQuarter The value of the month starting from the beginning of the current quarter + * @property int $monthOfYear The value of the month starting from the beginning of the current year + * @property int $quarterOfCentury The value of the quarter starting from the beginning of the current century + * @property int $quarterOfDecade The value of the quarter starting from the beginning of the current decade + * @property int $quarterOfMillennium The value of the quarter starting from the beginning of the current millennium + * @property int $quarterOfYear The value of the quarter starting from the beginning of the current year + * @property int $secondOfCentury The value of the second starting from the beginning of the current century + * @property int $secondOfDay The value of the second starting from the beginning of the current day + * @property int $secondOfDecade The value of the second starting from the beginning of the current decade + * @property int $secondOfHour The value of the second starting from the beginning of the current hour + * @property int $secondOfMillennium The value of the second starting from the beginning of the current millennium + * @property int $secondOfMinute The value of the second starting from the beginning of the current minute + * @property int $secondOfMonth The value of the second starting from the beginning of the current month + * @property int $secondOfQuarter The value of the second starting from the beginning of the current quarter + * @property int $secondOfWeek The value of the second starting from the beginning of the current week + * @property int $secondOfYear The value of the second starting from the beginning of the current year + * @property int $weekOfCentury The value of the week starting from the beginning of the current century + * @property int $weekOfDecade The value of the week starting from the beginning of the current decade + * @property int $weekOfMillennium The value of the week starting from the beginning of the current millennium + * @property int $weekOfMonth 1 through 5 + * @property int $weekOfQuarter The value of the week starting from the beginning of the current quarter + * @property int $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property int $yearOfCentury The value of the year starting from the beginning of the current century + * @property int $yearOfDecade The value of the year starting from the beginning of the current decade + * @property int $yearOfMillennium The value of the year starting from the beginning of the current millennium * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name @@ -80,13 +160,10 @@ use Throwable; * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language * @property-read int $noZeroHour current hour from 1 to 24 - * @property-read int $weeksInYear 51 through 53 * @property-read int $isoWeeksInYear 51 through 53 - * @property-read int $weekOfMonth 1 through 5 * @property-read int $weekNumberInMonth 1 through 5 * @property-read int $firstWeekDay 0 through 6 * @property-read int $lastWeekDay 0 through 6 - * @property-read int $daysInYear 365 or 366 * @property-read int $quarter the quarter of this instance, 1 - 4 * @property-read int $decade the decade of this instance * @property-read int $century the century of this instance @@ -97,6 +174,84 @@ use Throwable; * @property-read string $timezoneName the current timezone name * @property-read string $tzName alias of $timezoneName * @property-read string $locale locale of the current instance + * @property-read int $centuriesInMillennium The number of centuries contained in the current millennium + * @property-read int $daysInCentury The number of days contained in the current century + * @property-read int $daysInDecade The number of days contained in the current decade + * @property-read int $daysInMillennium The number of days contained in the current millennium + * @property-read int $daysInMonth number of days in the given month + * @property-read int $daysInQuarter The number of days contained in the current quarter + * @property-read int $daysInWeek The number of days contained in the current week + * @property-read int $daysInYear 365 or 366 + * @property-read int $decadesInCentury The number of decades contained in the current century + * @property-read int $decadesInMillennium The number of decades contained in the current millennium + * @property-read int $hoursInCentury The number of hours contained in the current century + * @property-read int $hoursInDay The number of hours contained in the current day + * @property-read int $hoursInDecade The number of hours contained in the current decade + * @property-read int $hoursInMillennium The number of hours contained in the current millennium + * @property-read int $hoursInMonth The number of hours contained in the current month + * @property-read int $hoursInQuarter The number of hours contained in the current quarter + * @property-read int $hoursInWeek The number of hours contained in the current week + * @property-read int $hoursInYear The number of hours contained in the current year + * @property-read int $microsecondsInCentury The number of microseconds contained in the current century + * @property-read int $microsecondsInDay The number of microseconds contained in the current day + * @property-read int $microsecondsInDecade The number of microseconds contained in the current decade + * @property-read int $microsecondsInHour The number of microseconds contained in the current hour + * @property-read int $microsecondsInMillennium The number of microseconds contained in the current millennium + * @property-read int $microsecondsInMillisecond The number of microseconds contained in the current millisecond + * @property-read int $microsecondsInMinute The number of microseconds contained in the current minute + * @property-read int $microsecondsInMonth The number of microseconds contained in the current month + * @property-read int $microsecondsInQuarter The number of microseconds contained in the current quarter + * @property-read int $microsecondsInSecond The number of microseconds contained in the current second + * @property-read int $microsecondsInWeek The number of microseconds contained in the current week + * @property-read int $microsecondsInYear The number of microseconds contained in the current year + * @property-read int $millisecondsInCentury The number of milliseconds contained in the current century + * @property-read int $millisecondsInDay The number of milliseconds contained in the current day + * @property-read int $millisecondsInDecade The number of milliseconds contained in the current decade + * @property-read int $millisecondsInHour The number of milliseconds contained in the current hour + * @property-read int $millisecondsInMillennium The number of milliseconds contained in the current millennium + * @property-read int $millisecondsInMinute The number of milliseconds contained in the current minute + * @property-read int $millisecondsInMonth The number of milliseconds contained in the current month + * @property-read int $millisecondsInQuarter The number of milliseconds contained in the current quarter + * @property-read int $millisecondsInSecond The number of milliseconds contained in the current second + * @property-read int $millisecondsInWeek The number of milliseconds contained in the current week + * @property-read int $millisecondsInYear The number of milliseconds contained in the current year + * @property-read int $minutesInCentury The number of minutes contained in the current century + * @property-read int $minutesInDay The number of minutes contained in the current day + * @property-read int $minutesInDecade The number of minutes contained in the current decade + * @property-read int $minutesInHour The number of minutes contained in the current hour + * @property-read int $minutesInMillennium The number of minutes contained in the current millennium + * @property-read int $minutesInMonth The number of minutes contained in the current month + * @property-read int $minutesInQuarter The number of minutes contained in the current quarter + * @property-read int $minutesInWeek The number of minutes contained in the current week + * @property-read int $minutesInYear The number of minutes contained in the current year + * @property-read int $monthsInCentury The number of months contained in the current century + * @property-read int $monthsInDecade The number of months contained in the current decade + * @property-read int $monthsInMillennium The number of months contained in the current millennium + * @property-read int $monthsInQuarter The number of months contained in the current quarter + * @property-read int $monthsInYear The number of months contained in the current year + * @property-read int $quartersInCentury The number of quarters contained in the current century + * @property-read int $quartersInDecade The number of quarters contained in the current decade + * @property-read int $quartersInMillennium The number of quarters contained in the current millennium + * @property-read int $quartersInYear The number of quarters contained in the current year + * @property-read int $secondsInCentury The number of seconds contained in the current century + * @property-read int $secondsInDay The number of seconds contained in the current day + * @property-read int $secondsInDecade The number of seconds contained in the current decade + * @property-read int $secondsInHour The number of seconds contained in the current hour + * @property-read int $secondsInMillennium The number of seconds contained in the current millennium + * @property-read int $secondsInMinute The number of seconds contained in the current minute + * @property-read int $secondsInMonth The number of seconds contained in the current month + * @property-read int $secondsInQuarter The number of seconds contained in the current quarter + * @property-read int $secondsInWeek The number of seconds contained in the current week + * @property-read int $secondsInYear The number of seconds contained in the current year + * @property-read int $weeksInCentury The number of weeks contained in the current century + * @property-read int $weeksInDecade The number of weeks contained in the current decade + * @property-read int $weeksInMillennium The number of weeks contained in the current millennium + * @property-read int $weeksInMonth The number of weeks contained in the current month + * @property-read int $weeksInQuarter The number of weeks contained in the current quarter + * @property-read int $weeksInYear 51 through 53 + * @property-read int $yearsInCentury The number of years contained in the current century + * @property-read int $yearsInDecade The number of years contained in the current decade + * @property-read int $yearsInMillennium The number of years contained in the current millennium * * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) * @method bool isLocal() Check if the current instance has non-UTC timezone. @@ -109,64 +264,72 @@ use Throwable; * @method bool isThursday() Checks if the instance day is thursday. * @method bool isFriday() Checks if the instance day is friday. * @method bool isSaturday() Checks if the instance day is saturday. - * @method bool isSameYear(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameYear(DateTimeInterface|string $date) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. - * @method bool isSameWeek(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. - * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. - * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. - * @method bool isSameDay(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. - * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. - * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. - * @method bool isSameHour(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. - * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. - * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. - * @method bool isSameMinute(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. - * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. - * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. - * @method bool isSameSecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. - * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. - * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. - * @method bool isSameMicro(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. - * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. - * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. - * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. - * @method bool isSameDecade(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameWeek(DateTimeInterface|string $date) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. + * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. + * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. + * @method bool isSameDay(DateTimeInterface|string $date) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. + * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. + * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. + * @method bool isSameHour(DateTimeInterface|string $date) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. + * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. + * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. + * @method bool isSameMinute(DateTimeInterface|string $date) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. + * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. + * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. + * @method bool isSameSecond(DateTimeInterface|string $date) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. + * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. + * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. + * @method bool isSameMilli(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMilli() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMilli() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMilli() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMillisecond(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillisecond() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMillisecond() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMillisecond() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMicro(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameMicrosecond(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameDecade(DateTimeInterface|string $date) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. - * @method bool isSameCentury(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameCentury(DateTimeInterface|string $date) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. - * @method bool isSameMillennium(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameMillennium(DateTimeInterface|string $date) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. + * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. + * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. + * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. * @method CarbonInterface years(int $value) Set current instance year to the given value. * @method CarbonInterface year(int $value) Set current instance year to the given value. * @method CarbonInterface setYears(int $value) Set current instance year to the given value. * @method CarbonInterface setYear(int $value) Set current instance year to the given value. - * @method CarbonInterface months(int $value) Set current instance month to the given value. - * @method CarbonInterface month(int $value) Set current instance month to the given value. - * @method CarbonInterface setMonths(int $value) Set current instance month to the given value. - * @method CarbonInterface setMonth(int $value) Set current instance month to the given value. + * @method CarbonInterface months(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface month(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface setMonths(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface setMonth(Month|int $value) Set current instance month to the given value. * @method CarbonInterface days(int $value) Set current instance day to the given value. * @method CarbonInterface day(int $value) Set current instance day to the given value. * @method CarbonInterface setDays(int $value) Set current instance day to the given value. @@ -199,241 +362,256 @@ use Throwable; * @method CarbonInterface microsecond(int $value) Set current instance microsecond to the given value. * @method CarbonInterface setMicroseconds(int $value) Set current instance microsecond to the given value. * @method CarbonInterface setMicrosecond(int $value) Set current instance microsecond to the given value. - * @method CarbonInterface addYears(int $value = 1) Add years (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addYear() Add one year to the instance (using date interval). - * @method CarbonInterface subYears(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subYear() Sub one year to the instance (using date interval). - * @method CarbonInterface addYearsWithOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addYearsWithOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subYearsWithOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subYearsWithOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addYearsWithoutOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsWithoutOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsWithoutOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsWithoutOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addYearsWithNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsWithNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsWithNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsWithNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addYearsNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonths(int $value = 1) Add months (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMonth() Add one month to the instance (using date interval). - * @method CarbonInterface subMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMonth() Sub one month to the instance (using date interval). - * @method CarbonInterface addMonthsWithOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addMonthsWithOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subMonthsWithOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subMonthsWithOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addMonthsWithoutOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsWithoutOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsWithoutOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsWithoutOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonthsWithNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsWithNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsWithNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsWithNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonthsNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDays(int $value = 1) Add days (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addDay() Add one day to the instance (using date interval). - * @method CarbonInterface subDays(int $value = 1) Sub days (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subDay() Sub one day to the instance (using date interval). - * @method CarbonInterface addHours(int $value = 1) Add hours (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addHour() Add one hour to the instance (using date interval). - * @method CarbonInterface subHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subHour() Sub one hour to the instance (using date interval). - * @method CarbonInterface addMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMinute() Add one minute to the instance (using date interval). - * @method CarbonInterface subMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMinute() Sub one minute to the instance (using date interval). - * @method CarbonInterface addSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addSecond() Add one second to the instance (using date interval). - * @method CarbonInterface subSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subSecond() Sub one second to the instance (using date interval). - * @method CarbonInterface addMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMilli() Add one millisecond to the instance (using date interval). - * @method CarbonInterface subMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMilli() Sub one millisecond to the instance (using date interval). - * @method CarbonInterface addMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMillisecond() Add one millisecond to the instance (using date interval). - * @method CarbonInterface subMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMillisecond() Sub one millisecond to the instance (using date interval). - * @method CarbonInterface addMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMicro() Add one microsecond to the instance (using date interval). - * @method CarbonInterface subMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMicro() Sub one microsecond to the instance (using date interval). - * @method CarbonInterface addMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMicrosecond() Add one microsecond to the instance (using date interval). - * @method CarbonInterface subMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMicrosecond() Sub one microsecond to the instance (using date interval). - * @method CarbonInterface addMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMillennium() Add one millennium to the instance (using date interval). - * @method CarbonInterface subMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMillennium() Sub one millennium to the instance (using date interval). - * @method CarbonInterface addMillenniaWithOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addMillenniaWithOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subMillenniaWithOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subMillenniaWithOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addMillenniaWithoutOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaWithoutOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaWithoutOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaWithoutOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMillenniaWithNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaWithNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaWithNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaWithNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMillenniaNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addCentury() Add one century to the instance (using date interval). - * @method CarbonInterface subCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subCentury() Sub one century to the instance (using date interval). - * @method CarbonInterface addCenturiesWithOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addCenturiesWithOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subCenturiesWithOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subCenturiesWithOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addCenturiesWithoutOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesWithoutOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesWithoutOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesWithoutOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturiesWithNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesWithNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesWithNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesWithNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturiesNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addDecade() Add one decade to the instance (using date interval). - * @method CarbonInterface subDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subDecade() Sub one decade to the instance (using date interval). - * @method CarbonInterface addDecadesWithOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addDecadesWithOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subDecadesWithOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subDecadesWithOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addDecadesWithoutOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesWithoutOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesWithoutOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesWithoutOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecadesWithNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesWithNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesWithNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesWithNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecadesNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addQuarter() Add one quarter to the instance (using date interval). - * @method CarbonInterface subQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subQuarter() Sub one quarter to the instance (using date interval). - * @method CarbonInterface addQuartersWithOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addQuartersWithOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subQuartersWithOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subQuartersWithOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addQuartersWithoutOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersWithoutOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersWithoutOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersWithoutOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuartersWithNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersWithNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersWithNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersWithNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuartersNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addWeek() Add one week to the instance (using date interval). - * @method CarbonInterface subWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subWeek() Sub one week to the instance (using date interval). - * @method CarbonInterface addWeekdays(int $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addWeekdays(int|float $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addWeekday() Add one weekday to the instance (using date interval). - * @method CarbonInterface subWeekdays(int $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subWeekdays(int|float $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subWeekday() Sub one weekday to the instance (using date interval). - * @method CarbonInterface addRealMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMicro() Add one microsecond to the instance (using timestamp). - * @method CarbonInterface subRealMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMicro() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonInterface addRealMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMicrosecond() Add one microsecond to the instance (using timestamp). - * @method CarbonInterface subRealMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMicrosecond() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonInterface addRealMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMilli() Add one millisecond to the instance (using timestamp). - * @method CarbonInterface subRealMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMilli() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonInterface addRealMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMillisecond() Add one millisecond to the instance (using timestamp). - * @method CarbonInterface subRealMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMillisecond() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonInterface addRealSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealSecond() Add one second to the instance (using timestamp). - * @method CarbonInterface subRealSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealSecond() Sub one second to the instance (using timestamp). - * @method CarbonPeriod secondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. - * @method CarbonInterface addRealMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMinute() Add one minute to the instance (using timestamp). - * @method CarbonInterface subRealMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMinute() Sub one minute to the instance (using timestamp). - * @method CarbonPeriod minutesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. - * @method CarbonInterface addRealHours(int $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealHour() Add one hour to the instance (using timestamp). - * @method CarbonInterface subRealHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealHour() Sub one hour to the instance (using timestamp). - * @method CarbonPeriod hoursUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. - * @method CarbonInterface addRealDays(int $value = 1) Add days (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealDay() Add one day to the instance (using timestamp). - * @method CarbonInterface subRealDays(int $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealDay() Sub one day to the instance (using timestamp). - * @method CarbonPeriod daysUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. - * @method CarbonInterface addRealWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealWeek() Add one week to the instance (using timestamp). - * @method CarbonInterface subRealWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealWeek() Sub one week to the instance (using timestamp). - * @method CarbonPeriod weeksUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. - * @method CarbonInterface addRealMonths(int $value = 1) Add months (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMonth() Add one month to the instance (using timestamp). - * @method CarbonInterface subRealMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMonth() Sub one month to the instance (using timestamp). - * @method CarbonPeriod monthsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. - * @method CarbonInterface addRealQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealQuarter() Add one quarter to the instance (using timestamp). - * @method CarbonInterface subRealQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealQuarter() Sub one quarter to the instance (using timestamp). - * @method CarbonPeriod quartersUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. - * @method CarbonInterface addRealYears(int $value = 1) Add years (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealYear() Add one year to the instance (using timestamp). - * @method CarbonInterface subRealYears(int $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealYear() Sub one year to the instance (using timestamp). - * @method CarbonPeriod yearsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. - * @method CarbonInterface addRealDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealDecade() Add one decade to the instance (using timestamp). - * @method CarbonInterface subRealDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealDecade() Sub one decade to the instance (using timestamp). - * @method CarbonPeriod decadesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. - * @method CarbonInterface addRealCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealCentury() Add one century to the instance (using timestamp). - * @method CarbonInterface subRealCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealCentury() Sub one century to the instance (using timestamp). - * @method CarbonPeriod centuriesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. - * @method CarbonInterface addRealMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMillennium() Add one millennium to the instance (using timestamp). - * @method CarbonInterface subRealMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMillennium() Sub one millennium to the instance (using timestamp). - * @method CarbonPeriod millenniaUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method CarbonInterface addUTCMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMicro() Add one microsecond to the instance (using timestamp). + * @method CarbonInterface subUTCMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMicro() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicros(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonInterface addUTCMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMicrosecond() Add one microsecond to the instance (using timestamp). + * @method CarbonInterface subUTCMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMicrosecond() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicroseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonInterface addUTCMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMilli() Add one millisecond to the instance (using timestamp). + * @method CarbonInterface subUTCMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMilli() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMillis(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonInterface addUTCMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMillisecond() Add one millisecond to the instance (using timestamp). + * @method CarbonInterface subUTCMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMillisecond() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMilliseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonInterface addUTCSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCSecond() Add one second to the instance (using timestamp). + * @method CarbonInterface subUTCSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCSecond() Sub one second to the instance (using timestamp). + * @method CarbonPeriod secondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. + * @method float diffInUTCSeconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of seconds. + * @method CarbonInterface addUTCMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMinute() Add one minute to the instance (using timestamp). + * @method CarbonInterface subUTCMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMinute() Sub one minute to the instance (using timestamp). + * @method CarbonPeriod minutesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. + * @method float diffInUTCMinutes(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of minutes. + * @method CarbonInterface addUTCHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCHour() Add one hour to the instance (using timestamp). + * @method CarbonInterface subUTCHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCHour() Sub one hour to the instance (using timestamp). + * @method CarbonPeriod hoursUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. + * @method float diffInUTCHours(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of hours. + * @method CarbonInterface addUTCDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCDay() Add one day to the instance (using timestamp). + * @method CarbonInterface subUTCDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCDay() Sub one day to the instance (using timestamp). + * @method CarbonPeriod daysUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. + * @method float diffInUTCDays(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of days. + * @method CarbonInterface addUTCWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCWeek() Add one week to the instance (using timestamp). + * @method CarbonInterface subUTCWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCWeek() Sub one week to the instance (using timestamp). + * @method CarbonPeriod weeksUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. + * @method float diffInUTCWeeks(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of weeks. + * @method CarbonInterface addUTCMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMonth() Add one month to the instance (using timestamp). + * @method CarbonInterface subUTCMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMonth() Sub one month to the instance (using timestamp). + * @method CarbonPeriod monthsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. + * @method float diffInUTCMonths(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of months. + * @method CarbonInterface addUTCQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCQuarter() Add one quarter to the instance (using timestamp). + * @method CarbonInterface subUTCQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCQuarter() Sub one quarter to the instance (using timestamp). + * @method CarbonPeriod quartersUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. + * @method float diffInUTCQuarters(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of quarters. + * @method CarbonInterface addUTCYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCYear() Add one year to the instance (using timestamp). + * @method CarbonInterface subUTCYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCYear() Sub one year to the instance (using timestamp). + * @method CarbonPeriod yearsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. + * @method float diffInUTCYears(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of years. + * @method CarbonInterface addUTCDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCDecade() Add one decade to the instance (using timestamp). + * @method CarbonInterface subUTCDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCDecade() Sub one decade to the instance (using timestamp). + * @method CarbonPeriod decadesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. + * @method float diffInUTCDecades(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of decades. + * @method CarbonInterface addUTCCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCCentury() Add one century to the instance (using timestamp). + * @method CarbonInterface subUTCCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCCentury() Sub one century to the instance (using timestamp). + * @method CarbonPeriod centuriesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. + * @method float diffInUTCCenturies(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of centuries. + * @method CarbonInterface addUTCMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMillennium() Add one millennium to the instance (using timestamp). + * @method CarbonInterface subUTCMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMillennium() Sub one millennium to the instance (using timestamp). + * @method CarbonPeriod millenniaUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method float diffInUTCMillennia(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of millennia. * @method CarbonInterface roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method CarbonInterface roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method CarbonInterface floorYear(float $precision = 1) Truncate the current instance year with given precision. @@ -514,8 +692,164 @@ use Throwable; * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method int centuriesInMillennium() Return the number of centuries contained in the current millennium + * @method int|static centuryOfMillennium(?int $century = null) Return the value of the century starting from the beginning of the current millennium when called with no parameters, change the current century when called with an integer value + * @method int|static dayOfCentury(?int $day = null) Return the value of the day starting from the beginning of the current century when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfDecade(?int $day = null) Return the value of the day starting from the beginning of the current decade when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMillennium(?int $day = null) Return the value of the day starting from the beginning of the current millennium when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMonth(?int $day = null) Return the value of the day starting from the beginning of the current month when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfQuarter(?int $day = null) Return the value of the day starting from the beginning of the current quarter when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfWeek(?int $day = null) Return the value of the day starting from the beginning of the current week when called with no parameters, change the current day when called with an integer value + * @method int daysInCentury() Return the number of days contained in the current century + * @method int daysInDecade() Return the number of days contained in the current decade + * @method int daysInMillennium() Return the number of days contained in the current millennium + * @method int daysInMonth() Return the number of days contained in the current month + * @method int daysInQuarter() Return the number of days contained in the current quarter + * @method int daysInWeek() Return the number of days contained in the current week + * @method int daysInYear() Return the number of days contained in the current year + * @method int|static decadeOfCentury(?int $decade = null) Return the value of the decade starting from the beginning of the current century when called with no parameters, change the current decade when called with an integer value + * @method int|static decadeOfMillennium(?int $decade = null) Return the value of the decade starting from the beginning of the current millennium when called with no parameters, change the current decade when called with an integer value + * @method int decadesInCentury() Return the number of decades contained in the current century + * @method int decadesInMillennium() Return the number of decades contained in the current millennium + * @method int|static hourOfCentury(?int $hour = null) Return the value of the hour starting from the beginning of the current century when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDay(?int $hour = null) Return the value of the hour starting from the beginning of the current day when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDecade(?int $hour = null) Return the value of the hour starting from the beginning of the current decade when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMillennium(?int $hour = null) Return the value of the hour starting from the beginning of the current millennium when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMonth(?int $hour = null) Return the value of the hour starting from the beginning of the current month when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfQuarter(?int $hour = null) Return the value of the hour starting from the beginning of the current quarter when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfWeek(?int $hour = null) Return the value of the hour starting from the beginning of the current week when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfYear(?int $hour = null) Return the value of the hour starting from the beginning of the current year when called with no parameters, change the current hour when called with an integer value + * @method int hoursInCentury() Return the number of hours contained in the current century + * @method int hoursInDay() Return the number of hours contained in the current day + * @method int hoursInDecade() Return the number of hours contained in the current decade + * @method int hoursInMillennium() Return the number of hours contained in the current millennium + * @method int hoursInMonth() Return the number of hours contained in the current month + * @method int hoursInQuarter() Return the number of hours contained in the current quarter + * @method int hoursInWeek() Return the number of hours contained in the current week + * @method int hoursInYear() Return the number of hours contained in the current year + * @method int|static microsecondOfCentury(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current century when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDay(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current day when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDecade(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current decade when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfHour(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current hour when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillennium(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millennium when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillisecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millisecond when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMinute(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current minute when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMonth(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current month when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfQuarter(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current quarter when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfSecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current second when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfWeek(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current week when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfYear(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current year when called with no parameters, change the current microsecond when called with an integer value + * @method int microsecondsInCentury() Return the number of microseconds contained in the current century + * @method int microsecondsInDay() Return the number of microseconds contained in the current day + * @method int microsecondsInDecade() Return the number of microseconds contained in the current decade + * @method int microsecondsInHour() Return the number of microseconds contained in the current hour + * @method int microsecondsInMillennium() Return the number of microseconds contained in the current millennium + * @method int microsecondsInMillisecond() Return the number of microseconds contained in the current millisecond + * @method int microsecondsInMinute() Return the number of microseconds contained in the current minute + * @method int microsecondsInMonth() Return the number of microseconds contained in the current month + * @method int microsecondsInQuarter() Return the number of microseconds contained in the current quarter + * @method int microsecondsInSecond() Return the number of microseconds contained in the current second + * @method int microsecondsInWeek() Return the number of microseconds contained in the current week + * @method int microsecondsInYear() Return the number of microseconds contained in the current year + * @method int|static millisecondOfCentury(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current century when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDay(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current day when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDecade(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current decade when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfHour(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current hour when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMillennium(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current millennium when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMinute(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current minute when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMonth(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current month when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfQuarter(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current quarter when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfSecond(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current second when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfWeek(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current week when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfYear(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current year when called with no parameters, change the current millisecond when called with an integer value + * @method int millisecondsInCentury() Return the number of milliseconds contained in the current century + * @method int millisecondsInDay() Return the number of milliseconds contained in the current day + * @method int millisecondsInDecade() Return the number of milliseconds contained in the current decade + * @method int millisecondsInHour() Return the number of milliseconds contained in the current hour + * @method int millisecondsInMillennium() Return the number of milliseconds contained in the current millennium + * @method int millisecondsInMinute() Return the number of milliseconds contained in the current minute + * @method int millisecondsInMonth() Return the number of milliseconds contained in the current month + * @method int millisecondsInQuarter() Return the number of milliseconds contained in the current quarter + * @method int millisecondsInSecond() Return the number of milliseconds contained in the current second + * @method int millisecondsInWeek() Return the number of milliseconds contained in the current week + * @method int millisecondsInYear() Return the number of milliseconds contained in the current year + * @method int|static minuteOfCentury(?int $minute = null) Return the value of the minute starting from the beginning of the current century when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDay(?int $minute = null) Return the value of the minute starting from the beginning of the current day when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDecade(?int $minute = null) Return the value of the minute starting from the beginning of the current decade when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfHour(?int $minute = null) Return the value of the minute starting from the beginning of the current hour when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMillennium(?int $minute = null) Return the value of the minute starting from the beginning of the current millennium when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMonth(?int $minute = null) Return the value of the minute starting from the beginning of the current month when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfQuarter(?int $minute = null) Return the value of the minute starting from the beginning of the current quarter when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfWeek(?int $minute = null) Return the value of the minute starting from the beginning of the current week when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfYear(?int $minute = null) Return the value of the minute starting from the beginning of the current year when called with no parameters, change the current minute when called with an integer value + * @method int minutesInCentury() Return the number of minutes contained in the current century + * @method int minutesInDay() Return the number of minutes contained in the current day + * @method int minutesInDecade() Return the number of minutes contained in the current decade + * @method int minutesInHour() Return the number of minutes contained in the current hour + * @method int minutesInMillennium() Return the number of minutes contained in the current millennium + * @method int minutesInMonth() Return the number of minutes contained in the current month + * @method int minutesInQuarter() Return the number of minutes contained in the current quarter + * @method int minutesInWeek() Return the number of minutes contained in the current week + * @method int minutesInYear() Return the number of minutes contained in the current year + * @method int|static monthOfCentury(?int $month = null) Return the value of the month starting from the beginning of the current century when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfDecade(?int $month = null) Return the value of the month starting from the beginning of the current decade when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfMillennium(?int $month = null) Return the value of the month starting from the beginning of the current millennium when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfQuarter(?int $month = null) Return the value of the month starting from the beginning of the current quarter when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfYear(?int $month = null) Return the value of the month starting from the beginning of the current year when called with no parameters, change the current month when called with an integer value + * @method int monthsInCentury() Return the number of months contained in the current century + * @method int monthsInDecade() Return the number of months contained in the current decade + * @method int monthsInMillennium() Return the number of months contained in the current millennium + * @method int monthsInQuarter() Return the number of months contained in the current quarter + * @method int monthsInYear() Return the number of months contained in the current year + * @method int|static quarterOfCentury(?int $quarter = null) Return the value of the quarter starting from the beginning of the current century when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfDecade(?int $quarter = null) Return the value of the quarter starting from the beginning of the current decade when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfMillennium(?int $quarter = null) Return the value of the quarter starting from the beginning of the current millennium when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfYear(?int $quarter = null) Return the value of the quarter starting from the beginning of the current year when called with no parameters, change the current quarter when called with an integer value + * @method int quartersInCentury() Return the number of quarters contained in the current century + * @method int quartersInDecade() Return the number of quarters contained in the current decade + * @method int quartersInMillennium() Return the number of quarters contained in the current millennium + * @method int quartersInYear() Return the number of quarters contained in the current year + * @method int|static secondOfCentury(?int $second = null) Return the value of the second starting from the beginning of the current century when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDay(?int $second = null) Return the value of the second starting from the beginning of the current day when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDecade(?int $second = null) Return the value of the second starting from the beginning of the current decade when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfHour(?int $second = null) Return the value of the second starting from the beginning of the current hour when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMillennium(?int $second = null) Return the value of the second starting from the beginning of the current millennium when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMinute(?int $second = null) Return the value of the second starting from the beginning of the current minute when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMonth(?int $second = null) Return the value of the second starting from the beginning of the current month when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfQuarter(?int $second = null) Return the value of the second starting from the beginning of the current quarter when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfWeek(?int $second = null) Return the value of the second starting from the beginning of the current week when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfYear(?int $second = null) Return the value of the second starting from the beginning of the current year when called with no parameters, change the current second when called with an integer value + * @method int secondsInCentury() Return the number of seconds contained in the current century + * @method int secondsInDay() Return the number of seconds contained in the current day + * @method int secondsInDecade() Return the number of seconds contained in the current decade + * @method int secondsInHour() Return the number of seconds contained in the current hour + * @method int secondsInMillennium() Return the number of seconds contained in the current millennium + * @method int secondsInMinute() Return the number of seconds contained in the current minute + * @method int secondsInMonth() Return the number of seconds contained in the current month + * @method int secondsInQuarter() Return the number of seconds contained in the current quarter + * @method int secondsInWeek() Return the number of seconds contained in the current week + * @method int secondsInYear() Return the number of seconds contained in the current year + * @method int|static weekOfCentury(?int $week = null) Return the value of the week starting from the beginning of the current century when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfDecade(?int $week = null) Return the value of the week starting from the beginning of the current decade when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMillennium(?int $week = null) Return the value of the week starting from the beginning of the current millennium when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMonth(?int $week = null) Return the value of the week starting from the beginning of the current month when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfQuarter(?int $week = null) Return the value of the week starting from the beginning of the current quarter when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfYear(?int $week = null) Return the value of the week starting from the beginning of the current year when called with no parameters, change the current week when called with an integer value + * @method int weeksInCentury() Return the number of weeks contained in the current century + * @method int weeksInDecade() Return the number of weeks contained in the current decade + * @method int weeksInMillennium() Return the number of weeks contained in the current millennium + * @method int weeksInMonth() Return the number of weeks contained in the current month + * @method int weeksInQuarter() Return the number of weeks contained in the current quarter + * @method int|static yearOfCentury(?int $year = null) Return the value of the year starting from the beginning of the current century when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfDecade(?int $year = null) Return the value of the year starting from the beginning of the current decade when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfMillennium(?int $year = null) Return the value of the year starting from the beginning of the current millennium when called with no parameters, change the current year when called with an integer value + * @method int yearsInCentury() Return the number of years contained in the current century + * @method int yearsInDecade() Return the number of years contained in the current decade + * @method int yearsInMillennium() Return the number of years contained in the current millennium * * + * + * @codeCoverageIgnore */ interface CarbonInterface extends DateTimeInterface, JsonSerializable { @@ -581,7 +915,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Number of X in Y. */ - public const YEARS_PER_MILLENNIUM = 1000; + public const YEARS_PER_MILLENNIUM = 1_000; public const YEARS_PER_CENTURY = 100; public const YEARS_PER_DECADE = 10; public const MONTHS_PER_YEAR = 12; @@ -594,9 +928,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable public const HOURS_PER_DAY = 24; public const MINUTES_PER_HOUR = 60; public const SECONDS_PER_MINUTE = 60; - public const MILLISECONDS_PER_SECOND = 1000; - public const MICROSECONDS_PER_MILLISECOND = 1000; - public const MICROSECONDS_PER_SECOND = 1000000; + public const MILLISECONDS_PER_SECOND = 1_000; + public const MICROSECONDS_PER_MILLISECOND = 1_000; + public const MICROSECONDS_PER_SECOND = 1_000_000; /** * Special settings to get the start of week from current locale culture. @@ -631,6 +965,13 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public const ISO_FORMAT_REGEXP = '(O[YMDHhms]|[Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY?|g{1,5}|G{1,5}|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?)'; + /** + * Default locale (language and region). + * + * @var string + */ + public const DEFAULT_LOCALE = 'en'; + // /** @@ -640,10 +981,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param array $parameters parameters list * * @throws UnknownMethodException|BadMethodCallException|ReflectionException|Throwable - * - * @return mixed */ - public function __call($method, $parameters); + public function __call(string $method, array $parameters): mixed; /** * Dynamically handle calls to the class. @@ -652,15 +991,13 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param array $parameters parameters list * * @throws BadMethodCallException - * - * @return mixed */ - public static function __callStatic($method, $parameters); + public static function __callStatic(string $method, array $parameters): mixed; /** * Update constructedObjectId on cloned. */ - public function __clone(); + public function __clone(): void; /** * Create a new Carbon instance. @@ -668,30 +1005,23 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Please see the testing aids section (specifically static::setTestNow()) * for more on the possibility of this constructor returning a test instance. * - * @param DateTimeInterface|string|null $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException */ - public function __construct($time = null, $tz = null); + public function __construct(DateTimeInterface|WeekDay|Month|string|int|float|null $time = null, DateTimeZone|string|int|null $timezone = null); /** * Show truthy properties on var_dump(). - * - * @return array */ - public function __debugInfo(); + public function __debugInfo(): array; /** - * Get a part of the Carbon object - * - * @param string $name + * Get a part of the Carbon object. * * @throws UnknownGetterException * * @return string|int|bool|DateTimeZone|null */ - public function __get($name); + public function __get(string $name): mixed; /** * Check if an attribute exists on the object @@ -722,7 +1052,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @return static */ #[ReturnTypeWillChange] - public static function __set_state($dump); + public static function __set_state($dump): static; /** * Returns the list of properties to dump on serialize() called on. @@ -740,8 +1070,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now(); // Carbon instances can be cast to string * ``` - * - * @return string */ public function __toString(); @@ -752,36 +1080,43 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @example $date->add(15, 'days') * @example $date->add(CarbonInterval::days(4)) * - * @param string|DateInterval|Closure|CarbonConverterInterface $unit - * @param int $value - * @param bool|null $overflow + * @param Unit|string|DateInterval|Closure|CarbonConverterInterface $unit + * @param int|float $value + * @param bool|null $overflow * * @return static */ #[ReturnTypeWillChange] - public function add($unit, $value = 1, $overflow = null); + public function add($unit, $value = 1, ?bool $overflow = null): static; + + /** + * @deprecated Prefer to use add addUTCUnit() which more accurately defines what it's doing. + * + * Add seconds to the instance using timestamp. Positive $value travels + * forward while negative $value travels into the past. + * + * @param string $unit + * @param int|float|null $value + * + * @return static + */ + public function addRealUnit(string $unit, $value = 1): static; /** * Add seconds to the instance using timestamp. Positive $value travels * forward while negative $value travels into the past. * - * @param string $unit - * @param int $value + * @param string $unit + * @param int|float|null $value * * @return static */ - public function addRealUnit($unit, $value = 1); + public function addUTCUnit(string $unit, $value = 1): static; /** * Add given units to the current instance. - * - * @param string $unit - * @param int $value - * @param bool|null $overflow - * - * @return static */ - public function addUnit($unit, $value = 1, $overflow = null); + public function addUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static; /** * Add any unit to a new value without overflowing current other unit given. @@ -789,10 +1124,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string $valueUnit unit name to modify * @param int $value amount to add to the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function addUnitNoOverflow($valueUnit, $value, $overflowUnit); + public function addUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static; /** * Get the difference in a human readable format in the current locale from an other @@ -842,7 +1175,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return static */ - public function avoidMutation(); + public function avoidMutation(): static; /** * Determines if the instance is between two others. @@ -859,13 +1192,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01', false); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * @param bool $equal Indicates if an equal to comparison should be done - * - * @return bool + * @param bool $equal Indicates if an equal to comparison should be done */ - public function between($date1, $date2, $equal = true): bool; + public function between(DateTimeInterface|string $date1, DateTimeInterface|string $date2, bool $equal = true): bool; /** * Determines if the instance is between two others, bounds excluded. @@ -876,13 +1205,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25')->betweenExcluded('2018-08-01', '2018-08-20'); // false * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-25', '2018-08-01'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * - * @return bool */ - public function betweenExcluded($date1, $date2): bool; + public function betweenExcluded(DateTimeInterface|string $date1, DateTimeInterface|string $date2): bool; /** * Determines if the instance is between two others, bounds included. @@ -893,13 +1217,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25')->betweenIncluded('2018-08-01', '2018-08-20'); // false * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-25', '2018-08-01'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * - * @return bool */ - public function betweenIncluded($date1, $date2): bool; + public function betweenIncluded(DateTimeInterface|string $date1, DateTimeInterface|string $date2): bool; /** * Returns either day of week + time (e.g. "Last Friday at 3:30 PM") if reference time is within 7 days, @@ -923,13 +1242,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::canBeCreatedFromFormat('11:12:45', 'h:i:s'); // true * Carbon::canBeCreatedFromFormat('13:12:45', 'h:i:s'); // false * ``` - * - * @param string $date - * @param string $format - * - * @return bool */ - public static function canBeCreatedFromFormat($date, $format); + public static function canBeCreatedFromFormat(?string $date, string $format): bool; /** * Return the Carbon instance passed through, a now instance in the same timezone @@ -944,39 +1258,30 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Cast the current instance into the given class. * - * @param string $className The $className::instance() method will be called to cast the current object. + * @template T * - * @return DateTimeInterface + * @param class-string $className The $className::instance() method will be called to cast the current object. + * + * @return T */ - public function cast(string $className); + public function cast(string $className): mixed; /** * Ceil the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * - * @return CarbonInterface */ - public function ceil($precision = 1); + public function ceil(DateInterval|string|int|float $precision = 1): static; /** * Ceil the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int $precision - * - * @return CarbonInterface */ - public function ceilUnit($unit, $precision = 1); + public function ceilUnit(string $unit, DateInterval|string|int|float $precision = 1): static; /** * Ceil the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function ceilWeek($weekStartsAt = null); + public function ceilWeek(WeekDay|int|null $weekStartsAt = null): static; /** * Similar to native modify() method of DateTime but can handle more grammars. @@ -990,7 +1295,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param string $modifier * - * @return static|false + * @return static */ public function change($modifier); @@ -1041,140 +1346,125 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * If $hour is not null then the default values for $minute and $second * will be 0. * - * @param DateTimeInterface|int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param DateTimeInterface|string|int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null); + public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null); /** * Create a Carbon instance from just a date. The time portion is set to now. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createFromDate($year = null, $month = null, $day = null, $tz = null); + public static function createFromDate($year = null, $month = null, $day = null, $timezone = null); /** * Create a Carbon instance from a specific format. * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ #[ReturnTypeWillChange] - public static function createFromFormat($format, $time, $tz = null); + public static function createFromFormat($format, $time, $timezone = null); /** * Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz optional timezone - * @param string|null $locale locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use) - * @param \Symfony\Component\Translation\TranslatorInterface $translator optional custom translator to use for macro-formats + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone optional timezone + * @param string|null $locale locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use) + * @param TranslatorInterface|null $translator optional custom translator to use for macro-formats * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null); + public static function createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null); /** * Create a Carbon instance from a specific format and a string in a given language. * - * @param string $format Datetime format - * @param string $locale - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $locale + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromLocaleFormat($format, $locale, $time, $tz = null); + public static function createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null); /** * Create a Carbon instance from a specific ISO format and a string in a given language. * - * @param string $format Datetime ISO format - * @param string $locale - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime ISO format + * @param string $locale + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromLocaleIsoFormat($format, $locale, $time, $tz = null); + public static function createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null); /** * Create a Carbon instance from just a time. The date portion is set to today. * - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null); + public static function createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null): static; /** * Create a Carbon instance from a time string. The date portion is set to today. * - * @param string $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function createFromTimeString($time, $tz = null); + public static function createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null): static; /** - * Create a Carbon instance from a timestamp and set the timezone (use default one if not specified). + * Create a Carbon instance from a timestamp and set the timezone (UTC by default). * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $timestamp - * @param \DateTimeZone|string|null $tz - * - * @return static */ - public static function createFromTimestamp($timestamp, $tz = null); + public static function createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null): static; /** * Create a Carbon instance from a timestamp in milliseconds. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $timestamp - * @param \DateTimeZone|string|null $tz - * - * @return static */ - public static function createFromTimestampMs($timestamp, $tz = null); + public static function createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null): static; /** * Create a Carbon instance from a timestamp in milliseconds. @@ -1185,32 +1475,28 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return static */ - public static function createFromTimestampMsUTC($timestamp); + public static function createFromTimestampMsUTC($timestamp): static; /** - * Create a Carbon instance from an timestamp keeping the timezone to UTC. + * Create a Carbon instance from a timestamp keeping the timezone to UTC. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $timestamp - * - * @return static */ - public static function createFromTimestampUTC($timestamp); + public static function createFromTimestampUTC(string|int|float $timestamp): static; /** * Create a Carbon instance from just a date. The time portion is set to midnight. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createMidnightDate($year = null, $month = null, $day = null, $tz = null); + public static function createMidnightDate($year = null, $month = null, $day = null, $timezone = null); /** * Create a new safe Carbon instance from a specific date and time. @@ -1227,47 +1513,53 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * If one of the set values is not valid, an InvalidDateException * will be thrown. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidDateException * - * @return static|false + * @return static|null */ - public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null); + public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null); /** * Create a new Carbon instance from a specific date and time using strict validation. * * @see create() * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null); + public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null): static; /** * Get/set the day of year. * + * @template T of int|null + * * @param int|null $value new value for day of year if using as setter. * + * @psalm-param T $value + * * @return static|int + * + * @psalm-return (T is int ? static : int) */ - public function dayOfYear($value = null); + public function dayOfYear(?int $value = null): static|int; /** * Get the difference as a CarbonInterval instance. @@ -1279,7 +1571,19 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return CarbonInterval */ - public function diffAsCarbonInterval($date = null, $absolute = true, array $skip = []); + public function diffAsCarbonInterval($date = null, bool $absolute = false, array $skip = []): CarbonInterval; + + /** + * Get the difference as a DateInterval instance. + * Return relative interval (negative if $absolute flag is not set to true and the given date is before + * current one). + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * + * @return DateInterval + */ + public function diffAsDateInterval($date = null, bool $absolute = false): DateInterval; /** * Get the difference by the given interval using a filter closure. @@ -1291,7 +1595,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return int */ - public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true); + public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, bool $absolute = false): int; /** * Get the difference in a human readable format in the current locale from current instance to an other @@ -1306,54 +1610,58 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . "\n"; * ``` * - * @param Carbon|\DateTimeInterface|string|array|null $other if array passed, will be used as parameters array, see $syntax below; - * if null passed, now will be used as comparison reference; - * if any other type, it will be converted to date and used as reference. - * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contains: - * - 'syntax' entry (see below) - * - 'short' entry (see below) - * - 'parts' entry (see below) - * - 'options' entry (see below) - * - 'skip' entry, list of units to skip (array of strings or a single string, - * ` it can be the unit name (singular or plural) or its shortcut - * ` (y, m, w, d, h, min, s, ms, µs). - * - 'aUnit' entry, prefer "an hour" over "1 hour" if true - * - 'join' entry determines how to join multiple parts of the string - * ` - if $join is a string, it's used as a joiner glue - * ` - if $join is a callable/closure, it get the list of string and should return a string - * ` - if $join is an array, the first item will be the default glue, and the second item - * ` will be used instead of the glue for the last item - * ` - if $join is true, it will be guessed from the locale ('list' translation file entry) - * ` - if $join is missing, a space will be used as glue - * - 'other' entry (see above) - * - 'minimumUnit' entry determines the smallest unit of time to display can be long or - * ` short form of the units, e.g. 'hour' or 'h' (default value: s) - * if int passed, it add modifiers: - * Possible values: - * - CarbonInterface::DIFF_ABSOLUTE no modifiers - * - CarbonInterface::DIFF_RELATIVE_TO_NOW add ago/from now modifier - * - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier - * Default value: CarbonInterface::DIFF_ABSOLUTE - * @param bool $short displays short format of time units - * @param int $parts maximum number of parts to display (default value: 1: single unit) - * @param int $options human diff options - * - * @return string + * @param Carbon|DateTimeInterface|string|array|null $other if array passed, will be used as parameters array, see $syntax below; + * if null passed, now will be used as comparison reference; + * if any other type, it will be converted to date and used as reference. + * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contains: + * ⦿ 'syntax' entry (see below) + * ⦿ 'short' entry (see below) + * ⦿ 'parts' entry (see below) + * ⦿ 'options' entry (see below) + * ⦿ 'skip' entry, list of units to skip (array of strings or a single string, + * ` it can be the unit name (singular or plural) or its shortcut + * ` (y, m, w, d, h, min, s, ms, µs). + * ⦿ 'aUnit' entry, prefer "an hour" over "1 hour" if true + * ⦿ 'altNumbers' entry, use alternative numbers if available + * ` (from the current language if true is passed, from the given language(s) + * ` if array or string is passed) + * ⦿ 'join' entry determines how to join multiple parts of the string + * ` - if $join is a string, it's used as a joiner glue + * ` - if $join is a callable/closure, it get the list of string and should return a string + * ` - if $join is an array, the first item will be the default glue, and the second item + * ` will be used instead of the glue for the last item + * ` - if $join is true, it will be guessed from the locale ('list' translation file entry) + * ` - if $join is missing, a space will be used as glue + * ⦿ 'other' entry (see above) + * ⦿ 'minimumUnit' entry determines the smallest unit of time to display can be long or + * ` short form of the units, e.g. 'hour' or 'h' (default value: s) + * ⦿ 'locale' language in which the diff should be output (has no effect if 'translator' key is set) + * ⦿ 'translator' a custom translator to use to translator the output. + * if int passed, it adds modifiers: + * Possible values: + * - CarbonInterface::DIFF_ABSOLUTE no modifiers + * - CarbonInterface::DIFF_RELATIVE_TO_NOW add ago/from now modifier + * - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier + * Default value: CarbonInterface::DIFF_ABSOLUTE + * @param bool $short displays short format of time units + * @param int $parts maximum number of parts to display (default value: 1: single unit) + * @param int $options human diff options */ - public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null); + public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null): string; /** - * Get the difference in days rounded down. + * Get the difference in days. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInDays($date = null, $absolute = true); + public function diffInDays($date = null, bool $absolute = false, bool $utc = false): float; /** - * Get the difference in days using a filter closure rounded down. + * Get the difference in days using a filter closure. * * @param Closure $callback * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date @@ -1361,20 +1669,20 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return int */ - public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true); + public function diffInDaysFiltered(Closure $callback, $date = null, bool $absolute = false): int; /** - * Get the difference in hours rounded down. + * Get the difference in hours. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInHours($date = null, $absolute = true); + public function diffInHours($date = null, bool $absolute = false): float; /** - * Get the difference in hours using a filter closure rounded down. + * Get the difference in hours using a filter closure. * * @param Closure $callback * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date @@ -1382,7 +1690,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return int */ - public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true); + public function diffInHoursFiltered(Closure $callback, $date = null, bool $absolute = false): int; /** * Get the difference in microseconds. @@ -1390,167 +1698,129 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInMicroseconds($date = null, $absolute = true); + public function diffInMicroseconds($date = null, bool $absolute = false): float; /** - * Get the difference in milliseconds rounded down. + * Get the difference in milliseconds. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * + * @return float + */ + public function diffInMilliseconds($date = null, bool $absolute = false): float; + + /** + * Get the difference in minutes. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * + * @return float + */ + public function diffInMinutes($date = null, bool $absolute = false): float; + + /** + * Get the difference in months. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInMonths($date = null, bool $absolute = false, bool $utc = false): float; + + /** + * Get the difference in quarters. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInQuarters($date = null, bool $absolute = false, bool $utc = false): float; + + /** + * Get the difference in seconds. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * + * @return float + */ + public function diffInSeconds($date = null, bool $absolute = false): float; + + /** + * @param Unit|string $unit microsecond, millisecond, second, minute, + * hour, day, week, month, quarter, year, + * century, millennium + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInUnit(Unit|string $unit, $date = null, bool $absolute = false, bool $utc = false): float; + + /** + * Get the difference in weekdays. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * * @return int */ - public function diffInMilliseconds($date = null, $absolute = true); + public function diffInWeekdays($date = null, bool $absolute = false): int; /** - * Get the difference in minutes rounded down. + * Get the difference in weekend days using a filter. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * * @return int */ - public function diffInMinutes($date = null, $absolute = true); + public function diffInWeekendDays($date = null, bool $absolute = false): int; /** - * Get the difference in months rounded down. + * Get the difference in weeks. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInMonths($date = null, $absolute = true); - - /** - * Get the difference in quarters rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInQuarters($date = null, $absolute = true); - - /** - * Get the difference in hours rounded down using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealHours($date = null, $absolute = true); - - /** - * Get the difference in microseconds using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMicroseconds($date = null, $absolute = true); - - /** - * Get the difference in milliseconds rounded down using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMilliseconds($date = null, $absolute = true); - - /** - * Get the difference in minutes rounded down using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMinutes($date = null, $absolute = true); - - /** - * Get the difference in seconds using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealSeconds($date = null, $absolute = true); - - /** - * Get the difference in seconds rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInSeconds($date = null, $absolute = true); - - /** - * Get the difference in weekdays rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInWeekdays($date = null, $absolute = true); - - /** - * Get the difference in weekend days using a filter rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInWeekendDays($date = null, $absolute = true); - - /** - * Get the difference in weeks rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInWeeks($date = null, $absolute = true); + public function diffInWeeks($date = null, bool $absolute = false, bool $utc = false): float; /** * Get the difference in years * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInYears($date = null, $absolute = true); + public function diffInYears($date = null, bool $absolute = false, bool $utc = false): float; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. * You should rather use the ->settings() method. * @see settings - * - * @param int $humanDiffOption */ - public static function disableHumanDiffOption($humanDiffOption); + public static function disableHumanDiffOption(int $humanDiffOption): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. * You should rather use the ->settings() method. * @see settings - * - * @param int $humanDiffOption */ - public static function enableHumanDiffOption($humanDiffOption); + public static function enableHumanDiffOption(int $humanDiffOption): void; /** * Modify to end of current given unit. @@ -1558,16 +1828,11 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @example * ``` * echo Carbon::parse('2018-07-25 12:45:16.334455') - * ->startOf('month') - * ->endOf('week', Carbon::FRIDAY); + * ->startOf(Unit::Month) + * ->endOf(Unit::Week, Carbon::FRIDAY); * ``` - * - * @param string $unit - * @param array $params - * - * @return static */ - public function endOf($unit, ...$params); + public function endOf(Unit|string $unit, mixed ...$params): static; /** * Resets the date to end of the century and time to 23:59:59.999999 @@ -1612,10 +1877,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::parse('2018-07-25 12:45:16')->endOfHour(); * ``` - * - * @return static */ - public function endOfHour(); + public function endOfHour(): static; /** * Resets the date to end of the millennium and time to 23:59:59.999999 @@ -1629,6 +1892,18 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function endOfMillennium(); + /** + * Modify to end of current millisecond, microseconds such as 12345 become 123999 + * + * @example + * ``` + * echo Carbon::parse('2018-07-25 12:45:16.334455') + * ->endOfSecond() + * ->format('H:i:s.u'); + * ``` + */ + public function endOfMillisecond(): static; + /** * Modify to end of current minute, seconds become 59 * @@ -1636,10 +1911,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::parse('2018-07-25 12:45:16')->endOfMinute(); * ``` - * - * @return static */ - public function endOfMinute(); + public function endOfMinute(): static; /** * Resets the date to end of the month and time to 23:59:59.999999 @@ -1674,10 +1947,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ->endOfSecond() * ->format('H:i:s.u'); * ``` - * - * @return static */ - public function endOfSecond(); + public function endOfSecond(): static; /** * Resets the date to end of week (defined in $weekEndsAt) and time to 23:59:59.999999 @@ -1689,11 +1960,11 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek(Carbon::SATURDAY) . "\n"; * ``` * - * @param int $weekEndsAt optional start allow you to specify the day of week to use to end the week + * @param WeekDay|int|null $weekEndsAt optional end allow you to specify the day of week to use to end the week * * @return static */ - public function endOfWeek($weekEndsAt = null); + public function endOfWeek(WeekDay|int|null $weekEndsAt = null): static; /** * Resets the date to end of the year and time to 23:59:59.999999 @@ -1717,13 +1988,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->eq('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see equalTo() - * - * @return bool */ - public function eq($date): bool; + public function eq(DateTimeInterface|string $date): bool; /** * Determines if the instance is equal to another @@ -1734,12 +2001,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->equalTo(Carbon::parse('2018-07-25 12:45:16')); // true * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function equalTo($date): bool; + public function equalTo(DateTimeInterface|string $date): bool; /** * Set the current locale to the given, execute the passed function, reset the locale to previous one, @@ -1750,7 +2013,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return mixed */ - public static function executeWithLocale($locale, $func); + public static function executeWithLocale(string $locale, callable $func): mixed; /** * Get the farthest date from the instance (second-precision). @@ -1798,187 +2061,22 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function firstOfYear($dayOfWeek = null); - /** - * Get the difference in days as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInDays($date = null, $absolute = true); - - /** - * Get the difference in hours as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInHours($date = null, $absolute = true); - - /** - * Get the difference in minutes as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInMinutes($date = null, $absolute = true); - - /** - * Get the difference in months as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInMonths($date = null, $absolute = true); - - /** - * Get the difference in days as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealDays($date = null, $absolute = true); - - /** - * Get the difference in hours as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealHours($date = null, $absolute = true); - - /** - * Get the difference in minutes as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealMinutes($date = null, $absolute = true); - - /** - * Get the difference in months as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealMonths($date = null, $absolute = true); - - /** - * Get the difference in seconds as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealSeconds($date = null, $absolute = true); - - /** - * Get the difference in weeks as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealWeeks($date = null, $absolute = true); - - /** - * Get the difference in year as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealYears($date = null, $absolute = true); - - /** - * Get the difference in seconds as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInSeconds($date = null, $absolute = true); - - /** - * Get the difference in weeks as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInWeeks($date = null, $absolute = true); - - /** - * Get the difference in year as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInYears($date = null, $absolute = true); - /** * Round the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * - * @return CarbonInterface */ - public function floor($precision = 1); + public function floor(DateInterval|string|int|float $precision = 1): static; /** * Truncate the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int $precision - * - * @return CarbonInterface */ - public function floorUnit($unit, $precision = 1); + public function floorUnit(string $unit, DateInterval|string|int|float $precision = 1): static; /** * Truncate the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function floorWeek($weekStartsAt = null); - - /** - * Format the instance with the current locale. You can set the current - * locale using setlocale() https://php.net/setlocale. - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat() instead. - * Deprecated since 2.55.0 - * - * @param string $format - * - * @return string - */ - public function formatLocalized($format); + public function floorWeek(WeekDay|int|null $weekStartsAt = null): static; /** * @alias diffForHumans @@ -2055,35 +2153,31 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return static */ - public static function fromSerialized($value); + public static function fromSerialized($value): static; /** * Register a custom macro. * - * @param object|callable $macro - * @param int $priority marco with higher priority is tried first + * @param callable $macro + * @param int $priority marco with higher priority is tried first * * @return void */ - public static function genericMacro($macro, $priority = 0); + public static function genericMacro(callable $macro, int $priority = 0): void; /** - * Get a part of the Carbon object - * - * @param string $name + * Get a part of the Carbon object. * * @throws UnknownGetterException * - * @return string|int|bool|DateTimeZone|null + * @return string|int|bool|DateTimeZone */ - public function get($name); + public function get(Unit|string $name): mixed; /** * Returns the alternative number for a given date property if available in the current locale. * * @param string $key date property - * - * @return string */ public function getAltNumber(string $key): string; @@ -2107,108 +2201,81 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Returns list of calendar formats for ISO formatting. * * @param string|null $locale current locale used if null - * - * @return array */ - public function getCalendarFormats($locale = null); + public function getCalendarFormats(?string $locale = null): array; + + public function getClock(): ?WrapperClock; /** - * Get the days of the week - * - * @return array + * Get the days of the week. */ - public static function getDays(); + public static function getDays(): array; /** * Return the number of days since the start of the week (using the current locale or the first parameter * if explicitly given). * - * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, - * if not provided, start of week is inferred from the locale - * (Sunday for en_US, Monday for de_DE, etc.) - * - * @return int + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, + * if not provided, start of week is inferred from the locale + * (Sunday for en_US, Monday for de_DE, etc.) */ - public function getDaysFromStartOfWeek(?int $weekStartsAt = null): int; + public function getDaysFromStartOfWeek(WeekDay|int|null $weekStartsAt = null): int; /** * Get the fallback locale. * * @see https://symfony.com/doc/current/components/translation.html#fallback-locales - * - * @return string|null */ - public static function getFallbackLocale(); + public static function getFallbackLocale(): ?string; /** * List of replacements from date() format to isoFormat(). - * - * @return array */ - public static function getFormatsToIsoReplacements(); + public static function getFormatsToIsoReplacements(): array; /** * Return default humanDiff() options (merged flags as integer). - * - * @return int */ - public static function getHumanDiffOptions(); + public static function getHumanDiffOptions(): int; /** * Returns list of locale formats for ISO formatting. * * @param string|null $locale current locale used if null - * - * @return array */ - public function getIsoFormats($locale = null); + public function getIsoFormats(?string $locale = null): array; /** * Returns list of locale units for ISO formatting. - * - * @return array */ - public static function getIsoUnits(); + public static function getIsoUnits(): array; /** * {@inheritdoc} - * - * @return array */ - #[ReturnTypeWillChange] - public static function getLastErrors(); + public static function getLastErrors(): array|false; /** * Get the raw callable macro registered globally or locally for a given name. - * - * @param string $name - * - * @return callable|null */ - public function getLocalMacro($name); + public function getLocalMacro(string $name): ?callable; /** * Get the translator of the current instance or the default if none set. - * - * @return \Symfony\Component\Translation\TranslatorInterface */ - public function getLocalTranslator(); + public function getLocalTranslator(): TranslatorInterface; /** * Get the current translator locale. * * @return string */ - public static function getLocale(); + public static function getLocale(): string; /** * Get the raw callable macro registered globally for a given name. - * - * @param string $name - * - * @return callable|null */ - public static function getMacro($name); + public static function getMacro(string $name): ?callable; /** * get midday/noon hour @@ -2224,10 +2291,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * like "-12:00". * * @param string $separator string to place between hours and minutes (":" by default) - * - * @return string */ - public function getOffsetString($separator = ':'); + public function getOffsetString(string $separator = ':'): string; /** * Returns a unit of the instance padded with 0 by default or any other string if specified. @@ -2236,10 +2301,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param int $length Length of the output (2 by default) * @param string $padString String to use for padding ("0" by default) * @param int $padType Side(s) to pad (STR_PAD_LEFT by default) - * - * @return string */ - public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = 0); + public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = 0): string; /** * Returns a timestamp rounded with the given precision (6 by default). @@ -2259,38 +2322,34 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return float */ - public function getPreciseTimestamp($precision = 6); + public function getPreciseTimestamp($precision = 6): float; /** * Returns current local settings. - * - * @return array */ - public function getSettings(); + public function getSettings(): array; /** * Get the Carbon instance (real or mock) to be returned when a "now" * instance is created. * - * @return Closure|static the current instance used for testing + * @return Closure|self|null the current instance used for testing */ - public static function getTestNow(); + public static function getTestNow(): Closure|self|null; /** * Return a format from H:i to H:i:s.u according to given unit precision. * * @param string $unitPrecision "minute", "second", "millisecond" or "microsecond" - * - * @return string */ - public static function getTimeFormatByPrecision($unitPrecision); + public static function getTimeFormatByPrecision(string $unitPrecision): string; /** * Returns the timestamp with millisecond precision. * * @return int */ - public function getTimestampMs(); + public function getTimestampMs(): int; /** * Get the translation of the current week day name (with context for languages with multiple forms). @@ -2298,19 +2357,15 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string|null $context whole format string * @param string $keySuffix "", "_short" or "_min" * @param string|null $defaultValue default value if translation missing - * - * @return string */ - public function getTranslatedDayName($context = null, $keySuffix = '', $defaultValue = null); + public function getTranslatedDayName(?string $context = null, string $keySuffix = '', ?string $defaultValue = null): string; /** * Get the translation of the current abbreviated week day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedMinDayName($context = null); + public function getTranslatedMinDayName(?string $context = null): string; /** * Get the translation of the current month day name (with context for languages with multiple forms). @@ -2318,36 +2373,30 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string|null $context whole format string * @param string $keySuffix "" or "_short" * @param string|null $defaultValue default value if translation missing - * - * @return string */ - public function getTranslatedMonthName($context = null, $keySuffix = '', $defaultValue = null); + public function getTranslatedMonthName(?string $context = null, string $keySuffix = '', ?string $defaultValue = null): string; /** * Get the translation of the current short week day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedShortDayName($context = null); + public function getTranslatedShortDayName(?string $context = null): string; /** * Get the translation of the current short month day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedShortMonthName($context = null); + public function getTranslatedShortMonthName(?string $context = null): string; /** * Returns raw translation message for a given key. * - * @param string $key key to find - * @param string|null $locale current locale used if null - * @param string|null $default default value if translation returns the key - * @param \Symfony\Component\Translation\TranslatorInterface $translator an optional translator to use + * @param string $key key to find + * @param string|null $locale current locale used if null + * @param string|null $default default value if translation returns the key + * @param TranslatorInterface $translator an optional translator to use * * @return string */ @@ -2356,42 +2405,40 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Returns raw translation message for a given key. * - * @param \Symfony\Component\Translation\TranslatorInterface $translator the translator to use - * @param string $key key to find - * @param string|null $locale current locale used if null - * @param string|null $default default value if translation returns the key + * @param TranslatorInterface|null $translator the translator to use + * @param string $key key to find + * @param string|null $locale current locale used if null + * @param string|null $default default value if translation returns the key * - * @return string + * @return string|Closure|null */ public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null); /** - * Get the default translator instance in use. - * - * @return \Symfony\Component\Translation\TranslatorInterface + * Initialize the default translator instance if necessary. */ - public static function getTranslator(); + public static function getTranslator(): TranslatorInterface; /** - * Get the last day of week + * Get the last day of week. + * + * @param string $locale local to consider the last day of week. * * @return int */ - public static function getWeekEndsAt(); + public static function getWeekEndsAt(?string $locale = null): int; /** - * Get the first day of week + * Get the first day of week. * * @return int */ - public static function getWeekStartsAt(); + public static function getWeekStartsAt(?string $locale = null): int; /** * Get weekend days - * - * @return array */ - public static function getWeekendDays(); + public static function getWeekendDays(): array; /** * Determines if the instance is greater (after) than another @@ -2402,12 +2449,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:16'); // false * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function greaterThan($date): bool; + public function greaterThan(DateTimeInterface|string $date): bool; /** * Determines if the instance is greater (after) than or equal to another @@ -2418,12 +2461,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:16'); // true * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function greaterThanOrEqualTo($date): bool; + public function greaterThanOrEqualTo(DateTimeInterface|string $date): bool; /** * Determines if the instance is greater (after) than another @@ -2435,13 +2474,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThan() - * - * @return bool */ - public function gt($date): bool; + public function gt(DateTimeInterface|string $date): bool; /** * Determines if the instance is greater (after) than or equal to another @@ -2453,13 +2488,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThanOrEqualTo() - * - * @return bool */ - public function gte($date): bool; + public function gte(DateTimeInterface|string $date): bool; /** * Checks if the (date)time string is in a given format. @@ -2469,13 +2500,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::hasFormat('11:12:45', 'h:i:s'); // true * Carbon::hasFormat('13:12:45', 'h:i:s'); // false * ``` - * - * @param string $date - * @param string $format - * - * @return bool */ - public static function hasFormat($date, $format); + public static function hasFormat(string $date, string $format): bool; /** * Checks if the (date)time string is in a given format. @@ -2491,23 +2517,17 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function hasFormatWithModifiers($date, $format): bool; + public static function hasFormatWithModifiers(?string $date, string $format): bool; /** * Checks if macro is registered globally or locally. - * - * @param string $name - * - * @return bool */ - public function hasLocalMacro($name); + public function hasLocalMacro(string $name): bool; /** * Return true if the current instance has its own translator. - * - * @return bool */ - public function hasLocalTranslator(); + public function hasLocalTranslator(): bool; /** * Checks if macro is registered globally. @@ -2516,16 +2536,14 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function hasMacro($name); + public static function hasMacro(string $name): bool; /** * Determine if a time string will produce a relative date. * - * @param string $time - * * @return bool true if time match a relative date, false if absolute or invalid time string */ - public static function hasRelativeKeywords($time); + public static function hasRelativeKeywords(?string $time): bool; /** * Determine if there is a valid test instance set. A valid test instance @@ -2533,16 +2551,12 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool true if there is a test instance, otherwise false */ - public static function hasTestNow(); + public static function hasTestNow(): bool; /** * Create a Carbon instance from a DateTime one. - * - * @param DateTimeInterface $date - * - * @return static */ - public static function instance($date); + public static function instance(DateTimeInterface $date): static; /** * Returns true if the current date matches the given string. @@ -2565,10 +2579,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * * @param string $tester day name, month name, hour, date, etc. as string - * - * @return bool */ - public function is(string $tester); + public function is(WeekDay|Month|string $tester): bool; /** * Determines if the instance is greater (after) than another @@ -2580,13 +2592,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThan() - * - * @return bool */ - public function isAfter($date): bool; + public function isAfter(DateTimeInterface|string $date): bool; /** * Determines if the instance is less (before) than another @@ -2598,13 +2606,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThan() - * - * @return bool */ - public function isBefore($date): bool; + public function isBefore(DateTimeInterface|string $date): bool; /** * Determines if the instance is between two others @@ -2617,13 +2621,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01', false); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * @param bool $equal Indicates if an equal to comparison should be done - * - * @return bool + * @param bool $equal Indicates if an equal to comparison should be done */ - public function isBetween($date1, $date2, $equal = true): bool; + public function isBetween(DateTimeInterface|string $date1, DateTimeInterface|string $date2, bool $equal = true): bool; /** * Check if its the birthday. Compares the date/month values of the two dates. @@ -2636,11 +2636,11 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-06')); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day. + * @param DateTimeInterface|string|null $date The instance to compare with or null to use current day. * * @return bool */ - public function isBirthday($date = null); + public function isBirthday(DateTimeInterface|string|null $date = null): bool; /** * Determines if the instance is in the current unit given. @@ -2654,10 +2654,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string $unit The unit to test. * * @throws BadMethodCallException - * - * @return bool */ - public function isCurrentUnit($unit); + public function isCurrentUnit(string $unit): bool; /** * Checks if this day is a specific day of the week. @@ -2670,11 +2668,16 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-07-17')->isDayOfWeek('Friday'); // false * ``` * - * @param int $dayOfWeek + * @param int|string $dayOfWeek * * @return bool */ - public function isDayOfWeek($dayOfWeek); + public function isDayOfWeek($dayOfWeek): bool; + + /** + * Determines if the instance is end of century (last day by default but interval can be customized). + */ + public function isEndOfCentury(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; /** * Check if the instance is end of day. @@ -2690,11 +2693,53 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(true); // false * ``` * - * @param bool $checkMicroseconds check time at microseconds precision - * - * @return bool + * @param bool $checkMicroseconds check time at microseconds precision + * @param Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval if an interval is specified it will be used as precision + * for instance with "15 minutes", it checks if current date-time + * is in the last 15 minutes of the day, with Unit::Hour, it + * checks if it's in the last hour of the day. */ - public function isEndOfDay($checkMicroseconds = false); + public function isEndOfDay(Unit|DateInterval|Closure|CarbonConverterInterface|string|bool $checkMicroseconds = false, Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of decade (last day by default but interval can be customized). + */ + public function isEndOfDecade(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of hour (last microsecond by default but interval can be customized). + */ + public function isEndOfHour(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of millennium (last day by default but interval can be customized). + */ + public function isEndOfMillennium(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of millisecond (last microsecond by default but interval can be customized). + */ + public function isEndOfMillisecond(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of minute (last microsecond by default but interval can be customized). + */ + public function isEndOfMinute(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of month (last day by default but interval can be customized). + */ + public function isEndOfMonth(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of quarter (last day by default but interval can be customized). + */ + public function isEndOfQuarter(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is end of second (last microsecond by default but interval can be customized). + */ + public function isEndOfSecond(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; /** * Returns true if the date was created using CarbonImmutable::endOfTime() @@ -2703,6 +2748,33 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function isEndOfTime(): bool; + /** + * Check if the instance is end of a given unit (tolerating a given interval). + * + * @example + * ``` + * // Check if a date-time is the last 15 minutes of the hour it's in + * Carbon::parse('2019-02-28 20:13:00')->isEndOfUnit(Unit::Hour, '15 minutes'); // false + * ``` + */ + public function isEndOfUnit(Unit $unit, Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, mixed ...$params): bool; + + /** + * Determines if the instance is end of week (last day by default but interval can be customized). + * + * @example + * ``` + * Carbon::parse('2024-08-31')->endOfWeek()->isEndOfWeek(); // true + * Carbon::parse('2024-08-31')->isEndOfWeek(); // false + * ``` + */ + public function isEndOfWeek(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, WeekDay|int|null $weekEndsAt = null): bool; + + /** + * Determines if the instance is end of year (last day by default but interval can be customized). + */ + public function isEndOfYear(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + /** * Determines if the instance is in the future, ie. greater (after) than now. * @@ -2711,17 +2783,13 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::now()->addHours(5)->isFuture(); // true * Carbon::now()->subHours(5)->isFuture(); // false * ``` - * - * @return bool */ - public function isFuture(); + public function isFuture(): bool; /** * Returns true if the current class/instance is immutable. - * - * @return bool */ - public static function isImmutable(); + public static function isImmutable(): bool; /** * Check if today is the last day of the Month @@ -2734,10 +2802,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-03-31')->isLastOfMonth(); // true * Carbon::parse('2019-04-30')->isLastOfMonth(); // true * ``` - * - * @return bool */ - public function isLastOfMonth(); + public function isLastOfMonth(): bool; /** * Determines if the instance is a leap year. @@ -2747,10 +2813,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2020-01-01')->isLeapYear(); // true * Carbon::parse('2019-01-01')->isLeapYear(); // false * ``` - * - * @return bool */ - public function isLeapYear(); + public function isLeapYear(): bool; /** * Determines if the instance is a long year (using ISO 8601 year). @@ -2765,10 +2829,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates - * - * @return bool */ - public function isLongIsoYear(); + public function isLongIsoYear(): bool; /** * Determines if the instance is a long year (using calendar year). @@ -2785,10 +2847,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates - * - * @return bool */ - public function isLongYear(); + public function isLongYear(): bool; /** * Check if the instance is midday. @@ -2800,10 +2860,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-02-28 12:00:00.999999')->isMidday(); // true * Carbon::parse('2019-02-28 12:00:01')->isMidday(); // false * ``` - * - * @return bool */ - public function isMidday(); + public function isMidday(): bool; /** * Check if the instance is start of day / midnight. @@ -2814,10 +2872,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-02-28 00:00:00.999999')->isMidnight(); // true * Carbon::parse('2019-02-28 00:00:01')->isMidnight(); // false * ``` - * - * @return bool */ - public function isMidnight(); + public function isMidnight(): bool; /** * Returns true if a property can be changed via setter. @@ -2826,14 +2882,36 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function isModifiableUnit($unit); + public static function isModifiableUnit($unit): bool; /** * Returns true if the current class/instance is mutable. - * - * @return bool */ - public static function isMutable(); + public static function isMutable(): bool; + + /** + * Determines if the instance is now or in the future, ie. greater (after) than or equal to now. + * + * @example + * ``` + * Carbon::now()->isNowOrFuture(); // true + * Carbon::now()->addHours(5)->isNowOrFuture(); // true + * Carbon::now()->subHours(5)->isNowOrFuture(); // false + * ``` + */ + public function isNowOrFuture(): bool; + + /** + * Determines if the instance is now or in the past, ie. less (before) than or equal to now. + * + * @example + * ``` + * Carbon::now()->isNowOrPast(); // true + * Carbon::now()->subHours(5)->isNowOrPast(); // true + * Carbon::now()->addHours(5)->isNowOrPast(); // false + * ``` + */ + public function isNowOrPast(): bool; /** * Determines if the instance is in the past, ie. less (before) than now. @@ -2843,10 +2921,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::now()->subHours(5)->isPast(); // true * Carbon::now()->addHours(5)->isPast(); // false * ``` - * - * @return bool */ - public function isPast(); + public function isPast(): bool; /** * Compares the formatted values of the two dates. @@ -2857,12 +2933,10 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-06-14')); // false * ``` * - * @param string $format date formats to compare. - * @param \Carbon\Carbon|\DateTimeInterface|string|null $date instance to compare with or null to use current day. - * - * @return bool + * @param string $format date formats to compare. + * @param DateTimeInterface|string $date instance to compare with or null to use current day. */ - public function isSameAs($format, $date = null); + public function isSameAs(string $format, DateTimeInterface|string $date): bool; /** * Checks if the passed in date is in the same month as the instance´s month. @@ -2875,12 +2949,12 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01'), false); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date. - * @param bool $ofSameYear Check if it is the same month in the same year. + * @param DateTimeInterface|string $date The instance to compare with or null to use the current date. + * @param bool $ofSameYear Check if it is the same month in the same year. * * @return bool */ - public function isSameMonth($date = null, $ofSameYear = true); + public function isSameMonth(DateTimeInterface|string $date, bool $ofSameYear = true): bool; /** * Checks if the passed in date is in the same quarter as the instance quarter (and year if needed). @@ -2893,12 +2967,12 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01'), false); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|string|null $date The instance to compare with or null to use current day. - * @param bool $ofSameYear Check if it is the same month in the same year. + * @param DateTimeInterface|string $date The instance to compare with or null to use current day. + * @param bool $ofSameYear Check if it is the same month in the same year. * * @return bool */ - public function isSameQuarter($date = null, $ofSameYear = true); + public function isSameQuarter(DateTimeInterface|string $date, bool $ofSameYear = true): bool; /** * Determines if the instance is in the current unit given. @@ -2909,14 +2983,19 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-12-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // false * ``` * - * @param string $unit singular unit string - * @param \Carbon\Carbon|\DateTimeInterface|null $date instance to compare with or null to use current day. + * @param string $unit singular unit string + * @param DateTimeInterface|string $date instance to compare with or null to use current day. * * @throws BadComparisonUnitException * * @return bool */ - public function isSameUnit($unit, $date = null); + public function isSameUnit(string $unit, DateTimeInterface|string $date): bool; + + /** + * Determines if the instance is start of century (first day by default but interval can be customized). + */ + public function isStartOfCentury(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; /** * Check if the instance is start of day / midnight. @@ -2930,11 +3009,53 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-02-28 00:00:00.000012')->isStartOfDay(true); // false * ``` * - * @param bool $checkMicroseconds check time at microseconds precision - * - * @return bool + * @param bool $checkMicroseconds check time at microseconds precision + * @param Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval if an interval is specified it will be used as precision + * for instance with "15 minutes", it checks if current date-time + * is in the last 15 minutes of the day, with Unit::Hour, it + * checks if it's in the last hour of the day. */ - public function isStartOfDay($checkMicroseconds = false); + public function isStartOfDay(Unit|DateInterval|Closure|CarbonConverterInterface|string|bool $checkMicroseconds = false, Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of decade (first day by default but interval can be customized). + */ + public function isStartOfDecade(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of hour (first microsecond by default but interval can be customized). + */ + public function isStartOfHour(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of millennium (first day by default but interval can be customized). + */ + public function isStartOfMillennium(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of millisecond (first microsecond by default but interval can be customized). + */ + public function isStartOfMillisecond(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of minute (first microsecond by default but interval can be customized). + */ + public function isStartOfMinute(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of month (first day by default but interval can be customized). + */ + public function isStartOfMonth(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of quarter (first day by default but interval can be customized). + */ + public function isStartOfQuarter(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + + /** + * Determines if the instance is start of second (first microsecond by default but interval can be customized). + */ + public function isStartOfSecond(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; /** * Returns true if the date was created using CarbonImmutable::startOfTime() @@ -2943,13 +3064,40 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function isStartOfTime(): bool; + /** + * Check if the instance is start of a given unit (tolerating a given interval). + * + * @example + * ``` + * // Check if a date-time is the first 15 minutes of the hour it's in + * Carbon::parse('2019-02-28 20:13:00')->isStartOfUnit(Unit::Hour, '15 minutes'); // true + * ``` + */ + public function isStartOfUnit(Unit $unit, Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, mixed ...$params): bool; + + /** + * Determines if the instance is start of week (first day by default but interval can be customized). + * + * @example + * ``` + * Carbon::parse('2024-08-31')->startOfWeek()->isStartOfWeek(); // true + * Carbon::parse('2024-08-31')->isStartOfWeek(); // false + * ``` + */ + public function isStartOfWeek(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, WeekDay|int|null $weekStartsAt = null): bool; + + /** + * Determines if the instance is start of year (first day by default but interval can be customized). + */ + public function isStartOfYear(Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null): bool; + /** * Returns true if the strict mode is globally in use, false else. * (It can be overridden in specific instances.) * * @return bool */ - public static function isStrictModeEnabled(); + public static function isStrictModeEnabled(): bool; /** * Determines if the instance is today. @@ -2959,10 +3107,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::today()->isToday(); // true * Carbon::tomorrow()->isToday(); // false * ``` - * - * @return bool */ - public function isToday(); + public function isToday(): bool; /** * Determines if the instance is tomorrow. @@ -2972,10 +3118,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::tomorrow()->isTomorrow(); // true * Carbon::yesterday()->isTomorrow(); // false * ``` - * - * @return bool */ - public function isTomorrow(); + public function isTomorrow(): bool; /** * Determines if the instance is a weekday. @@ -2985,10 +3129,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-07-14')->isWeekday(); // false * Carbon::parse('2019-07-15')->isWeekday(); // true * ``` - * - * @return bool */ - public function isWeekday(); + public function isWeekday(): bool; /** * Determines if the instance is a weekend day. @@ -2998,10 +3140,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2019-07-14')->isWeekend(); // true * Carbon::parse('2019-07-15')->isWeekend(); // false * ``` - * - * @return bool */ - public function isWeekend(); + public function isWeekend(): bool; /** * Determines if the instance is yesterday. @@ -3011,18 +3151,13 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::yesterday()->isYesterday(); // true * Carbon::tomorrow()->isYesterday(); // false * ``` - * - * @return bool */ - public function isYesterday(); + public function isYesterday(): bool; /** * Format in the current language using ISO replacement patterns. * - * @param string $format * @param string|null $originalFormat provide context if a chunk has been passed alone - * - * @return string */ public function isoFormat(string $format, ?string $originalFormat = null): string; @@ -3055,11 +3190,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Get/set the ISO weekday from 1 (Monday) to 7 (Sunday). * - * @param int|null $value new value for weekday if using as setter. - * - * @return static|int + * @param WeekDay|int|null $value new value for weekday if using as setter. */ - public function isoWeekday($value = null); + public function isoWeekday(WeekDay|int|null $value = null): static|int; /** * Get the number of weeks of the current week-year using given first day of week and first @@ -3075,11 +3208,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Prepare the object for JSON serialization. - * - * @return array|string */ - #[ReturnTypeWillChange] - public function jsonSerialize(); + public function jsonSerialize(): mixed; /** * Modify to the last occurrence of a given day of the week @@ -3126,12 +3256,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:16'); // false * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function lessThan($date): bool; + public function lessThan(DateTimeInterface|string $date): bool; /** * Determines if the instance is less (before) or equal to another @@ -3142,12 +3268,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:16'); // true * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function lessThanOrEqualTo($date): bool; + public function lessThanOrEqualTo(DateTimeInterface|string $date): bool; /** * Get/set the locale for the current instance. @@ -3157,7 +3279,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return $this|string */ - public function locale(?string $locale = null, ...$fallbackLocales); + public function locale(?string $locale = null, string ...$fallbackLocales): static|string; /** * Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow). @@ -3167,7 +3289,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function localeHasDiffOneDayWords($locale); + public static function localeHasDiffOneDayWords(string $locale): bool; /** * Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after). @@ -3177,7 +3299,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function localeHasDiffSyntax($locale); + public static function localeHasDiffSyntax(string $locale): bool; /** * Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow). @@ -3187,7 +3309,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function localeHasDiffTwoDayWords($locale); + public static function localeHasDiffTwoDayWords(string $locale): bool; /** * Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X). @@ -3207,7 +3329,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return bool */ - public static function localeHasShortUnits($locale); + public static function localeHasShortUnits(string $locale): bool; /** * Determines if the instance is less (before) than another @@ -3219,13 +3341,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThan() - * - * @return bool */ - public function lt($date): bool; + public function lt(DateTimeInterface|string $date): bool; /** * Determines if the instance is less (before) or equal to another @@ -3237,17 +3355,15 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThanOrEqualTo() - * - * @return bool */ - public function lte($date): bool; + public function lte(DateTimeInterface|string $date): bool; /** * Register a custom macro. * + * Pass null macro to remove it. + * * @example * ``` * $userSettings = [ @@ -3260,12 +3376,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo Carbon::yesterday()->hours(11)->userFormat(); * ``` * - * @param string $name - * @param object|callable $macro - * - * @return void + * @param-closure-this static $macro */ - public static function macro($name, $macro); + public static function macro(string $name, ?callable $macro): void; /** * Make a Carbon instance from given variable if possible. @@ -3279,7 +3392,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return static|null */ - public static function make($var); + public static function make($var, DateTimeZone|string|null $timezone = null); /** * Get the maximum instance between a given instance (default now) and the current instance. @@ -3290,13 +3403,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function max($date = null); - /** - * Create a Carbon instance for the greatest supported date. - * - * @return static - */ - public static function maxValue(); - /** * Get the maximum instance between a given instance (default now) and the current instance. * @@ -3312,8 +3418,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Return the meridiem of the current time in the current locale. * * @param bool $isLower if true, returns lowercase variant if available in the current locale. - * - * @return string */ public function meridiem(bool $isLower = false): string; @@ -3333,13 +3437,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function min($date = null); - /** - * Create a Carbon instance for the lowest supported date. - * - * @return static - */ - public static function minValue(); - /** * Get the minimum instance between a given instance (default now) and the current instance. * @@ -3376,20 +3473,16 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo "$previousBlackMoon\n"; * ``` * - * @param object|string $mixin - * * @throws ReflectionException - * - * @return void */ - public static function mixin($mixin); + public static function mixin(object|string $mixin): void; /** * Calls \DateTime::modify if mutable or \DateTimeImmutable::modify else. * * @see https://php.net/manual/en/datetime.modify.php * - * @return static|false + * @return static */ #[ReturnTypeWillChange] public function modify($modify); @@ -3404,13 +3497,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see notEqualTo() - * - * @return bool */ - public function ne($date): bool; + public function ne(DateTimeInterface|string $date): bool; /** * Modify to the next occurrence of a given modifier such as a day of @@ -3420,7 +3509,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param string|int|null $modifier * - * @return static|false + * @return static */ public function next($modifier = null); @@ -3447,28 +3536,20 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * Carbon::parse('2018-07-25 12:45:16')->notEqualTo(Carbon::parse('2018-07-25 12:45:16')); // false * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function notEqualTo($date): bool; + public function notEqualTo(DateTimeInterface|string $date): bool; /** * Get a Carbon instance for the current date and time. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function now($tz = null); + public static function now(DateTimeZone|string|int|null $timezone = null): static; /** * Returns a present instance in the same timezone. * * @return static */ - public function nowWithSameTz(); + public function nowWithSameTz(): static; /** * Modify to the given occurrence of a given day of the week @@ -3511,11 +3592,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Return a property with its ordinal. - * - * @param string $key - * @param string|null $period - * - * @return string */ public function ordinal(string $key, ?string $period = null): string; @@ -3526,35 +3602,24 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * as it allows you to do Carbon::parse('Monday next week')->fn() rather * than (new Carbon('Monday next week'))->fn(). * - * @param string|DateTimeInterface|null $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function parse($time = null, $tz = null); + public static function parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null): static; /** * Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). * - * @param string $time date/time string in the given language (may also contain English). - * @param string|null $locale if locale is null or not specified, current global locale will be - * used instead. - * @param DateTimeZone|string|null $tz optional timezone for the new instance. + * @param string $time date/time string in the given language (may also contain English). + * @param string|null $locale if locale is null or not specified, current global locale will be + * used instead. + * @param DateTimeZone|string|int|null $timezone optional timezone for the new instance. * * @throws InvalidFormatException - * - * @return static */ - public static function parseFromLocale($time, $locale = null, $tz = null); + public static function parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null): static; /** * Returns standardized plural of a given singular/plural unit name (in English). - * - * @param string $unit - * - * @return string */ public static function pluralUnit(string $unit): string; @@ -3566,7 +3631,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param string|int|null $modifier * - * @return static|false + * @return static */ public function previous($modifier = null); @@ -3590,10 +3655,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param \DateTimeInterface|Carbon|CarbonImmutable|null $end period end date * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit * @param string|null $unit if specified, $interval must be an integer - * - * @return CarbonPeriod */ - public function range($end = null, $interval = null, $unit = null); + public function range($end = null, $interval = null, $unit = null): CarbonPeriod; /** * Call native PHP DateTime/DateTimeImmutable add() method. @@ -3602,29 +3665,25 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return static */ - public function rawAdd(DateInterval $interval); + public function rawAdd(DateInterval $interval): static; /** * Create a Carbon instance from a specific format. * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function rawCreateFromFormat($format, $time, $tz = null); + public static function rawCreateFromFormat(string $format, string $time, $timezone = null); /** * @see https://php.net/manual/en/datetime.format.php - * - * @param string $format - * - * @return string */ - public function rawFormat($format); + public function rawFormat(string $format): string; /** * Create a carbon instance from a string. @@ -3633,28 +3692,19 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * as it allows you to do Carbon::parse('Monday next week')->fn() rather * than (new Carbon('Monday next week'))->fn(). * - * @param string|DateTimeInterface|null $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function rawParse($time = null, $tz = null); + public static function rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null): static; /** * Call native PHP DateTime/DateTimeImmutable sub() method. - * - * @param DateInterval $interval - * - * @return static */ - public function rawSub(DateInterval $interval); + public function rawSub(DateInterval $interval): static; /** * Remove all macros and generic macros. */ - public static function resetMacros(); + public static function resetMacros(): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -3667,14 +3717,14 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return void */ - public static function resetMonthsOverflow(); + public static function resetMonthsOverflow(): void; /** * Reset the format used to the default when type juggling a Carbon instance to a string * * @return void */ - public static function resetToStringFormat(); + public static function resetToStringFormat(): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -3687,142 +3737,93 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return void */ - public static function resetYearsOverflow(); + public static function resetYearsOverflow(): void; /** * Round the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * @param string $function - * - * @return CarbonInterface */ - public function round($precision = 1, $function = 'round'); + public function round(DateInterval|string|int|float $precision = 1, callable|string $function = 'round'): static; /** * Round the current instance at the given unit with given precision if specified and the given function. - * - * @param string $unit - * @param float|int $precision - * @param string $function - * - * @return CarbonInterface */ - public function roundUnit($unit, $precision = 1, $function = 'round'); + public function roundUnit(string $unit, DateInterval|string|int|float $precision = 1, callable|string $function = 'round'): static; /** * Round the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function roundWeek($weekStartsAt = null); + public function roundWeek(WeekDay|int|null $weekStartsAt = null): static; /** * The number of seconds since midnight. * - * @return int + * @return float */ - public function secondsSinceMidnight(); + public function secondsSinceMidnight(): float; /** * The number of seconds until 23:59:59. * - * @return int + * @return float */ - public function secondsUntilEndOfDay(); + public function secondsUntilEndOfDay(): float; /** * Return a serialized string of the instance. - * - * @return string */ - public function serialize(); + public function serialize(): string; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. * You should rather transform Carbon object before the serialization. * * JSON serialize all Carbon instances using the given callback. - * - * @param callable $callback - * - * @return void */ - public static function serializeUsing($callback); + public static function serializeUsing(callable|string|null $format): void; /** - * Set a part of the Carbon object - * - * @param string|array $name - * @param string|int|DateTimeZone $value + * Set a part of the Carbon object. * * @throws ImmutableException|UnknownSetterException * * @return $this */ - public function set($name, $value = null); + public function set(Unit|array|string $name, DateTimeZone|Month|string|int|float|null $value = null): static; /** * Set the date with gregorian year, month and day numbers. * * @see https://php.net/manual/en/datetime.setdate.php - * - * @param int $year - * @param int $month - * @param int $day - * - * @return static */ - #[ReturnTypeWillChange] - public function setDate($year, $month, $day); + public function setDate(int $year, int $month, int $day): static; /** * Set the year, month, and date for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date now if null - * - * @return static */ - public function setDateFrom($date = null); + public function setDateFrom(DateTimeInterface|string $date): static; /** * Set the date and time all together. - * - * @param int $year - * @param int $month - * @param int $day - * @param int $hour - * @param int $minute - * @param int $second - * @param int $microseconds - * - * @return static */ - public function setDateTime($year, $month, $day, $hour, $minute, $second = 0, $microseconds = 0); + public function setDateTime(int $year, int $month, int $day, int $hour, int $minute, int $second = 0, int $microseconds = 0): static; /** * Set the date and time for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date - * - * @return static */ - public function setDateTimeFrom($date = null); + public function setDateTimeFrom(DateTimeInterface|string $date): static; /** * Set the day (keeping the current time) to the start of the week + the number of days passed as the first * parameter. First day of week is driven by the locale unless explicitly set with the second parameter. * - * @param int $numberOfDays number of days to add after the start of the current week - * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, - * if not provided, start of week is inferred from the locale - * (Sunday for en_US, Monday for de_DE, etc.) - * - * @return static + * @param int $numberOfDays number of days to add after the start of the current week + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, + * if not provided, start of week is inferred from the locale + * (Sunday for en_US, Monday for de_DE, etc.) */ - public function setDaysFromStartOfWeek(int $numberOfDays, ?int $weekStartsAt = null); + public function setDaysFromStartOfWeek(int $numberOfDays, WeekDay|int|null $weekStartsAt = null): static; /** * Set the fallback locale. @@ -3831,49 +3832,34 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param string $locale */ - public static function setFallbackLocale($locale); + public static function setFallbackLocale(string $locale): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. * You should rather use the ->settings() method. * @see settings - * - * @param int $humanDiffOptions */ - public static function setHumanDiffOptions($humanDiffOptions); + public static function setHumanDiffOptions(int $humanDiffOptions): void; /** * Set a date according to the ISO 8601 standard - using weeks and day offsets rather than specific dates. * * @see https://php.net/manual/en/datetime.setisodate.php - * - * @param int $year - * @param int $week - * @param int $day - * - * @return static */ - #[ReturnTypeWillChange] - public function setISODate($year, $week, $day = 1); + public function setISODate(int $year, int $week, int $day = 1): static; /** * Set the translator for the current instance. - * - * @param \Symfony\Component\Translation\TranslatorInterface $translator - * - * @return $this */ public function setLocalTranslator(TranslatorInterface $translator); /** * Set the current translator locale and indicate if the source locale file exists. - * Pass 'auto' as locale to use closest language from the current LC_TIME locale. + * Pass 'auto' as locale to use the closest language to the current LC_TIME locale. * * @param string $locale locale ex. en - * - * @return bool */ - public static function setLocale($locale); + public static function setLocale(string $locale): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -3913,7 +3899,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance */ - public static function setTestNow($testNow = null); + public static function setTestNow(mixed $testNow = null): void; /** * Set a Carbon instance (real or mock) to be returned when a "now" @@ -3934,62 +3920,36 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance */ - public static function setTestNowAndTimezone($testNow = null, $tz = null); + public static function setTestNowAndTimezone($testNow = null, $timezone = null): void; /** * Resets the current time of the DateTime object to a different time. * * @see https://php.net/manual/en/datetime.settime.php - * - * @param int $hour - * @param int $minute - * @param int $second - * @param int $microseconds - * - * @return static */ - #[ReturnTypeWillChange] - public function setTime($hour, $minute, $second = 0, $microseconds = 0); + public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0): static; /** * Set the hour, minute, second and microseconds for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date now if null - * - * @return static */ - public function setTimeFrom($date = null); + public function setTimeFrom(DateTimeInterface|string $date): static; /** * Set the time by time string. - * - * @param string $time - * - * @return static */ - public function setTimeFromTimeString($time); + public function setTimeFromTimeString(string $time): static; /** * Set the instance's timestamp. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $unixTimestamp - * - * @return static */ - #[ReturnTypeWillChange] - public function setTimestamp($unixTimestamp); + public function setTimestamp(string|int|float $timestamp): static; /** * Set the instance's timezone from a string or object. - * - * @param DateTimeZone|string $value - * - * @return static */ - #[ReturnTypeWillChange] - public function setTimezone($value); + public function setTimezone(DateTimeZone|string|int $timeZone): static; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -4003,26 +3963,24 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return void */ - public static function setToStringFormat($format); + public static function setToStringFormat(Closure|string|null $format): void; /** * Set the default translator instance to use. * - * @param \Symfony\Component\Translation\TranslatorInterface $translator + * @param TranslatorInterface $translator * * @return void */ - public static function setTranslator(TranslatorInterface $translator); + public static function setTranslator(TranslatorInterface $translator): void; /** * Set specified unit to new given value. * - * @param string $unit year, month, day, hour, minute, second or microsecond - * @param int $value new value for given unit - * - * @return static + * @param string $unit year, month, day, hour, minute, second or microsecond + * @param Month|int $value new value for given unit */ - public function setUnit($unit, $value = null); + public function setUnit(string $unit, Month|int|float|null $value = null): static; /** * Set any unit to a new value without overflowing current other unit given. @@ -4030,49 +3988,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string $valueUnit unit name to modify * @param int $value new value for the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function setUnitNoOverflow($valueUnit, $value, $overflowUnit); - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use UTF-8 language packages on every machine. - * - * Set if UTF8 will be used for localized date/time. - * - * @param bool $utf8 - */ - public static function setUtf8($utf8); - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek - * or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the - * start of week according to current locale selected and implicitly the end of week. - * - * Set the last day of week - * - * @param int|string $day week end day (or 'auto' to get the day before the first day of week - * from Carbon::getLocale() culture). - * - * @return void - */ - public static function setWeekEndsAt($day); - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the - * 'first_day_of_week' locale setting to change the start of week according to current locale - * selected and implicitly the end of week. - * - * Set the first day of week - * - * @param int|string $day week start day (or 'auto' to get the first day of week from Carbon::getLocale() culture). - * - * @return void - */ - public static function setWeekStartsAt($day); + public function setUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -4096,12 +4013,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * * Set weekend days - * - * @param array $days - * - * @return void */ - public static function setWeekendDays($days); + public static function setWeekendDays(array $days): void; /** * Set specific options. @@ -4120,30 +4033,26 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return $this|static */ - public function settings(array $settings); + public function settings(array $settings): static; /** * Set the instance's timezone from a string or object and add/subtract the offset difference. - * - * @param DateTimeZone|string $value - * - * @return static */ - public function shiftTimezone($value); + public function shiftTimezone(DateTimeZone|string $value): static; /** * Get the month overflow global behavior (can be overridden in specific instances). * * @return bool */ - public static function shouldOverflowMonths(); + public static function shouldOverflowMonths(): bool; /** * Get the month overflow global behavior (can be overridden in specific instances). * * @return bool */ - public static function shouldOverflowYears(); + public static function shouldOverflowYears(): bool; /** * @alias diffForHumans @@ -4155,29 +4064,22 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Returns standardized singular of a given singular/plural unit name (in English). - * - * @param string $unit - * - * @return string */ public static function singularUnit(string $unit): string; + public static function sleep(int|float $seconds): void; + /** * Modify to start of current given unit. * * @example * ``` * echo Carbon::parse('2018-07-25 12:45:16.334455') - * ->startOf('month') - * ->endOf('week', Carbon::FRIDAY); + * ->startOf(Unit::Month) + * ->endOf(Unit::Week, Carbon::FRIDAY); * ``` - * - * @param string $unit - * @param array $params - * - * @return static */ - public function startOf($unit, ...$params); + public function startOf(Unit|string $unit, mixed ...$params): static; /** * Resets the date to the first day of the century and the time to 00:00:00 @@ -4222,10 +4124,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::parse('2018-07-25 12:45:16')->startOfHour(); * ``` - * - * @return static */ - public function startOfHour(); + public function startOfHour(): static; /** * Resets the date to the first day of the millennium and the time to 00:00:00 @@ -4239,6 +4139,18 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable */ public function startOfMillennium(); + /** + * Modify to start of current millisecond, microseconds such as 12345 become 123000 + * + * @example + * ``` + * echo Carbon::parse('2018-07-25 12:45:16.334455') + * ->startOfSecond() + * ->format('H:i:s.u'); + * ``` + */ + public function startOfMillisecond(): static; + /** * Modify to start of current minute, seconds become 0 * @@ -4246,10 +4158,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::parse('2018-07-25 12:45:16')->startOfMinute(); * ``` - * - * @return static */ - public function startOfMinute(); + public function startOfMinute(): static; /** * Resets the date to the first day of the month and the time to 00:00:00 @@ -4284,10 +4194,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ->startOfSecond() * ->format('H:i:s.u'); * ``` - * - * @return static */ - public function startOfSecond(); + public function startOfSecond(): static; /** * Resets the date to the first day of week (defined in $weekStartsAt) and the time to 00:00:00 @@ -4299,11 +4207,11 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo Carbon::parse('2018-07-25 12:45:16')->startOfWeek(Carbon::SUNDAY) . "\n"; * ``` * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week * * @return static */ - public function startOfWeek($weekStartsAt = null); + public function startOfWeek(WeekDay|int|null $weekStartsAt = null): static; /** * Resets the date to the first day of the year and the time to 00:00:00 @@ -4324,27 +4232,43 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @example $date->sub(15, 'days') * @example $date->sub(CarbonInterval::days(4)) * - * @param string|DateInterval|Closure|CarbonConverterInterface $unit - * @param int $value - * @param bool|null $overflow + * @param Unit|string|DateInterval|Closure|CarbonConverterInterface $unit + * @param int|float $value + * @param bool|null $overflow * * @return static */ #[ReturnTypeWillChange] - public function sub($unit, $value = 1, $overflow = null); - - public function subRealUnit($unit, $value = 1); + public function sub($unit, $value = 1, ?bool $overflow = null): static; /** - * Subtract given units to the current instance. + * @deprecated Prefer to use add subUTCUnit() which more accurately defines what it's doing. * - * @param string $unit - * @param int $value - * @param bool|null $overflow + * Subtract seconds to the instance using timestamp. Positive $value travels + * into the past while negative $value travels forward. + * + * @param string $unit + * @param int $value * * @return static */ - public function subUnit($unit, $value = 1, $overflow = null); + public function subRealUnit($unit, $value = 1): static; + + /** + * Subtract seconds to the instance using timestamp. Positive $value travels + * into the past while negative $value travels forward. + * + * @param string $unit + * @param int $value + * + * @return static + */ + public function subUTCUnit($unit, $value = 1): static; + + /** + * Subtract given units to the current instance. + */ + public function subUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static; /** * Subtract any unit to a new value without overflowing current other unit given. @@ -4352,10 +4276,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param string $valueUnit unit name to modify * @param int $value amount to subtract to the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function subUnitNoOverflow($valueUnit, $value, $overflowUnit); + public function subUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static; /** * Subtract given units or interval to the current instance. @@ -4363,40 +4285,32 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @see sub() * * @param string|DateInterval $unit - * @param int $value + * @param int|float $value * @param bool|null $overflow * * @return static */ - public function subtract($unit, $value = 1, $overflow = null); + public function subtract($unit, $value = 1, ?bool $overflow = null): static; /** - * Get the difference in a human readable format in the current locale from current instance to an other + * Get the difference in a human-readable format in the current locale from current instance to another * instance given (or now if null given). * * @return string */ - public function timespan($other = null, $timezone = null); + public function timespan($other = null, $timezone = null): string; /** * Set the instance's timestamp. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $unixTimestamp - * - * @return static */ - public function timestamp($unixTimestamp); + public function timestamp(string|int|float $timestamp): static; /** * @alias setTimezone - * - * @param DateTimeZone|string $value - * - * @return static */ - public function timezone($value); + public function timezone(DateTimeZone|string|int $value): static; /** * Get the difference in a human readable format in the current locale from an other @@ -4455,10 +4369,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * var_dump(Carbon::now()->toArray()); * ``` - * - * @return array */ - public function toArray(); + public function toArray(): array; /** * Format the instance as ATOM @@ -4467,10 +4379,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toAtomString(); * ``` - * - * @return string */ - public function toAtomString(); + public function toAtomString(): string; /** * Format the instance as COOKIE @@ -4479,10 +4389,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toCookieString(); * ``` - * - * @return string */ - public function toCookieString(); + public function toCookieString(): string; /** * @alias toDateTime @@ -4493,10 +4401,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * var_dump(Carbon::now()->toDate()); * ``` - * - * @return DateTime */ - public function toDate(); + public function toDate(): DateTime; /** * Format the instance as date @@ -4505,10 +4411,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toDateString(); * ``` - * - * @return string */ - public function toDateString(); + public function toDateString(): string; /** * Return native DateTime PHP object matching the current instance. @@ -4517,10 +4421,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * var_dump(Carbon::now()->toDateTime()); * ``` - * - * @return DateTime */ - public function toDateTime(); + public function toDateTime(): DateTime; /** * Return native toDateTimeImmutable PHP object matching the current instance. @@ -4529,10 +4431,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * var_dump(Carbon::now()->toDateTimeImmutable()); * ``` - * - * @return DateTimeImmutable */ - public function toDateTimeImmutable(); + public function toDateTimeImmutable(): DateTimeImmutable; /** * Format the instance as date and time T-separated with no timezone @@ -4543,12 +4443,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * echo "\n"; * echo Carbon::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toDateTimeLocalString($unitPrecision = 'second'); + public function toDateTimeLocalString(string $unitPrecision = 'second'): string; /** * Format the instance as date and time @@ -4557,12 +4453,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toDateTimeString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toDateTimeString($unitPrecision = 'second'); + public function toDateTimeString(string $unitPrecision = 'second'): string; /** * Format the instance with day, date and time @@ -4571,10 +4463,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toDayDateTimeString(); * ``` - * - * @return string */ - public function toDayDateTimeString(); + public function toDayDateTimeString(): string; /** * Format the instance as a readable date @@ -4583,10 +4473,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toFormattedDateString(); * ``` - * - * @return string */ - public function toFormattedDateString(); + public function toFormattedDateString(): string; /** * Format the instance with the day, and a readable date @@ -4595,8 +4483,6 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toFormattedDayDateString(); * ``` - * - * @return string */ public function toFormattedDayDateString(): string; @@ -4611,10 +4497,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * * @param bool $keepOffset Pass true to keep the date offset. Else forced to UTC. - * - * @return null|string */ - public function toISOString($keepOffset = false); + public function toISOString(bool $keepOffset = false): ?string; /** * Return a immutable copy of the instance. @@ -4630,10 +4514,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toIso8601String(); * ``` - * - * @return string */ - public function toIso8601String(); + public function toIso8601String(): string; /** * Convert the instance to UTC and return as Zulu ISO8601 @@ -4642,12 +4524,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toIso8601ZuluString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toIso8601ZuluString($unitPrecision = 'second'); + public function toIso8601ZuluString(string $unitPrecision = 'second'): string; /** * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z) with UTC timezone. @@ -4656,10 +4534,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now('America/Toronto')->toJSON(); * ``` - * - * @return null|string */ - public function toJSON(); + public function toJSON(): ?string; /** * Return a mutable copy of the instance. @@ -4705,10 +4581,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * var_dump(Carbon::now()->toObject()); * ``` - * - * @return object */ - public function toObject(); + public function toObject(): object; /** * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval). @@ -4716,10 +4590,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * @param \DateTimeInterface|Carbon|CarbonImmutable|int|null $end period end date or recurrences count if int * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit * @param string|null $unit if specified, $interval must be an integer - * - * @return CarbonPeriod */ - public function toPeriod($end = null, $interval = null, $unit = null); + public function toPeriod($end = null, $interval = null, $unit = null): CarbonPeriod; /** * Format the instance as RFC1036 @@ -4728,10 +4600,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc1036String(); * ``` - * - * @return string */ - public function toRfc1036String(); + public function toRfc1036String(): string; /** * Format the instance as RFC1123 @@ -4740,10 +4610,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc1123String(); * ``` - * - * @return string */ - public function toRfc1123String(); + public function toRfc1123String(): string; /** * Format the instance as RFC2822 @@ -4752,25 +4620,19 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc2822String(); * ``` - * - * @return string */ - public function toRfc2822String(); + public function toRfc2822String(): string; /** - * Format the instance as RFC3339 - * - * @param bool $extended + * Format the instance as RFC3339. * * @example * ``` * echo Carbon::now()->toRfc3339String() . "\n"; * echo Carbon::now()->toRfc3339String(true) . "\n"; * ``` - * - * @return string */ - public function toRfc3339String($extended = false); + public function toRfc3339String(bool $extended = false): string; /** * Format the instance as RFC7231 @@ -4779,10 +4641,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc7231String(); * ``` - * - * @return string */ - public function toRfc7231String(); + public function toRfc7231String(): string; /** * Format the instance as RFC822 @@ -4791,10 +4651,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc822String(); * ``` - * - * @return string */ - public function toRfc822String(); + public function toRfc822String(): string; /** * Format the instance as RFC850 @@ -4803,10 +4661,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRfc850String(); * ``` - * - * @return string */ - public function toRfc850String(); + public function toRfc850String(): string; /** * Format the instance as RSS @@ -4815,22 +4671,18 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toRssString(); * ``` - * - * @return string */ - public function toRssString(); + public function toRssString(): string; /** - * Returns english human readable complete date string. + * Returns english human-readable complete date string. * * @example * ``` * echo Carbon::now()->toString(); * ``` - * - * @return string */ - public function toString(); + public function toString(): string; /** * Format the instance as time @@ -4839,12 +4691,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toTimeString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toTimeString($unitPrecision = 'second'); + public function toTimeString(string $unitPrecision = 'second'): string; /** * Format the instance as W3C @@ -4853,41 +4701,31 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * ``` * echo Carbon::now()->toW3cString(); * ``` - * - * @return string */ - public function toW3cString(); + public function toW3cString(): string; /** * Create a Carbon instance for today. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function today($tz = null); + public static function today(DateTimeZone|string|int|null $timezone = null): static; /** * Create a Carbon instance for tomorrow. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function tomorrow($tz = null); + public static function tomorrow(DateTimeZone|string|int|null $timezone = null): static; /** * Translate using translation string or callback available. * - * @param string $key - * @param array $parameters - * @param string|int|float|null $number - * @param \Symfony\Component\Translation\TranslatorInterface|null $translator - * @param bool $altNumbers + * @param string $key key to find + * @param array $parameters replacement parameters + * @param string|int|float|null $number number if plural + * @param TranslatorInterface|null $translator an optional translator to use + * @param bool $altNumbers pass true to use alternative numbers * * @return string */ - public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string; + public function translate(string $key, array $parameters = [], string|int|float|null $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string; /** * Returns the alternative number for a given integer if available in the current locale. @@ -4914,7 +4752,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return string */ - public static function translateTimeString($timeString, $from = null, $to = null, $mode = self::TRANSLATE_ALL); + public static function translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = self::TRANSLATE_ALL): string; /** * Translate a time string from the current locale (`$date->locale()`) to an other. @@ -4924,15 +4762,15 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return string */ - public function translateTimeStringTo($timeString, $to = null); + public function translateTimeStringTo(string $timeString, ?string $to = null): string; /** * Translate using translation string or callback available. * - * @param \Symfony\Component\Translation\TranslatorInterface $translator - * @param string $key - * @param array $parameters - * @param null $number + * @param TranslatorInterface $translator an optional translator to use + * @param string $key key to find + * @param array $parameters replacement parameters + * @param int|float|null $number number if plural * * @return string */ @@ -4941,21 +4779,13 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php) * but translate words whenever possible (months, day names, etc.) using the current locale. - * - * @param string $format - * - * @return string */ public function translatedFormat(string $format): string; /** * Set the timezone or returns the timezone name if no arguments passed. - * - * @param DateTimeZone|string $value - * - * @return static|string */ - public function tz($value = null); + public function tz(DateTimeZone|string|int|null $value = null): static|string; /** * @alias getTimestamp @@ -4964,7 +4794,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return int */ - public function unix(); + public function unix(): int; /** * @alias to @@ -5015,7 +4845,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return void */ - public static function useMonthsOverflow($monthsOverflow = true); + public static function useMonthsOverflow(bool $monthsOverflow = true): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -5026,7 +4856,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @param bool $strictModeEnabled */ - public static function useStrictMode($strictModeEnabled = true); + public static function useStrictMode(bool $strictModeEnabled = true): void; /** * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. @@ -5041,30 +4871,24 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return void */ - public static function useYearsOverflow($yearsOverflow = true); + public static function useYearsOverflow(bool $yearsOverflow = true): void; /** * Set the instance's timezone to UTC. - * - * @return static */ - public function utc(); + public function utc(): static; /** * Returns the minutes offset to UTC if no arguments passed, else set the timezone with given minutes shift passed. - * - * @param int|null $minuteOffset - * - * @return int|static */ - public function utcOffset(?int $minuteOffset = null); + public function utcOffset(?int $minuteOffset = null): static|int; /** * Returns the milliseconds timestamps used amongst other by Date javascript objects. * * @return float */ - public function valueOf(); + public function valueOf(): float; /** * Get/set the week number using given first day of week and first @@ -5095,11 +4919,9 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable /** * Get/set the weekday from 0 (Sunday) to 6 (Saturday). * - * @param int|null $value new value for weekday if using as setter. - * - * @return static|int + * @param WeekDay|int|null $value new value for weekday if using as setter. */ - public function weekday($value = null); + public function weekday(WeekDay|int|null $value = null): static|int; /** * Get the number of weeks of the current week-year using given first day of week and first @@ -5127,16 +4949,12 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable * * @return T */ - public static function withTestNow($testNow, $callback); + public static function withTestNow(mixed $testNow, callable $callback): mixed; /** * Create a Carbon instance for yesterday. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function yesterday($tz = null); + public static function yesterday(DateTimeZone|string|int|null $timezone = null): static; // } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterval.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterval.php index 8437c545e..a582ddb10 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterval.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonInterval.php @@ -1,5 +1,7 @@ seconds(34)->microseconds(567_890)->seconds = 34) + * @property int $milliseconds Milliseconds component of the current interval. (CarbonInterval::seconds(34)->microseconds(567_890)->milliseconds = 567) + * @property int $microseconds Microseconds component of the current interval. (CarbonInterval::seconds(34)->microseconds(567_890)->microseconds = 567_890) * @property int $microExcludeMilli Remaining microseconds without the milliseconds. * @property int $dayzExcludeWeeks Total days remaining in the final week of the current instance (days % 7). * @property int $daysExcludeWeeks alias of dayzExcludeWeeks - * @property-read float $totalYears Number of years equivalent to the interval. - * @property-read float $totalMonths Number of months equivalent to the interval. - * @property-read float $totalWeeks Number of weeks equivalent to the interval. - * @property-read float $totalDays Number of days equivalent to the interval. + * @property-read float $totalYears Number of years equivalent to the interval. (For P1Y6M, the value will be 1.5) + * @property-read float $totalMonths Number of months equivalent to the interval. (For P1Y6M10D, the value will be ~12.357) + * @property-read float $totalWeeks Number of weeks equivalent to the interval. (For P6M17DT20H, the value will be ~26.548) + * @property-read float $totalDays Number of days equivalent to the interval. (For P17DT20H, the value will be ~17.833) * @property-read float $totalDayz Alias for totalDays. - * @property-read float $totalHours Number of hours equivalent to the interval. - * @property-read float $totalMinutes Number of minutes equivalent to the interval. - * @property-read float $totalSeconds Number of seconds equivalent to the interval. - * @property-read float $totalMilliseconds Number of milliseconds equivalent to the interval. - * @property-read float $totalMicroseconds Number of microseconds equivalent to the interval. + * @property-read float $totalHours Number of hours equivalent to the interval. (For P1DT20H5M, the value will be ~44.083) + * @property-read float $totalMinutes Number of minutes equivalent to the interval. (For PT20H5M30S, the value will be 1205.5) + * @property-read float $totalSeconds Number of seconds equivalent to the interval. (CarbonInterval::minutes(2)->seconds(34)->microseconds(567_890)->totalSeconds = 154.567_890) + * @property-read float $totalMilliseconds Number of milliseconds equivalent to the interval. (CarbonInterval::seconds(34)->microseconds(567_890)->totalMilliseconds = 34567.890) + * @property-read float $totalMicroseconds Number of microseconds equivalent to the interval. (CarbonInterval::seconds(34)->microseconds(567_890)->totalMicroseconds = 34567890) * @property-read string $locale locale of the current instance * * @method static CarbonInterval years($years = 1) Create instance specifying a number of years or modify the number of years if called on an instance. @@ -188,6 +193,7 @@ use Throwable; */ class CarbonInterval extends DateInterval implements CarbonConverterInterface { + use LocalFactory; use IntervalRounding; use IntervalStep; use MagicParameter; @@ -197,6 +203,16 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface use Options; use ToStringFormat; + /** + * Unlimited parts for forHumans() method. + * + * INF constant can be used instead. + */ + public const NO_LIMIT = -1; + + public const POSITIVE = 1; + public const NEGATIVE = -1; + /** * Interval spec period designators */ @@ -209,22 +225,22 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface public const PERIOD_MINUTES = 'M'; public const PERIOD_SECONDS = 'S'; - /** - * A translator to ... er ... translate stuff - * - * @var \Symfony\Component\Translation\TranslatorInterface - */ - protected static $translator; + public const SPECIAL_TRANSLATIONS = [ + 1 => [ + 'option' => CarbonInterface::ONE_DAY_WORDS, + 'future' => 'diff_tomorrow', + 'past' => 'diff_yesterday', + ], + 2 => [ + 'option' => CarbonInterface::TWO_DAY_WORDS, + 'future' => 'diff_after_tomorrow', + 'past' => 'diff_before_yesterday', + ], + ]; - /** - * @var array|null - */ - protected static $cascadeFactors; + protected static ?array $cascadeFactors = null; - /** - * @var array - */ - protected static $formats = [ + protected static array $formats = [ 'y' => 'y', 'Y' => 'y', 'o' => 'y', @@ -244,56 +260,93 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface 'v' => 'milli', ]; - /** - * @var array|null - */ - private static $flipCascadeFactors; + private static ?array $flipCascadeFactors = null; - /** - * @var bool - */ - private static $floatSettersEnabled = false; + private static bool $floatSettersEnabled = false; /** * The registered macros. - * - * @var array */ - protected static $macros = []; + protected static array $macros = []; /** * Timezone handler for settings() method. - * - * @var mixed */ - protected $tzName; + protected DateTimeZone|string|int|null $timezoneSetting = null; + + /** + * The input used to create the interval. + */ + protected mixed $originalInput = null; + + /** + * Start date if interval was created from a difference between 2 dates. + */ + protected ?CarbonInterface $startDate = null; + + /** + * End date if interval was created from a difference between 2 dates. + */ + protected ?CarbonInterface $endDate = null; + + /** + * End date if interval was created from a difference between 2 dates. + */ + protected ?DateInterval $rawInterval = null; + + /** + * Flag if the interval was made from a diff with absolute flag on. + */ + protected bool $absolute = false; + + protected ?array $initialValues = null; /** * Set the instance's timezone from a string or object. - * - * @param \DateTimeZone|string $tzName - * - * @return static */ - public function setTimezone($tzName) + public function setTimezone(DateTimeZone|string|int $timezone): static { - $this->tzName = $tzName; + $this->timezoneSetting = $timezone; + $this->checkStartAndEnd(); + + if ($this->startDate) { + $this->startDate = $this->startDate + ->avoidMutation() + ->setTimezone($timezone); + $this->rawInterval = null; + } + + if ($this->endDate) { + $this->endDate = $this->endDate + ->avoidMutation() + ->setTimezone($timezone); + $this->rawInterval = null; + } return $this; } /** - * @internal - * * Set the instance's timezone from a string or object and add/subtract the offset difference. - * - * @param \DateTimeZone|string $tzName - * - * @return static */ - public function shiftTimezone($tzName) + public function shiftTimezone(DateTimeZone|string|int $timezone): static { - $this->tzName = $tzName; + $this->timezoneSetting = $timezone; + $this->checkStartAndEnd(); + + if ($this->startDate) { + $this->startDate = $this->startDate + ->avoidMutation() + ->shiftTimezone($timezone); + $this->rawInterval = null; + } + + if ($this->endDate) { + $this->endDate = $this->endDate + ->avoidMutation() + ->shiftTimezone($timezone); + $this->rawInterval = null; + } return $this; } @@ -302,10 +355,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * Mapping of units and factors for cascading. * * Should only be modified by changing the factors or referenced constants. - * - * @return array */ - public static function getCascadeFactors() + public static function getCascadeFactors(): array { return static::$cascadeFactors ?: static::getDefaultCascadeFactors(); } @@ -313,37 +364,17 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface protected static function getDefaultCascadeFactors(): array { return [ - 'milliseconds' => [Carbon::MICROSECONDS_PER_MILLISECOND, 'microseconds'], - 'seconds' => [Carbon::MILLISECONDS_PER_SECOND, 'milliseconds'], - 'minutes' => [Carbon::SECONDS_PER_MINUTE, 'seconds'], - 'hours' => [Carbon::MINUTES_PER_HOUR, 'minutes'], - 'dayz' => [Carbon::HOURS_PER_DAY, 'hours'], - 'weeks' => [Carbon::DAYS_PER_WEEK, 'dayz'], - 'months' => [Carbon::WEEKS_PER_MONTH, 'weeks'], - 'years' => [Carbon::MONTHS_PER_YEAR, 'months'], + 'milliseconds' => [CarbonInterface::MICROSECONDS_PER_MILLISECOND, 'microseconds'], + 'seconds' => [CarbonInterface::MILLISECONDS_PER_SECOND, 'milliseconds'], + 'minutes' => [CarbonInterface::SECONDS_PER_MINUTE, 'seconds'], + 'hours' => [CarbonInterface::MINUTES_PER_HOUR, 'minutes'], + 'dayz' => [CarbonInterface::HOURS_PER_DAY, 'hours'], + 'weeks' => [CarbonInterface::DAYS_PER_WEEK, 'dayz'], + 'months' => [CarbonInterface::WEEKS_PER_MONTH, 'weeks'], + 'years' => [CarbonInterface::MONTHS_PER_YEAR, 'months'], ]; } - private static function standardizeUnit($unit) - { - $unit = rtrim($unit, 'sz').'s'; - - return $unit === 'days' ? 'dayz' : $unit; - } - - private static function getFlipCascadeFactors() - { - if (!self::$flipCascadeFactors) { - self::$flipCascadeFactors = []; - - foreach (static::getCascadeFactors() as $to => [$factor, $from]) { - self::$flipCascadeFactors[self::standardizeUnit($from)] = [self::standardizeUnit($to), $factor]; - } - } - - return self::$flipCascadeFactors; - } - /** * Set default cascading factors for ->cascade() method. * @@ -386,8 +417,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @throws Exception when the interval_spec (passed as $years) cannot be parsed as an interval. */ - public function __construct($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) + public function __construct($years = null, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) { + $this->originalInput = \func_num_args() === 1 ? $years : \func_get_args(); + if ($years instanceof Closure) { $this->step = $years; $years = null; @@ -464,6 +497,11 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $this->assertSafeForInteger('minute', $minutes); $seconds = (float) ($match['second'] ?? 0); $this->assertSafeForInteger('second', $seconds); + $microseconds = (int) str_pad( + substr(explode('.', $match['second'] ?? '0.0')[1] ?? '0', 0, 6), + 6, + '0', + ); } $totalDays = (($weeks * static::getDaysPerWeek()) + $days); @@ -475,6 +513,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $this->h = (int) $hours; $this->i = (int) $minutes; $this->s = (int) $seconds; + $secondFloatPart = (float) ($microseconds / CarbonInterface::MICROSECONDS_PER_SECOND); + $this->f = $secondFloatPart; + $intervalMicroseconds = (int) ($this->f * CarbonInterface::MICROSECONDS_PER_SECOND); + $intervalSeconds = $seconds - $secondFloatPart; if ( ((float) $this->y) !== $years || @@ -482,7 +524,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface ((float) $this->d) !== $totalDays || ((float) $this->h) !== $hours || ((float) $this->i) !== $minutes || - ((float) $this->s) !== $seconds + ((float) $this->s) !== $intervalSeconds || + $intervalMicroseconds !== ((int) $microseconds) ) { $this->add(static::fromString( ($years - $this->y).' years '. @@ -490,7 +533,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface ($totalDays - $this->d).' days '. ($hours - $this->h).' hours '. ($minutes - $this->i).' minutes '. - ($seconds - $this->s).' seconds ' + number_format($intervalSeconds - $this->s, 6, '.', '').' seconds '. + ($microseconds - $intervalMicroseconds).' microseconds ', )); } } catch (Throwable $secondException) { @@ -499,7 +543,13 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface } if ($microseconds !== null) { - $this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND; + $this->f = $microseconds / CarbonInterface::MICROSECONDS_PER_SECOND; + } + + foreach (['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'] as $unit) { + if ($$unit < 0) { + $this->set($unit, $$unit); + } } } @@ -640,7 +690,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public static function create($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) + public static function create($years = null, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) { return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $microseconds); } @@ -660,7 +710,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public static function createFromFormat(string $format, ?string $interval) + public static function createFromFormat(string $format, ?string $interval): static { $instance = new static(0); $length = mb_strlen($format); @@ -672,7 +722,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $interval = implode($match[1], $interval); } - $interval = $interval ?? ''; + $interval ??= ''; for ($index = 0; $index < $length; $index++) { $expected = mb_substr($format, $index, 1); @@ -685,7 +735,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface } $interval = mb_substr($interval, mb_strlen($match[0])); - $instance->$unit += (int) ($match[0]); + self::incrementUnit($instance, $unit, (int) ($match[0])); continue; } @@ -695,7 +745,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface "'$expected'", $nextCharacter, 'Allowed substitutes for interval formats are '.implode(', ', array_keys(static::$formats))."\n". - 'See https://php.net/manual/en/function.date.php for their meaning' + 'See https://php.net/manual/en/function.date.php for their meaning', ); } @@ -705,19 +755,69 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface if ($interval !== '') { throw new ParseErrorException( 'end of string', - $interval + $interval, ); } return $instance; } + /** + * Return the original source used to create the current interval. + * + * @return array|int|string|DateInterval|mixed|null + */ + public function original() + { + return $this->originalInput; + } + + /** + * Return the start date if interval was created from a difference between 2 dates. + * + * @return CarbonInterface|null + */ + public function start(): ?CarbonInterface + { + $this->checkStartAndEnd(); + + return $this->startDate; + } + + /** + * Return the end date if interval was created from a difference between 2 dates. + * + * @return CarbonInterface|null + */ + public function end(): ?CarbonInterface + { + $this->checkStartAndEnd(); + + return $this->endDate; + } + + /** + * Get rid of the original input, start date and end date that may be kept in memory. + * + * @return $this + */ + public function optimize(): static + { + $this->originalInput = null; + $this->startDate = null; + $this->endDate = null; + $this->rawInterval = null; + $this->absolute = false; + + return $this; + } + /** * Get a copy of the instance. * * @return static */ - public function copy() + public function copy(): static { $date = new static(0); $date->copyProperties($this); @@ -731,7 +831,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public function clone() + public function clone(): static { return $this->copy(); } @@ -745,9 +845,9 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * @param string $method magic method name called * @param array $parameters parameters list * - * @return static|null + * @return static|mixed|null */ - public static function __callStatic($method, $parameters) + public static function __callStatic(string $method, array $parameters) { try { $interval = new static(0); @@ -794,7 +894,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - protected static function this() + protected static function this(): static { return end(static::$macroContextStack) ?: new static(0); } @@ -823,12 +923,14 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @param string $intervalDefinition * + * @throws InvalidIntervalException + * * @return static */ - public static function fromString($intervalDefinition) + public static function fromString(string $intervalDefinition): static { if (empty($intervalDefinition)) { - return new static(0); + return self::withOriginal(new static(0), $intervalDefinition); } $years = 0; @@ -841,7 +943,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $milliseconds = 0; $microseconds = 0; - $pattern = '/(\d+(?:\.\d+)?)\h*([^\d\h]*)/i'; + $pattern = '/(-?\d+(?:\.\d+)?)\h*([^\d\h]*)/i'; preg_match_all($pattern, $intervalDefinition, $parts, PREG_SET_ORDER); while ([$part, $value, $unit] = array_shift($parts)) { @@ -980,12 +1082,15 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface default: throw new InvalidIntervalException( - sprintf('Invalid part %s in definition %s', $part, $intervalDefinition) + "Invalid part $part in definition $intervalDefinition", ); } } - return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $milliseconds * Carbon::MICROSECONDS_PER_MILLISECOND + $microseconds); + return self::withOriginal( + new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $milliseconds * Carbon::MICROSECONDS_PER_MILLISECOND + $microseconds), + $intervalDefinition, + ); } /** @@ -996,59 +1101,75 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public static function parseFromLocale($interval, $locale = null) + public static function parseFromLocale(string $interval, ?string $locale = null): static { - return static::fromString(Carbon::translateTimeString($interval, $locale ?: static::getLocale(), 'en')); + return static::fromString(Carbon::translateTimeString($interval, $locale ?: static::getLocale(), CarbonInterface::DEFAULT_LOCALE)); } - private static function castIntervalToClass(DateInterval $interval, string $className, array $skip = []) + /** + * Create an interval from the difference between 2 dates. + * + * @param \Carbon\Carbon|\DateTimeInterface|mixed $start + * @param \Carbon\Carbon|\DateTimeInterface|mixed $end + * + * @return static + */ + public static function diff($start, $end = null, bool $absolute = false, array $skip = []): static { - $mainClass = DateInterval::class; + $start = $start instanceof CarbonInterface ? $start : Carbon::make($start); + $end = $end instanceof CarbonInterface ? $end : Carbon::make($end); + $rawInterval = $start->diffAsDateInterval($end, $absolute); + $interval = static::instance($rawInterval, $skip); - if (!is_a($className, $mainClass, true)) { - throw new InvalidCastException("$className is not a sub-class of $mainClass."); - } + $interval->absolute = $absolute; + $interval->rawInterval = $rawInterval; + $interval->startDate = $start; + $interval->endDate = $end; + $interval->initialValues = $interval->getInnerValues(); - $microseconds = $interval->f; - $instance = new $className(static::getDateIntervalSpec($interval, false, $skip)); - - if ($microseconds) { - $instance->f = $microseconds; - } - - if ($interval instanceof self && is_a($className, self::class, true)) { - self::copyStep($interval, $instance); - } - - self::copyNegativeUnits($interval, $instance); - - return $instance; + return $interval; } - private static function copyNegativeUnits(DateInterval $from, DateInterval $to): void + /** + * Invert the interval if it's inverted. + * + * @param bool $absolute do nothing if set to false + * + * @return $this + */ + public function abs(bool $absolute = false): static { - $to->invert = $from->invert; - - foreach (['y', 'm', 'd', 'h', 'i', 's'] as $unit) { - if ($from->$unit < 0) { - $to->$unit *= -1; - } + if ($absolute && $this->invert) { + $this->invert(); } + + return $this; } - private static function copyStep(self $from, self $to): void + /** + * @alias abs + * + * Invert the interval if it's inverted. + * + * @param bool $absolute do nothing if set to false + * + * @return $this + */ + public function absolute(bool $absolute = true): static { - $to->setStep($from->getStep()); + return $this->abs($absolute); } /** * Cast the current instance into the given class. * - * @param string $className The $className::instance() method will be called to cast the current object. + * @template T of DateInterval * - * @return DateInterval + * @psalm-param class-string $className The $className::instance() method will be called to cast the current object. + * + * @return T */ - public function cast(string $className) + public function cast(string $className): mixed { return self::castIntervalToClass($this, $className); } @@ -1065,7 +1186,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public static function instance(DateInterval $interval, array $skip = [], bool $skipCopy = false) + public static function instance(DateInterval $interval, array $skip = [], bool $skipCopy = false): static { if ($skipCopy && $interval instanceof static) { return $interval; @@ -1080,18 +1201,26 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * Always return a new instance. Parse only strings and only these likely to be intervals (skip dates * and recurrences). Throw an exception for invalid format, but otherwise return null. * - * @param mixed|int|DateInterval|string|Closure|null $interval interval or number of the given $unit - * @param string|null $unit if specified, $interval must be an integer - * @param bool $skipCopy set to true to return the passed object - * (without copying it) if it's already of the - * current class + * @param mixed|int|DateInterval|string|Closure|Unit|null $interval interval or number of the given $unit + * @param Unit|string|null $unit if specified, $interval must be an integer + * @param bool $skipCopy set to true to return the passed object + * (without copying it) if it's already of the + * current class * * @return static|null */ - public static function make($interval, $unit = null, bool $skipCopy = false) + public static function make($interval, $unit = null, bool $skipCopy = false): ?self { + if ($interval instanceof Unit) { + $interval = $interval->interval(); + } + + if ($unit instanceof Unit) { + $unit = $unit->value; + } + if ($unit) { - $interval = "$interval ".Carbon::pluralUnit($unit); + $interval = "$interval $unit"; } if ($interval instanceof DateInterval) { @@ -1099,7 +1228,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface } if ($interval instanceof Closure) { - return new static($interval); + return self::withOriginal(new static($interval), $interval); } if (!\is_string($interval)) { @@ -1109,7 +1238,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface return static::makeFromString($interval); } - protected static function makeFromString(string $interval) + protected static function makeFromString(string $interval): ?self { $interval = preg_replace('/\s+/', ' ', trim($interval)); @@ -1117,23 +1246,16 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface return new static($interval); } - if (preg_match('/^(?:\h*\d+(?:\.\d+)?\h*[a-z]+)+$/i', $interval)) { + if (preg_match('/^(?:\h*-?\d+(?:\.\d+)?\h*[a-z]+)+$/i', $interval)) { return static::fromString($interval); } - // @codeCoverageIgnoreStart - try { - /** @var static $interval */ - $interval = static::createFromDateString($interval); - } catch (DateMalformedIntervalStringException $e) { - return null; - } - // @codeCoverageIgnoreEnd + $intervalInstance = static::createFromDateString($interval); - return !$interval || $interval->isEmpty() ? null : $interval; + return $intervalInstance->isEmpty() ? null : $intervalInstance; } - protected function resolveInterval($interval) + protected function resolveInterval($interval): ?self { if (!($interval instanceof self)) { return self::make($interval); @@ -1145,25 +1267,37 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Sets up a DateInterval from the relative parts of the string. * - * @param string $time + * @param string $datetime * * @return static * * @link https://php.net/manual/en/dateinterval.createfromdatestring.php */ - #[ReturnTypeWillChange] - public static function createFromDateString($time) + public static function createFromDateString(string $datetime): static { - $interval = @parent::createFromDateString(strtr($time, [ + $string = strtr($datetime, [ ',' => ' ', ' and ' => ' ', - ])); + ]); + $previousException = null; - if ($interval instanceof DateInterval) { + try { + $interval = parent::createFromDateString($string); + } catch (Throwable $exception) { + $interval = null; + $previousException = $exception; + } + + $interval ?: throw new InvalidFormatException( + 'Could not create interval from: '.var_export($datetime, true), + previous: $previousException, + ); + + if (!($interval instanceof static)) { $interval = static::instance($interval); } - return $interval; + return self::withOriginal($interval, $datetime); } /////////////////////////////////////////////////////////////////// @@ -1172,74 +1306,46 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Get a part of the CarbonInterval object. - * - * @param string $name - * - * @throws UnknownGetterException - * - * @return int|float|string */ - public function get($name) + public function get(Unit|string $name): int|float|string|null { + $name = Unit::toName($name); + if (str_starts_with($name, 'total')) { return $this->total(substr($name, 5)); } - switch ($name) { - case 'years': - return $this->y; + $resolvedUnit = Carbon::singularUnit(rtrim($name, 'z')); - case 'months': - return $this->m; - - case 'dayz': - return $this->d; - - case 'hours': - return $this->h; - - case 'minutes': - return $this->i; - - case 'seconds': - return $this->s; - - case 'milli': - case 'milliseconds': - return (int) (round($this->f * Carbon::MICROSECONDS_PER_SECOND) / Carbon::MICROSECONDS_PER_MILLISECOND); - - case 'micro': - case 'microseconds': - return (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND); - - case 'microExcludeMilli': - return (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND) % Carbon::MICROSECONDS_PER_MILLISECOND; - - case 'weeks': - return (int) ($this->d / (int) static::getDaysPerWeek()); - - case 'daysExcludeWeeks': - case 'dayzExcludeWeeks': - return $this->d % (int) static::getDaysPerWeek(); - - case 'locale': - return $this->getTranslatorLocale(); - - default: - throw new UnknownGetterException($name); - } + return match ($resolvedUnit) { + 'tzname', 'tz_name' => match (true) { + ($this->timezoneSetting === null) => null, + \is_string($this->timezoneSetting) => $this->timezoneSetting, + ($this->timezoneSetting instanceof DateTimeZone) => $this->timezoneSetting->getName(), + default => CarbonTimeZone::instance($this->timezoneSetting)->getName(), + }, + 'year' => $this->y, + 'month' => $this->m, + 'day' => $this->d, + 'hour' => $this->h, + 'minute' => $this->i, + 'second' => $this->s, + 'milli', 'millisecond' => (int) (round($this->f * Carbon::MICROSECONDS_PER_SECOND) / + Carbon::MICROSECONDS_PER_MILLISECOND), + 'micro', 'microsecond' => (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND), + 'microexcludemilli' => (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND) % + Carbon::MICROSECONDS_PER_MILLISECOND, + 'week' => (int) ($this->d / (int) static::getDaysPerWeek()), + 'daysexcludeweek', 'dayzexcludeweek' => $this->d % (int) static::getDaysPerWeek(), + 'locale' => $this->getTranslatorLocale(), + default => throw new UnknownGetterException($name, previous: new UnknownGetterException($resolvedUnit)), + }; } /** * Get a part of the CarbonInterval object. - * - * @param string $name - * - * @throws UnknownGetterException - * - * @return int|float|string */ - public function __get($name) + public function __get(string $name): int|float|string|null { return $this->get($name); } @@ -1247,19 +1353,19 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Set a part of the CarbonInterval object. * - * @param string|array $name - * @param int $value + * @param Unit|string|array $name + * @param int $value * * @throws UnknownSetterException * * @return $this */ - public function set($name, $value = null) + public function set($name, $value = null): static { $properties = \is_array($name) ? $name : [$name => $value]; foreach ($properties as $key => $value) { - switch (Carbon::singularUnit(rtrim($key, 'z'))) { + switch (Carbon::singularUnit($key instanceof Unit ? $key->value : rtrim((string) $key, 'z'))) { case 'year': $this->checkIntegerValue($key, $value); $this->y = $value; @@ -1284,6 +1390,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface break; case 'day': + if ($value === false) { + break; + } + $this->checkIntegerValue($key, $value); $this->d = $value; $this->handleDecimalPart('day', $value, $this->d); @@ -1334,6 +1444,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface break; default: + if (str_starts_with($key, ' * ')) { + return $this->setSetting(substr($key, 3), $value); + } + if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) { throw new UnknownSetterException($key); } @@ -1353,7 +1467,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @throws UnknownSetterException */ - public function __set($name, $value) + public function __set(string $name, $value) { $this->set($name, $value); } @@ -1366,7 +1480,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return static */ - public function weeksAndDays($weeks, $days) + public function weeksAndDays(int $weeks, int $days): static { $this->dayz = ($weeks * static::getDaysPerWeek()) + $days; @@ -1378,7 +1492,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return bool */ - public function isEmpty() + public function isEmpty(): bool { return $this->years === 0 && $this->months === 0 && @@ -1393,6 +1507,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Register a custom macro. * + * Pass null macro to remove it. + * * @example * ``` * CarbonInterval::macro('twice', function () { @@ -1401,12 +1517,9 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * echo CarbonInterval::hours(2)->twice(); * ``` * - * @param string $name - * @param object|callable $macro - * - * @return void + * @param-closure-this static $macro */ - public static function macro($name, $macro) + public static function macro(string $name, ?callable $macro): void { static::$macros[$name] = $macro; } @@ -1444,7 +1557,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return void */ - public static function mixin($mixin) + public static function mixin($mixin): void { static::baseMixin($mixin); } @@ -1456,7 +1569,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return bool */ - public static function hasMacro($name) + public static function hasMacro(string $name): bool { return isset(static::$macros[$name]); } @@ -1469,7 +1582,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return mixed */ - protected function callMacro($name, $parameters) + protected function callMacro(string $name, array $parameters) { $macro = static::$macros[$name]; @@ -1493,9 +1606,9 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @throws BadFluentSetterException|Throwable * - * @return static + * @return static|int|float|string */ - public function __call($method, $parameters) + public function __call(string $method, array $parameters) { if (static::hasMacro($method)) { return static::bindMacroContext($this, function () use (&$method, &$parameters) { @@ -1528,7 +1641,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface return $this; } - protected function getForHumansInitialVariables($syntax, $short) + protected function getForHumansInitialVariables($syntax, $short): array { if (\is_array($syntax)) { return $syntax; @@ -1559,31 +1672,34 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return array */ - protected function getForHumansParameters($syntax = null, $short = false, $parts = -1, $options = null) + protected function getForHumansParameters($syntax = null, $short = false, $parts = self::NO_LIMIT, $options = null): array { $optionalSpace = ' '; $default = $this->getTranslationMessage('list.0') ?? $this->getTranslationMessage('list') ?? ' '; + /** @var bool|string $join */ $join = $default === '' ? '' : ' '; + /** @var bool|array|string $altNumbers */ $altNumbers = false; $aUnit = false; $minimumUnit = 's'; $skip = []; extract($this->getForHumansInitialVariables($syntax, $short)); - $skip = array_map('strtolower', array_filter((array) $skip, static function ($value) { - return \is_string($value) && $value !== ''; - })); + $skip = array_map( + static fn ($unit) => $unit instanceof Unit ? $unit->value : $unit, + (array) $skip, + ); + $skip = array_map( + 'strtolower', + array_filter($skip, static fn ($unit) => \is_string($unit) && $unit !== ''), + ); - if ($syntax === null) { - $syntax = CarbonInterface::DIFF_ABSOLUTE; - } + $syntax ??= CarbonInterface::DIFF_ABSOLUTE; - if ($parts === -1) { + if ($parts === self::NO_LIMIT) { $parts = INF; } - if ($options === null) { - $options = static::getHumanDiffOptions(); - } + $options ??= static::getHumanDiffOptions(); if ($join === false) { $join = ' '; @@ -1623,16 +1739,16 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface } $glue = $join; - $join = function ($list) use ($glue) { - return implode($glue, $list); - }; + $join = static fn ($list) => implode($glue, $list); } $interpolations = [ ':optional-space' => $optionalSpace, ]; - return [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip]; + $translator ??= isset($locale) ? Translator::get($locale) : null; + + return [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip, $translator]; } protected static function getRoundingMethodFromOptions(int $options): ?string @@ -1657,7 +1773,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return int[] */ - public function toArray() + public function toArray(): array { return [ 'years' => $this->years, @@ -1676,7 +1792,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return int[] */ - public function getNonZeroValues() + public function getNonZeroValues(): array { return array_filter($this->toArray(), 'intval'); } @@ -1687,7 +1803,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return int[] */ - public function getValuesSequence() + public function getValuesSequence(): array { $nonZeroValues = $this->getNonZeroValues(); @@ -1731,25 +1847,30 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * echo CarbonInterval::fromString('1d 24h')->forHumans(['minimumUnit' => 'hour']) . "\n"; * ``` * - * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contains: - * - 'syntax' entry (see below) - * - 'short' entry (see below) - * - 'parts' entry (see below) - * - 'options' entry (see below) - * - 'skip' entry, list of units to skip (array of strings or a single string, + * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contain: + * ⦿ 'syntax' entry (see below) + * ⦿ 'short' entry (see below) + * ⦿ 'parts' entry (see below) + * ⦿ 'options' entry (see below) + * ⦿ 'skip' entry, list of units to skip (array of strings or a single string, * ` it can be the unit name (singular or plural) or its shortcut * ` (y, m, w, d, h, min, s, ms, µs). - * - 'aUnit' entry, prefer "an hour" over "1 hour" if true - * - 'join' entry determines how to join multiple parts of the string + * ⦿ 'aUnit' entry, prefer "an hour" over "1 hour" if true + * ⦿ 'altNumbers' entry, use alternative numbers if available + * ` (from the current language if true is passed, from the given language(s) + * ` if array or string is passed) + * ⦿ 'join' entry determines how to join multiple parts of the string * ` - if $join is a string, it's used as a joiner glue * ` - if $join is a callable/closure, it get the list of string and should return a string * ` - if $join is an array, the first item will be the default glue, and the second item * ` will be used instead of the glue for the last item * ` - if $join is true, it will be guessed from the locale ('list' translation file entry) * ` - if $join is missing, a space will be used as glue - * - 'minimumUnit' entry determines the smallest unit of time to display can be long or + * ⦿ 'minimumUnit' entry determines the smallest unit of time to display can be long or * ` short form of the units, e.g. 'hour' or 'h' (default value: s) - * if int passed, it add modifiers: + * ⦿ 'locale' language in which the diff should be output (has no effect if 'translator' key is set) + * ⦿ 'translator' a custom translator to use to translator the output. + * if int passed, it adds modifiers: * Possible values: * - CarbonInterface::DIFF_ABSOLUTE no modifiers * - CarbonInterface::DIFF_RELATIVE_TO_NOW add ago/from now modifier @@ -1763,9 +1884,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return string */ - public function forHumans($syntax = null, $short = false, $parts = -1, $options = null) + public function forHumans($syntax = null, $short = false, $parts = self::NO_LIMIT, $options = null): string { - [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip] = $this + /* @var TranslatorInterface|null $translator */ + [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip, $translator] = $this ->getForHumansParameters($syntax, $short, $parts, $options); $interval = []; @@ -1779,8 +1901,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $transId = $relativeToNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before'); $declensionMode = null; - /** @var \Symfony\Component\Translation\Translator $translator */ - $translator = $this->getLocalTranslator(); + $translator ??= $this->getLocalTranslator(); $handleDeclensions = function ($unit, $count, $index = 0, $parts = 1) use ($interpolations, $transId, $translator, $altNumbers, $absolute, &$declensionMode) { if (!$absolute) { @@ -1825,7 +1946,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $intervalValues = $this->copy()->roundUnit( $keys[$index], 1, - $method + $method, ); $previousCount = $count; } @@ -1942,17 +2063,10 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface if ($parts === 1) { if ($relativeToNow && $unit === 'day') { - if ($count === 1 && $options & CarbonInterface::ONE_DAY_WORDS) { - $key = $isFuture ? 'diff_tomorrow' : 'diff_yesterday'; - $translation = $this->translate($key, $interpolations, null, $translator); + $specialTranslations = static::SPECIAL_TRANSLATIONS[$count] ?? null; - if ($translation !== $key) { - return $translation; - } - } - - if ($count === 2 && $options & CarbonInterface::TWO_DAY_WORDS) { - $key = $isFuture ? 'diff_after_tomorrow' : 'diff_before_yesterday'; + if ($specialTranslations && $options & $specialTranslations['option']) { + $key = $specialTranslations[$isFuture ? 'future' : 'past']; $translation = $this->translate($key, $interpolations, null, $translator); if ($translation !== $key) { @@ -1971,6 +2085,19 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface return $this->translate($transId, array_merge($time, $interpolations, $time), null, $translator); } + public function format(string $format): string + { + $output = parent::format($format); + + if (!str_contains($format, '%a') || !isset($this->startDate, $this->endDate)) { + return $output; + } + + $this->rawInterval ??= $this->startDate->diffAsDateInterval($this->endDate); + + return str_replace('(unknown)', $this->rawInterval->format('%a'), $output); + } + /** * Format the instance as a string using the forHumans() function. * @@ -1978,9 +2105,11 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return string */ - public function __toString() + public function __toString(): string { - $format = $this->localToStringFormat ?? static::$toStringFormat; + $format = $this->localToStringFormat + ?? $this->getFactory()->getSettings()['toStringFormat'] + ?? null; if (!$format) { return $this->forHumans(); @@ -2003,7 +2132,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return DateInterval */ - public function toDateInterval() + public function toDateInterval(): DateInterval { return self::castIntervalToClass($this, DateInterval::class); } @@ -2015,17 +2144,50 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return CarbonPeriod */ - public function toPeriod(...$params) + public function toPeriod(...$params): CarbonPeriod { - if ($this->tzName) { - $tz = \is_string($this->tzName) ? new DateTimeZone($this->tzName) : $this->tzName; + if ($this->timezoneSetting) { + $timeZone = \is_string($this->timezoneSetting) + ? new DateTimeZone($this->timezoneSetting) + : $this->timezoneSetting; - if ($tz instanceof DateTimeZone) { - array_unshift($params, $tz); + if ($timeZone instanceof DateTimeZone) { + array_unshift($params, $timeZone); } } - return CarbonPeriod::create($this, ...$params); + $class = ($params[0] ?? null) instanceof DateTime ? CarbonPeriod::class : CarbonPeriodImmutable::class; + + return $class::create($this, ...$params); + } + + /** + * Decompose the current interval into + * + * @param mixed|int|DateInterval|string|Closure|Unit|null $interval interval or number of the given $unit + * @param Unit|string|null $unit if specified, $interval must be an integer + * + * @return CarbonPeriod + */ + public function stepBy($interval, Unit|string|null $unit = null): CarbonPeriod + { + $this->checkStartAndEnd(); + $start = $this->startDate ?? CarbonImmutable::make('now'); + $end = $this->endDate ?? $start->copy()->add($this); + + try { + $step = static::make($interval, $unit); + } catch (InvalidFormatException $exception) { + if ($unit || (\is_string($interval) ? preg_match('/(\s|\d)/', $interval) : !($interval instanceof Unit))) { + throw $exception; + } + + $step = static::make(1, $interval); + } + + $class = $start instanceof DateTime ? CarbonPeriod::class : CarbonPeriodImmutable::class; + + return $class::create($step, $start, $end); } /** @@ -2036,23 +2198,23 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function invert($inverted = null) + public function invert($inverted = null): static { $this->invert = (\func_num_args() === 0 ? !$this->invert : $inverted) ? 1 : 0; return $this; } - protected function solveNegativeInterval() + protected function solveNegativeInterval(): static { if (!$this->isEmpty() && $this->years <= 0 && $this->months <= 0 && $this->dayz <= 0 && $this->hours <= 0 && $this->minutes <= 0 && $this->seconds <= 0 && $this->microseconds <= 0) { - $this->years *= -1; - $this->months *= -1; - $this->dayz *= -1; - $this->hours *= -1; - $this->minutes *= -1; - $this->seconds *= -1; - $this->microseconds *= -1; + $this->years *= self::NEGATIVE; + $this->months *= self::NEGATIVE; + $this->dayz *= self::NEGATIVE; + $this->hours *= self::NEGATIVE; + $this->minutes *= self::NEGATIVE; + $this->seconds *= self::NEGATIVE; + $this->microseconds *= self::NEGATIVE; $this->invert(); } @@ -2067,13 +2229,13 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function add($unit, $value = 1) + public function add($unit, $value = 1): static { if (is_numeric($unit)) { [$value, $unit] = [$unit, $value]; } - if (\is_string($unit) && !preg_match('/^\s*\d/', $unit)) { + if (\is_string($unit) && !preg_match('/^\s*-?\d/', $unit)) { $unit = "$value $unit"; $value = 1; } @@ -2088,7 +2250,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $interval->times($value); } - $sign = ($this->invert === 1) !== ($interval->invert === 1) ? -1 : 1; + $sign = ($this->invert === 1) !== ($interval->invert === 1) ? self::NEGATIVE : self::POSITIVE; $this->years += $interval->y * $sign; $this->months += $interval->m * $sign; $this->dayz += ($interval->days === false ? $interval->d : $interval->days) * $sign; @@ -2110,7 +2272,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function sub($unit, $value = 1) + public function sub($unit, $value = 1): static { if (is_numeric($unit)) { [$value, $unit] = [$unit, $value]; @@ -2127,7 +2289,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function subtract($unit, $value = 1) + public function subtract($unit, $value = 1): static { return $this->sub($unit, $value); } @@ -2155,7 +2317,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $minutes = 0, $seconds = 0, $microseconds = 0 - ): self { + ): static { return $this->add(" $years years $months months $weeks weeks $days days $hours hours $minutes minutes $seconds seconds $microseconds microseconds @@ -2185,7 +2347,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $minutes = 0, $seconds = 0, $microseconds = 0 - ): self { + ): static { return $this->sub(" $years years $months months $weeks weeks $days days $hours hours $minutes minutes $seconds seconds $microseconds microseconds @@ -2207,7 +2369,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function times($factor) + public function times($factor): static { if ($factor < 0) { $this->invert = $this->invert ? 0 : 1; @@ -2240,12 +2402,12 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function shares($divider) + public function shares($divider): static { return $this->times(1 / $divider); } - protected function copyProperties(self $interval, $ignoreSign = false) + protected function copyProperties(self $interval, $ignoreSign = false): static { $this->years = $interval->years; $this->months = $interval->months; @@ -2269,7 +2431,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function multiply($factor) + public function multiply($factor): static { if ($factor < 0) { $this->invert = $this->invert ? 0 : 1; @@ -2286,7 +2448,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface static::create($yearPart) ->microseconds(abs($this->totalMicroseconds) * $factor) ->cascade(), - true + true, ); } @@ -2297,7 +2459,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function divide($divider) + public function divide($divider): static { return $this->multiply(1 / $divider); } @@ -2309,7 +2471,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return string */ - public static function getDateIntervalSpec(DateInterval $interval, bool $microseconds = false, array $skip = []) + public static function getDateIntervalSpec(DateInterval $interval, bool $microseconds = false, array $skip = []): string { $date = array_filter([ static::PERIOD_YEARS => abs($interval->y), @@ -2317,6 +2479,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface static::PERIOD_DAYS => abs($interval->d), ]); + $skip = array_map([Unit::class, 'toNameIfUnit'], $skip); + if ( $interval->days >= CarbonInterface::DAYS_PER_WEEK * CarbonInterface::WEEKS_PER_MONTH && (!isset($date[static::PERIOD_YEARS]) || \count(array_intersect(['y', 'year', 'years'], $skip))) && @@ -2329,7 +2493,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $seconds = abs($interval->s); if ($microseconds && $interval->f > 0) { - $seconds = sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000); + $seconds = \sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000); } $time = array_filter([ @@ -2359,7 +2523,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return string */ - public function spec(bool $microseconds = false) + public function spec(bool $microseconds = false): string { return static::getDateIntervalSpec($this, $microseconds); } @@ -2370,22 +2534,15 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * @param DateInterval $first * @param DateInterval $second * - * @return int + * @return int 0, 1 or -1 */ - public static function compareDateIntervals(DateInterval $first, DateInterval $second) + public static function compareDateIntervals(DateInterval $first, DateInterval $second): int { $current = Carbon::now(); $passed = $current->avoidMutation()->add($second); $current->add($first); - if ($current < $passed) { - return -1; - } - if ($current > $passed) { - return 1; - } - - return 0; + return $current <=> $passed; } /** @@ -2393,93 +2550,19 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @param DateInterval $interval * - * @return int + * @return int 0, 1 or -1 */ - public function compare(DateInterval $interval) + public function compare(DateInterval $interval): int { return static::compareDateIntervals($this, $interval); } - private function invertCascade(array $values) - { - return $this->set(array_map(function ($value) { - return -$value; - }, $values))->doCascade(true)->invert(); - } - - private function doCascade(bool $deep) - { - $originalData = $this->toArray(); - $originalData['milliseconds'] = (int) ($originalData['microseconds'] / static::getMicrosecondsPerMillisecond()); - $originalData['microseconds'] = $originalData['microseconds'] % static::getMicrosecondsPerMillisecond(); - $originalData['weeks'] = (int) ($this->d / static::getDaysPerWeek()); - $originalData['daysExcludeWeeks'] = fmod($this->d, static::getDaysPerWeek()); - unset($originalData['days']); - $newData = $originalData; - $previous = []; - - foreach (self::getFlipCascadeFactors() as $source => [$target, $factor]) { - foreach (['source', 'target'] as $key) { - if ($$key === 'dayz') { - $$key = 'daysExcludeWeeks'; - } - } - - $value = $newData[$source]; - $modulo = fmod($factor + fmod($value, $factor), $factor); - $newData[$source] = $modulo; - $newData[$target] += ($value - $modulo) / $factor; - - $decimalPart = fmod($newData[$source], 1); - - if ($decimalPart !== 0.0) { - $unit = $source; - - foreach ($previous as [$subUnit, $subFactor]) { - $newData[$unit] -= $decimalPart; - $newData[$subUnit] += $decimalPart * $subFactor; - $decimalPart = fmod($newData[$subUnit], 1); - - if ($decimalPart === 0.0) { - break; - } - - $unit = $subUnit; - } - } - - array_unshift($previous, [$source, $factor]); - } - - $positive = null; - - if (!$deep) { - foreach ($newData as $value) { - if ($value) { - if ($positive === null) { - $positive = ($value > 0); - - continue; - } - - if (($value > 0) !== $positive) { - return $this->invertCascade($originalData) - ->solveNegativeInterval(); - } - } - } - } - - return $this->set($newData) - ->solveNegativeInterval(); - } - /** * Convert overflowed values into bigger units. * * @return $this */ - public function cascade() + public function cascade(): static { return $this->doCascade(false); } @@ -2515,7 +2598,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return float */ - public function total($unit) + public function total(string $unit): float { $realUnit = $unit = strtolower($unit); @@ -2525,6 +2608,14 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface throw new UnknownUnitException($unit); } + $this->checkStartAndEnd(); + + if ($this->startDate && $this->endDate) { + $diff = $this->startDate->diffInUnit($unit, $this->endDate); + + return $this->absolute ? abs($diff) : $diff; + } + $result = 0; $cumulativeFactor = 0; $unitFound = false; @@ -2592,7 +2683,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface } if ($this->invert) { - $result *= -1; + $result *= self::NEGATIVE; } if ($unit === 'weeks') { @@ -2628,7 +2719,25 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface { $interval = $this->resolveInterval($interval); - return $interval !== null && $this->totalMicroseconds === $interval->totalMicroseconds; + if ($interval === null) { + return false; + } + + $step = $this->getStep(); + + if ($step) { + return $step === $interval->getStep(); + } + + if ($this->isEmpty()) { + return $interval->isEmpty(); + } + + $cascadedInterval = $this->copy()->cascade(); + $comparedInterval = $interval->copy()->cascade(); + + return $cascadedInterval->invert === $comparedInterval->invert && + $cascadedInterval->getNonZeroValues() === $comparedInterval->getNonZeroValues(); } /** @@ -2786,7 +2895,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return bool */ - public function between($interval1, $interval2, $equal = true): bool + public function between($interval1, $interval2, bool $equal = true): bool { return $equal ? $this->greaterThanOrEqualTo($interval1) && $this->lessThanOrEqualTo($interval2) @@ -2850,7 +2959,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return bool */ - public function isBetween($interval1, $interval2, $equal = true): bool + public function isBetween($interval1, $interval2, bool $equal = true): bool { return $this->between($interval1, $interval2, $equal); } @@ -2858,15 +2967,9 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Round the current instance at the given unit with given precision if specified and the given function. * - * @param string $unit - * @param float|int|string|DateInterval|null $precision - * @param string $function - * * @throws Exception - * - * @return $this */ - public function roundUnit($unit, $precision = 1, $function = 'round') + public function roundUnit(string $unit, DateInterval|string|int|float $precision = 1, string $function = 'round'): static { if (static::getCascadeFactors() !== static::getDefaultCascadeFactors()) { $value = $function($this->total($unit) / $precision) * $precision; @@ -2889,7 +2992,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $this->copyProperties( $next ->roundUnit($unit, $precision, $function) - ->diffAsCarbonInterval($base) + ->diff($base), ); return $this->invert($inverted); @@ -2905,7 +3008,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function floorUnit($unit, $precision = 1) + public function floorUnit(string $unit, $precision = 1): static { return $this->roundUnit($unit, $precision, 'floor'); } @@ -2920,7 +3023,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function ceilUnit($unit, $precision = 1) + public function ceilUnit(string $unit, $precision = 1): static { return $this->roundUnit($unit, $precision, 'ceil'); } @@ -2935,7 +3038,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface * * @return $this */ - public function round($precision = 1, $function = 'round') + public function round($precision = 1, string $function = 'round'): static { return $this->roundWith($precision, $function); } @@ -2943,13 +3046,11 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Round the current instance second with given precision if specified. * - * @param float|int|string|DateInterval|null $precision - * * @throws Exception * * @return $this */ - public function floor($precision = 1) + public function floor(DateInterval|string|float|int $precision = 1): static { return $this->round($precision, 'floor'); } @@ -2957,28 +3058,333 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Ceil the current instance second with given precision if specified. * - * @param float|int|string|DateInterval|null $precision - * * @throws Exception * * @return $this */ - public function ceil($precision = 1) + public function ceil(DateInterval|string|float|int $precision = 1): static { return $this->round($precision, 'ceil'); } - private function needsDeclension(string $mode, int $index, int $parts): bool + public function __unserialize(array $data): void { - switch ($mode) { - case 'last': - return $index === $parts - 1; - default: - return true; + $properties = array_combine( + array_map( + static fn (mixed $key) => \is_string($key) + ? str_replace('tzName', 'timezoneSetting', $key) + : $key, + array_keys($data), + ), + $data, + ); + + if (method_exists(parent::class, '__unserialize')) { + // PHP >= 8.2 + parent::__unserialize($properties); + + return; + } + + // PHP <= 8.1 + // @codeCoverageIgnoreStart + $properties = array_combine( + array_map( + static fn (string $property) => preg_replace('/^\0.+\0/', '', $property), + array_keys($data), + ), + $data, + ); + $localStrictMode = $this->localStrictModeEnabled; + $this->localStrictModeEnabled = false; + $days = $properties['days'] ?? false; + $this->days = $days === false ? false : (int) $days; + $this->y = (int) ($properties['y'] ?? 0); + $this->m = (int) ($properties['m'] ?? 0); + $this->d = (int) ($properties['d'] ?? 0); + $this->h = (int) ($properties['h'] ?? 0); + $this->i = (int) ($properties['i'] ?? 0); + $this->s = (int) ($properties['s'] ?? 0); + $this->f = (float) ($properties['f'] ?? 0.0); + // @phpstan-ignore-next-line + $this->weekday = (int) ($properties['weekday'] ?? 0); + // @phpstan-ignore-next-line + $this->weekday_behavior = (int) ($properties['weekday_behavior'] ?? 0); + // @phpstan-ignore-next-line + $this->first_last_day_of = (int) ($properties['first_last_day_of'] ?? 0); + $this->invert = (int) ($properties['invert'] ?? 0); + // @phpstan-ignore-next-line + $this->special_type = (int) ($properties['special_type'] ?? 0); + // @phpstan-ignore-next-line + $this->special_amount = (int) ($properties['special_amount'] ?? 0); + // @phpstan-ignore-next-line + $this->have_weekday_relative = (int) ($properties['have_weekday_relative'] ?? 0); + // @phpstan-ignore-next-line + $this->have_special_relative = (int) ($properties['have_special_relative'] ?? 0); + parent::__construct(self::getDateIntervalSpec($this)); + + foreach ($properties as $property => $value) { + if ($property === 'localStrictModeEnabled') { + continue; + } + + $this->$property = $value; + } + + $this->localStrictModeEnabled = $properties['localStrictModeEnabled'] ?? $localStrictMode; + // @codeCoverageIgnoreEnd + } + + /** + * @template T + * + * @param T $interval + * @param mixed $original + * + * @return T + */ + private static function withOriginal(mixed $interval, mixed $original): mixed + { + if ($interval instanceof self) { + $interval->originalInput = $original; + } + + return $interval; + } + + private static function standardizeUnit(string $unit): string + { + $unit = rtrim($unit, 'sz').'s'; + + return $unit === 'days' ? 'dayz' : $unit; + } + + private static function getFlipCascadeFactors(): array + { + if (!self::$flipCascadeFactors) { + self::$flipCascadeFactors = []; + + foreach (self::getCascadeFactors() as $to => [$factor, $from]) { + self::$flipCascadeFactors[self::standardizeUnit($from)] = [self::standardizeUnit($to), $factor]; + } + } + + return self::$flipCascadeFactors; + } + + /** + * @template T of DateInterval + * + * @param DateInterval $interval + * + * @psalm-param class-string $className + * + * @return T + */ + private static function castIntervalToClass(DateInterval $interval, string $className, array $skip = []): object + { + $mainClass = DateInterval::class; + + if (!is_a($className, $mainClass, true)) { + throw new InvalidCastException("$className is not a sub-class of $mainClass."); + } + + $microseconds = $interval->f; + $instance = self::buildInstance($interval, $className, $skip); + + if ($instance instanceof self) { + $instance->originalInput = $interval; + } + + if ($microseconds) { + $instance->f = $microseconds; + } + + if ($interval instanceof self && is_a($className, self::class, true)) { + self::copyStep($interval, $instance); + } + + self::copyNegativeUnits($interval, $instance); + + return self::withOriginal($instance, $interval); + } + + /** + * @template T of DateInterval + * + * @param DateInterval $interval + * + * @psalm-param class-string $className + * + * @return T + */ + private static function buildInstance( + DateInterval $interval, + string $className, + array $skip = [], + ): object { + $serialization = self::buildSerializationString($interval, $className, $skip); + + return match ($serialization) { + null => new $className(static::getDateIntervalSpec($interval, false, $skip)), + default => unserialize($serialization), + }; + } + + /** + * As demonstrated by rlanvin (https://github.com/rlanvin) in + * https://github.com/briannesbitt/Carbon/issues/3018#issuecomment-2888538438 + * + * Modifying the output of serialize() to change the class name and unserializing + * the tweaked string allows creating new interval instances where the ->days + * property can be set. It's not possible neither with `new` nto with `__set_state`. + * + * It has a non-negligible performance cost, so we'll use this method only if + * $interval->days !== false. + */ + private static function buildSerializationString( + DateInterval $interval, + string $className, + array $skip = [], + ): ?string { + if ($interval->days === false || PHP_VERSION_ID < 8_02_00 || $skip !== []) { + return null; + } + + // De-enhance CarbonInterval objects to be serializable back to DateInterval + if ($interval instanceof self && !is_a($className, self::class, true)) { + $interval = clone $interval; + unset($interval->timezoneSetting); + unset($interval->originalInput); + unset($interval->startDate); + unset($interval->endDate); + unset($interval->rawInterval); + unset($interval->absolute); + unset($interval->initialValues); + unset($interval->clock); + unset($interval->step); + unset($interval->localMonthsOverflow); + unset($interval->localYearsOverflow); + unset($interval->localStrictModeEnabled); + unset($interval->localHumanDiffOptions); + unset($interval->localToStringFormat); + unset($interval->localSerializer); + unset($interval->localMacros); + unset($interval->localGenericMacros); + unset($interval->localFormatFunction); + unset($interval->localTranslator); + } + + $serialization = serialize($interval); + $inputClass = $interval::class; + $expectedStart = 'O:'.\strlen($inputClass).':"'.$inputClass.'":'; + + if (!str_starts_with($serialization, $expectedStart)) { + return null; // @codeCoverageIgnore + } + + return 'O:'.\strlen($className).':"'.$className.'":'.substr($serialization, \strlen($expectedStart)); + } + + private static function copyStep(self $from, self $to): void + { + $to->setStep($from->getStep()); + } + + private static function copyNegativeUnits(DateInterval $from, DateInterval $to): void + { + $to->invert = $from->invert; + + foreach (['y', 'm', 'd', 'h', 'i', 's'] as $unit) { + if ($from->$unit < 0) { + self::setIntervalUnit($to, $unit, $to->$unit * self::NEGATIVE); + } } } - private function checkIntegerValue(string $name, $value) + private function invertCascade(array $values): static + { + return $this->set(array_map(function ($value) { + return -$value; + }, $values))->doCascade(true)->invert(); + } + + private function doCascade(bool $deep): static + { + $originalData = $this->toArray(); + $originalData['milliseconds'] = (int) ($originalData['microseconds'] / static::getMicrosecondsPerMillisecond()); + $originalData['microseconds'] = $originalData['microseconds'] % static::getMicrosecondsPerMillisecond(); + $originalData['weeks'] = (int) ($this->d / static::getDaysPerWeek()); + $originalData['daysExcludeWeeks'] = fmod($this->d, static::getDaysPerWeek()); + unset($originalData['days']); + $newData = $originalData; + $previous = []; + + foreach (self::getFlipCascadeFactors() as $source => [$target, $factor]) { + foreach (['source', 'target'] as $key) { + if ($$key === 'dayz') { + $$key = 'daysExcludeWeeks'; + } + } + + $value = $newData[$source]; + $modulo = fmod($factor + fmod($value, $factor), $factor); + $newData[$source] = $modulo; + $newData[$target] += ($value - $modulo) / $factor; + + $decimalPart = fmod($newData[$source], 1); + + if ($decimalPart !== 0.0) { + $unit = $source; + + foreach ($previous as [$subUnit, $subFactor]) { + $newData[$unit] -= $decimalPart; + $newData[$subUnit] += $decimalPart * $subFactor; + $decimalPart = fmod($newData[$subUnit], 1); + + if ($decimalPart === 0.0) { + break; + } + + $unit = $subUnit; + } + } + + array_unshift($previous, [$source, $factor]); + } + + $positive = null; + + if (!$deep) { + foreach ($newData as $value) { + if ($value) { + if ($positive === null) { + $positive = ($value > 0); + + continue; + } + + if (($value > 0) !== $positive) { + return $this->invertCascade($originalData) + ->solveNegativeInterval(); + } + } + } + } + + return $this->set($newData) + ->solveNegativeInterval(); + } + + private function needsDeclension(string $mode, int $index, int $parts): bool + { + return match ($mode) { + 'last' => $index === $parts - 1, + default => true, + }; + } + + private function checkIntegerValue(string $name, mixed $value): void { if (\is_int($value)) { return; @@ -2998,7 +3404,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface "From 3.0.0, decimal part will no longer be truncated and will be cascaded to smaller units.\n". "- To maintain the current behavior, use explicit cast: $name((int) \$value)\n". "- To adopt the new behavior globally, call CarbonInterval::enableFloatSetters()\n", - \E_USER_DEPRECATED + \E_USER_DEPRECATED, ); } } @@ -3006,14 +3412,14 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface /** * Throw an exception if precision loss when storing the given value as an integer would be >= 1.0. */ - private function assertSafeForInteger(string $name, $value) + private function assertSafeForInteger(string $name, mixed $value): void { if ($value && !\is_int($value) && ($value >= 0x7fffffffffffffff || $value <= -0x7fffffffffffffff)) { throw new OutOfRangeException($name, -0x7fffffffffffffff, 0x7fffffffffffffff, $value); } } - private function handleDecimalPart(string $unit, $value, $integerValue) + private function handleDecimalPart(string $unit, mixed $value, mixed $integerValue): void { if (self::$floatSettersEnabled) { $floatValue = (float) $value; @@ -3051,4 +3457,116 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface $this->add($unit, $floatValue - $base); } } + + private function getInnerValues(): array + { + return [$this->y, $this->m, $this->d, $this->h, $this->i, $this->s, $this->f, $this->invert, $this->days]; + } + + private function checkStartAndEnd(): void + { + if ( + $this->initialValues !== null + && ($this->startDate !== null || $this->endDate !== null) + && $this->initialValues !== $this->getInnerValues() + ) { + $this->absolute = false; + $this->startDate = null; + $this->endDate = null; + $this->rawInterval = null; + } + } + + /** @return $this */ + private function setSetting(string $setting, mixed $value): self + { + switch ($setting) { + case 'timezoneSetting': + return $value === null ? $this : $this->setTimezone($value); + + case 'step': + $this->setStep($value); + + return $this; + + case 'localMonthsOverflow': + return $value === null ? $this : $this->settings(['monthOverflow' => $value]); + + case 'localYearsOverflow': + return $value === null ? $this : $this->settings(['yearOverflow' => $value]); + + case 'localStrictModeEnabled': + case 'localHumanDiffOptions': + case 'localToStringFormat': + case 'localSerializer': + case 'localMacros': + case 'localGenericMacros': + case 'localFormatFunction': + case 'localTranslator': + $this->$setting = $value; + + return $this; + + default: + // Drop unknown settings + return $this; + } + } + + private static function incrementUnit(DateInterval $instance, string $unit, int $value): void + { + if ($value === 0) { + return; + } + + // @codeCoverageIgnoreStart + if (PHP_VERSION_ID !== 8_03_20) { + $instance->$unit += $value; + + return; + } + + // Cannot use +=, nor set to a negative value directly as it segfaults in PHP 8.3.20 + self::setIntervalUnit($instance, $unit, ($instance->$unit ?? 0) + $value); + // @codeCoverageIgnoreEnd + } + + /** @codeCoverageIgnore */ + private static function setIntervalUnit(DateInterval $instance, string $unit, mixed $value): void + { + switch ($unit) { + case 'y': + $instance->y = $value; + + break; + + case 'm': + $instance->m = $value; + + break; + + case 'd': + $instance->d = $value; + + break; + + case 'h': + $instance->h = $value; + + break; + + case 'i': + $instance->i = $value; + + break; + + case 's': + $instance->s = $value; + + break; + + default: + $instance->$unit = $value; + } + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriod.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriod.php index d12a98697..7ae64ebf8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriod.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriod.php @@ -1,5 +1,7 @@ rewind(); + + while ($this->valid()) { + $key = $this->key(); + $value = $this->current(); + + yield $key => $value; + + $this->next(); + } + } /** * Make a CarbonPeriod instance from given variable if possible. - * - * @param mixed $var - * - * @return static|null */ - public static function make($var) + public static function make(mixed $var): ?static { try { return static::instance($var); - } catch (NotAPeriodException $e) { + } catch (NotAPeriodException) { return static::create($var); } } /** * Create a new instance from a DatePeriod or CarbonPeriod object. - * - * @param CarbonPeriod|DatePeriod $period - * - * @return static */ - public static function instance($period) + public static function instance(mixed $period): static { if ($period instanceof static) { return $period->copy(); @@ -384,9 +363,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable if ($period instanceof self) { return new static( $period->getStartDate(), - $period->getEndDate() ?: $period->getRecurrences(), + $period->getEndDate() ?? $period->getRecurrences(), $period->getDateInterval(), - $period->getOptions() + $period->getOptions(), ); } @@ -395,71 +374,61 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $period->start, $period->end ?: ($period->recurrences - 1), $period->interval, - $period->include_start_date ? 0 : static::EXCLUDE_START_DATE + $period->include_start_date ? 0 : static::EXCLUDE_START_DATE, ); } $class = static::class; $type = \gettype($period); + $chunks = explode('::', __METHOD__); throw new NotAPeriodException( - 'Argument 1 passed to '.$class.'::'.__METHOD__.'() '. + 'Argument 1 passed to '.$class.'::'.end($chunks).'() '. 'must be an instance of DatePeriod or '.$class.', '. - ($type === 'object' ? 'instance of '.\get_class($period) : $type).' given.' + ($type === 'object' ? 'instance of '.\get_class($period) : $type).' given.', ); } /** * Create a new instance. - * - * @return static */ - public static function create(...$params) + public static function create(...$params): static { return static::createFromArray($params); } /** * Create a new instance from an array of parameters. - * - * @param array $params - * - * @return static */ - public static function createFromArray(array $params) + public static function createFromArray(array $params): static { return new static(...$params); } /** * Create CarbonPeriod from ISO 8601 string. - * - * @param string $iso - * @param int|null $options - * - * @return static */ - public static function createFromIso($iso, $options = null) + public static function createFromIso(string $iso, ?int $options = null): static { $params = static::parseIso8601($iso); $instance = static::createFromArray($params); - if ($options !== null) { - $instance->setOptions($options); - } + $instance->options = ($instance instanceof CarbonPeriodImmutable ? static::IMMUTABLE : 0) | $options; + $instance->handleChangedParameters(); return $instance; } + public static function createFromISO8601String(string $iso, ?int $options = null): static + { + return self::createFromIso($iso, $options); + } + /** - * Return whether given interval contains non zero value of any time unit. - * - * @param \DateInterval $interval - * - * @return bool + * Return whether the given interval contains non-zero value of any time unit. */ - protected static function intervalHasTime(DateInterval $interval) + protected static function intervalHasTime(DateInterval $interval): bool { return $interval->h || $interval->i || $interval->s || $interval->f; } @@ -468,13 +437,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Return whether given variable is an ISO 8601 specification. * * Note: Check is very basic, as actual validation will be done later when parsing. - * We just want to ensure that variable is not any other type of a valid parameter. - * - * @param mixed $var - * - * @return bool + * We just want to ensure that variable is not any other type of valid parameter. */ - protected static function isIso8601($var) + protected static function isIso8601(mixed $var): bool { if (!\is_string($var)) { return false; @@ -491,13 +456,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Parse given ISO 8601 string into an array of arguments. * - * @SuppressWarnings(PHPMD.ElseExpression) - * - * @param string $iso - * - * @return array + * @SuppressWarnings(ElseExpression) */ - protected static function parseIso8601($iso) + protected static function parseIso8601(string $iso): array { $result = []; @@ -509,7 +470,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable foreach (explode('/', $iso) as $key => $part) { if ($key === 0 && preg_match('/^R(\d*|INF)$/', $part, $match)) { $parsed = \strlen($match[1]) ? (($match[1] !== 'INF') ? (int) $match[1] : INF) : null; - } elseif ($interval === null && $parsed = CarbonInterval::make($part)) { + } elseif ($interval === null && $parsed = self::makeInterval($part)) { $interval = $part; } elseif ($start === null && $parsed = $dateClass::make($part)) { $start = $part; @@ -527,13 +488,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Add missing parts of the target date from the source date. - * - * @param string $source - * @param string $target - * - * @return string */ - protected static function addMissingParts($source, $target) + protected static function addMissingParts(string $source, string $target): string { $pattern = '/'.preg_replace('/\d+/', '[0-9]+', preg_quote($target, '/')).'$/'; @@ -542,9 +498,33 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $count ? $result : $target; } + private static function makeInterval(mixed $input): ?CarbonInterval + { + try { + return CarbonInterval::make($input); + } catch (Throwable) { + return null; + } + } + + private static function makeTimezone(mixed $input): ?CarbonTimeZone + { + if (!\is_string($input)) { + return null; + } + + try { + return CarbonTimeZone::create($input); + } catch (Throwable) { + return null; + } + } + /** * Register a custom macro. * + * Pass null macro to remove it. + * * @example * ``` * CarbonPeriod::macro('middle', function () { @@ -553,12 +533,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * echo CarbonPeriod::since('2011-05-12')->until('2011-06-03')->middle(); * ``` * - * @param string $name - * @param object|callable $macro - * - * @return void + * @param-closure-this static $macro */ - public static function macro($name, $macro) + public static function macro(string $name, ?callable $macro): void { static::$macros[$name] = $macro; } @@ -591,45 +568,30 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * echo CarbonPeriod::create('2000-01-01', '2000-02-01')->addDays(5)->subDays(3); * ``` * - * @param object|string $mixin - * * @throws ReflectionException - * - * @return void */ - public static function mixin($mixin) + public static function mixin(object|string $mixin): void { static::baseMixin($mixin); } /** * Check if macro is registered. - * - * @param string $name - * - * @return bool */ - public static function hasMacro($name) + public static function hasMacro(string $name): bool { return isset(static::$macros[$name]); } /** * Provide static proxy for instance aliases. - * - * @param string $method - * @param array $parameters - * - * @return mixed */ - public static function __callStatic($method, $parameters) + public static function __callStatic(string $method, array $parameters): mixed { $date = new static(); if (static::hasMacro($method)) { - return static::bindMacroContext(null, function () use (&$method, &$parameters, &$date) { - return $date->callMacro($method, $parameters); - }); + return static::bindMacroContext(null, static fn () => $date->callMacro($method, $parameters)); } return $date->$method(...$parameters); @@ -638,14 +600,23 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * CarbonPeriod constructor. * - * @SuppressWarnings(PHPMD.ElseExpression) + * @SuppressWarnings(ElseExpression) * * @throws InvalidArgumentException */ public function __construct(...$arguments) { - if (is_a($this->dateClass, DateTimeImmutable::class, true)) { - $this->options = static::IMMUTABLE; + $raw = null; + + if (isset($arguments['raw'])) { + $raw = $arguments['raw']; + $this->isDefaultInterval = $arguments['isDefaultInterval'] ?? false; + + if (isset($arguments['dateClass'])) { + $this->dateClass = $arguments['dateClass']; + } + + $arguments = $raw; } // Parse and assign arguments one by one. First argument may be an ISO 8601 spec, @@ -658,56 +629,87 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable } if ($argumentsCount === 1) { - if ($arguments[0] instanceof DatePeriod) { + if ($arguments[0] instanceof self) { + $arguments = [ + $arguments[0]->getStartDate(), + $arguments[0]->getEndDate() ?? $arguments[0]->getRecurrences(), + $arguments[0]->getDateInterval(), + $arguments[0]->getOptions(), + ]; + } elseif ($arguments[0] instanceof DatePeriod) { $arguments = [ $arguments[0]->start, $arguments[0]->end ?: ($arguments[0]->recurrences - 1), $arguments[0]->interval, $arguments[0]->include_start_date ? 0 : static::EXCLUDE_START_DATE, ]; - } elseif ($arguments[0] instanceof self) { - $arguments = [ - $arguments[0]->getStartDate(), - $arguments[0]->getEndDate() ?: $arguments[0]->getRecurrences(), - $arguments[0]->getDateInterval(), - $arguments[0]->getOptions(), - ]; } } + if (is_a($this->dateClass, DateTimeImmutable::class, true)) { + $this->options = static::IMMUTABLE; + } + $optionsSet = false; + $originalArguments = []; + $sortedArguments = []; foreach ($arguments as $argument) { $parsedDate = null; if ($argument instanceof DateTimeZone) { - $this->setTimezone($argument); - } elseif ($this->dateInterval === null && + $sortedArguments = $this->configureTimezone($argument, $sortedArguments, $originalArguments); + } elseif (!isset($sortedArguments['interval']) && ( (\is_string($argument) && preg_match( '/^(-?\d(\d(?![\/-])|[^\d\/-]([\/-])?)*|P[T\d].*|(?:\h*\d+(?:\.\d+)?\h*[a-z]+)+)$/i', - $argument + $argument, )) || $argument instanceof DateInterval || - $argument instanceof Closure + $argument instanceof Closure || + $argument instanceof Unit ) && - $parsedInterval = @CarbonInterval::make($argument) + $parsedInterval = self::makeInterval($argument) ) { - $this->setDateInterval($parsedInterval); - } elseif ($this->startDate === null && $parsedDate = $this->makeDateTime($argument)) { - $this->setStartDate($parsedDate); - } elseif ($this->endDate === null && ($parsedDate = $parsedDate ?? $this->makeDateTime($argument))) { - $this->setEndDate($parsedDate); - } elseif ($this->recurrences === null && $this->endDate === null && is_numeric($argument)) { - $this->setRecurrences($argument); + $sortedArguments['interval'] = $parsedInterval; + } elseif (!isset($sortedArguments['start']) && $parsedDate = $this->makeDateTime($argument)) { + $sortedArguments['start'] = $parsedDate; + $originalArguments['start'] = $argument; + } elseif (!isset($sortedArguments['end']) && ($parsedDate = $parsedDate ?? $this->makeDateTime($argument))) { + $sortedArguments['end'] = $parsedDate; + $originalArguments['end'] = $argument; + } elseif (!isset($sortedArguments['recurrences']) && + !isset($sortedArguments['end']) && + (\is_int($argument) || \is_float($argument)) + && $argument >= 0 + ) { + $sortedArguments['recurrences'] = $argument; } elseif (!$optionsSet && (\is_int($argument) || $argument === null)) { $optionsSet = true; - $this->setOptions(((int) $this->options) | ((int) $argument)); + $sortedArguments['options'] = (((int) $this->options) | ((int) $argument)); + } elseif ($parsedTimezone = self::makeTimezone($argument)) { + $sortedArguments = $this->configureTimezone($parsedTimezone, $sortedArguments, $originalArguments); } else { throw new InvalidPeriodParameterException('Invalid constructor parameters.'); } } + if ($raw === null && isset($sortedArguments['start'])) { + $end = $sortedArguments['end'] ?? max(1, $sortedArguments['recurrences'] ?? 1); + + if (\is_float($end)) { + $end = $end === INF ? PHP_INT_MAX : (int) round($end); + } + + $raw = [ + $sortedArguments['start'], + $sortedArguments['interval'] ?? CarbonInterval::day(), + $end, + ]; + } + + $this->setFromAssociativeArray($sortedArguments); + if ($this->startDate === null) { $dateClass = $this->dateClass; $this->setStartDate($dateClass::now()); @@ -723,15 +725,20 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $this->setOptions(0); } + parent::__construct( + $this->startDate, + $this->dateInterval, + $this->endDate ?? max(1, min(2147483639, $this->recurrences ?? 1)), + $this->options, + ); + $this->constructed = true; } /** * Get a copy of the instance. - * - * @return static */ - public function copy() + public function copy(): static { return clone $this; } @@ -739,44 +746,34 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Prepare the instance to be set (self if mutable to be mutated, * copy if immutable to generate a new instance). - * - * @return static */ - protected function copyIfImmutable() + protected function copyIfImmutable(): static { return $this; } /** * Get the getter for a property allowing both `DatePeriod` snakeCase and camelCase names. - * - * @param string $name - * - * @return callable|null */ - protected function getGetter(string $name) + protected function getGetter(string $name): ?callable { - switch (strtolower(preg_replace('/[A-Z]/', '_$0', $name))) { - case 'start': - case 'start_date': - return [$this, 'getStartDate']; - case 'end': - case 'end_date': - return [$this, 'getEndDate']; - case 'interval': - case 'date_interval': - return [$this, 'getDateInterval']; - case 'recurrences': - return [$this, 'getRecurrences']; - case 'include_start_date': - return [$this, 'isStartIncluded']; - case 'include_end_date': - return [$this, 'isEndIncluded']; - case 'current': - return [$this, 'current']; - default: - return null; - } + return match (strtolower(preg_replace('/[A-Z]/', '_$0', $name))) { + 'start', 'start_date' => [$this, 'getStartDate'], + 'end', 'end_date' => [$this, 'getEndDate'], + 'interval', 'date_interval' => [$this, 'getDateInterval'], + 'recurrences' => [$this, 'getRecurrences'], + 'include_start_date' => [$this, 'isStartIncluded'], + 'include_end_date' => [$this, 'isEndIncluded'], + 'current' => [$this, 'current'], + 'locale' => [$this, 'locale'], + 'tzname', 'tz_name' => fn () => match (true) { + $this->timezoneSetting === null => null, + \is_string($this->timezoneSetting) => $this->timezoneSetting, + $this->timezoneSetting instanceof DateTimeZone => $this->timezoneSetting->getName(), + default => CarbonTimeZone::instance($this->timezoneSetting)->getName(), + }, + default => null, + }; } /** @@ -871,15 +868,24 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Change the period date interval. * - * @param DateInterval|string $interval + * @param DateInterval|Unit|string|int $interval + * @param Unit|string $unit the unit of $interval if it's a number * * @throws InvalidIntervalException * * @return static */ - public function setDateInterval($interval) + public function setDateInterval(mixed $interval, Unit|string|null $unit = null): static { - if (!$interval = CarbonInterval::make($interval)) { + if ($interval instanceof Unit) { + $interval = $interval->interval(); + } + + if ($unit instanceof Unit) { + $unit = $unit->name; + } + + if (!$interval = CarbonInterval::make($interval, $unit)) { throw new InvalidIntervalException('Invalid interval.'); } @@ -898,11 +904,25 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable } /** - * Invert the period date interval. + * Reset the date interval to the default value. * - * @return static + * Difference with simply setting interval to 1-day is that P1D will not appear when calling toIso8601String() + * and also next adding to the interval won't include the default 1-day. */ - public function invertDateInterval() + public function resetDateInterval(): static + { + $self = $this->copyIfImmutable(); + $self->setDateInterval(CarbonInterval::day()); + + $self->isDefaultInterval = true; + + return $self; + } + + /** + * Invert the period date interval. + */ + public function invertDateInterval(): static { return $this->setDateInterval($this->dateInterval->invert()); } @@ -915,7 +935,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return static */ - public function setDates($start, $end) + public function setDates(mixed $start, mixed $end): static { return $this->setStartDate($start)->setEndDate($end); } @@ -925,18 +945,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @param int|null $options * - * @throws InvalidArgumentException - * * @return static */ - public function setOptions($options) + public function setOptions(?int $options): static { - if (!\is_int($options) && $options !== null) { - throw new InvalidPeriodParameterException('Invalid options.'); - } - $self = $this->copyIfImmutable(); - $self->options = $options ?: 0; + $self->options = $options ?? 0; $self->handleChangedParameters(); @@ -945,12 +959,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Get the period options. - * - * @return int */ - public function getOptions() + public function getOptions(): int { - return $this->options; + return $this->options ?? 0; } /** @@ -959,53 +971,45 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * @param int $options * @param bool|null $state * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return static */ - public function toggleOptions($options, $state = null) + public function toggleOptions(int $options, ?bool $state = null): static { + $self = $this->copyIfImmutable(); + if ($state === null) { $state = ($this->options & $options) !== $options; } - return $this->setOptions( + return $self->setOptions( $state ? $this->options | $options : - $this->options & ~$options + $this->options & ~$options, ); } /** * Toggle EXCLUDE_START_DATE option. - * - * @param bool $state - * - * @return static */ - public function excludeStartDate($state = true) + public function excludeStartDate(bool $state = true): static { return $this->toggleOptions(static::EXCLUDE_START_DATE, $state); } /** * Toggle EXCLUDE_END_DATE option. - * - * @param bool $state - * - * @return static */ - public function excludeEndDate($state = true) + public function excludeEndDate(bool $state = true): static { return $this->toggleOptions(static::EXCLUDE_END_DATE, $state); } /** * Get the underlying date interval. - * - * @return CarbonInterval */ - public function getDateInterval() + public function getDateInterval(): CarbonInterval { return $this->dateInterval->copy(); } @@ -1014,10 +1018,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Get start date of the period. * * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval. - * - * @return CarbonInterface */ - public function getStartDate(string $rounding = null) + public function getStartDate(?string $rounding = null): CarbonInterface { $date = $this->startDate->avoidMutation(); @@ -1028,10 +1030,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Get end date of the period. * * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval. - * - * @return CarbonInterface|null */ - public function getEndDate(string $rounding = null) + public function getEndDate(?string $rounding = null): ?CarbonInterface { if (!$this->endDate) { return null; @@ -1044,60 +1044,49 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Get number of recurrences. - * - * @return int|float|null */ - public function getRecurrences() + #[ReturnTypeWillChange] + public function getRecurrences(): int|float|null { - return $this->recurrences; + return $this->carbonRecurrences; } /** * Returns true if the start date should be excluded. - * - * @return bool */ - public function isStartExcluded() + public function isStartExcluded(): bool { return ($this->options & static::EXCLUDE_START_DATE) !== 0; } /** * Returns true if the end date should be excluded. - * - * @return bool */ - public function isEndExcluded() + public function isEndExcluded(): bool { return ($this->options & static::EXCLUDE_END_DATE) !== 0; } /** * Returns true if the start date should be included. - * - * @return bool */ - public function isStartIncluded() + public function isStartIncluded(): bool { return !$this->isStartExcluded(); } /** * Returns true if the end date should be included. - * - * @return bool */ - public function isEndIncluded() + public function isEndIncluded(): bool { return !$this->isEndExcluded(); } /** * Return the start if it's included by option, else return the start + 1 period interval. - * - * @return CarbonInterface */ - public function getIncludedStartDate() + public function getIncludedStartDate(): CarbonInterface { $start = $this->getStartDate(); @@ -1111,10 +1100,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return the end if it's included by option, else return the end - 1 period interval. * Warning: if the period has no fixed end, this method will iterate the period to calculate it. - * - * @return CarbonInterface */ - public function getIncludedEndDate() + public function getIncludedEndDate(): CarbonInterface { $end = $this->getEndDate(); @@ -1132,14 +1119,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Add a filter to the stack. * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param callable $callback - * @param string $name - * - * @return static + * @SuppressWarnings(UnusedFormalParameter) */ - public function addFilter($callback, $name = null) + public function addFilter(callable|string $callback, ?string $name = null): static { $self = $this->copyIfImmutable(); $tuple = $self->createFilterTuple(\func_get_args()); @@ -1154,14 +1136,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Prepend a filter to the stack. * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param callable $callback - * @param string $name - * - * @return static + * @SuppressWarnings(UnusedFormalParameter) */ - public function prependFilter($callback, $name = null) + public function prependFilter(callable|string $callback, ?string $name = null): static { $self = $this->copyIfImmutable(); $tuple = $self->createFilterTuple(\func_get_args()); @@ -1175,21 +1152,15 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Remove a filter by instance or name. - * - * @param callable|string $filter - * - * @return static */ - public function removeFilter($filter) + public function removeFilter(callable|string $filter): static { $self = $this->copyIfImmutable(); $key = \is_callable($filter) ? 0 : 1; $self->filters = array_values(array_filter( $this->filters, - function ($tuple) use ($key, $filter) { - return $tuple[$key] !== $filter; - } + static fn ($tuple) => $tuple[$key] !== $filter, )); $self->updateInternalState(); @@ -1201,12 +1172,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return whether given instance or name is in the filter stack. - * - * @param callable|string $filter - * - * @return bool */ - public function hasFilter($filter) + public function hasFilter(callable|string $filter): bool { $key = \is_callable($filter) ? 0 : 1; @@ -1221,22 +1188,16 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Get filters stack. - * - * @return array */ - public function getFilters() + public function getFilters(): array { return $this->filters; } /** * Set filters stack. - * - * @param array $filters - * - * @return static */ - public function setFilters(array $filters) + public function setFilters(array $filters): static { $self = $this->copyIfImmutable(); $self->filters = $filters; @@ -1250,10 +1211,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Reset filters stack. - * - * @return static */ - public function resetFilters() + public function resetFilters(): static { $self = $this->copyIfImmutable(); $self->filters = []; @@ -1262,7 +1221,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $self->filters[] = [static::END_DATE_FILTER, null]; } - if ($self->recurrences !== null) { + if ($self->carbonRecurrences !== null) { $self->filters[] = [static::RECURRENCES_FILTER, null]; } @@ -1274,25 +1233,21 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Add a recurrences filter (set maximum number of recurrences). * - * @param int|float|null $recurrences - * * @throws InvalidArgumentException - * - * @return static */ - public function setRecurrences($recurrences) + public function setRecurrences(int|float|null $recurrences): static { - if ((!is_numeric($recurrences) && $recurrences !== null) || $recurrences < 0) { - throw new InvalidPeriodParameterException('Invalid number of recurrences.'); - } - if ($recurrences === null) { return $this->removeFilter(static::RECURRENCES_FILTER); } + if ($recurrences < 0) { + throw new InvalidPeriodParameterException('Invalid number of recurrences.'); + } + /** @var self $self */ $self = $this->copyIfImmutable(); - $self->recurrences = $recurrences === INF ? INF : (int) $recurrences; + $self->carbonRecurrences = $recurrences === INF ? INF : (int) $recurrences; if (!$self->hasFilter(static::RECURRENCES_FILTER)) { return $self->addFilter(static::RECURRENCES_FILTER); @@ -1313,9 +1268,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return static */ - public function setStartDate($date, $inclusive = null) + public function setStartDate(mixed $date, ?bool $inclusive = null): static { - if (!$this->isInfiniteDate($date) && !($date = ([$this->dateClass, 'make'])($date))) { + if (!$this->isInfiniteDate($date) && !($date = ([$this->dateClass, 'make'])($date, $this->timezone))) { throw new InvalidPeriodDateException('Invalid start date.'); } @@ -1339,9 +1294,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return static */ - public function setEndDate($date, $inclusive = null) + public function setEndDate(mixed $date, ?bool $inclusive = null): static { - if ($date !== null && !$this->isInfiniteDate($date) && !$date = ([$this->dateClass, 'make'])($date)) { + if ($date !== null && !$this->isInfiniteDate($date) && !$date = ([$this->dateClass, 'make'])($date, $this->timezone)) { throw new InvalidPeriodDateException('Invalid end date.'); } @@ -1367,22 +1322,16 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Check if the current position is valid. - * - * @return bool */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return $this->validateCurrentDate() === true; } /** * Return the current key. - * - * @return int|null */ - #[ReturnTypeWillChange] - public function key() + public function key(): ?int { return $this->valid() ? $this->key @@ -1391,14 +1340,11 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return the current date. - * - * @return CarbonInterface|null */ - #[ReturnTypeWillChange] - public function current() + public function current(): ?CarbonInterface { return $this->valid() - ? $this->prepareForReturn($this->current) + ? $this->prepareForReturn($this->carbonCurrent) : null; } @@ -1406,13 +1352,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Move forward to the next date. * * @throws RuntimeException - * - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { - if ($this->current === null) { + if ($this->carbonCurrent === null) { $this->rewind(); } @@ -1433,25 +1376,22 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * @see https://wiki.php.net/rfc/datetime_and_daylight_saving_time * * @throws RuntimeException - * - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { $this->key = 0; - $this->current = ([$this->dateClass, 'make'])($this->startDate); + $this->carbonCurrent = ([$this->dateClass, 'make'])($this->startDate); $settings = $this->getSettings(); if ($this->hasLocalTranslator()) { $settings['locale'] = $this->getTranslatorLocale(); } - $this->current->settings($settings); - $this->timezone = static::intervalHasTime($this->dateInterval) ? $this->current->getTimezone() : null; + $this->carbonCurrent->settings($settings); + $this->timezone = static::intervalHasTime($this->dateInterval) ? $this->carbonCurrent->getTimezone() : null; if ($this->timezone) { - $this->current = $this->current->utc(); + $this->carbonCurrent = $this->carbonCurrent->utc(); } $this->validationResult = null; @@ -1468,7 +1408,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return bool */ - public function skip($count = 1) + public function skip(int $count = 1): bool { for ($i = $count; $this->valid() && $i > 0; $i--) { $this->next(); @@ -1479,20 +1419,20 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Format the date period as ISO 8601. - * - * @return string */ - public function toIso8601String() + public function toIso8601String(): string { $parts = []; - if ($this->recurrences !== null) { - $parts[] = 'R'.$this->recurrences; + if ($this->carbonRecurrences !== null) { + $parts[] = 'R'.$this->carbonRecurrences; } $parts[] = $this->startDate->toIso8601String(); - $parts[] = $this->dateInterval->spec(); + if (!$this->isDefaultInterval) { + $parts[] = $this->dateInterval->spec(); + } if ($this->endDate !== null) { $parts[] = $this->endDate->toIso8601String(); @@ -1503,12 +1443,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Convert the date period into a string. - * - * @return string */ - public function toString() + public function toString(): string { - $format = $this->localToStringFormat ?? static::$toStringFormat; + $format = $this->localToStringFormat + ?? $this->getFactory()->getSettings()['toStringFormat'] + ?? null; if ($format instanceof Closure) { return $format($this); @@ -1524,8 +1464,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable : 'Y-m-d' ); - if ($this->recurrences !== null) { - $parts[] = $this->translate('period_recurrences', [], $this->recurrences, $translator); + if ($this->carbonRecurrences !== null) { + $parts[] = $this->translate('period_recurrences', [], $this->carbonRecurrences, $translator); } $parts[] = $this->translate('period_interval', [':interval' => $this->dateInterval->forHumans([ @@ -1545,10 +1485,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Format the date period as ISO 8601. - * - * @return string */ - public function spec() + public function spec(): string { return $this->toIso8601String(); } @@ -1558,9 +1496,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @param string $className The $className::instance() method will be called to cast the current object. * - * @return DatePeriod + * @return DatePeriod|object */ - public function cast(string $className) + public function cast(string $className): object { if (!method_exists($className, 'instance')) { if (is_a($className, DatePeriod::class, true)) { @@ -1568,7 +1506,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $this->rawDate($this->getStartDate()), $this->getDateInterval(), $this->getEndDate() ? $this->rawDate($this->getIncludedEndDate()) : $this->getRecurrences(), - $this->isStartExcluded() ? DatePeriod::EXCLUDE_START_DATE : 0 + $this->isStartExcluded() ? DatePeriod::EXCLUDE_START_DATE : 0, ); } @@ -1585,10 +1523,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * ``` * var_dump(CarbonPeriod::create('2021-01-05', '2021-02-15')->toDatePeriod()); * ``` - * - * @return DatePeriod */ - public function toDatePeriod() + public function toDatePeriod(): DatePeriod { return $this->cast(DatePeriod::class); } @@ -1605,7 +1541,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable foreach ($this->filters as $filter) { switch ($filter) { case [static::RECURRENCES_FILTER, null]: - if ($this->recurrences !== null && is_finite($this->recurrences)) { + if ($this->carbonRecurrences !== null && is_finite($this->carbonRecurrences)) { return false; } @@ -1631,7 +1567,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return CarbonInterface[] */ - public function toArray() + public function toArray(): array { if ($this->isUnfilteredAndEndLess()) { throw new EndLessPeriodException("Endless period can't be converted to array nor counted."); @@ -1639,34 +1575,29 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $state = [ $this->key, - $this->current ? $this->current->avoidMutation() : null, + $this->carbonCurrent ? $this->carbonCurrent->avoidMutation() : null, $this->validationResult, ]; $result = iterator_to_array($this); - [$this->key, $this->current, $this->validationResult] = $state; + [$this->key, $this->carbonCurrent, $this->validationResult] = $state; return $result; } /** * Count dates in the date period. - * - * @return int */ - #[ReturnTypeWillChange] - public function count() + public function count(): int { return \count($this->toArray()); } /** * Return the first date in the date period. - * - * @return CarbonInterface|null */ - public function first() + public function first(): ?CarbonInterface { if ($this->isUnfilteredAndEndLess()) { foreach ($this as $date) { @@ -1683,10 +1614,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return the last date in the date period. - * - * @return CarbonInterface|null */ - public function last() + public function last(): ?CarbonInterface { $array = $this->toArray(); @@ -1695,10 +1624,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Convert the date period into a string. - * - * @return string */ - public function __toString() + public function __toString(): string { return $this->toString(); } @@ -1712,18 +1639,11 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * ->count() * * Note: We use magic method to let static and instance aliases with the same names. - * - * @param string $method - * @param array $parameters - * - * @return mixed */ - public function __call($method, $parameters) + public function __call(string $method, array $parameters): mixed { if (static::hasMacro($method)) { - return static::bindMacroContext($this, function () use (&$method, &$parameters) { - return $this->callMacro($method, $parameters); - }); + return static::bindMacroContext($this, fn () => $this->callMacro($method, $parameters)); } $roundedValue = $this->callRoundMethod($method, $parameters); @@ -1732,9 +1652,15 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $roundedValue; } + $count = \count($parameters); + switch ($method) { case 'start': case 'since': + if ($count === 0) { + return $this->getStartDate(); + } + self::setDefaultParameters($parameters, [ [0, 'date', null], ]); @@ -1746,6 +1672,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable case 'end': case 'until': + if ($count === 0) { + return $this->getEndDate(); + } + self::setDefaultParameters($parameters, [ [0, 'date', null], ]); @@ -1766,6 +1696,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable case 'recurrences': case 'times': + if ($count === 0) { + return $this->getRecurrences(); + } + self::setDefaultParameters($parameters, [ [0, 'recurrences', null], ]); @@ -1773,6 +1707,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $this->setRecurrences(...$parameters); case 'options': + if ($count === 0) { + return $this->getOptions(); + } + self::setDefaultParameters($parameters, [ [0, 'options', null], ]); @@ -1794,6 +1732,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $this->prependFilter(...$parameters); case 'filters': + if ($count === 0) { + return $this->getFilters(); + } + self::setDefaultParameters($parameters, [ [0, 'filters', []], ]); @@ -1805,6 +1747,10 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable case 'every': case 'step': case 'stepBy': + if ($count === 0) { + return $this->getDateInterval(); + } + return $this->setDateInterval(...$parameters); case 'invert': @@ -1846,16 +1792,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Set the instance's timezone from a string or object and apply it to start/end. - * - * @param \DateTimeZone|string $timezone - * - * @return static */ - public function setTimezone($timezone) + public function setTimezone(DateTimeZone|string|int $timezone): static { $self = $this->copyIfImmutable(); - $self->tzName = $timezone; - $self->timezone = $timezone; + $self->timezoneSetting = $timezone; + $self->timezone = CarbonTimeZone::instance($timezone); if ($self->startDate) { $self = $self->setStartDate($self->startDate->setTimezone($timezone)); @@ -1870,16 +1812,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Set the instance's timezone from a string or object and add/subtract the offset difference to start/end. - * - * @param \DateTimeZone|string $timezone - * - * @return static */ - public function shiftTimezone($timezone) + public function shiftTimezone(DateTimeZone|string|int $timezone): static { $self = $this->copyIfImmutable(); - $self->tzName = $timezone; - $self->timezone = $timezone; + $self->timezoneSetting = $timezone; + $self->timezone = CarbonTimeZone::instance($timezone); if ($self->startDate) { $self = $self->setStartDate($self->startDate->shiftTimezone($timezone)); @@ -1893,13 +1831,13 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable } /** - * Returns the end is set, else calculated from start an recurrences. + * Returns the end is set, else calculated from start and recurrences. * * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval. * * @return CarbonInterface */ - public function calculateEnd(string $rounding = null) + public function calculateEnd(?string $rounding = null): CarbonInterface { if ($end = $this->getEndDate($rounding)) { return $end; @@ -1918,19 +1856,16 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $date; } - /** - * @return CarbonInterface|null - */ - private function getEndFromRecurrences() + private function getEndFromRecurrences(): ?CarbonInterface { - if ($this->recurrences === null) { + if ($this->carbonRecurrences === null) { throw new UnreachableException( "Could not calculate period end without either explicit end or recurrences.\n". - "If you're looking for a forever-period, use ->setRecurrences(INF)." + "If you're looking for a forever-period, use ->setRecurrences(INF).", ); } - if ($this->recurrences === INF) { + if ($this->carbonRecurrences === INF) { $start = $this->getStartDate(); return $start < $start->avoidMutation()->add($this->getDateInterval()) @@ -1941,18 +1876,15 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable if ($this->filters === [[static::RECURRENCES_FILTER, null]]) { return $this->getStartDate()->avoidMutation()->add( $this->getDateInterval()->times( - $this->recurrences - ($this->isStartExcluded() ? 0 : 1) - ) + $this->carbonRecurrences - ($this->isStartExcluded() ? 0 : 1), + ), ); } return null; } - /** - * @return CarbonInterface|null - */ - private function iterateUntilEnd() + private function iterateUntilEnd(): ?CarbonInterface { $attempts = 0; $date = null; @@ -1960,7 +1892,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable foreach ($this as $date) { if (++$attempts > static::END_MAX_ATTEMPTS) { throw new UnreachableException( - 'Could not calculate period end after iterating '.static::END_MAX_ATTEMPTS.' times.' + 'Could not calculate period end after iterating '.static::END_MAX_ATTEMPTS.' times.', ); } } @@ -1977,7 +1909,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return bool */ - public function overlaps($rangeOrRangeStart, $rangeEnd = null) + public function overlaps(mixed $rangeOrRangeStart, mixed $rangeEnd = null): bool { $range = $rangeEnd ? static::create($rangeOrRangeStart, $rangeEnd) : $rangeOrRangeStart; @@ -2000,10 +1932,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * echo $date->diffInDays('2020-12-25')." days before Christmas!\n"; * }); * ``` - * - * @param callable $callback */ - public function forEach(callable $callback) + public function forEach(callable $callback): void { foreach ($this as $date) { $callback($date); @@ -2020,12 +1950,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * return $date->diffInDays('2020-12-25').' days before Christmas!'; * }))); * ``` - * - * @param callable $callback - * - * @return \Generator */ - public function map(callable $callback) + public function map(callable $callback): Generator { foreach ($this as $date) { yield $callback($date); @@ -2036,13 +1962,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Determines if the instance is equal to another. * Warning: if options differ, instances will never be equal. * - * @param mixed $period - * * @see equalTo() - * - * @return bool */ - public function eq($period): bool + public function eq(mixed $period): bool { return $this->equalTo($period); } @@ -2050,12 +1972,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the instance is equal to another. * Warning: if options differ, instances will never be equal. - * - * @param mixed $period - * - * @return bool */ - public function equalTo($period): bool + public function equalTo(mixed $period): bool { if (!($period instanceof self)) { $period = self::make($period); @@ -2074,13 +1992,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Determines if the instance is not equal to another. * Warning: if options differ, instances will never be equal. * - * @param mixed $period - * * @see notEqualTo() - * - * @return bool */ - public function ne($period): bool + public function ne(mixed $period): bool { return $this->notEqualTo($period); } @@ -2088,25 +2002,17 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the instance is not equal to another. * Warning: if options differ, instances will never be equal. - * - * @param mixed $period - * - * @return bool */ - public function notEqualTo($period): bool + public function notEqualTo(mixed $period): bool { return !$this->eq($period); } /** - * Determines if the start date is before an other given date. + * Determines if the start date is before another given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function startsBefore($date = null): bool + public function startsBefore(mixed $date = null): bool { return $this->getStartDate()->lessThan($this->resolveCarbon($date)); } @@ -2114,25 +2020,17 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the start date is before or the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function startsBeforeOrAt($date = null): bool + public function startsBeforeOrAt(mixed $date = null): bool { return $this->getStartDate()->lessThanOrEqualTo($this->resolveCarbon($date)); } /** - * Determines if the start date is after an other given date. + * Determines if the start date is after another given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function startsAfter($date = null): bool + public function startsAfter(mixed $date = null): bool { return $this->getStartDate()->greaterThan($this->resolveCarbon($date)); } @@ -2140,12 +2038,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the start date is after or the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function startsAfterOrAt($date = null): bool + public function startsAfterOrAt(mixed $date = null): bool { return $this->getStartDate()->greaterThanOrEqualTo($this->resolveCarbon($date)); } @@ -2153,25 +2047,17 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the start date is the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function startsAt($date = null): bool + public function startsAt(mixed $date = null): bool { return $this->getStartDate()->equalTo($this->resolveCarbon($date)); } /** - * Determines if the end date is before an other given date. + * Determines if the end date is before another given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function endsBefore($date = null): bool + public function endsBefore(mixed $date = null): bool { return $this->calculateEnd()->lessThan($this->resolveCarbon($date)); } @@ -2179,25 +2065,17 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the end date is before or the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function endsBeforeOrAt($date = null): bool + public function endsBeforeOrAt(mixed $date = null): bool { return $this->calculateEnd()->lessThanOrEqualTo($this->resolveCarbon($date)); } /** - * Determines if the end date is after an other given date. + * Determines if the end date is after another given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function endsAfter($date = null): bool + public function endsAfter(mixed $date = null): bool { return $this->calculateEnd()->greaterThan($this->resolveCarbon($date)); } @@ -2205,12 +2083,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the end date is after or the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function endsAfterOrAt($date = null): bool + public function endsAfterOrAt(mixed $date = null): bool { return $this->calculateEnd()->greaterThanOrEqualTo($this->resolveCarbon($date)); } @@ -2218,12 +2092,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Determines if the end date is the same as a given date. * (Rather start/end are included by options is ignored.) - * - * @param mixed $date - * - * @return bool */ - public function endsAt($date = null): bool + public function endsAt(mixed $date = null): bool { return $this->calculateEnd()->equalTo($this->resolveCarbon($date)); } @@ -2231,8 +2101,6 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return true if start date is now or later. * (Rather start/end are included by options is ignored.) - * - * @return bool */ public function isStarted(): bool { @@ -2242,8 +2110,6 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return true if end date is now or later. * (Rather start/end are included by options is ignored.) - * - * @return bool */ public function isEnded(): bool { @@ -2253,8 +2119,6 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Return true if now is between start date (included) and end date (excluded). * (Rather start/end are included by options is ignored.) - * - * @return bool */ public function isInProgress(): bool { @@ -2263,15 +2127,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Round the current instance at the given unit with given precision if specified and the given function. - * - * @param string $unit - * @param float|int|string|\DateInterval|null $precision - * @param string $function - * - * @return static */ - public function roundUnit($unit, $precision = 1, $function = 'round') - { + public function roundUnit( + string $unit, + DateInterval|float|int|string|null $precision = 1, + callable|string $function = 'round', + ): static { $self = $this->copyIfImmutable(); $self = $self->setStartDate($self->getStartDate()->roundUnit($unit, $precision, $function)); @@ -2284,40 +2145,27 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Truncate the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int|string|\DateInterval|null $precision - * - * @return static */ - public function floorUnit($unit, $precision = 1) + public function floorUnit(string $unit, DateInterval|float|int|string|null $precision = 1): static { return $this->roundUnit($unit, $precision, 'floor'); } /** * Ceil the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int|string|\DateInterval|null $precision - * - * @return static */ - public function ceilUnit($unit, $precision = 1) + public function ceilUnit(string $unit, DateInterval|float|int|string|null $precision = 1): static { return $this->roundUnit($unit, $precision, 'ceil'); } /** * Round the current instance second with given precision if specified (else period interval is used). - * - * @param float|int|string|\DateInterval|null $precision - * @param string $function - * - * @return static */ - public function round($precision = null, $function = 'round') - { + public function round( + DateInterval|float|int|string|null $precision = null, + callable|string $function = 'round', + ): static { return $this->roundWith( $precision ?? $this->getDateInterval()->setLocalTranslator(TranslatorImmutable::get('en'))->forHumans(), $function @@ -2326,24 +2174,16 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Round the current instance second with given precision if specified (else period interval is used). - * - * @param float|int|string|\DateInterval|null $precision - * - * @return static */ - public function floor($precision = null) + public function floor(DateInterval|float|int|string|null $precision = null): static { return $this->round($precision, 'floor'); } /** * Ceil the current instance second with given precision if specified (else period interval is used). - * - * @param float|int|string|\DateInterval|null $precision - * - * @return static */ - public function ceil($precision = null) + public function ceil(DateInterval|float|int|string|null $precision = null): static { return $this->round($precision, 'ceil'); } @@ -2355,20 +2195,15 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @return CarbonInterface[] */ - #[ReturnTypeWillChange] - public function jsonSerialize() + public function jsonSerialize(): array { return $this->toArray(); } /** * Return true if the given date is between start and end. - * - * @param \Carbon\Carbon|\Carbon\CarbonPeriod|\Carbon\CarbonInterval|\DateInterval|\DatePeriod|\DateTimeInterface|string|null $date - * - * @return bool */ - public function contains($date = null): bool + public function contains(mixed $date = null): bool { $startMethod = 'startsBefore'.($this->isStartIncluded() ? 'OrAt' : ''); $endMethod = 'endsAfter'.($this->isEndIncluded() ? 'OrAt' : ''); @@ -2380,12 +2215,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Return true if the current period follows a given other period (with no overlap). * For instance, [2019-08-01 -> 2019-08-12] follows [2019-07-29 -> 2019-07-31] * Note than in this example, follows() would be false if 2019-08-01 or 2019-07-31 was excluded by options. - * - * @param \Carbon\CarbonPeriod|\DatePeriod|string $period - * - * @return bool */ - public function follows($period, ...$arguments): bool + public function follows(mixed $period, mixed ...$arguments): bool { $period = $this->resolveCarbonPeriod($period, ...$arguments); @@ -2396,12 +2227,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Return true if the given other period follows the current one (with no overlap). * For instance, [2019-07-29 -> 2019-07-31] is followed by [2019-08-01 -> 2019-08-12] * Note than in this example, isFollowedBy() would be false if 2019-08-01 or 2019-07-31 was excluded by options. - * - * @param \Carbon\CarbonPeriod|\DatePeriod|string $period - * - * @return bool */ - public function isFollowedBy($period, ...$arguments): bool + public function isFollowedBy(mixed $period, mixed ...$arguments): bool { $period = $this->resolveCarbonPeriod($period, ...$arguments); @@ -2413,29 +2240,120 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * * @see follows() * @see isFollowedBy() - * - * @param \Carbon\CarbonPeriod|\DatePeriod|string $period - * - * @return bool */ - public function isConsecutiveWith($period, ...$arguments): bool + public function isConsecutiveWith(mixed $period, mixed ...$arguments): bool { return $this->follows($period, ...$arguments) || $this->isFollowedBy($period, ...$arguments); } + public function __debugInfo(): array + { + $info = $this->baseDebugInfo(); + unset( + $info['start'], + $info['end'], + $info['interval'], + $info['include_start_date'], + $info['include_end_date'], + $info['constructed'], + $info["\0*\0constructed"], + ); + + return $info; + } + + public function __unserialize(array $data): void + { + try { + $values = array_combine( + array_map( + static fn (string $key): string => preg_replace('/^\0\*\0/', '', $key), + array_keys($data), + ), + $data, + ); + + $this->initializeSerialization($values); + + foreach ($values as $key => $value) { + if ($value === null) { + continue; + } + + $property = match ($key) { + 'tzName' => $this->setTimezone(...), + 'options' => $this->setOptions(...), + 'recurrences' => $this->setRecurrences(...), + 'current' => function (mixed $current): void { + if (!($current instanceof CarbonInterface)) { + $current = $this->resolveCarbon($current); + } + + $this->carbonCurrent = $current; + }, + 'start' => 'startDate', + 'interval' => $this->setDateInterval(...), + 'end' => 'endDate', + 'key' => null, + 'include_start_date' => function (bool $included): void { + $this->excludeStartDate(!$included); + }, + 'include_end_date' => function (bool $included): void { + $this->excludeEndDate(!$included); + }, + default => $key, + }; + + if ($property === null) { + continue; + } + + if (\is_callable($property)) { + $property($value); + + continue; + } + + if ($value instanceof DateTimeInterface && !($value instanceof CarbonInterface)) { + $value = ($value instanceof DateTime) + ? Carbon::instance($value) + : CarbonImmutable::instance($value); + } + + try { + $this->$property = $value; + } catch (Throwable) { + // Must be ignored for backward-compatibility + } + } + + if (\array_key_exists('carbonRecurrences', $values)) { + $this->carbonRecurrences = $values['carbonRecurrences']; + } elseif (((int) ($values['recurrences'] ?? 0)) <= 1 && $this->endDate !== null) { + $this->carbonRecurrences = null; + } + } catch (Throwable $e) { + // @codeCoverageIgnoreStart + if (!method_exists(parent::class, '__unserialize')) { + throw $e; + } + + parent::__unserialize($data); + // @codeCoverageIgnoreEnd + } + } + /** * Update properties after removing built-in filters. - * - * @return void */ - protected function updateInternalState() + protected function updateInternalState(): void { if (!$this->hasFilter(static::END_DATE_FILTER)) { $this->endDate = null; } if (!$this->hasFilter(static::RECURRENCES_FILTER)) { - $this->recurrences = null; + $this->carbonRecurrences = null; } } @@ -2443,12 +2361,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Create a filter tuple from raw parameters. * * Will create an automatic filter callback for one of Carbon's is* methods. - * - * @param array $parameters - * - * @return array */ - protected function createFilterTuple(array $parameters) + protected function createFilterTuple(array $parameters): array { $method = array_shift($parameters); @@ -2456,20 +2370,14 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return [$method, array_shift($parameters)]; } - return [function ($date) use ($method, $parameters) { - return ([$date, $method])(...$parameters); - }, $method]; + return [static fn ($date) => ([$date, $method])(...$parameters), $method]; } /** * Return whether given callable is a string pointing to one of Carbon's is* methods * and should be automatically converted to a filter callback. - * - * @param callable $callable - * - * @return bool */ - protected function isCarbonPredicateMethod($callable) + protected function isCarbonPredicateMethod(callable|string $callable): bool { return \is_string($callable) && str_starts_with($callable, 'is') && (method_exists($this->dateClass, $callable) || ([$this->dateClass, 'hasMacro'])($callable)); @@ -2478,16 +2386,11 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Recurrences filter callback (limits number of recurrences). * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param \Carbon\Carbon $current - * @param int $key - * - * @return bool|string + * @SuppressWarnings(UnusedFormalParameter) */ - protected function filterRecurrences($current, $key) + protected function filterRecurrences(CarbonInterface $current, int $key): bool|callable { - if ($key < $this->recurrences) { + if ($key < $this->carbonRecurrences) { return true; } @@ -2497,11 +2400,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * End date filter callback. * - * @param \Carbon\Carbon $current - * - * @return bool|string + * @return bool|static::END_ITERATION */ - protected function filterEndDate($current) + protected function filterEndDate(CarbonInterface $current): bool|callable { if (!$this->isEndExcluded() && $current == $this->endDate) { return true; @@ -2517,9 +2418,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * End iteration filter callback. * - * @return string + * @return static::END_ITERATION */ - protected function endIteration() + protected function endIteration(): callable { return static::END_ITERATION; } @@ -2527,7 +2428,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Handle change of the parameters. */ - protected function handleChangedParameters() + protected function handleChangedParameters(): void { if (($this->getOptions() & static::IMMUTABLE) && $this->dateClass === Carbon::class) { $this->dateClass = CarbonImmutable::class; @@ -2544,11 +2445,11 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Returns true when current date is valid, false if it is not, or static::END_ITERATION * when iteration should be stopped. * - * @return bool|string + * @return bool|static::END_ITERATION */ - protected function validateCurrentDate() + protected function validateCurrentDate(): bool|callable { - if ($this->current === null) { + if ($this->carbonCurrent === null) { $this->rewind(); } @@ -2559,19 +2460,14 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Check whether current value and key pass all the filters. * - * @return bool|string + * @return bool|static::END_ITERATION */ - protected function checkFilters() + protected function checkFilters(): bool|callable { - $current = $this->prepareForReturn($this->current); + $current = $this->prepareForReturn($this->carbonCurrent); foreach ($this->filters as $tuple) { - $result = \call_user_func( - $tuple[0], - $current->avoidMutation(), - $this->key, - $this - ); + $result = \call_user_func($tuple[0], $current->avoidMutation(), $this->key, $this); if ($result === static::END_ITERATION) { return static::END_ITERATION; @@ -2597,7 +2493,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable $date = ([$this->dateClass, 'make'])($date); if ($this->timezone) { - $date = $date->setTimezone($this->timezone); + return $date->setTimezone($this->timezone); } return $date; @@ -2607,15 +2503,13 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable * Keep incrementing the current date until a valid date is found or the iteration is ended. * * @throws RuntimeException - * - * @return void */ - protected function incrementCurrentDateUntilValid() + protected function incrementCurrentDateUntilValid(): void { $attempts = 0; do { - $this->current = $this->current->add($this->dateInterval); + $this->carbonCurrent = $this->carbonCurrent->add($this->dateInterval); $this->validationResult = null; @@ -2627,13 +2521,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Call given macro. - * - * @param string $name - * @param array $parameters - * - * @return mixed */ - protected function callMacro($name, $parameters) + protected function callMacro(string $name, array $parameters): mixed { $macro = static::$macros[$name]; @@ -2661,13 +2550,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable /** * Resolve passed arguments or DatePeriod to a CarbonPeriod object. - * - * @param mixed $period - * @param mixed ...$arguments - * - * @return static */ - protected function resolveCarbonPeriod($period, ...$arguments) + protected function resolveCarbonPeriod(mixed $period, mixed ...$arguments): self { if ($period instanceof self) { return $period; @@ -2689,6 +2573,12 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable return $value; } + if ($value instanceof WeekDay || $value instanceof Month) { + $dateClass = $this->dateClass; + + return new $dateClass($value, $this->timezoneSetting); + } + if (\is_string($value)) { $value = trim($value); @@ -2698,7 +2588,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable ) { $dateClass = $this->dateClass; - return $dateClass::parse($value, $this->tzName); + return $dateClass::parse($value, $this->timezoneSetting); } } @@ -2739,4 +2629,89 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable } } } + + private function setFromAssociativeArray(array $parameters): void + { + if (isset($parameters['start'])) { + $this->setStartDate($parameters['start']); + } + + if (isset($parameters['start'])) { + $this->setStartDate($parameters['start']); + } + + if (isset($parameters['end'])) { + $this->setEndDate($parameters['end']); + } + + if (isset($parameters['recurrences'])) { + $this->setRecurrences($parameters['recurrences']); + } + + if (isset($parameters['interval'])) { + $this->setDateInterval($parameters['interval']); + } + + if (isset($parameters['options'])) { + $this->setOptions($parameters['options']); + } + } + + private function configureTimezone(DateTimeZone $timezone, array $sortedArguments, array $originalArguments): array + { + $this->setTimezone($timezone); + + if (\is_string($originalArguments['start'] ?? null)) { + $sortedArguments['start'] = $this->makeDateTime($originalArguments['start']); + } + + if (\is_string($originalArguments['end'] ?? null)) { + $sortedArguments['end'] = $this->makeDateTime($originalArguments['end']); + } + + return $sortedArguments; + } + + private function initializeSerialization(array $values): void + { + $serializationBase = [ + 'start' => $values['start'] ?? $values['startDate'] ?? null, + 'current' => $values['current'] ?? $values['carbonCurrent'] ?? null, + 'end' => $values['end'] ?? $values['endDate'] ?? null, + 'interval' => $values['interval'] ?? $values['dateInterval'] ?? null, + 'recurrences' => max(1, (int) ($values['recurrences'] ?? $values['carbonRecurrences'] ?? 1)), + 'include_start_date' => $values['include_start_date'] ?? true, + 'include_end_date' => $values['include_end_date'] ?? false, + ]; + + foreach (['start', 'current', 'end'] as $dateProperty) { + if ($serializationBase[$dateProperty] instanceof Carbon) { + $serializationBase[$dateProperty] = $serializationBase[$dateProperty]->toDateTime(); + } elseif ($serializationBase[$dateProperty] instanceof CarbonInterface) { + $serializationBase[$dateProperty] = $serializationBase[$dateProperty]->toDateTimeImmutable(); + } + } + + if ($serializationBase['interval'] instanceof CarbonInterval) { + $serializationBase['interval'] = $serializationBase['interval']->toDateInterval(); + } + + // @codeCoverageIgnoreStart + if (method_exists(parent::class, '__unserialize')) { + parent::__unserialize($serializationBase); + + return; + } + + $excludeStart = !($values['include_start_date'] ?? true); + $includeEnd = $values['include_end_date'] ?? true; + + parent::__construct( + $serializationBase['start'], + $serializationBase['interval'], + $serializationBase['end'] ?? $serializationBase['recurrences'], + ($excludeStart ? self::EXCLUDE_START_DATE : 0) | ($includeEnd && \defined('DatePeriod::INCLUDE_END_DATE') ? self::INCLUDE_END_DATE : 0), + ); + // @codeCoverageIgnoreEnd + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php index f0d0ee281..0e8ff28e2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php @@ -1,5 +1,7 @@ constructed ? clone $this : $this; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonTimeZone.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonTimeZone.php index c81899f1e..45a46d171 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonTimeZone.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/CarbonTimeZone.php @@ -1,5 +1,7 @@ initLocalFactory(); + parent::__construct(static::getDateTimeZoneNameFromMixed($timezone)); } - protected static function parseNumericTimezone($timezone) + protected static function parseNumericTimezone(string|int|float $timezone): string { - if ($timezone <= -100 || $timezone >= 100) { - throw new InvalidTimeZoneException('Absolute timezone offset cannot be greater than 100.'); + if (abs((float) $timezone) > static::MAXIMUM_TIMEZONE_OFFSET) { + throw new InvalidTimeZoneException( + 'Absolute timezone offset cannot be greater than '. + static::MAXIMUM_TIMEZONE_OFFSET.'.', + ); } - return ($timezone >= 0 ? '+' : '').ltrim($timezone, '+').':00'; + return ($timezone >= 0 ? '+' : '').ltrim((string) $timezone, '+').':00'; } - protected static function getDateTimeZoneNameFromMixed($timezone) + protected static function getDateTimeZoneNameFromMixed(string|int|float $timezone): string { - if ($timezone === null) { - return date_default_timezone_get(); - } - if (\is_string($timezone)) { $timezone = preg_replace('/^\s*([+-]\d+)(\d{2})\s*$/', '$1:$2', $timezone); } @@ -50,19 +60,14 @@ class CarbonTimeZone extends DateTimeZone return $timezone; } - protected static function getDateTimeZoneFromName(&$name) - { - return @timezone_open($name = (string) static::getDateTimeZoneNameFromMixed($name)); - } - /** * Cast the current instance into the given class. * - * @param string $className The $className::instance() method will be called to cast the current object. + * @param class-string $className The $className::instance() method will be called to cast the current object. * - * @return DateTimeZone + * @return DateTimeZone|mixed */ - public function cast(string $className) + public function cast(string $className): mixed { if (!method_exists($className, 'instance')) { if (is_a($className, DateTimeZone::class, true)) { @@ -78,38 +83,40 @@ class CarbonTimeZone extends DateTimeZone /** * Create a CarbonTimeZone from mixed input. * - * @param DateTimeZone|string|int|null $object original value to get CarbonTimeZone from it. - * @param DateTimeZone|string|int|null $objectDump dump of the object for error messages. + * @param DateTimeZone|string|int|false|null $object original value to get CarbonTimeZone from it. + * @param DateTimeZone|string|int|false|null $objectDump dump of the object for error messages. * * @throws InvalidTimeZoneException * - * @return false|static + * @return static|null */ - public static function instance($object = null, $objectDump = null) - { - $tz = $object; + public static function instance( + DateTimeZone|string|int|false|null $object, + DateTimeZone|string|int|false|null $objectDump = null, + ): ?self { + $timezone = $object; - if ($tz instanceof static) { - return $tz; + if ($timezone instanceof static) { + return $timezone; } - if ($tz === null) { - return new static(); + if ($timezone === null || $timezone === false) { + return null; } - if (!$tz instanceof DateTimeZone) { - $tz = static::getDateTimeZoneFromName($object); - } + try { + if (!($timezone instanceof DateTimeZone)) { + $name = static::getDateTimeZoneNameFromMixed($object); + $timezone = new static($name); + } - if ($tz !== false) { - return new static($tz->getName()); + return $timezone instanceof static ? $timezone : new static($timezone->getName()); + } catch (Exception $exception) { + throw new InvalidTimeZoneException( + 'Unknown or bad timezone ('.($objectDump ?: $object).')', + previous: $exception, + ); } - - if (Carbon::isStrictModeEnabled()) { - throw new InvalidTimeZoneException('Unknown or bad timezone ('.($objectDump ?: $object).')'); - } - - return false; } /** @@ -119,14 +126,27 @@ class CarbonTimeZone extends DateTimeZone * * @return string */ - public function getAbbreviatedName($dst = false) + public function getAbbreviatedName(bool $dst = false): string { $name = $this->getName(); - foreach ($this->listAbbreviations() as $abbreviation => $zones) { + $date = new DateTimeImmutable($dst ? 'July 1' : 'January 1', $this); + $timezone = $date->format('T'); + $abbreviations = $this->listAbbreviations(); + $matchingZones = array_merge($abbreviations[$timezone] ?? [], $abbreviations[strtolower($timezone)] ?? []); + + if ($matchingZones !== []) { + foreach ($matchingZones as $zone) { + if ($zone['timezone_id'] === $name && $zone['dst'] == $dst) { + return $timezone; + } + } + } + + foreach ($abbreviations as $abbreviation => $zones) { foreach ($zones as $zone) { if ($zone['timezone_id'] === $name && $zone['dst'] == $dst) { - return $abbreviation; + return strtoupper($abbreviation); } } } @@ -143,33 +163,25 @@ class CarbonTimeZone extends DateTimeZone * * @return string */ - public function getAbbr($dst = false) + public function getAbbr(bool $dst = false): string { return $this->getAbbreviatedName($dst); } /** * Get the offset as string "sHH:MM" (such as "+00:00" or "-12:30"). - * - * @param DateTimeInterface|null $date - * - * @return string */ - public function toOffsetName(DateTimeInterface $date = null) + public function toOffsetName(?DateTimeInterface $date = null): string { return static::getOffsetNameFromMinuteOffset( - $this->getOffset($date ?: Carbon::now($this)) / 60 + $this->getOffset($this->resolveCarbon($date)) / 60, ); } /** * Returns a new CarbonTimeZone object using the offset string instead of region string. - * - * @param DateTimeInterface|null $date - * - * @return CarbonTimeZone */ - public function toOffsetTimeZone(DateTimeInterface $date = null) + public function toOffsetTimeZone(?DateTimeInterface $date = null): static { return new static($this->toOffsetName($date)); } @@ -179,13 +191,8 @@ class CarbonTimeZone extends DateTimeZone * false if no match is found. * * @see timezone_name_from_abbr native PHP function. - * - * @param DateTimeInterface|null $date - * @param int $isDst - * - * @return string|false */ - public function toRegionName(DateTimeInterface $date = null, $isDst = 1) + public function toRegionName(?DateTimeInterface $date = null, int $isDST = 1): ?string { $name = $this->getName(); $firstChar = substr($name, 0, 1); @@ -194,52 +201,48 @@ class CarbonTimeZone extends DateTimeZone return $name; } - $date = $date ?: Carbon::now($this); + $date = $this->resolveCarbon($date); // Integer construction no longer supported since PHP 8 // @codeCoverageIgnoreStart try { $offset = @$this->getOffset($date) ?: 0; - } catch (Throwable $e) { + } catch (Throwable) { $offset = 0; } // @codeCoverageIgnoreEnd - $name = @timezone_name_from_abbr('', $offset, $isDst); + $name = @timezone_name_from_abbr('', $offset, $isDST); if ($name) { return $name; } foreach (timezone_identifiers_list() as $timezone) { - if (Carbon::instance($date)->tz($timezone)->getOffset() === $offset) { + if (Carbon::instance($date)->setTimezone($timezone)->getOffset() === $offset) { return $timezone; } } - return false; + return null; } /** * Returns a new CarbonTimeZone object using the region string instead of offset string. - * - * @param DateTimeInterface|null $date - * - * @return CarbonTimeZone|false */ - public function toRegionTimeZone(DateTimeInterface $date = null) + public function toRegionTimeZone(?DateTimeInterface $date = null): ?self { - $tz = $this->toRegionName($date); + $timezone = $this->toRegionName($date); - if ($tz !== false) { - return new static($tz); + if ($timezone !== null) { + return new static($timezone); } if (Carbon::isStrictModeEnabled()) { - throw new InvalidTimeZoneException('Unknown timezone for offset '.$this->getOffset($date ?: Carbon::now($this)).' seconds.'); + throw new InvalidTimeZoneException('Unknown timezone for offset '.$this->getOffset($this->resolveCarbon($date)).' seconds.'); } - return false; + return null; } /** @@ -317,4 +320,17 @@ class CarbonTimeZone extends DateTimeZone ':'. str_pad((string) ($unsignedMinutes % 60), 2, '0', STR_PAD_LEFT); } + + private function resolveCarbon(?DateTimeInterface $date): DateTimeInterface + { + if ($date) { + return $date; + } + + if (isset($this->clock)) { + return $this->clock->now()->setTimezone($this); + } + + return Carbon::now($this); + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Cli/Invoker.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Cli/Invoker.php index 4f35d6c61..3aabe3f63 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Cli/Invoker.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Cli/Invoker.php @@ -1,5 +1,7 @@ unit = $unit; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php index 2e222e54e..e8cded033 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php @@ -1,5 +1,7 @@ method = $method; - parent::__construct(sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous); + parent::__construct(\sprintf("Unknown fluent constructor '%s'.", $method), $code, $previous); } /** diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php index 4ceaa2ef0..b3111bff0 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php @@ -1,5 +1,7 @@ setter = $setter; - parent::__construct(sprintf("Unknown fluent setter '%s'", $setter), $code, $previous); + parent::__construct(\sprintf("Unknown fluent setter '%s'", $setter), $code, $previous); } /** diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadMethodCallException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadMethodCallException.php index 108206d3e..3f10af992 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadMethodCallException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/BadMethodCallException.php @@ -1,5 +1,7 @@ value = $value; parent::__construct("$value is immutable.", $code, $previous); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidArgumentException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidArgumentException.php index 5b013cd50..7fb5a991d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidArgumentException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidArgumentException.php @@ -1,5 +1,7 @@ field = $field; $this->value = $value; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidFormatException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidFormatException.php index 92d55fe35..ffc5f212f 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidFormatException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/InvalidFormatException.php @@ -1,5 +1,7 @@ className = $className; - parent::__construct(sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous); + parent::__construct(\sprintf( + 'Given class does not implement %s: %s', + CarbonInterface::class, + $className, + ), $code, $previous); } /** diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/NotAPeriodException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/NotAPeriodException.php index 4edd7a484..23e09a286 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/NotAPeriodException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/NotAPeriodException.php @@ -1,5 +1,7 @@ unit = $unit; $this->min = $min; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php index 5416fd149..556bfedeb 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php @@ -1,5 +1,7 @@ expected = $expected; $this->actual = $actual; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/RuntimeException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/RuntimeException.php index ad196f79d..85bfb142b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/RuntimeException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/RuntimeException.php @@ -1,5 +1,7 @@ unit = $unit; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php index 5c504975a..982a30820 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php @@ -1,5 +1,7 @@ getter = $getter; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php index 75273a706..c72c368cf 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php @@ -1,5 +1,7 @@ method = $method; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php index a795f5d72..e97db4bb2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php @@ -1,5 +1,7 @@ setter = $setter; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php index ecd7f7a59..833c4d73c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php @@ -1,5 +1,7 @@ unit = $unit; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnreachableException.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnreachableException.php index 1654ab11b..c637d3b20 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnreachableException.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Exceptions/UnreachableException.php @@ -1,5 +1,7 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\Exceptions; + +use Exception; + +/** + * @codeCoverageIgnore + */ +class UnsupportedUnitException extends UnitException +{ + public function __construct(string $unit, int $code = 0, ?Exception $previous = null) + { + parent::__construct("Unsupported unit '$unit'", $code, $previous); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Factory.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Factory.php index d497535f7..7831c158e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Factory.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Factory.php @@ -1,5 +1,7 @@ * - * @method bool canBeCreatedFromFormat($date, $format) Checks if the (date)time string is in a given format and valid to create a - * new instance. - * @method Carbon|false create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) Create a new Carbon instance from a specific date and time. - * If any of $year, $month or $day are set to null their now() values will - * be used. - * If $hour is null it will be set to its now() value and the default - * values for $minute and $second will be their now() values. - * If $hour is not null then the default values for $minute and $second - * will be 0. - * @method Carbon createFromDate($year = null, $month = null, $day = null, $tz = null) Create a Carbon instance from just a date. The time portion is set to now. - * @method Carbon|false createFromFormat($format, $time, $tz = null) Create a Carbon instance from a specific format. - * @method Carbon|false createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null) Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). - * @method Carbon|false createFromLocaleFormat($format, $locale, $time, $tz = null) Create a Carbon instance from a specific format and a string in a given language. - * @method Carbon|false createFromLocaleIsoFormat($format, $locale, $time, $tz = null) Create a Carbon instance from a specific ISO format and a string in a given language. - * @method Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) Create a Carbon instance from just a time. The date portion is set to today. - * @method Carbon createFromTimeString($time, $tz = null) Create a Carbon instance from a time string. The date portion is set to today. - * @method Carbon createFromTimestamp($timestamp, $tz = null) Create a Carbon instance from a timestamp and set the timezone (use default one if not specified). - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method Carbon createFromTimestampMs($timestamp, $tz = null) Create a Carbon instance from a timestamp in milliseconds. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method Carbon createFromTimestampMsUTC($timestamp) Create a Carbon instance from a timestamp in milliseconds. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method Carbon createFromTimestampUTC($timestamp) Create a Carbon instance from an timestamp keeping the timezone to UTC. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null) Create a Carbon instance from just a date. The time portion is set to midnight. - * @method Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) Create a new safe Carbon instance from a specific date and time. - * If any of $year, $month or $day are set to null their now() values will - * be used. - * If $hour is null it will be set to its now() value and the default - * values for $minute and $second will be their now() values. - * If $hour is not null then the default values for $minute and $second - * will be 0. - * If one of the set values is not valid, an InvalidDateException - * will be thrown. - * @method CarbonInterface createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null) Create a new Carbon instance from a specific date and time using strict validation. - * @method Carbon disableHumanDiffOption($humanDiffOption) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method Carbon enableHumanDiffOption($humanDiffOption) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method mixed executeWithLocale($locale, $func) Set the current locale to the given, execute the passed function, reset the locale to previous one, - * then return the result of the closure (or null if the closure was void). - * @method Carbon fromSerialized($value) Create an instance from a serialized string. - * @method void genericMacro($macro, $priority = 0) Register a custom macro. - * @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales. - * (It will ignore custom translator dynamic loading.) - * @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native - * name, region and variant of the locale. - * @method array getDays() Get the days of the week - * @method string|null getFallbackLocale() Get the fallback locale. - * @method array getFormatsToIsoReplacements() List of replacements from date() format to isoFormat(). - * @method int getHumanDiffOptions() Return default humanDiff() options (merged flags as integer). - * @method array getIsoUnits() Returns list of locale units for ISO formatting. - * @method array getLastErrors() {@inheritdoc} - * @method string getLocale() Get the current translator locale. - * @method callable|null getMacro($name) Get the raw callable macro registered globally for a given name. - * @method int getMidDayAt() get midday/noon hour - * @method Closure|Carbon getTestNow() Get the Carbon instance (real or mock) to be returned when a "now" - * instance is created. - * @method string getTimeFormatByPrecision($unitPrecision) Return a format from H:i to H:i:s.u according to given unit precision. - * @method string getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) Returns raw translation message for a given key. - * @method \Symfony\Component\Translation\TranslatorInterface getTranslator() Get the default translator instance in use. - * @method int getWeekEndsAt() Get the last day of week - * @method int getWeekStartsAt() Get the first day of week - * @method array getWeekendDays() Get weekend days - * @method bool hasFormat($date, $format) Checks if the (date)time string is in a given format. - * @method bool hasFormatWithModifiers($date, $format) Checks if the (date)time string is in a given format. - * @method bool hasMacro($name) Checks if macro is registered globally. - * @method bool hasRelativeKeywords($time) Determine if a time string will produce a relative date. - * @method bool hasTestNow() Determine if there is a valid test instance set. A valid test instance - * is anything that is not null. - * @method Carbon instance($date) Create a Carbon instance from a DateTime one. - * @method bool isImmutable() Returns true if the current class/instance is immutable. - * @method bool isModifiableUnit($unit) Returns true if a property can be changed via setter. - * @method bool isMutable() Returns true if the current class/instance is mutable. - * @method bool isStrictModeEnabled() Returns true if the strict mode is globally in use, false else. - * (It can be overridden in specific instances.) - * @method bool localeHasDiffOneDayWords($locale) Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow). - * Support is considered enabled if the 3 words are translated in the given locale. - * @method bool localeHasDiffSyntax($locale) Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after). - * Support is considered enabled if the 4 sentences are translated in the given locale. - * @method bool localeHasDiffTwoDayWords($locale) Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow). - * Support is considered enabled if the 2 words are translated in the given locale. - * @method bool localeHasPeriodSyntax($locale) Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X). - * Support is considered enabled if the 4 sentences are translated in the given locale. - * @method bool localeHasShortUnits($locale) Returns true if the given locale is internally supported and has short-units support. - * Support is considered enabled if either year, day or hour has a short variant translated. - * @method void macro($name, $macro) Register a custom macro. - * @method Carbon|null make($var) Make a Carbon instance from given variable if possible. - * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals - * and recurrences). Throw an exception for invalid format, but otherwise return null. - * @method Carbon maxValue() Create a Carbon instance for the greatest supported date. - * @method Carbon minValue() Create a Carbon instance for the lowest supported date. - * @method void mixin($mixin) Mix another object into the class. - * @method Carbon now($tz = null) Get a Carbon instance for the current date and time. - * @method Carbon parse($time = null, $tz = null) Create a carbon instance from a string. - * This is an alias for the constructor that allows better fluent syntax - * as it allows you to do Carbon::parse('Monday next week')->fn() rather - * than (new Carbon('Monday next week'))->fn(). - * @method Carbon parseFromLocale($time, $locale = null, $tz = null) Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). - * @method string pluralUnit(string $unit) Returns standardized plural of a given singular/plural unit name (in English). - * @method Carbon|false rawCreateFromFormat($format, $time, $tz = null) Create a Carbon instance from a specific format. - * @method Carbon rawParse($time = null, $tz = null) Create a carbon instance from a string. - * This is an alias for the constructor that allows better fluent syntax - * as it allows you to do Carbon::parse('Monday next week')->fn() rather - * than (new Carbon('Monday next week'))->fn(). - * @method Carbon resetMacros() Remove all macros and generic macros. - * @method void resetMonthsOverflow() @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method void resetToStringFormat() Reset the format used to the default when type juggling a Carbon instance to a string - * @method void resetYearsOverflow() @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method void serializeUsing($callback) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather transform Carbon object before the serialization. - * JSON serialize all Carbon instances using the given callback. - * @method Carbon setFallbackLocale($locale) Set the fallback locale. - * @method Carbon setHumanDiffOptions($humanDiffOptions) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method bool setLocale($locale) Set the current translator locale and indicate if the source locale file exists. - * Pass 'auto' as locale to use closest language from the current LC_TIME locale. - * @method void setMidDayAt($hour) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather consider mid-day is always 12pm, then if you need to test if it's an other - * hour, test it explicitly: - * $date->format('G') == 13 - * or to set explicitly to a given hour: - * $date->setTime(13, 0, 0, 0) - * Set midday/noon hour - * @method Carbon setTestNow($testNow = null) Set a Carbon instance (real or mock) to be returned when a "now" - * instance is created. The provided instance will be returned - * specifically under the following conditions: - * - A call to the static now() method, ex. Carbon::now() - * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) - * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') - * - When a string containing the desired time is passed to Carbon::parse(). - * Note the timezone parameter was left out of the examples above and - * has no affect as the mock value will be returned regardless of its value. - * Only the moment is mocked with setTestNow(), the timezone will still be the one passed - * as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()). - * To clear the test instance call this method using the default - * parameter of null. - * /!\ Use this method for unit tests only. - * @method Carbon setTestNowAndTimezone($testNow = null, $tz = null) Set a Carbon instance (real or mock) to be returned when a "now" - * instance is created. The provided instance will be returned - * specifically under the following conditions: - * - A call to the static now() method, ex. Carbon::now() - * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) - * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') - * - When a string containing the desired time is passed to Carbon::parse(). - * It will also align default timezone (e.g. call date_default_timezone_set()) with - * the second argument or if null, with the timezone of the given date object. - * To clear the test instance call this method using the default - * parameter of null. - * /!\ Use this method for unit tests only. - * @method void setToStringFormat($format) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and - * use other method or custom format passed to format() method if you need to dump another string - * format. - * Set the default format used when type juggling a Carbon instance to a string. - * @method void setTranslator(TranslatorInterface $translator) Set the default translator instance to use. - * @method Carbon setUtf8($utf8) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use UTF-8 language packages on every machine. - * Set if UTF8 will be used for localized date/time. - * @method void setWeekEndsAt($day) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek - * or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the - * start of week according to current locale selected and implicitly the end of week. - * Set the last day of week - * @method void setWeekStartsAt($day) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the - * 'first_day_of_week' locale setting to change the start of week according to current locale - * selected and implicitly the end of week. - * Set the first day of week - * @method void setWeekendDays($days) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather consider week-end is always saturday and sunday, and if you have some custom - * week-end days to handle, give to those days an other name and create a macro for them: - * ``` - * Carbon::macro('isDayOff', function ($date) { - * return $date->isSunday() || $date->isMonday(); - * }); - * Carbon::macro('isNotDayOff', function ($date) { - * return !$date->isDayOff(); - * }); - * if ($someDate->isDayOff()) ... - * if ($someDate->isNotDayOff()) ... - * // Add 5 not-off days - * $count = 5; - * while ($someDate->isDayOff() || ($count-- > 0)) { - * $someDate->addDay(); - * } - * ``` - * Set weekend days - * @method bool shouldOverflowMonths() Get the month overflow global behavior (can be overridden in specific instances). - * @method bool shouldOverflowYears() Get the month overflow global behavior (can be overridden in specific instances). - * @method string singularUnit(string $unit) Returns standardized singular of a given singular/plural unit name (in English). - * @method Carbon today($tz = null) Create a Carbon instance for today. - * @method Carbon tomorrow($tz = null) Create a Carbon instance for tomorrow. - * @method string translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL) Translate a time string from a locale to an other. - * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) Translate using translation string or callback available. - * @method void useMonthsOverflow($monthsOverflow = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method Carbon useStrictMode($strictModeEnabled = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method void useYearsOverflow($yearsOverflow = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method mixed withTestNow($testNow, $callback) Temporarily sets a static date to be used within the callback. - * Using setTestNow to set the date, executing the callback, then - * clearing the test instance. - * /!\ Use this method for unit tests only. - * @method Carbon yesterday($tz = null) Create a Carbon instance for yesterday. + * @method bool canBeCreatedFromFormat(?string $date, string $format) Checks if the (date)time string is in a given format and valid to create a + * new instance. + * @method ?Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) Create a new Carbon instance from a specific date and time. + * If any of $year, $month or $day are set to null their now() values will + * be used. + * If $hour is null it will be set to its now() value and the default + * values for $minute and $second will be their now() values. + * If $hour is not null then the default values for $minute and $second + * will be 0. + * @method Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) Create a Carbon instance from just a date. The time portion is set to now. + * @method ?Carbon createFromFormat($format, $time, $timezone = null) Create a Carbon instance from a specific format. + * @method ?Carbon createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). + * @method ?Carbon createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) Create a Carbon instance from a specific format and a string in a given language. + * @method ?Carbon createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) Create a Carbon instance from a specific ISO format and a string in a given language. + * @method Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) Create a Carbon instance from just a time. The date portion is set to today. + * @method Carbon createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a time string. The date portion is set to today. + * @method Carbon createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a timestamp and set the timezone (UTC by default). + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method Carbon createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a timestamp in milliseconds. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method Carbon createFromTimestampMsUTC($timestamp) Create a Carbon instance from a timestamp in milliseconds. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method Carbon createFromTimestampUTC(string|int|float $timestamp) Create a Carbon instance from a timestamp keeping the timezone to UTC. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) Create a Carbon instance from just a date. The time portion is set to midnight. + * @method ?Carbon createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) Create a new safe Carbon instance from a specific date and time. + * If any of $year, $month or $day are set to null their now() values will + * be used. + * If $hour is null it will be set to its now() value and the default + * values for $minute and $second will be their now() values. + * If $hour is not null then the default values for $minute and $second + * will be 0. + * If one of the set values is not valid, an InvalidDateException + * will be thrown. + * @method Carbon createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null) Create a new Carbon instance from a specific date and time using strict validation. + * @method mixed executeWithLocale(string $locale, callable $func) Set the current locale to the given, execute the passed function, reset the locale to previous one, + * then return the result of the closure (or null if the closure was void). + * @method Carbon fromSerialized($value) Create an instance from a serialized string. + * @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales. + * (It will ignore custom translator dynamic loading.) + * @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native + * name, region and variant of the locale. + * @method array getDays() Get the days of the week. + * @method ?string getFallbackLocale() Get the fallback locale. + * @method array getFormatsToIsoReplacements() List of replacements from date() format to isoFormat(). + * @method array getIsoUnits() Returns list of locale units for ISO formatting. + * @method array|false getLastErrors() {@inheritdoc} + * @method string getLocale() Get the current translator locale. + * @method int getMidDayAt() get midday/noon hour + * @method string getTimeFormatByPrecision(string $unitPrecision) Return a format from H:i to H:i:s.u according to given unit precision. + * @method string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) Returns raw translation message for a given key. + * @method int getWeekEndsAt(?string $locale = null) Get the last day of week. + * @method int getWeekStartsAt(?string $locale = null) Get the first day of week. + * @method bool hasRelativeKeywords(?string $time) Determine if a time string will produce a relative date. + * @method Carbon instance(DateTimeInterface $date) Create a Carbon instance from a DateTime one. + * @method bool isImmutable() Returns true if the current class/instance is immutable. + * @method bool isModifiableUnit($unit) Returns true if a property can be changed via setter. + * @method bool isMutable() Returns true if the current class/instance is mutable. + * @method bool localeHasDiffOneDayWords(string $locale) Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow). + * Support is considered enabled if the 3 words are translated in the given locale. + * @method bool localeHasDiffSyntax(string $locale) Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after). + * Support is considered enabled if the 4 sentences are translated in the given locale. + * @method bool localeHasDiffTwoDayWords(string $locale) Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow). + * Support is considered enabled if the 2 words are translated in the given locale. + * @method bool localeHasPeriodSyntax($locale) Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X). + * Support is considered enabled if the 4 sentences are translated in the given locale. + * @method bool localeHasShortUnits(string $locale) Returns true if the given locale is internally supported and has short-units support. + * Support is considered enabled if either year, day or hour has a short variant translated. + * @method ?Carbon make($var, DateTimeZone|string|null $timezone = null) Make a Carbon instance from given variable if possible. + * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals + * and recurrences). Throw an exception for invalid format, but otherwise return null. + * @method void mixin(object|string $mixin) Mix another object into the class. + * @method Carbon now(DateTimeZone|string|int|null $timezone = null) Get a Carbon instance for the current date and time. + * @method Carbon parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a string. + * This is an alias for the constructor that allows better fluent syntax + * as it allows you to do Carbon::parse('Monday next week')->fn() rather + * than (new Carbon('Monday next week'))->fn(). + * @method Carbon parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). + * @method string pluralUnit(string $unit) Returns standardized plural of a given singular/plural unit name (in English). + * @method ?Carbon rawCreateFromFormat(string $format, string $time, $timezone = null) Create a Carbon instance from a specific format. + * @method Carbon rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a string. + * This is an alias for the constructor that allows better fluent syntax + * as it allows you to do Carbon::parse('Monday next week')->fn() rather + * than (new Carbon('Monday next week'))->fn(). + * @method void setFallbackLocale(string $locale) Set the fallback locale. + * @method void setLocale(string $locale) Set the current translator locale and indicate if the source locale file exists. + * Pass 'auto' as locale to use the closest language to the current LC_TIME locale. + * @method void setMidDayAt($hour) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather consider mid-day is always 12pm, then if you need to test if it's an other + * hour, test it explicitly: + * $date->format('G') == 13 + * or to set explicitly to a given hour: + * $date->setTime(13, 0, 0, 0) + * Set midday/noon hour + * @method string singularUnit(string $unit) Returns standardized singular of a given singular/plural unit name (in English). + * @method void sleep(int|float $seconds) + * @method Carbon today(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for today. + * @method Carbon tomorrow(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for tomorrow. + * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) Translate a time string from a locale to an other. + * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) Translate using translation string or callback available. + * @method Carbon yesterday(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for yesterday. * * */ class Factory { - protected $className = Carbon::class; + protected string $className = Carbon::class; - protected $settings = []; + protected array $settings = []; + + /** + * A test Carbon instance to be returned when now instances are created. + */ + protected Closure|CarbonInterface|null $testNow = null; + + /** + * The timezone to restore to when clearing the time mock. + */ + protected ?string $testDefaultTimezone = null; + + /** + * Is true when test-now is generated by a closure and timezone should be taken on the fly from it. + */ + protected bool $useTimezoneFromTestNow = false; + + /** + * Default translator. + */ + protected TranslatorInterface $translator; + + /** + * Days of weekend. + */ + protected array $weekendDays = [ + CarbonInterface::SATURDAY, + CarbonInterface::SUNDAY, + ]; + + /** + * Format regex patterns. + * + * @var array + */ + protected array $regexFormats = [ + 'd' => '(3[01]|[12][0-9]|0[1-9])', + 'D' => '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)', + 'j' => '([123][0-9]|[1-9])', + 'l' => '([a-zA-Z]{2,})', + 'N' => '([1-7])', + 'S' => '(st|nd|rd|th)', + 'w' => '([0-6])', + 'z' => '(36[0-5]|3[0-5][0-9]|[12][0-9]{2}|[1-9]?[0-9])', + 'W' => '(5[012]|[1-4][0-9]|0?[1-9])', + 'F' => '([a-zA-Z]{2,})', + 'm' => '(1[012]|0[1-9])', + 'M' => '([a-zA-Z]{3})', + 'n' => '(1[012]|[1-9])', + 't' => '(2[89]|3[01])', + 'L' => '(0|1)', + 'o' => '([1-9][0-9]{0,4})', + 'Y' => '([1-9]?[0-9]{4})', + 'y' => '([0-9]{2})', + 'a' => '(am|pm)', + 'A' => '(AM|PM)', + 'B' => '([0-9]{3})', + 'g' => '(1[012]|[1-9])', + 'G' => '(2[0-3]|1?[0-9])', + 'h' => '(1[012]|0[1-9])', + 'H' => '(2[0-3]|[01][0-9])', + 'i' => '([0-5][0-9])', + 's' => '([0-5][0-9])', + 'u' => '([0-9]{1,6})', + 'v' => '([0-9]{1,3})', + 'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\/[a-zA-Z]*)', + 'I' => '(0|1)', + 'O' => '([+-](1[0123]|0[0-9])[0134][05])', + 'P' => '([+-](1[0123]|0[0-9]):[0134][05])', + 'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])', + 'T' => '([a-zA-Z]{1,5})', + 'Z' => '(-?[1-5]?[0-9]{1,4})', + 'U' => '([0-9]*)', + + // The formats below are combinations of the above formats. + 'c' => '(([1-9]?[0-9]{4})-(1[012]|0[1-9])-(3[01]|[12][0-9]|0[1-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])[+-](1[012]|0[0-9]):([0134][05]))', // Y-m-dTH:i:sP + 'r' => '(([a-zA-Z]{3}), ([123][0-9]|0[1-9]) ([a-zA-Z]{3}) ([1-9]?[0-9]{4}) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]) [+-](1[012]|0[0-9])([0134][05]))', // D, d M Y H:i:s O + ]; + + /** + * Format modifiers (such as available in createFromFormat) regex patterns. + * + * @var array + */ + protected array $regexFormatModifiers = [ + '*' => '.+', + ' ' => '[ ]', + '#' => '[;:\\/.,()-]', + '?' => '([^a]|[a])', + '!' => '', + '|' => '', + '+' => '', + ]; public function __construct(array $settings = [], ?string $className = null) { @@ -254,56 +239,497 @@ class Factory $this->settings = $settings; } - public function getClassName() + public function getClassName(): string { return $this->className; } - public function setClassName(string $className) + public function setClassName(string $className): self { $this->className = $className; return $this; } - public function className(string $className = null) + public function className(?string $className = null): self|string { return $className === null ? $this->getClassName() : $this->setClassName($className); } - public function getSettings() + public function getSettings(): array { return $this->settings; } - public function setSettings(array $settings) + public function setSettings(array $settings): self { $this->settings = $settings; return $this; } - public function settings(array $settings = null) + public function settings(?array $settings = null): self|array { return $settings === null ? $this->getSettings() : $this->setSettings($settings); } - public function mergeSettings(array $settings) + public function mergeSettings(array $settings): self { $this->settings = array_merge($this->settings, $settings); return $this; } - public function __call($name, $arguments) + public function setHumanDiffOptions(int $humanDiffOptions): void + { + $this->mergeSettings([ + 'humanDiffOptions' => $humanDiffOptions, + ]); + } + + public function enableHumanDiffOption($humanDiffOption): void + { + $this->setHumanDiffOptions($this->getHumanDiffOptions() | $humanDiffOption); + } + + public function disableHumanDiffOption(int $humanDiffOption): void + { + $this->setHumanDiffOptions($this->getHumanDiffOptions() & ~$humanDiffOption); + } + + public function getHumanDiffOptions(): int + { + return (int) ($this->getSettings()['humanDiffOptions'] ?? 0); + } + + /** + * Register a custom macro. + * + * Pass null macro to remove it. + * + * @example + * ``` + * $userSettings = [ + * 'locale' => 'pt', + * 'timezone' => 'America/Sao_Paulo', + * ]; + * $factory->macro('userFormat', function () use ($userSettings) { + * return $this->copy()->locale($userSettings['locale'])->tz($userSettings['timezone'])->calendar(); + * }); + * echo $factory->yesterday()->hours(11)->userFormat(); + * ``` + * + * @param-closure-this static $macro + */ + public function macro(string $name, ?callable $macro): void + { + $macros = $this->getSettings()['macros'] ?? []; + $macros[$name] = $macro; + + $this->mergeSettings([ + 'macros' => $macros, + ]); + } + + /** + * Remove all macros and generic macros. + */ + public function resetMacros(): void + { + $this->mergeSettings([ + 'macros' => null, + 'genericMacros' => null, + ]); + } + + /** + * Register a custom macro. + * + * @param callable $macro + * @param int $priority marco with higher priority is tried first + * + * @return void + */ + public function genericMacro(callable $macro, int $priority = 0): void + { + $genericMacros = $this->getSettings()['genericMacros'] ?? []; + + if (!isset($genericMacros[$priority])) { + $genericMacros[$priority] = []; + krsort($genericMacros, SORT_NUMERIC); + } + + $genericMacros[$priority][] = $macro; + + $this->mergeSettings([ + 'genericMacros' => $genericMacros, + ]); + } + + /** + * Checks if macro is registered globally. + */ + public function hasMacro(string $name): bool + { + return isset($this->getSettings()['macros'][$name]); + } + + /** + * Get the raw callable macro registered globally for a given name. + */ + public function getMacro(string $name): ?callable + { + return $this->getSettings()['macros'][$name] ?? null; + } + + /** + * Set the default translator instance to use. + */ + public function setTranslator(TranslatorInterface $translator): void + { + $this->translator = $translator; + } + + /** + * Initialize the default translator instance if necessary. + */ + public function getTranslator(): TranslatorInterface + { + return $this->translator ??= Translator::get(); + } + + /** + * Reset the format used to the default when type juggling a Carbon instance to a string + * + * @return void + */ + public function resetToStringFormat(): void + { + $this->setToStringFormat(null); + } + + /** + * Set the default format used when type juggling a Carbon instance to a string. + */ + public function setToStringFormat(string|Closure|null $format): void + { + $this->mergeSettings([ + 'toStringFormat' => $format, + ]); + } + + /** + * JSON serialize all Carbon instances using the given callback. + */ + public function serializeUsing(string|callable|null $format): void + { + $this->mergeSettings([ + 'toJsonFormat' => $format, + ]); + } + + /** + * Enable the strict mode (or disable with passing false). + */ + public function useStrictMode(bool $strictModeEnabled = true): void + { + $this->mergeSettings([ + 'strictMode' => $strictModeEnabled, + ]); + } + + /** + * Returns true if the strict mode is globally in use, false else. + * (It can be overridden in specific instances.) + */ + public function isStrictModeEnabled(): bool + { + return $this->getSettings()['strictMode'] ?? true; + } + + /** + * Indicates if months should be calculated with overflow. + */ + public function useMonthsOverflow(bool $monthsOverflow = true): void + { + $this->mergeSettings([ + 'monthOverflow' => $monthsOverflow, + ]); + } + + /** + * Reset the month overflow behavior. + */ + public function resetMonthsOverflow(): void + { + $this->useMonthsOverflow(); + } + + /** + * Get the month overflow global behavior (can be overridden in specific instances). + */ + public function shouldOverflowMonths(): bool + { + return $this->getSettings()['monthOverflow'] ?? true; + } + + /** + * Indicates if years should be calculated with overflow. + */ + public function useYearsOverflow(bool $yearsOverflow = true): void + { + $this->mergeSettings([ + 'yearOverflow' => $yearsOverflow, + ]); + } + + /** + * Reset the month overflow behavior. + */ + public function resetYearsOverflow(): void + { + $this->useYearsOverflow(); + } + + /** + * Get the month overflow global behavior (can be overridden in specific instances). + */ + public function shouldOverflowYears(): bool + { + return $this->getSettings()['yearOverflow'] ?? true; + } + + /** + * Get weekend days + * + * @return array + */ + public function getWeekendDays(): array + { + return $this->weekendDays; + } + + /** + * Set weekend days + */ + public function setWeekendDays(array $days): void + { + $this->weekendDays = $days; + } + + /** + * Checks if the (date)time string is in a given format. + * + * @example + * ``` + * Carbon::hasFormat('11:12:45', 'h:i:s'); // true + * Carbon::hasFormat('13:12:45', 'h:i:s'); // false + * ``` + */ + public function hasFormat(string $date, string $format): bool + { + // createFromFormat() is known to handle edge cases silently. + // E.g. "1975-5-1" (Y-n-j) will still be parsed correctly when "Y-m-d" is supplied as the format. + // To ensure we're really testing against our desired format, perform an additional regex validation. + + return $this->matchFormatPattern($date, preg_quote($format, '/'), $this->regexFormats); + } + + /** + * Checks if the (date)time string is in a given format. + * + * @example + * ``` + * Carbon::hasFormatWithModifiers('31/08/2015', 'd#m#Y'); // true + * Carbon::hasFormatWithModifiers('31/08/2015', 'm#d#Y'); // false + * ``` + */ + public function hasFormatWithModifiers(string $date, string $format): bool + { + return $this->matchFormatPattern($date, $format, array_merge($this->regexFormats, $this->regexFormatModifiers)); + } + + /** + * Set a Carbon instance (real or mock) to be returned when a "now" + * instance is created. The provided instance will be returned + * specifically under the following conditions: + * - A call to the static now() method, ex. Carbon::now() + * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) + * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') + * - When a string containing the desired time is passed to Carbon::parse(). + * + * Note the timezone parameter was left out of the examples above and + * has no affect as the mock value will be returned regardless of its value. + * + * Only the moment is mocked with setTestNow(), the timezone will still be the one passed + * as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()). + * + * To clear the test instance call this method using the default + * parameter of null. + * + * /!\ Use this method for unit tests only. + * + * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance + */ + public function setTestNow(mixed $testNow = null): void + { + $this->useTimezoneFromTestNow = false; + $this->testNow = $testNow instanceof self || $testNow instanceof Closure + ? $testNow + : $this->make($testNow); + } + + /** + * Set a Carbon instance (real or mock) to be returned when a "now" + * instance is created. The provided instance will be returned + * specifically under the following conditions: + * - A call to the static now() method, ex. Carbon::now() + * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) + * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') + * - When a string containing the desired time is passed to Carbon::parse(). + * + * It will also align default timezone (e.g. call date_default_timezone_set()) with + * the second argument or if null, with the timezone of the given date object. + * + * To clear the test instance call this method using the default + * parameter of null. + * + * /!\ Use this method for unit tests only. + * + * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance + */ + public function setTestNowAndTimezone(mixed $testNow = null, $timezone = null): void + { + if ($testNow) { + $this->testDefaultTimezone ??= date_default_timezone_get(); + } + + $useDateInstanceTimezone = $testNow instanceof DateTimeInterface; + + if ($useDateInstanceTimezone) { + $this->setDefaultTimezone($testNow->getTimezone()->getName(), $testNow); + } + + $this->setTestNow($testNow); + $this->useTimezoneFromTestNow = ($timezone === null && $testNow instanceof Closure); + + if (!$useDateInstanceTimezone) { + $now = $this->getMockedTestNow(\func_num_args() === 1 ? null : $timezone); + $this->setDefaultTimezone($now?->tzName ?? $this->testDefaultTimezone ?? 'UTC', $now); + } + + if (!$testNow) { + $this->testDefaultTimezone = null; + } + } + + /** + * Temporarily sets a static date to be used within the callback. + * Using setTestNow to set the date, executing the callback, then + * clearing the test instance. + * + * /!\ Use this method for unit tests only. + * + * @template T + * + * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance + * @param Closure(): T $callback + * + * @return T + */ + public function withTestNow(mixed $testNow, callable $callback): mixed + { + $this->setTestNow($testNow); + + try { + $result = $callback(); + } finally { + $this->setTestNow(); + } + + return $result; + } + + /** + * Get the Carbon instance (real or mock) to be returned when a "now" + * instance is created. + * + * @return Closure|CarbonInterface|null the current instance used for testing + */ + public function getTestNow(): Closure|CarbonInterface|null + { + if ($this->testNow === null) { + $factory = FactoryImmutable::getDefaultInstance(); + + if ($factory !== $this) { + return $factory->getTestNow(); + } + } + + return $this->testNow; + } + + public function handleTestNowClosure( + Closure|CarbonInterface|null $testNow, + DateTimeZone|string|int|null $timezone = null, + ): ?CarbonInterface { + if ($testNow instanceof Closure) { + $callback = Callback::fromClosure($testNow); + $realNow = new DateTimeImmutable('now'); + $testNow = $testNow($callback->prepareParameter($this->parse( + $realNow->format('Y-m-d H:i:s.u'), + $timezone ?? $realNow->getTimezone(), + ))); + + if ($testNow !== null && !($testNow instanceof DateTimeInterface)) { + $function = $callback->getReflectionFunction(); + $type = \is_object($testNow) ? $testNow::class : \gettype($testNow); + + throw new RuntimeException( + 'The test closure defined in '.$function->getFileName(). + ' at line '.$function->getStartLine().' returned '.$type. + '; expected '.CarbonInterface::class.'|null', + ); + } + + if (!($testNow instanceof CarbonInterface)) { + $timezone ??= $this->useTimezoneFromTestNow ? $testNow->getTimezone() : null; + $testNow = $this->__call('instance', [$testNow, $timezone]); + } + } + + return $testNow; + } + + /** + * Determine if there is a valid test instance set. A valid test instance + * is anything that is not null. + * + * @return bool true if there is a test instance, otherwise false + */ + public function hasTestNow(): bool + { + return $this->getTestNow() !== null; + } + + public function withTimeZone(DateTimeZone|string|int|null $timezone): static + { + $factory = clone $this; + $factory->settings['timezone'] = $timezone; + + return $factory; + } + + public function __call(string $name, array $arguments): mixed { $method = new ReflectionMethod($this->className, $name); $settings = $this->settings; if ($settings && isset($settings['timezone'])) { - $tzParameters = array_filter($method->getParameters(), function ($parameter) { + $timezoneParameters = array_filter($method->getParameters(), function ($parameter) { return \in_array($parameter->getName(), ['tz', 'timezone'], true); }); + $timezoneSetting = $settings['timezone']; if (isset($arguments[0]) && \in_array($name, ['instance', 'make', 'create', 'parse'], true)) { if ($arguments[0] instanceof DateTimeInterface) { @@ -311,16 +737,112 @@ class Factory } elseif (\is_string($arguments[0]) && date_parse($arguments[0])['is_localtime']) { unset($settings['timezone'], $settings['innerTimezone']); } - } elseif (\count($tzParameters)) { - array_splice($arguments, key($tzParameters), 0, [$settings['timezone']]); + } + + if (\count($timezoneParameters)) { + $index = key($timezoneParameters); + + if (!isset($arguments[$index])) { + array_splice($arguments, key($timezoneParameters), 0, [$timezoneSetting]); + } + unset($settings['timezone']); } } - $result = $this->className::$name(...$arguments); + $clock = FactoryImmutable::getCurrentClock(); + FactoryImmutable::setCurrentClock($this); + + try { + $result = $this->className::$name(...$arguments); + } finally { + FactoryImmutable::setCurrentClock($clock); + } + + if (isset($this->translator)) { + $settings['translator'] = $this->translator; + } return $result instanceof CarbonInterface && !empty($settings) ? $result->settings($settings) : $result; } + + /** + * Get the mocked date passed in setTestNow() and if it's a Closure, execute it. + */ + protected function getMockedTestNow(DateTimeZone|string|int|null $timezone): ?CarbonInterface + { + $testNow = $this->handleTestNowClosure($this->getTestNow()); + + if ($testNow instanceof CarbonInterface) { + $testNow = $testNow->avoidMutation(); + + if ($timezone !== null) { + return $testNow->setTimezone($timezone); + } + } + + return $testNow; + } + + /** + * Checks if the (date)time string is in a given format with + * given list of pattern replacements. + * + * @example + * ``` + * Carbon::hasFormat('11:12:45', 'h:i:s'); // true + * Carbon::hasFormat('13:12:45', 'h:i:s'); // false + * ``` + * + * @param string $date + * @param string $format + * @param array $replacements + * + * @return bool + */ + private function matchFormatPattern(string $date, string $format, array $replacements): bool + { + // Preg quote, but remove escaped backslashes since we'll deal with escaped characters in the format string. + $regex = str_replace('\\\\', '\\', $format); + // Replace not-escaped letters + $regex = preg_replace_callback( + '/(? $match[1].strtr($match[2], $replacements), + $regex, + ); + // Replace escaped letters by the letter itself + $regex = preg_replace('/(?toRegionName($date); + + throw new InvalidArgumentException( + "Timezone ID '$timezone' is invalid". + ($suggestion && $suggestion !== $timezone ? ", did you mean '$suggestion'?" : '.')."\n". + "It must be one of the IDs from DateTimeZone::listIdentifiers(),\n". + 'For the record, hours/minutes offset are relevant only for a particular moment, '. + 'but not as a default timezone.', + 0, + $previous + ); + } + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/FactoryImmutable.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/FactoryImmutable.php index d88a1cf67..e1d6f03ef 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/FactoryImmutable.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/FactoryImmutable.php @@ -1,5 +1,7 @@ * - * @method bool canBeCreatedFromFormat($date, $format) Checks if the (date)time string is in a given format and valid to create a - * new instance. - * @method CarbonImmutable|false create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) Create a new Carbon instance from a specific date and time. - * If any of $year, $month or $day are set to null their now() values will - * be used. - * If $hour is null it will be set to its now() value and the default - * values for $minute and $second will be their now() values. - * If $hour is not null then the default values for $minute and $second - * will be 0. - * @method CarbonImmutable createFromDate($year = null, $month = null, $day = null, $tz = null) Create a Carbon instance from just a date. The time portion is set to now. - * @method CarbonImmutable|false createFromFormat($format, $time, $tz = null) Create a Carbon instance from a specific format. - * @method CarbonImmutable|false createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null) Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). - * @method CarbonImmutable|false createFromLocaleFormat($format, $locale, $time, $tz = null) Create a Carbon instance from a specific format and a string in a given language. - * @method CarbonImmutable|false createFromLocaleIsoFormat($format, $locale, $time, $tz = null) Create a Carbon instance from a specific ISO format and a string in a given language. - * @method CarbonImmutable createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) Create a Carbon instance from just a time. The date portion is set to today. - * @method CarbonImmutable createFromTimeString($time, $tz = null) Create a Carbon instance from a time string. The date portion is set to today. - * @method CarbonImmutable createFromTimestamp($timestamp, $tz = null) Create a Carbon instance from a timestamp and set the timezone (use default one if not specified). - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method CarbonImmutable createFromTimestampMs($timestamp, $tz = null) Create a Carbon instance from a timestamp in milliseconds. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method CarbonImmutable createFromTimestampMsUTC($timestamp) Create a Carbon instance from a timestamp in milliseconds. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method CarbonImmutable createFromTimestampUTC($timestamp) Create a Carbon instance from an timestamp keeping the timezone to UTC. - * Timestamp input can be given as int, float or a string containing one or more numbers. - * @method CarbonImmutable createMidnightDate($year = null, $month = null, $day = null, $tz = null) Create a Carbon instance from just a date. The time portion is set to midnight. - * @method CarbonImmutable|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) Create a new safe Carbon instance from a specific date and time. - * If any of $year, $month or $day are set to null their now() values will - * be used. - * If $hour is null it will be set to its now() value and the default - * values for $minute and $second will be their now() values. - * If $hour is not null then the default values for $minute and $second - * will be 0. - * If one of the set values is not valid, an InvalidDateException - * will be thrown. - * @method CarbonInterface createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null) Create a new Carbon instance from a specific date and time using strict validation. - * @method CarbonImmutable disableHumanDiffOption($humanDiffOption) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method CarbonImmutable enableHumanDiffOption($humanDiffOption) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method mixed executeWithLocale($locale, $func) Set the current locale to the given, execute the passed function, reset the locale to previous one, - * then return the result of the closure (or null if the closure was void). - * @method CarbonImmutable fromSerialized($value) Create an instance from a serialized string. - * @method void genericMacro($macro, $priority = 0) Register a custom macro. - * @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales. - * (It will ignore custom translator dynamic loading.) - * @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native - * name, region and variant of the locale. - * @method array getDays() Get the days of the week - * @method string|null getFallbackLocale() Get the fallback locale. - * @method array getFormatsToIsoReplacements() List of replacements from date() format to isoFormat(). - * @method int getHumanDiffOptions() Return default humanDiff() options (merged flags as integer). - * @method array getIsoUnits() Returns list of locale units for ISO formatting. - * @method array getLastErrors() {@inheritdoc} - * @method string getLocale() Get the current translator locale. - * @method callable|null getMacro($name) Get the raw callable macro registered globally for a given name. - * @method int getMidDayAt() get midday/noon hour - * @method Closure|CarbonImmutable getTestNow() Get the Carbon instance (real or mock) to be returned when a "now" - * instance is created. - * @method string getTimeFormatByPrecision($unitPrecision) Return a format from H:i to H:i:s.u according to given unit precision. - * @method string getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) Returns raw translation message for a given key. - * @method \Symfony\Component\Translation\TranslatorInterface getTranslator() Get the default translator instance in use. - * @method int getWeekEndsAt() Get the last day of week - * @method int getWeekStartsAt() Get the first day of week - * @method array getWeekendDays() Get weekend days - * @method bool hasFormat($date, $format) Checks if the (date)time string is in a given format. - * @method bool hasFormatWithModifiers($date, $format) Checks if the (date)time string is in a given format. - * @method bool hasMacro($name) Checks if macro is registered globally. - * @method bool hasRelativeKeywords($time) Determine if a time string will produce a relative date. - * @method bool hasTestNow() Determine if there is a valid test instance set. A valid test instance - * is anything that is not null. - * @method CarbonImmutable instance($date) Create a Carbon instance from a DateTime one. - * @method bool isImmutable() Returns true if the current class/instance is immutable. - * @method bool isModifiableUnit($unit) Returns true if a property can be changed via setter. - * @method bool isMutable() Returns true if the current class/instance is mutable. - * @method bool isStrictModeEnabled() Returns true if the strict mode is globally in use, false else. - * (It can be overridden in specific instances.) - * @method bool localeHasDiffOneDayWords($locale) Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow). - * Support is considered enabled if the 3 words are translated in the given locale. - * @method bool localeHasDiffSyntax($locale) Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after). - * Support is considered enabled if the 4 sentences are translated in the given locale. - * @method bool localeHasDiffTwoDayWords($locale) Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow). - * Support is considered enabled if the 2 words are translated in the given locale. - * @method bool localeHasPeriodSyntax($locale) Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X). - * Support is considered enabled if the 4 sentences are translated in the given locale. - * @method bool localeHasShortUnits($locale) Returns true if the given locale is internally supported and has short-units support. - * Support is considered enabled if either year, day or hour has a short variant translated. - * @method void macro($name, $macro) Register a custom macro. - * @method CarbonImmutable|null make($var) Make a Carbon instance from given variable if possible. - * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals - * and recurrences). Throw an exception for invalid format, but otherwise return null. - * @method CarbonImmutable maxValue() Create a Carbon instance for the greatest supported date. - * @method CarbonImmutable minValue() Create a Carbon instance for the lowest supported date. - * @method void mixin($mixin) Mix another object into the class. - * @method CarbonImmutable parse($time = null, $tz = null) Create a carbon instance from a string. - * This is an alias for the constructor that allows better fluent syntax - * as it allows you to do Carbon::parse('Monday next week')->fn() rather - * than (new Carbon('Monday next week'))->fn(). - * @method CarbonImmutable parseFromLocale($time, $locale = null, $tz = null) Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). - * @method string pluralUnit(string $unit) Returns standardized plural of a given singular/plural unit name (in English). - * @method CarbonImmutable|false rawCreateFromFormat($format, $time, $tz = null) Create a Carbon instance from a specific format. - * @method CarbonImmutable rawParse($time = null, $tz = null) Create a carbon instance from a string. - * This is an alias for the constructor that allows better fluent syntax - * as it allows you to do Carbon::parse('Monday next week')->fn() rather - * than (new Carbon('Monday next week'))->fn(). - * @method CarbonImmutable resetMacros() Remove all macros and generic macros. - * @method void resetMonthsOverflow() @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method void resetToStringFormat() Reset the format used to the default when type juggling a Carbon instance to a string - * @method void resetYearsOverflow() @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method void serializeUsing($callback) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather transform Carbon object before the serialization. - * JSON serialize all Carbon instances using the given callback. - * @method CarbonImmutable setFallbackLocale($locale) Set the fallback locale. - * @method CarbonImmutable setHumanDiffOptions($humanDiffOptions) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method bool setLocale($locale) Set the current translator locale and indicate if the source locale file exists. - * Pass 'auto' as locale to use closest language from the current LC_TIME locale. - * @method void setMidDayAt($hour) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather consider mid-day is always 12pm, then if you need to test if it's an other - * hour, test it explicitly: - * $date->format('G') == 13 - * or to set explicitly to a given hour: - * $date->setTime(13, 0, 0, 0) - * Set midday/noon hour - * @method CarbonImmutable setTestNow($testNow = null) Set a Carbon instance (real or mock) to be returned when a "now" - * instance is created. The provided instance will be returned - * specifically under the following conditions: - * - A call to the static now() method, ex. Carbon::now() - * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) - * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') - * - When a string containing the desired time is passed to Carbon::parse(). - * Note the timezone parameter was left out of the examples above and - * has no affect as the mock value will be returned regardless of its value. - * Only the moment is mocked with setTestNow(), the timezone will still be the one passed - * as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()). - * To clear the test instance call this method using the default - * parameter of null. - * /!\ Use this method for unit tests only. - * @method CarbonImmutable setTestNowAndTimezone($testNow = null, $tz = null) Set a Carbon instance (real or mock) to be returned when a "now" - * instance is created. The provided instance will be returned - * specifically under the following conditions: - * - A call to the static now() method, ex. Carbon::now() - * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) - * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') - * - When a string containing the desired time is passed to Carbon::parse(). - * It will also align default timezone (e.g. call date_default_timezone_set()) with - * the second argument or if null, with the timezone of the given date object. - * To clear the test instance call this method using the default - * parameter of null. - * /!\ Use this method for unit tests only. - * @method void setToStringFormat($format) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and - * use other method or custom format passed to format() method if you need to dump another string - * format. - * Set the default format used when type juggling a Carbon instance to a string. - * @method void setTranslator(TranslatorInterface $translator) Set the default translator instance to use. - * @method CarbonImmutable setUtf8($utf8) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use UTF-8 language packages on every machine. - * Set if UTF8 will be used for localized date/time. - * @method void setWeekEndsAt($day) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek - * or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the - * start of week according to current locale selected and implicitly the end of week. - * Set the last day of week - * @method void setWeekStartsAt($day) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the - * 'first_day_of_week' locale setting to change the start of week according to current locale - * selected and implicitly the end of week. - * Set the first day of week - * @method void setWeekendDays($days) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather consider week-end is always saturday and sunday, and if you have some custom - * week-end days to handle, give to those days an other name and create a macro for them: - * ``` - * Carbon::macro('isDayOff', function ($date) { - * return $date->isSunday() || $date->isMonday(); - * }); - * Carbon::macro('isNotDayOff', function ($date) { - * return !$date->isDayOff(); - * }); - * if ($someDate->isDayOff()) ... - * if ($someDate->isNotDayOff()) ... - * // Add 5 not-off days - * $count = 5; - * while ($someDate->isDayOff() || ($count-- > 0)) { - * $someDate->addDay(); - * } - * ``` - * Set weekend days - * @method bool shouldOverflowMonths() Get the month overflow global behavior (can be overridden in specific instances). - * @method bool shouldOverflowYears() Get the month overflow global behavior (can be overridden in specific instances). - * @method string singularUnit(string $unit) Returns standardized singular of a given singular/plural unit name (in English). - * @method CarbonImmutable today($tz = null) Create a Carbon instance for today. - * @method CarbonImmutable tomorrow($tz = null) Create a Carbon instance for tomorrow. - * @method string translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL) Translate a time string from a locale to an other. - * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) Translate using translation string or callback available. - * @method void useMonthsOverflow($monthsOverflow = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method CarbonImmutable useStrictMode($strictModeEnabled = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @method void useYearsOverflow($yearsOverflow = true) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @method mixed withTestNow($testNow, $callback) Temporarily sets a static date to be used within the callback. - * Using setTestNow to set the date, executing the callback, then - * clearing the test instance. - * /!\ Use this method for unit tests only. - * @method CarbonImmutable yesterday($tz = null) Create a Carbon instance for yesterday. + * @method bool canBeCreatedFromFormat(?string $date, string $format) Checks if the (date)time string is in a given format and valid to create a + * new instance. + * @method ?CarbonImmutable create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) Create a new Carbon instance from a specific date and time. + * If any of $year, $month or $day are set to null their now() values will + * be used. + * If $hour is null it will be set to its now() value and the default + * values for $minute and $second will be their now() values. + * If $hour is not null then the default values for $minute and $second + * will be 0. + * @method CarbonImmutable createFromDate($year = null, $month = null, $day = null, $timezone = null) Create a Carbon instance from just a date. The time portion is set to now. + * @method ?CarbonImmutable createFromFormat($format, $time, $timezone = null) Create a Carbon instance from a specific format. + * @method ?CarbonImmutable createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?TranslatorInterface $translator = null) Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). + * @method ?CarbonImmutable createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) Create a Carbon instance from a specific format and a string in a given language. + * @method ?CarbonImmutable createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) Create a Carbon instance from a specific ISO format and a string in a given language. + * @method CarbonImmutable createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) Create a Carbon instance from just a time. The date portion is set to today. + * @method CarbonImmutable createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a time string. The date portion is set to today. + * @method CarbonImmutable createFromTimestamp(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a timestamp and set the timezone (UTC by default). + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method CarbonImmutable createFromTimestampMs(string|int|float $timestamp, DateTimeZone|string|int|null $timezone = null) Create a Carbon instance from a timestamp in milliseconds. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method CarbonImmutable createFromTimestampMsUTC($timestamp) Create a Carbon instance from a timestamp in milliseconds. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method CarbonImmutable createFromTimestampUTC(string|int|float $timestamp) Create a Carbon instance from a timestamp keeping the timezone to UTC. + * Timestamp input can be given as int, float or a string containing one or more numbers. + * @method CarbonImmutable createMidnightDate($year = null, $month = null, $day = null, $timezone = null) Create a Carbon instance from just a date. The time portion is set to midnight. + * @method ?CarbonImmutable createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) Create a new safe Carbon instance from a specific date and time. + * If any of $year, $month or $day are set to null their now() values will + * be used. + * If $hour is null it will be set to its now() value and the default + * values for $minute and $second will be their now() values. + * If $hour is not null then the default values for $minute and $second + * will be 0. + * If one of the set values is not valid, an InvalidDateException + * will be thrown. + * @method CarbonImmutable createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null) Create a new Carbon instance from a specific date and time using strict validation. + * @method mixed executeWithLocale(string $locale, callable $func) Set the current locale to the given, execute the passed function, reset the locale to previous one, + * then return the result of the closure (or null if the closure was void). + * @method CarbonImmutable fromSerialized($value) Create an instance from a serialized string. + * @method array getAvailableLocales() Returns the list of internally available locales and already loaded custom locales. + * (It will ignore custom translator dynamic loading.) + * @method Language[] getAvailableLocalesInfo() Returns list of Language object for each available locale. This object allow you to get the ISO name, native + * name, region and variant of the locale. + * @method array getDays() Get the days of the week. + * @method ?string getFallbackLocale() Get the fallback locale. + * @method array getFormatsToIsoReplacements() List of replacements from date() format to isoFormat(). + * @method array getIsoUnits() Returns list of locale units for ISO formatting. + * @method array|false getLastErrors() {@inheritdoc} + * @method string getLocale() Get the current translator locale. + * @method int getMidDayAt() get midday/noon hour + * @method string getTimeFormatByPrecision(string $unitPrecision) Return a format from H:i to H:i:s.u according to given unit precision. + * @method string|Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) Returns raw translation message for a given key. + * @method int getWeekEndsAt(?string $locale = null) Get the last day of week. + * @method int getWeekStartsAt(?string $locale = null) Get the first day of week. + * @method bool hasRelativeKeywords(?string $time) Determine if a time string will produce a relative date. + * @method CarbonImmutable instance(DateTimeInterface $date) Create a Carbon instance from a DateTime one. + * @method bool isImmutable() Returns true if the current class/instance is immutable. + * @method bool isModifiableUnit($unit) Returns true if a property can be changed via setter. + * @method bool isMutable() Returns true if the current class/instance is mutable. + * @method bool localeHasDiffOneDayWords(string $locale) Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow). + * Support is considered enabled if the 3 words are translated in the given locale. + * @method bool localeHasDiffSyntax(string $locale) Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after). + * Support is considered enabled if the 4 sentences are translated in the given locale. + * @method bool localeHasDiffTwoDayWords(string $locale) Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow). + * Support is considered enabled if the 2 words are translated in the given locale. + * @method bool localeHasPeriodSyntax($locale) Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X). + * Support is considered enabled if the 4 sentences are translated in the given locale. + * @method bool localeHasShortUnits(string $locale) Returns true if the given locale is internally supported and has short-units support. + * Support is considered enabled if either year, day or hour has a short variant translated. + * @method ?CarbonImmutable make($var, DateTimeZone|string|null $timezone = null) Make a Carbon instance from given variable if possible. + * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals + * and recurrences). Throw an exception for invalid format, but otherwise return null. + * @method void mixin(object|string $mixin) Mix another object into the class. + * @method CarbonImmutable parse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a string. + * This is an alias for the constructor that allows better fluent syntax + * as it allows you to do Carbon::parse('Monday next week')->fn() rather + * than (new Carbon('Monday next week'))->fn(). + * @method CarbonImmutable parseFromLocale(string $time, ?string $locale = null, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). + * @method string pluralUnit(string $unit) Returns standardized plural of a given singular/plural unit name (in English). + * @method ?CarbonImmutable rawCreateFromFormat(string $format, string $time, $timezone = null) Create a Carbon instance from a specific format. + * @method CarbonImmutable rawParse(DateTimeInterface|WeekDay|Month|string|int|float|null $time, DateTimeZone|string|int|null $timezone = null) Create a carbon instance from a string. + * This is an alias for the constructor that allows better fluent syntax + * as it allows you to do Carbon::parse('Monday next week')->fn() rather + * than (new Carbon('Monday next week'))->fn(). + * @method void setFallbackLocale(string $locale) Set the fallback locale. + * @method void setLocale(string $locale) Set the current translator locale and indicate if the source locale file exists. + * Pass 'auto' as locale to use the closest language to the current LC_TIME locale. + * @method void setMidDayAt($hour) @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather consider mid-day is always 12pm, then if you need to test if it's an other + * hour, test it explicitly: + * $date->format('G') == 13 + * or to set explicitly to a given hour: + * $date->setTime(13, 0, 0, 0) + * Set midday/noon hour + * @method string singularUnit(string $unit) Returns standardized singular of a given singular/plural unit name (in English). + * @method CarbonImmutable today(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for today. + * @method CarbonImmutable tomorrow(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for tomorrow. + * @method string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = CarbonInterface::TRANSLATE_ALL) Translate a time string from a locale to an other. + * @method string translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null) Translate using translation string or callback available. + * @method CarbonImmutable yesterday(DateTimeZone|string|int|null $timezone = null) Create a Carbon instance for yesterday. * * */ class FactoryImmutable extends Factory implements ClockInterface { - protected $className = CarbonImmutable::class; + protected string $className = CarbonImmutable::class; + + private static ?self $defaultInstance = null; + + private static ?WrapperClock $currentClock = null; + + /** + * @internal Instance used for static calls, such as Carbon::getTranslator(), CarbonImmutable::setTestNow(), etc. + */ + public static function getDefaultInstance(): self + { + return self::$defaultInstance ??= new self(); + } + + /** + * @internal Instance used for static calls possibly called by non-static methods. + */ + public static function getInstance(): Factory + { + return self::$currentClock?->getFactory() ?? self::getDefaultInstance(); + } + + /** + * @internal Set instance before creating new dates. + */ + public static function setCurrentClock(ClockInterface|Factory|DateTimeInterface|null $currentClock): void + { + if ($currentClock && !($currentClock instanceof WrapperClock)) { + $currentClock = new WrapperClock($currentClock); + } + + self::$currentClock = $currentClock; + } + + /** + * @internal Instance used to link new object to their factory creator. + */ + public static function getCurrentClock(): ?WrapperClock + { + return self::$currentClock; + } /** * Get a Carbon instance for the current date and time. - * - * @param DateTimeZone|string|int|null $tz - * - * @return CarbonImmutable */ - public function now($tz = null): DateTimeImmutable + public function now(DateTimeZone|string|int|null $timezone = null): CarbonImmutable { - $className = $this->className; + return $this->__call('now', [$timezone]); + } - return new $className(null, $tz); + public function sleep(int|float $seconds): void + { + if ($this->hasTestNow()) { + $this->setTestNow($this->getTestNow()->avoidMutation()->addSeconds($seconds)); + + return; + } + + (new NativeClock('UTC'))->sleep($seconds); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/aa_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/aa_ET.php index e55e591b5..b6f7d0b3a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/aa_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/aa_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Acaada', 'Etleeni', 'Talaata', 'Arbaqa', 'Kamiisi', 'Gumqata', 'Sabti'], 'weekdays_short' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'], 'weekdays_min' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['saaku', 'carra'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/af.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/af.php index 27771d7aa..87592fe1b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/af.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/af.php @@ -64,9 +64,7 @@ return [ 'lastWeek' => '[Laas] dddd [om] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { - return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de'); - }, + 'ordinal' => static fn ($number) => $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de'), 'meridiem' => ['VM', 'NM'], 'months' => ['Januarie', 'Februarie', 'Maart', 'April', 'Mei', 'Junie', 'Julie', 'Augustus', 'September', 'Oktober', 'November', 'Desember'], 'months_short' => ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/am_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/am_ET.php index ece80621a..7cc676b37 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/am_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/am_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['እሑድ', 'ሰኞ', 'ማክሰኞ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'], 'weekdays_short' => ['እሑድ', 'ሰኞ ', 'ማክሰ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'], 'weekdays_min' => ['እሑድ', 'ሰኞ ', 'ማክሰ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ጡዋት', 'ከሰዓት'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/anp_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/anp_IN.php index 11069be3f..00baa980a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/anp_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/anp_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'बृहस्पतिवार', 'शुक्रवार', 'शनिवार'], 'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'], 'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/as_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/as_IN.php index 5fbc3dba3..f2499abf2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/as_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/as_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['দেওবাৰ', 'সোমবাৰ', 'মঙ্গলবাৰ', 'বুধবাৰ', 'বৃহষ্পতিবাৰ', 'শুক্ৰবাৰ', 'শনিবাৰ'], 'weekdays_short' => ['দেও', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহষ্পতি', 'শুক্ৰ', 'শনি'], 'weekdays_min' => ['দেও', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহষ্পতি', 'শুক্ৰ', 'শনি'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['পূৰ্ব্বাহ্ন', 'অপৰাহ্ন'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ayc_PE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ayc_PE.php index ff18504f0..22374e007 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ayc_PE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ayc_PE.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['tuminku', 'lunisa', 'martisa', 'mirkulisa', 'juywisa', 'wirnisa', 'sawäru'], 'weekdays_short' => ['tum', 'lun', 'mar', 'mir', 'juy', 'wir', 'saw'], 'weekdays_min' => ['tum', 'lun', 'mar', 'mir', 'juy', 'wir', 'saw'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['VM', 'NM'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/az.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/az.php index 1e92106df..1d71d1da2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/az.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/az.php @@ -18,29 +18,30 @@ * - Orxan * - Şəhriyar İmanov * - Baran Şengül + * - Novruz Rahimov */ return [ 'year' => ':count il', - 'a_year' => '{1}bir il|]1,Inf[:count il', + 'a_year' => '{1}bir il|[-Inf,Inf]:count il', 'y' => ':count il', 'month' => ':count ay', - 'a_month' => '{1}bir ay|]1,Inf[:count ay', + 'a_month' => '{1}bir ay|[-Inf,Inf]:count ay', 'm' => ':count ay', 'week' => ':count həftə', - 'a_week' => '{1}bir həftə|]1,Inf[:count həftə', + 'a_week' => '{1}bir həftə|[-Inf,Inf]:count həftə', 'w' => ':count h.', 'day' => ':count gün', - 'a_day' => '{1}bir gün|]1,Inf[:count gün', + 'a_day' => '{1}bir gün|[-Inf,Inf]:count gün', 'd' => ':count g.', 'hour' => ':count saat', - 'a_hour' => '{1}bir saat|]1,Inf[:count saat', - 'h' => ':count saat', - 'minute' => ':count d.', - 'a_minute' => '{1}bir dəqiqə|]1,Inf[:count dəqiqə', - 'min' => ':count dəqiqə', - 'second' => ':count san.', - 'a_second' => '{1}birneçə saniyə|]1,Inf[:count saniyə', - 's' => ':count saniyə', + 'a_hour' => '{1}bir saat|[-Inf,Inf]:count saat', + 'h' => ':count s.', + 'minute' => ':count dəqiqə', + 'a_minute' => '{1}bir dəqiqə|[-Inf,Inf]:count dəqiqə', + 'min' => ':count d.', + 'second' => ':count saniyə', + 'a_second' => '{1}birneçə saniyə|[-Inf,Inf]:count saniyə', + 's' => ':count san.', 'ago' => ':time əvvəl', 'from_now' => ':time sonra', 'after' => ':time sonra', @@ -73,7 +74,7 @@ return [ 'lastWeek' => '[keçən həftə] dddd [saat] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { if ($number === 0) { // special case for zero return "$number-ıncı"; } @@ -103,7 +104,7 @@ return [ return $number.($suffixes[$lastDigit] ?? $suffixes[$number % 100 - $lastDigit] ?? $suffixes[$number >= 100 ? 100 : -1] ?? ''); }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'gecə'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/be.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/be.php index ee736365a..06f4043dc 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/be.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/be.php @@ -117,39 +117,27 @@ return [ 'nextDay' => '[Заўтра ў] LT', 'nextWeek' => '[У] dddd [ў] LT', 'lastDay' => '[Учора ў] LT', - 'lastWeek' => function (CarbonInterface $current) { - switch ($current->dayOfWeek) { - case 1: - case 2: - case 4: - return '[У мінулы] dddd [ў] LT'; - default: - return '[У мінулую] dddd [ў] LT'; - } + 'lastWeek' => static fn (CarbonInterface $current) => match ($current->dayOfWeek) { + 1, 2, 4 => '[У мінулы] dddd [ў] LT', + default => '[У мінулую] dddd [ў] LT', }, 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return ($number % 10 === 2 || $number % 10 === 3) && ($number % 100 !== 12 && $number % 100 !== 13) ? $number.'-і' : $number.'-ы'; - case 'D': - return $number.'-га'; - default: - return $number; - } + 'ordinal' => static fn ($number, $period) => match ($period) { + 'M', 'd', 'DDD', 'w', 'W' => ($number % 10 === 2 || $number % 10 === 3) && + ($number % 100 !== 12 && $number % 100 !== 13) ? $number.'-і' : $number.'-ы', + 'D' => $number.'-га', + default => $number, }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'ночы'; } + if ($hour < 12) { return 'раніцы'; } + if ($hour < 17) { return 'дня'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bg.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bg.php index f76807403..c793ab7c5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bg.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bg.php @@ -66,19 +66,13 @@ return [ 'nextDay' => '[Утре в] LT', 'nextWeek' => 'dddd [в] LT', 'lastDay' => '[Вчера в] LT', - 'lastWeek' => function (CarbonInterface $current) { - switch ($current->dayOfWeek) { - case 0: - case 3: - case 6: - return '[В изминалата] dddd [в] LT'; - default: - return '[В изминалия] dddd [в] LT'; - } + 'lastWeek' => static fn (CarbonInterface $current) => match ($current->dayOfWeek) { + 0, 3, 6 => '[В изминалата] dddd [в] LT', + default => '[В изминалия] dddd [в] LT', }, 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { $lastDigit = $number % 10; $last2Digits = $number % 100; if ($number === 0) { diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bhb_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bhb_IN.php index ab557cbf3..fadbf77fb 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bhb_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bhb_IN.php @@ -22,5 +22,6 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 'weekdays_short' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 'weekdays_min' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bho_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bho_IN.php index bc54f3631..2f4cdfa02 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bho_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bho_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार'], 'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'], 'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bi_VU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bi_VU.php index 1fe777056..15d335c89 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bi_VU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bi_VU.php @@ -14,6 +14,7 @@ * - Samsung Electronics Co., Ltd. akhilesh.k@samsung.com & maninder1.s@samsung.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'dddd DD MMM YYYY', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bn.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bn.php index 8e147899b..663cf25a5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bn.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bn.php @@ -69,7 +69,7 @@ return [ 'lastWeek' => '[গত] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'রাত'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bo.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bo.php index 99e1bf4c9..21cc90d1d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bo.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bo.php @@ -15,13 +15,20 @@ * - JD Isaacks */ return [ - 'year' => '{1}ལོ་གཅིག|]1,Inf[:count ལོ', - 'month' => '{1}ཟླ་བ་གཅིག|]1,Inf[:count ཟླ་བ', - 'week' => ':count བདུན་ཕྲག', - 'day' => '{1}ཉིན་གཅིག|]1,Inf[:count ཉིན་', - 'hour' => '{1}ཆུ་ཚོད་གཅིག|]1,Inf[:count ཆུ་ཚོད', - 'minute' => '{1}སྐར་མ་གཅིག|]1,Inf[:count སྐར་མ', - 'second' => '{1}ལམ་སང|]1,Inf[:count སྐར་ཆ།', + 'year' => 'ལོ:count', + 'a_year' => '{1}ལོ་གཅིག|[-Inf,Inf]ལོ:count', + 'month' => 'ཟླ་བ:count', + 'a_month' => '{1}ཟླ་བ་གཅིག|[-Inf,Inf]ཟླ་བ:count', + 'week' => 'གཟའ་འཁོར་:count', + 'a_week' => 'གཟའ་འཁོར་གཅིག', + 'day' => 'ཉིན:count་', + 'a_day' => '{1}ཉིན་གཅིག|[-Inf,Inf]ཉིན:count', + 'hour' => 'ཆུ་ཚོད:count', + 'a_hour' => '{1}ཆུ་ཚོད་གཅིག|[-Inf,Inf]ཆུ་ཚོད:count', + 'minute' => 'སྐར་མ་:count', + 'a_minute' => '{1}སྐར་མ་གཅིག|[-Inf,Inf]སྐར་མ་:count', + 'second' => 'སྐར་ཆ:count', + 'a_second' => '{01}ལམ་སང|[-Inf,Inf]སྐར་ཆ:count', 'ago' => ':time སྔན་ལ', 'from_now' => ':time ལ་', 'diff_yesterday' => 'ཁ་སང', @@ -43,7 +50,7 @@ return [ 'lastWeek' => '[བདུན་ཕྲག་མཐའ་མ] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'མཚན་མོ'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/br.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/br.php index 583472fb0..cdc0545b1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/br.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/br.php @@ -55,9 +55,7 @@ return [ 'lastWeek' => 'dddd [paset da] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { - return $number.($number === 1 ? 'añ' : 'vet'); - }, + 'ordinal' => static fn ($number) => $number.($number === 1 ? 'añ' : 'vet'), 'months' => ['Genver', 'C\'hwevrer', 'Meurzh', 'Ebrel', 'Mae', 'Mezheven', 'Gouere', 'Eost', 'Gwengolo', 'Here', 'Du', 'Kerzu'], 'months_short' => ['Gen', 'C\'hwe', 'Meu', 'Ebr', 'Mae', 'Eve', 'Gou', 'Eos', 'Gwe', 'Her', 'Du', 'Ker'], 'weekdays' => ['Sul', 'Lun', 'Meurzh', 'Merc\'her', 'Yaou', 'Gwener', 'Sadorn'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/brx_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/brx_IN.php index 2d80ced20..e678aa966 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/brx_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/brx_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रबिबार', 'सोबार', 'मंगलबार', 'बुदबार', 'बिसथिबार', 'सुखुरबार', 'सुनिबार'], 'weekdays_short' => ['रबि', 'सम', 'मंगल', 'बुद', 'बिसथि', 'सुखुर', 'सुनि'], 'weekdays_min' => ['रबि', 'सम', 'मंगल', 'बुद', 'बिसथि', 'सुखुर', 'सुनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['फुं.', 'बेलासे.'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bs.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bs.php index e5d68083e..52b6d12aa 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bs.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/bs.php @@ -17,6 +17,7 @@ * - shaishavgandhi05 * - Serhan Apaydın * - JD Isaacks + * - Ademir Šehić */ use Carbon\CarbonInterface; @@ -26,8 +27,8 @@ return [ 'y' => ':count godina|:count godine|:count godina', 'month' => ':count mjesec|:count mjeseca|:count mjeseci', 'm' => ':count mjesec|:count mjeseca|:count mjeseci', - 'week' => ':count sedmice|:count sedmicu|:count sedmica', - 'w' => ':count sedmice|:count sedmicu|:count sedmica', + 'week' => ':count sedmica|:count sedmice|:count sedmica', + 'w' => ':count sedmica|:count sedmice|:count sedmica', 'day' => ':count dan|:count dana|:count dana', 'd' => ':count dan|:count dana|:count dana', 'hour' => ':count sat|:count sata|:count sati', @@ -36,10 +37,17 @@ return [ 'min' => ':count minut|:count minuta|:count minuta', 'second' => ':count sekund|:count sekunda|:count sekundi', 's' => ':count sekund|:count sekunda|:count sekundi', + 'ago' => 'prije :time', 'from_now' => 'za :time', 'after' => 'nakon :time', 'before' => ':time ranije', + + 'year_ago' => ':count godinu|:count godine|:count godina', + 'year_from_now' => ':count godinu|:count godine|:count godina', + 'week_ago' => ':count sedmicu|:count sedmice|:count sedmica', + 'week_from_now' => ':count sedmicu|:count sedmice|:count sedmica', + 'diff_now' => 'sada', 'diff_today' => 'danas', 'diff_today_regexp' => 'danas(?:\\s+u)?', @@ -58,29 +66,17 @@ return [ 'calendar' => [ 'sameDay' => '[danas u] LT', 'nextDay' => '[sutra u] LT', - 'nextWeek' => function (CarbonInterface $current) { - switch ($current->dayOfWeek) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - default: - return '[u] dddd [u] LT'; - } + 'nextWeek' => static fn (CarbonInterface $current) => match ($current->dayOfWeek) { + 0 => '[u] [nedjelju] [u] LT', + 3 => '[u] [srijedu] [u] LT', + 6 => '[u] [subotu] [u] LT', + default => '[u] dddd [u] LT', }, 'lastDay' => '[jučer u] LT', - 'lastWeek' => function (CarbonInterface $current) { - switch ($current->dayOfWeek) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - default: - return '[prošli] dddd [u] LT'; - } + 'lastWeek' => static fn (CarbonInterface $current) => match ($current->dayOfWeek) { + 0, 3 => '[prošlu] dddd [u] LT', + 6 => '[prošle] [subote] [u] LT', + default => '[prošli] dddd [u] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ca.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ca.php index b8b19946b..824c9ce7a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ca.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ca.php @@ -72,24 +72,24 @@ return [ 'LLLL' => 'dddd D MMMM [de] YYYY [a les] H:mm', ], 'calendar' => [ - 'sameDay' => function (CarbonInterface $current) { + 'sameDay' => static function (CarbonInterface $current) { return '[avui a '.($current->hour !== 1 ? 'les' : 'la').'] LT'; }, - 'nextDay' => function (CarbonInterface $current) { + 'nextDay' => static function (CarbonInterface $current) { return '[demà a '.($current->hour !== 1 ? 'les' : 'la').'] LT'; }, - 'nextWeek' => function (CarbonInterface $current) { + 'nextWeek' => static function (CarbonInterface $current) { return 'dddd [a '.($current->hour !== 1 ? 'les' : 'la').'] LT'; }, - 'lastDay' => function (CarbonInterface $current) { + 'lastDay' => static function (CarbonInterface $current) { return '[ahir a '.($current->hour !== 1 ? 'les' : 'la').'] LT'; }, - 'lastWeek' => function (CarbonInterface $current) { + 'lastWeek' => static function (CarbonInterface $current) { return '[el] dddd [passat a '.($current->hour !== 1 ? 'les' : 'la').'] LT'; }, 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { + 'ordinal' => static function ($number, $period) { return $number.( ($period === 'w' || $period === 'W') ? 'a' : ( ($number === 1) ? 'r' : ( diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ccp.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ccp.php index 99c1dcacd..b536d4bfe 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ccp.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ccp.php @@ -24,4 +24,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM, YYYY h:mm a', 'LLLL' => 'dddd, D MMMM, YYYY h:mm a', ], + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/chr_US.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/chr_US.php index 371353ef8..3fb022198 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/chr_US.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/chr_US.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ᎤᎾᏙᏓᏆᏍᎬ', 'ᎤᎾᏙᏓᏉᏅᎯ', 'ᏔᎵᏁᎢᎦ', 'ᏦᎢᏁᎢᎦ', 'ᏅᎩᏁᎢᎦ', 'ᏧᎾᎩᎶᏍᏗ', 'ᎤᎾᏙᏓᏈᏕᎾ'], 'weekdays_short' => ['ᏆᏍᎬ', 'ᏉᏅᎯ', 'ᏔᎵᏁ', 'ᏦᎢᏁ', 'ᏅᎩᏁ', 'ᏧᎾᎩ', 'ᏈᏕᎾ'], 'weekdays_min' => ['ᏆᏍᎬ', 'ᏉᏅᎯ', 'ᏔᎵᏁ', 'ᏦᎢᏁ', 'ᏅᎩᏁ', 'ᏧᎾᎩ', 'ᏈᏕᎾ'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ᏌᎾᎴ', 'ᏒᎯᏱᎢᏗᏢ', 'ꮜꮎꮄ', 'ꮢꭿᏹꭲꮧꮲ'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ckb.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ckb.php index acf4dc280..35ac60a95 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ckb.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ckb.php @@ -12,20 +12,21 @@ /* * Authors: * - Swara Mohammed + * - Kawan Pshtiwan */ $months = [ - 'ڕێبەندان', - 'ڕەشەمە', - 'نەورۆز', - 'گوڵان', - 'جۆزەردان', - 'پوشپەڕ', - 'گەلاوێژ', - 'خەرمانان', - 'ڕەزبەر', - 'گەڵاڕێزان', - 'سەرماوەرز', - 'بەفرانبار', + 'کانونی دووەم', + 'شوبات', + 'ئازار', + 'نیسان', + 'ئایار', + 'حوزەیران', + 'تەمموز', + 'ئاب', + 'ئەیلوول', + 'تشرینی یەکەم', + 'تشرینی دووەم', + 'کانونی یەکەم', ]; return [ diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cmn_TW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cmn_TW.php index 7e43f9de3..eee9c806b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cmn_TW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cmn_TW.php @@ -14,6 +14,7 @@ * - bug-glibc-locales@gnu.org */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'YYYY年MM月DD號', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cs.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cs.php index c01e3ccc8..9530d363d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cs.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cs.php @@ -104,6 +104,7 @@ return [ 'months' => ['ledna', 'února', 'března', 'dubna', 'května', 'června', 'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'], 'months_standalone' => ['leden', 'únor', 'březen', 'duben', 'květen', 'červen', 'červenec', 'srpen', 'září', 'říjen', 'listopad', 'prosinec'], 'months_short' => ['led', 'úno', 'bře', 'dub', 'kvě', 'čvn', 'čvc', 'srp', 'zář', 'říj', 'lis', 'pro'], + 'months_regexp' => '/(DD?o?\.?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/', 'weekdays' => ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], 'weekdays_short' => ['ned', 'pon', 'úte', 'stř', 'čtv', 'pát', 'sob'], 'weekdays_min' => ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cv.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cv.php index 8aeb73aa8..fe7696853 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cv.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cv.php @@ -31,8 +31,8 @@ return [ 'second' => ':count ҫеккунт', 'a_second' => '{1}пӗр-ик ҫеккунт|:count ҫеккунт', 'ago' => ':time каялла', - 'from_now' => function ($time) { - return $time.(preg_match('/сехет$/u', $time) ? 'рен' : (preg_match('/ҫул/u', $time) ? 'тан' : 'ран')); + 'from_now' => static function ($time) { + return $time.(preg_match('/сехет$/u', $time) ? 'рен' : (preg_match('/ҫул/', $time) ? 'тан' : 'ран')); }, 'diff_yesterday' => 'Ӗнер', 'diff_today' => 'Паян', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cy.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cy.php index 119274f01..d769d2f5f 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cy.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/cy.php @@ -16,19 +16,26 @@ * - Daniel Monaghan */ return [ - 'year' => '{1}blwyddyn|]1,Inf[:count flynedd', + 'year' => '{1}:count flwyddyn|[-Inf,Inf]:count flynedd', + 'a_year' => '{1}blwyddyn|[-Inf,Inf]:count flynedd', 'y' => ':countbl', - 'month' => '{1}mis|]1,Inf[:count mis', + 'month' => ':count mis', + 'a_month' => '{1}mis|[-Inf,Inf]:count mis', 'm' => ':countmi', 'week' => ':count wythnos', + 'a_week' => '{1}wythnos|[-Inf,Inf]:count wythnos', 'w' => ':countw', - 'day' => '{1}diwrnod|]1,Inf[:count diwrnod', + 'day' => ':count diwrnod', + 'a_day' => '{1}diwrnod|[-Inf,Inf]:count diwrnod', 'd' => ':countd', - 'hour' => '{1}awr|]1,Inf[:count awr', + 'hour' => ':count awr', + 'a_hour' => '{1}awr|[-Inf,Inf]:count awr', 'h' => ':counth', - 'minute' => '{1}munud|]1,Inf[:count munud', + 'minute' => ':count munud', + 'a_minute' => '{1}munud|[-Inf,Inf]:count munud', 'min' => ':countm', - 'second' => '{1}ychydig eiliadau|]1,Inf[:count eiliad', + 'second' => ':count eiliad', + 'a_second' => '{0,1}ychydig eiliadau|[-Inf,Inf]:count eiliad', 's' => ':counts', 'ago' => ':time yn ôl', 'from_now' => 'mewn :time', @@ -57,7 +64,7 @@ return [ 'lastWeek' => 'dddd [diwethaf am] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { return $number.( $number > 20 ? (\in_array((int) $number, [40, 50, 60, 80, 100], true) ? 'fed' : 'ain') diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/da.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/da.php index 322f91d5b..d0e7168e5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/da.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/da.php @@ -71,10 +71,10 @@ return [ ], 'ordinal' => ':number.', 'months' => ['januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'], - 'months_short' => ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'], + 'months_short' => ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'], 'weekdays' => ['søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'], 'weekdays_short' => ['søn.', 'man.', 'tir.', 'ons.', 'tor.', 'fre.', 'lør.'], - 'weekdays_min' => ['sø', 'ma', 'ti', 'on', 'to', 'fr', 'lø'], + 'weekdays_min' => ['sø.', 'ma.', 'ti.', 'on.', 'to.', 'fr.', 'lø.'], 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, 'list' => [', ', ' og '], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dav.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dav.php index e95ec4bb2..4f8d1e73c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dav.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dav.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Luma lwa K', 'luma lwa p'], 'weekdays' => ['Ituku ja jumwa', 'Kuramuka jimweri', 'Kuramuka kawi', 'Kuramuka kadadu', 'Kuramuka kana', 'Kuramuka kasanu', 'Kifula nguwo'], 'weekdays_short' => ['Jum', 'Jim', 'Kaw', 'Kad', 'Kan', 'Kas', 'Ngu'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/de.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/de.php index 3b70750e4..90b1e350c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/de.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/de.php @@ -78,6 +78,24 @@ return [ 'diff_before_yesterday' => 'Vorgestern', 'diff_after_tomorrow' => 'Übermorgen', + 'period_recurrences' => 'einmal|:count mal', + 'period_interval' => static function (string $interval = '') { + /** @var string $output */ + $output = preg_replace('/^(ein|eine|1)\s+/u', '', $interval); + + if (preg_match('/^(ein|1)( Monat| Mon.| Tag| Tg.)/u', $interval)) { + return "jeden $output"; + } + + if (preg_match('/^(ein|1)( Jahr| J.)/u', $interval)) { + return "jedes $output"; + } + + return "jede $output"; + }, + 'period_start_date' => 'von :date', + 'period_end_date' => 'bis :date', + 'formats' => [ 'LT' => 'HH:mm', 'LTS' => 'HH:mm:ss', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/doi_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/doi_IN.php index d35972142..f3d43ce38 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/doi_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/doi_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ऐतबार', 'सोमबार', 'मंगलबर', 'बुधबार', 'बीरबार', 'शुक्करबार', 'श्नीचरबार'], 'weekdays_short' => ['ऐत', 'सोम', 'मंगल', 'बुध', 'बीर', 'शुक्कर', 'श्नीचर'], 'weekdays_min' => ['ऐत', 'सोम', 'मंगल', 'बुध', 'बीर', 'शुक्कर', 'श्नीचर'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['सञं', 'सबेर'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dv.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dv.php index 4b8d7e1a4..b2062eb66 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dv.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dv.php @@ -10,18 +10,18 @@ */ $months = [ - 'ޖެނުއަރީ', - 'ފެބްރުއަރީ', + 'ޖަނަވަރީ', + 'ފެބުރުވަރީ', 'މާރިޗު', - 'އޭޕްރީލު', + 'އެޕްރީލް', 'މޭ', 'ޖޫން', 'ޖުލައި', - 'އޯގަސްޓު', - 'ސެޕްޓެމްބަރު', - 'އޮކްޓޯބަރު', - 'ނޮވެމްބަރު', - 'ޑިސެމްބަރު', + 'އޮގަސްޓު', + 'ސެޕްޓެންބަރު', + 'އޮކްޓޫބަރު', + 'ނޮވެންބަރު', + 'ޑިސެންބަރު', ]; $weekdays = [ @@ -38,6 +38,7 @@ $weekdays = [ * Authors: * - Josh Soref * - Jawish Hameed + * - Saiph Muhammad */ return [ 'year' => ':count '.'އަހަރު', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dz_BT.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dz_BT.php index bfbcaf468..5c40142d2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dz_BT.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/dz_BT.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['གཟའ་ཟླ་བ་', 'གཟའ་མིག་དམར་', 'གཟའ་ལྷག་ཕ་', 'གཟའ་པུར་བུ་', 'གཟའ་པ་སངས་', 'གཟའ་སྤེན་ཕ་', 'གཟའ་ཉི་མ་'], 'weekdays_short' => ['ཟླ་', 'མིར་', 'ལྷག་', 'པུར་', 'སངས་', 'སྤེན་', 'ཉི་'], 'weekdays_min' => ['ཟླ་', 'མིར་', 'ལྷག་', 'པུར་', 'སངས་', 'སྤེན་', 'ཉི་'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ངས་ཆ', 'ཕྱི་ཆ'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ebu.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ebu.php index f60bc6f2f..9e7d95771 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ebu.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ebu.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['KI', 'UT'], 'weekdays' => ['Kiumia', 'Njumatatu', 'Njumaine', 'Njumatano', 'Aramithi', 'Njumaa', 'NJumamothii'], 'weekdays_short' => ['Kma', 'Tat', 'Ine', 'Tan', 'Arm', 'Maa', 'NMM'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/el.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/el.php index 7c40f9c12..8711fa2b4 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/el.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/el.php @@ -68,13 +68,9 @@ return [ 'nextDay' => '[Αύριο {}] LT', 'nextWeek' => 'dddd [{}] LT', 'lastDay' => '[Χθες {}] LT', - 'lastWeek' => function (CarbonInterface $current) { - switch ($current->dayOfWeek) { - case 6: - return '[το προηγούμενο] dddd [{}] LT'; - default: - return '[την προηγούμενη] dddd [{}] LT'; - } + 'lastWeek' => static fn (CarbonInterface $current) => match ($current->dayOfWeek) { + 6 => '[το προηγούμενο] dddd [{}] LT', + default => '[την προηγούμενη] dddd [{}] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en.php index f81f617e3..79f50aad8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en.php @@ -17,37 +17,37 @@ */ return [ /* - * {1}, {0} and ]1,Inf[ are not needed as it's the default for English pluralization. + * {1}, {0} and [-Inf,Inf] are not needed as it's the default for English pluralization. * But as some languages are using en.php as a fallback, it's better to specify it * explicitly so those languages also fallback to English pluralization when a unit * is missing. */ - 'year' => '{1}:count year|{0}:count years|]1,Inf[:count years', - 'a_year' => '{1}a year|{0}:count years|]1,Inf[:count years', - 'y' => '{1}:countyr|{0}:countyrs|]1,Inf[:countyrs', - 'month' => '{1}:count month|{0}:count months|]1,Inf[:count months', - 'a_month' => '{1}a month|{0}:count months|]1,Inf[:count months', - 'm' => '{1}:countmo|{0}:countmos|]1,Inf[:countmos', - 'week' => '{1}:count week|{0}:count weeks|]1,Inf[:count weeks', - 'a_week' => '{1}a week|{0}:count weeks|]1,Inf[:count weeks', + 'year' => '{1}:count year|{0}:count years|[-Inf,Inf]:count years', + 'a_year' => '{1}a year|{0}:count years|[-Inf,Inf]:count years', + 'y' => '{1}:countyr|{0}:countyrs|[-Inf,Inf]:countyrs', + 'month' => '{1}:count month|{0}:count months|[-Inf,Inf]:count months', + 'a_month' => '{1}a month|{0}:count months|[-Inf,Inf]:count months', + 'm' => '{1}:countmo|{0}:countmos|[-Inf,Inf]:countmos', + 'week' => '{1}:count week|{0}:count weeks|[-Inf,Inf]:count weeks', + 'a_week' => '{1}a week|{0}:count weeks|[-Inf,Inf]:count weeks', 'w' => ':countw', - 'day' => '{1}:count day|{0}:count days|]1,Inf[:count days', - 'a_day' => '{1}a day|{0}:count days|]1,Inf[:count days', + 'day' => '{1}:count day|{0}:count days|[-Inf,Inf]:count days', + 'a_day' => '{1}a day|{0}:count days|[-Inf,Inf]:count days', 'd' => ':countd', - 'hour' => '{1}:count hour|{0}:count hours|]1,Inf[:count hours', - 'a_hour' => '{1}an hour|{0}:count hours|]1,Inf[:count hours', + 'hour' => '{1}:count hour|{0}:count hours|[-Inf,Inf]:count hours', + 'a_hour' => '{1}an hour|{0}:count hours|[-Inf,Inf]:count hours', 'h' => ':counth', - 'minute' => '{1}:count minute|{0}:count minutes|]1,Inf[:count minutes', - 'a_minute' => '{1}a minute|{0}:count minutes|]1,Inf[:count minutes', + 'minute' => '{1}:count minute|{0}:count minutes|[-Inf,Inf]:count minutes', + 'a_minute' => '{1}a minute|{0}:count minutes|[-Inf,Inf]:count minutes', 'min' => ':countm', - 'second' => '{1}:count second|{0}:count seconds|]1,Inf[:count seconds', - 'a_second' => '{1}a few seconds|{0}:count seconds|]1,Inf[:count seconds', + 'second' => '{1}:count second|{0}:count seconds|[-Inf,Inf]:count seconds', + 'a_second' => '{0,1}a few seconds|[-Inf,Inf]:count seconds', 's' => ':counts', - 'millisecond' => '{1}:count millisecond|{0}:count milliseconds|]1,Inf[:count milliseconds', - 'a_millisecond' => '{1}a millisecond|{0}:count milliseconds|]1,Inf[:count milliseconds', + 'millisecond' => '{1}:count millisecond|{0}:count milliseconds|[-Inf,Inf]:count milliseconds', + 'a_millisecond' => '{1}a millisecond|{0}:count milliseconds|[-Inf,Inf]:count milliseconds', 'ms' => ':countms', - 'microsecond' => '{1}:count microsecond|{0}:count microseconds|]1,Inf[:count microseconds', - 'a_microsecond' => '{1}a microsecond|{0}:count microseconds|]1,Inf[:count microseconds', + 'microsecond' => '{1}:count microsecond|{0}:count microseconds|[-Inf,Inf]:count microseconds', + 'a_microsecond' => '{1}a microsecond|{0}:count microseconds|[-Inf,Inf]:count microseconds', 'µs' => ':countµs', 'ago' => ':time ago', 'from_now' => ':time from now', @@ -59,7 +59,7 @@ return [ 'diff_tomorrow' => 'tomorrow', 'diff_before_yesterday' => 'before yesterday', 'diff_after_tomorrow' => 'after tomorrow', - 'period_recurrences' => '{1}once|{0}:count times|]1,Inf[:count times', + 'period_recurrences' => '{1}once|{0}:count times|[-Inf,Inf]:count times', 'period_interval' => 'every :interval', 'period_start_date' => 'from :date', 'period_end_date' => 'to :date', @@ -68,7 +68,7 @@ return [ 'weekdays' => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 'weekdays_short' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 'weekdays_min' => ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { $lastDigit = $number % 10; return $number.( @@ -81,7 +81,15 @@ return [ ) ); }, + 'formats' => [ + 'LT' => 'h:mm A', + 'LTS' => 'h:mm:ss A', + 'L' => 'MM/DD/YYYY', + 'LL' => 'MMMM D, YYYY', + 'LLL' => 'MMMM D, YYYY h:mm A', + 'LLLL' => 'dddd, MMMM D, YYYY h:mm A', + ], 'list' => [', ', ' and '], - 'first_day_of_week' => 0, + 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 1, ]; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_001.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_001.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_001.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_001.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_150.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_150.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_150.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_150.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AG.php index 2c1c64f06..06c6e1ac1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AG.php @@ -17,5 +17,4 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'formats' => [ 'L' => 'DD/MM/YY', ], - 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AS.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AS.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AT.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AT.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AT.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AT.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AU.php index f16bd4f54..d1df6144c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_AU.php @@ -26,6 +26,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY h:mm A', 'LLLL' => 'dddd, D MMMM YYYY h:mm A', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BB.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BB.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BB.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BB.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BE.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BE.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BM.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BM.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BS.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BS.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BW.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BW.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BZ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BZ.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BZ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_BZ.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CA.php index e65608688..824571e08 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CA.php @@ -26,4 +26,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'MMMM D, YYYY h:mm A', 'LLLL' => 'dddd, MMMM D, YYYY h:mm A', ], + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CC.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CC.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CC.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CC.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CH.php index 10d9cd8f1..16668ffdf 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CH.php @@ -10,7 +10,6 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, 'formats' => [ 'LT' => 'HH:mm', 'LTS' => 'HH:mm:ss', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CK.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CK.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CM.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CM.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CX.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CX.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CX.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CX.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CY.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CY.php index a44c3508e..7dfb7210e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CY.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_CY.php @@ -23,6 +23,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY HH:mm', 'LLLL' => 'dddd, D MMMM YYYY HH:mm', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DE.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DE.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DK.php index 9e8a8c68b..9615e0438 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DK.php @@ -17,6 +17,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'formats' => [ 'L' => 'YYYY-MM-DD', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DM.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_DM.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ER.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ER.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ER.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ER.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FJ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FJ.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FJ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FJ.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FK.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FK.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FM.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_FM.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GB.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GB.php index 67d9fd649..6ba710152 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GB.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GB.php @@ -25,6 +25,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY HH:mm', 'LLLL' => 'dddd, D MMMM YYYY HH:mm', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GD.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GD.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GD.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GD.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GH.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GH.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GM.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GM.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GU.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GU.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GY.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GY.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GY.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_GY.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_HK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_HK.php index 34aae989b..d0963b4e1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_HK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_HK.php @@ -14,5 +14,5 @@ * - IBM Globalization Center of Competency, Yamato Software Laboratory bug-glibc-locales@gnu.org */ return array_replace_recursive(require __DIR__.'/en.php', [ - 'day_of_first_week_of_year' => 1, + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IE.php index c8d3c2fc9..62e5092f8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IE.php @@ -26,6 +26,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY HH:mm', 'LLLL' => 'dddd D MMMM YYYY HH:mm', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IL.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IL.php index e607924e7..b6107a96c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IL.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IL.php @@ -26,4 +26,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY HH:mm', 'LLLL' => 'dddd, D MMMM YYYY HH:mm', ], + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IM.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IM.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IN.php index 00414e9ad..4a3f03146 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IN.php @@ -22,5 +22,4 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'DD MMM HH:mm', 'LLLL' => 'MMMM DD, YYYY HH:mm', ], - 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IO.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IO.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IO.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_IO.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ISO.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ISO.php index 11457b0c8..6688b137f 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ISO.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ISO.php @@ -18,4 +18,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'YYYY MMMM D HH:mm', 'LLLL' => 'dddd, YYYY MMMM DD HH:mm', ], + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JE.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JE.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JM.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_JM.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KE.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KE.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KN.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KN.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KY.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KY.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KY.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_KY.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LC.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LC.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LC.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LC.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LR.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LR.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LR.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LR.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LS.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_LS.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MH.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MH.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MO.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MO.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MO.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MO.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MP.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MP.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MP.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MP.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MS.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MS.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MT.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MT.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MT.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MT.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MU.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MU.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MW.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MW.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MY.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MY.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MY.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_MY.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NA.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NA.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NF.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NF.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NF.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NF.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NG.php index 67bceaad7..c337cfc04 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NG.php @@ -13,6 +13,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'formats' => [ 'L' => 'DD/MM/YY', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NL.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NL.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NL.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NL.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NR.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NR.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NR.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NR.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NU.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NU.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NZ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NZ.php index 6a206a0d0..be65cd3e1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NZ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_NZ.php @@ -26,6 +26,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY h:mm A', 'LLLL' => 'dddd, D MMMM YYYY h:mm A', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PH.php index 34aae989b..d0963b4e1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PH.php @@ -14,5 +14,5 @@ * - IBM Globalization Center of Competency, Yamato Software Laboratory bug-glibc-locales@gnu.org */ return array_replace_recursive(require __DIR__.'/en.php', [ - 'day_of_first_week_of_year' => 1, + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PK.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PK.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PN.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PN.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PR.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PR.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PR.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PR.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PW.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_PW.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_RW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_RW.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_RW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_RW.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SB.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SB.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SB.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SB.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SC.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SC.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SC.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SC.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SE.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SE.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SG.php index 5ee95241d..e31e8264f 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SG.php @@ -19,6 +19,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'D MMMM YYYY HH:mm', 'LLLL' => 'dddd, D MMMM YYYY HH:mm', ], - 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SH.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SH.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SI.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SI.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SL.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SL.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SL.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SL.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SS.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SS.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SX.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SX.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SX.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SX.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SZ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SZ.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SZ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_SZ.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TC.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TC.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TC.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TC.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TK.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TK.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TO.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TO.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TO.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TO.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TT.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TT.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TT.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TT.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TV.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TV.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TV.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TV.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TZ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TZ.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TZ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_TZ.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UM.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_UM.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US_Posix.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US_Posix.php index f086dc632..135bc0c36 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US_Posix.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_US_Posix.php @@ -9,4 +9,4 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return require __DIR__.'/en_US.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VC.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VC.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VC.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VC.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VG.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VG.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VI.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VI.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VI.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VI.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VU.php index e2dd81db5..f086dc632 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_VU.php @@ -9,6 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/en.php', [ - 'first_day_of_week' => 1, -]); +return require __DIR__.'/en.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_WS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_WS.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_WS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_WS.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZA.php index 48ea9471c..54d8d8818 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZA.php @@ -22,5 +22,4 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'LLL' => 'DD MMM HH:mm', 'LLLL' => 'MMMM DD, YYYY HH:mm', ], - 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZM.php index d8a8cb598..c6bc0b2ff 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZM.php @@ -17,6 +17,4 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'formats' => [ 'L' => 'DD/MM/YY', ], - 'first_day_of_week' => 1, - 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZW.php index f086dc632..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/en_ZW.php @@ -9,4 +9,6 @@ * file that was distributed with this source code. */ -return require __DIR__.'/en.php'; +return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/es.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/es.php index 1c4fcfd0b..dc24945cf 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/es.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/es.php @@ -72,6 +72,10 @@ return [ 'diff_tomorrow_regexp' => 'mañana(?:\\s+a)?(?:\\s+las)?', 'diff_before_yesterday' => 'anteayer', 'diff_after_tomorrow' => 'pasado mañana', + 'period_recurrences' => 'una vez|:count veces', + 'period_interval' => 'cada :interval', + 'period_start_date' => 'de :date', + 'period_end_date' => 'a :date', 'formats' => [ 'LT' => 'H:mm', 'LTS' => 'H:mm:ss', @@ -81,19 +85,19 @@ return [ 'LLLL' => 'dddd, D [de] MMMM [de] YYYY H:mm', ], 'calendar' => [ - 'sameDay' => function (CarbonInterface $current) { + 'sameDay' => static function (CarbonInterface $current) { return '[hoy a la'.($current->hour !== 1 ? 's' : '').'] LT'; }, - 'nextDay' => function (CarbonInterface $current) { + 'nextDay' => static function (CarbonInterface $current) { return '[mañana a la'.($current->hour !== 1 ? 's' : '').'] LT'; }, - 'nextWeek' => function (CarbonInterface $current) { + 'nextWeek' => static function (CarbonInterface $current) { return 'dddd [a la'.($current->hour !== 1 ? 's' : '').'] LT'; }, - 'lastDay' => function (CarbonInterface $current) { + 'lastDay' => static function (CarbonInterface $current) { return '[ayer a la'.($current->hour !== 1 ? 's' : '').'] LT'; }, - 'lastWeek' => function (CarbonInterface $current) { + 'lastWeek' => static function (CarbonInterface $current) { return '[el] dddd [pasado a la'.($current->hour !== 1 ? 's' : '').'] LT'; }, 'sameElse' => 'L', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fil_PH.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fil_PH.php index bcf158078..60751dd53 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fil_PH.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fil_PH.php @@ -23,6 +23,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Linggo', 'Lunes', 'Martes', 'Miyerkoles', 'Huwebes', 'Biyernes', 'Sabado'], 'weekdays_short' => ['Lin', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab'], 'weekdays_min' => ['Lin', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['N.U.', 'N.H.'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr.php index f4c7247b4..da696e79e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr.php @@ -23,6 +23,12 @@ * - Pete Scopes (pdscopes) */ return [ + 'millennium' => ':count millénaire|:count millénaires', + 'a_millennium' => 'un millénaire|:count millénaires', + 'century' => ':count siècle|:count siècles', + 'a_century' => 'un siècle|:count siècles', + 'decade' => ':count décennie|:count décennies', + 'a_decade' => 'une décennie|:count décennies', 'year' => ':count an|:count ans', 'a_year' => 'un an|:count ans', 'y' => ':count an|:count ans', @@ -88,25 +94,14 @@ return [ 'weekdays' => ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'], 'weekdays_short' => ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'], 'weekdays_min' => ['di', 'lu', 'ma', 'me', 'je', 've', 'sa'], - 'ordinal' => function ($number, $period) { - switch ($period) { + 'ordinal' => static function ($number, $period) { + return match ($period) { // In French, only the first has to be ordinal, other number remains cardinal // @link https://fr.wikihow.com/%C3%A9crire-la-date-en-fran%C3%A7ais - case 'D': - return $number.($number === 1 ? 'er' : ''); - - default: - case 'M': - case 'Q': - case 'DDD': - case 'd': - return $number.($number === 1 ? 'er' : 'e'); - - // Words with feminine grammatical gender: semaine - case 'w': - case 'W': - return $number.($number === 1 ? 're' : 'e'); - } + 'D' => $number.($number === 1 ? 'er' : ''), + default => $number.($number === 1 ? 'er' : 'e'), + 'w', 'W' => $number.($number === 1 ? 're' : 'e'), + }; }, 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_BE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_BE.php index f6cafe87c..8ed032847 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_BE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_BE.php @@ -13,6 +13,4 @@ * Authors: * - RAP bug-glibc-locales@gnu.org */ -return array_replace_recursive(require __DIR__.'/fr.php', [ - 'months_short' => ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'], -]); +return require __DIR__.'/fr.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_LU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_LU.php index 8e37d852b..6dda77226 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_LU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fr_LU.php @@ -17,5 +17,4 @@ return array_replace_recursive(require __DIR__.'/fr.php', [ 'formats' => [ 'L' => 'DD.MM.YYYY', ], - 'months_short' => ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fy.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fy.php index c1b543970..42ecaed1e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fy.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/fy.php @@ -61,7 +61,7 @@ return [ 'lastWeek' => '[ôfrûne] dddd [om] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de'); }, 'months' => ['jannewaris', 'febrewaris', 'maart', 'april', 'maaie', 'juny', 'july', 'augustus', 'septimber', 'oktober', 'novimber', 'desimber'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ga.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ga.php index 9f07a26ce..013367bd8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ga.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ga.php @@ -67,9 +67,7 @@ return [ 'weekdays' => ['Dé Domhnaigh', 'Dé Luain', 'Dé Máirt', 'Dé Céadaoin', 'Déardaoin', 'Dé hAoine', 'Dé Satharn'], 'weekdays_short' => ['Dom', 'Lua', 'Mái', 'Céa', 'Déa', 'hAo', 'Sat'], 'weekdays_min' => ['Do', 'Lu', 'Má', 'Ce', 'Dé', 'hA', 'Sa'], - 'ordinal' => function ($number) { - return $number.($number === 1 ? 'd' : ($number % 10 === 2 ? 'na' : 'mh')); - }, + 'ordinal' => static fn ($number) => $number.($number === 1 ? 'd' : ($number % 10 === 2 ? 'na' : 'mh')), 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 4, 'list' => [', ', ' agus '], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gd.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gd.php index 63d064ddd..05437bff5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gd.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gd.php @@ -60,7 +60,7 @@ return [ 'lastWeek' => 'dddd [seo chaidh] [aig] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { return $number.($number === 1 ? 'd' : ($number % 10 === 2 ? 'na' : 'mh')); }, 'months' => ['Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gez_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gez_ET.php index 393300962..857954981 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gez_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gez_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚት'], 'weekdays_short' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'], 'weekdays_min' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ጽባሕ', 'ምሴት'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gl.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gl.php index 088b0f281..96bf14561 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gl.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gl.php @@ -43,7 +43,7 @@ return [ 'a_second' => 'uns segundos|:count segundos', 's' => ':count seg.', 'ago' => 'hai :time', - 'from_now' => function ($time) { + 'from_now' => static function ($time) { if (str_starts_with($time, 'un')) { return "n$time"; } @@ -68,19 +68,19 @@ return [ 'LLLL' => 'dddd, D [de] MMMM [de] YYYY H:mm', ], 'calendar' => [ - 'sameDay' => function (CarbonInterface $current) { + 'sameDay' => static function (CarbonInterface $current) { return '[hoxe '.($current->hour !== 1 ? 'ás' : 'á').'] LT'; }, - 'nextDay' => function (CarbonInterface $current) { + 'nextDay' => static function (CarbonInterface $current) { return '[mañá '.($current->hour !== 1 ? 'ás' : 'á').'] LT'; }, - 'nextWeek' => function (CarbonInterface $current) { + 'nextWeek' => static function (CarbonInterface $current) { return 'dddd ['.($current->hour !== 1 ? 'ás' : 'á').'] LT'; }, - 'lastDay' => function (CarbonInterface $current) { + 'lastDay' => static function (CarbonInterface $current) { return '[onte '.($current->hour !== 1 ? 'á' : 'a').'] LT'; }, - 'lastWeek' => function (CarbonInterface $current) { + 'lastWeek' => static function (CarbonInterface $current) { return '[o] dddd [pasado '.($current->hour !== 1 ? 'ás' : 'á').'] LT'; }, 'sameElse' => 'L', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gom_Latn.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gom_Latn.php index 612bb8865..ef50d96e2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gom_Latn.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gom_Latn.php @@ -53,11 +53,9 @@ return [ 'weekdays_short' => ['Ait.', 'Som.', 'Mon.', 'Bud.', 'Bre.', 'Suk.', 'Son.'], 'weekdays_min' => ['Ai', 'Sm', 'Mo', 'Bu', 'Br', 'Su', 'Sn'], - 'ordinal' => function ($number, $period) { - return $number.($period === 'D' ? 'er' : ''); - }, + 'ordinal' => static fn ($number, $period) => $number.($period === 'D' ? 'er' : ''), - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'rati'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gu.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gu.php index 8bc431140..16455eded 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gu.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/gu.php @@ -54,7 +54,7 @@ return [ 'lastWeek' => '[પાછલા] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'રાત'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/guz.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/guz.php index 6230165c1..d39e9ca3b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/guz.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/guz.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Ma', 'Mo'], 'weekdays' => ['Chumapiri', 'Chumatato', 'Chumaine', 'Chumatano', 'Aramisi', 'Ichuma', 'Esabato'], 'weekdays_short' => ['Cpr', 'Ctt', 'Cmn', 'Cmt', 'Ars', 'Icm', 'Est'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hak_TW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hak_TW.php index fe2398650..2a3bc9614 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hak_TW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hak_TW.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['禮拜日', '禮拜一', '禮拜二', '禮拜三', '禮拜四', '禮拜五', '禮拜六'], 'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'], 'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['上晝', '下晝'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/haw.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/haw.php index cdd36861e..e46993a3c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/haw.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/haw.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'months' => ['Ianuali', 'Pepeluali', 'Malaki', 'ʻApelila', 'Mei', 'Iune', 'Iulai', 'ʻAukake', 'Kepakemapa', 'ʻOkakopa', 'Nowemapa', 'Kekemapa'], 'months_short' => ['Ian.', 'Pep.', 'Mal.', 'ʻAp.', 'Mei', 'Iun.', 'Iul.', 'ʻAu.', 'Kep.', 'ʻOk.', 'Now.', 'Kek.'], 'weekdays' => ['Lāpule', 'Poʻakahi', 'Poʻalua', 'Poʻakolu', 'Poʻahā', 'Poʻalima', 'Poʻaono'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/he.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/he.php index c3fb3e976..6d8f01ee6 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/he.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/he.php @@ -60,7 +60,7 @@ return [ 'lastWeek' => '[ביום] dddd [האחרון בשעה] LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour, $minute, $isLower) { + 'meridiem' => static function ($hour, $minute, $isLower) { if ($hour < 5) { return 'לפנות בוקר'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hi.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hi.php index 70c57a297..1fc180102 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hi.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hi.php @@ -54,7 +54,7 @@ return [ 'lastWeek' => '[पिछले] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'रात'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hif_FJ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hif_FJ.php index 30ad5e74c..54e880e36 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hif_FJ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hif_FJ.php @@ -14,6 +14,7 @@ * - Samsung Electronics Co., Ltd. akhilesh.k@samsung.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'dddd DD MMM YYYY', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hne_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hne_IN.php index a5ca758b6..27b3b396a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hne_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hne_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['इतवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'बिरसपत', 'सुकरवार', 'सनिवार'], 'weekdays_short' => ['इत', 'सोम', 'मंग', 'बुध', 'बिर', 'सुक', 'सनि'], 'weekdays_min' => ['इत', 'सोम', 'मंग', 'बुध', 'बिर', 'सुक', 'सनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['बिहिनियाँ', 'मंझनियाँ'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hr.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hr.php index cfd85fd40..dcf775659 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hr.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hr.php @@ -70,29 +70,17 @@ return [ 'calendar' => [ 'sameDay' => '[danas u] LT', 'nextDay' => '[sutra u] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - default: - return '[u] dddd [u] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[u] [nedjelju] [u] LT', + 3 => '[u] [srijedu] [u] LT', + 6 => '[u] [subotu] [u] LT', + default => '[u] dddd [u] LT', }, 'lastDay' => '[jučer u] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - default: - return '[prošli] dddd [u] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0, 3 => '[prošlu] dddd [u] LT', + 6 => '[prošle] [subote] [u] LT', + default => '[prošli] dddd [u] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hu.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hu.php index b7583eecd..635a30cf9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hu.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hu.php @@ -102,11 +102,11 @@ return [ 'calendar' => [ 'sameDay' => '[ma] LT[-kor]', 'nextDay' => '[holnap] LT[-kor]', - 'nextWeek' => function (CarbonInterface $date) use ($huWeekEndings) { + 'nextWeek' => static function (CarbonInterface $date) use ($huWeekEndings) { return '['.$huWeekEndings[$date->dayOfWeek].'] LT[-kor]'; }, 'lastDay' => '[tegnap] LT[-kor]', - 'lastWeek' => function (CarbonInterface $date) use ($huWeekEndings) { + 'lastWeek' => static function (CarbonInterface $date) use ($huWeekEndings) { return '[múlt '.$huWeekEndings[$date->dayOfWeek].'] LT[-kor]'; }, 'sameElse' => 'L', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hy.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hy.php index 8b129947d..8145ba31e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hy.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/hy.php @@ -59,18 +59,13 @@ return [ 'lastWeek' => '[անցած] dddd [օրը ժամը] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'DDD': - case 'w': - case 'W': - case 'DDDo': - return $number.($number === 1 ? '-ին' : '-րդ'); - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'DDD', 'w', 'W', 'DDDo' => $number.($number === 1 ? '-ին' : '-րդ'), + default => $number, + }; }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'գիշերվա'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/id.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/id.php index afaf78f29..a49a29327 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/id.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/id.php @@ -21,25 +21,25 @@ */ return [ 'year' => ':count tahun', - 'a_year' => '{1}setahun|]1,Inf[:count tahun', + 'a_year' => '{1}setahun|[-Inf,Inf]:count tahun', 'y' => ':countthn', 'month' => ':count bulan', - 'a_month' => '{1}sebulan|]1,Inf[:count bulan', + 'a_month' => '{1}sebulan|[-Inf,Inf]:count bulan', 'm' => ':countbln', 'week' => ':count minggu', - 'a_week' => '{1}seminggu|]1,Inf[:count minggu', + 'a_week' => '{1}seminggu|[-Inf,Inf]:count minggu', 'w' => ':countmgg', 'day' => ':count hari', - 'a_day' => '{1}sehari|]1,Inf[:count hari', + 'a_day' => '{1}sehari|[-Inf,Inf]:count hari', 'd' => ':counthr', 'hour' => ':count jam', - 'a_hour' => '{1}sejam|]1,Inf[:count jam', + 'a_hour' => '{1}sejam|[-Inf,Inf]:count jam', 'h' => ':countj', 'minute' => ':count menit', - 'a_minute' => '{1}semenit|]1,Inf[:count menit', + 'a_minute' => '{1}semenit|[-Inf,Inf]:count menit', 'min' => ':countmnt', 'second' => ':count detik', - 'a_second' => '{1}beberapa detik|]1,Inf[:count detik', + 'a_second' => '{1}beberapa detik|[-Inf,Inf]:count detik', 's' => ':countdt', 'ago' => ':time yang lalu', 'from_now' => ':time dari sekarang', @@ -68,7 +68,7 @@ return [ 'lastWeek' => 'dddd [lalu pukul] LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 11) { return 'pagi'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ii.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ii.php index a4246c277..592a53f41 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ii.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ii.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['ꎸꄑ', 'ꁯꋒ'], 'weekdays' => ['ꑭꆏꑍ', 'ꆏꊂꋍ', 'ꆏꊂꑍ', 'ꆏꊂꌕ', 'ꆏꊂꇖ', 'ꆏꊂꉬ', 'ꆏꊂꃘ'], 'weekdays_short' => ['ꑭꆏ', 'ꆏꋍ', 'ꆏꑍ', 'ꆏꌕ', 'ꆏꇖ', 'ꆏꉬ', 'ꆏꃘ'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ik_CA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ik_CA.php index bb2a109b9..02dbbef22 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ik_CA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ik_CA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Minġuiqsioiq', 'Savałłiq', 'Ilaqtchiioiq', 'Qitchiioiq', 'Sisamiioiq', 'Tallimmiioiq', 'Maqinġuoiq'], 'weekdays_short' => ['Min', 'Sav', 'Ila', 'Qit', 'Sis', 'Tal', 'Maq'], 'weekdays_min' => ['Min', 'Sav', 'Ila', 'Qit', 'Sis', 'Tal', 'Maq'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count ukiuq', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/it.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/it.php index 49875d7ef..c48369517 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/it.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/it.php @@ -54,7 +54,7 @@ return [ 'a_microsecond' => 'un microsecondo|:count microsecondi', 'µs' => ':countµs', 'ago' => ':time fa', - 'from_now' => function ($time) { + 'from_now' => static function ($time) { return (preg_match('/^\d.+$/', $time) ? 'tra' : 'in')." $time"; }, 'after' => ':time dopo', @@ -84,13 +84,9 @@ return [ 'nextDay' => '[Domani alle] LT', 'nextWeek' => 'dddd [alle] LT', 'lastDay' => '[Ieri alle] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[la scorsa] dddd [alle] LT'; - default: - return '[lo scorso] dddd [alle] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[la scorsa] dddd [alle] LT', + default => '[lo scorso] dddd [alle] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iu_CA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iu_CA.php index 6ab7e1497..5acee9390 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iu_CA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iu_CA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ᓈᑦᑎᖑᔭᕐᕕᒃ', 'ᓇᒡᒐᔾᔭᐅ', 'ᓇᒡᒐᔾᔭᐅᓕᖅᑭᑦ', 'ᐱᖓᓲᓕᖅᓯᐅᑦ', 'ᕿᑎᖅᑰᑦ', 'ᐅᓪᓗᕈᓘᑐᐃᓇᖅ', 'ᓯᕙᑖᕕᒃ'], 'weekdays_short' => ['ᓈ', 'ᓇ', 'ᓕ', 'ᐱ', 'ᕿ', 'ᐅ', 'ᓯ'], 'weekdays_min' => ['ᓈ', 'ᓇ', 'ᓕ', 'ᐱ', 'ᕿ', 'ᐅ', 'ᓯ'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count ᐅᑭᐅᖅ', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iw.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iw.php index a26e35062..5dedd3c02 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iw.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/iw.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'months' => ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'], 'months_short' => ['ינו׳', 'פבר׳', 'מרץ', 'אפר׳', 'מאי', 'יוני', 'יולי', 'אוג׳', 'ספט׳', 'אוק׳', 'נוב׳', 'דצמ׳'], 'weekdays' => ['יום ראשון', 'יום שני', 'יום שלישי', 'יום רביעי', 'יום חמישי', 'יום שישי', 'יום שבת'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ja.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ja.php index 1ca675195..a857db5cc 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ja.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ja.php @@ -38,7 +38,7 @@ return [ 'minute' => ':count分', 'min' => ':count分', 'second' => ':count秒', - 'a_second' => '{1}数秒|]1,Inf[:count秒', + 'a_second' => '{1}数秒|[-Inf,Inf]:count秒', 's' => ':count秒', 'ago' => ':time前', 'from_now' => ':time後', @@ -59,7 +59,7 @@ return [ 'calendar' => [ 'sameDay' => '[今日] LT', 'nextDay' => '[明日] LT', - 'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) { + 'nextWeek' => static function (CarbonInterface $current, \Carbon\CarbonInterface $other) { if ($other->week !== $current->week) { return '[来週]dddd LT'; } @@ -67,7 +67,7 @@ return [ return 'dddd LT'; }, 'lastDay' => '[昨日] LT', - 'lastWeek' => function (CarbonInterface $current, CarbonInterface $other) { + 'lastWeek' => static function (CarbonInterface $current, \Carbon\CarbonInterface $other) { if ($other->week !== $current->week) { return '[先週]dddd LT'; } @@ -76,15 +76,11 @@ return [ }, 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'd': - case 'D': - case 'DDD': - return $number.'日'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'd', 'D', 'DDD' => $number.'日', + default => $number, + }; }, 'meridiem' => ['午前', '午後'], 'months' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jgo.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jgo.php index 6a1e77a85..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jgo.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jgo.php @@ -10,4 +10,5 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jv.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jv.php index bcbe044e3..10fe5383c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jv.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/jv.php @@ -16,13 +16,20 @@ * - JD Isaacks */ return [ - 'year' => '{1}setaun|]1,Inf[:count taun', - 'month' => '{1}sewulan|]1,Inf[:count wulan', - 'week' => '{1}sakminggu|]1,Inf[:count minggu', - 'day' => '{1}sedinten|]1,Inf[:count dinten', - 'hour' => '{1}setunggal jam|]1,Inf[:count jam', - 'minute' => '{1}setunggal menit|]1,Inf[:count menit', - 'second' => '{1}sawetawis detik|]1,Inf[:count detik', + 'year' => ':count taun', + 'a_year' => '{1}setaun|[-Inf,Inf]:count taun', + 'month' => ':count wulan', + 'a_month' => '{1}sewulan|[-Inf,Inf]:count wulan', + 'week' => ':count minggu', + 'a_week' => '{1}sakminggu|[-Inf,Inf]:count minggu', + 'day' => ':count dina', + 'a_day' => '{1}sedina|[-Inf,Inf]:count dina', + 'hour' => ':count jam', + 'a_hour' => '{1}setunggal jam|[-Inf,Inf]:count jam', + 'minute' => ':count menit', + 'a_minute' => '{1}setunggal menit|[-Inf,Inf]:count menit', + 'second' => ':count detik', + 'a_second' => '{0,1}sawetawis detik|[-Inf,Inf]:count detik', 'ago' => ':time ingkang kepengker', 'from_now' => 'wonten ing :time', 'diff_today' => 'Dinten', @@ -47,7 +54,7 @@ return [ 'lastWeek' => 'dddd [kepengker pukul] LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 11) { return 'enjing'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ka.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ka.php index a5d563d3c..b3051d598 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ka.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ka.php @@ -30,26 +30,26 @@ use Carbon\CarbonInterface; return [ 'year' => ':count წელი', 'y' => ':count წელი', - 'a_year' => '{1}წელი|]1,Inf[:count წელი', + 'a_year' => '{1}წელი|[-Inf,Inf]:count წელი', 'month' => ':count თვე', 'm' => ':count თვე', - 'a_month' => '{1}თვე|]1,Inf[:count თვე', + 'a_month' => '{1}თვე|[-Inf,Inf]:count თვე', 'week' => ':count კვირა', 'w' => ':count კვირა', - 'a_week' => '{1}კვირა|]1,Inf[:count კვირა', + 'a_week' => '{1}კვირა|[-Inf,Inf]:count კვირა', 'day' => ':count დღე', 'd' => ':count დღე', - 'a_day' => '{1}დღე|]1,Inf[:count დღე', + 'a_day' => '{1}დღე|[-Inf,Inf]:count დღე', 'hour' => ':count საათი', 'h' => ':count საათი', - 'a_hour' => '{1}საათი|]1,Inf[:count საათი', + 'a_hour' => '{1}საათი|[-Inf,Inf]:count საათი', 'minute' => ':count წუთი', 'min' => ':count წუთი', - 'a_minute' => '{1}წუთი|]1,Inf[:count წუთი', + 'a_minute' => '{1}წუთი|[-Inf,Inf]:count წუთი', 'second' => ':count წამი', 's' => ':count წამი', - 'a_second' => '{1}რამდენიმე წამი|]1,Inf[:count წამი', - 'ago' => function ($time) { + 'a_second' => '{1}რამდენიმე წამი|[-Inf,Inf]:count წამი', + 'ago' => static function ($time) { $replacements = [ // year 'წელი' => 'წლის', @@ -71,7 +71,7 @@ return [ return "$time წინ"; }, - 'from_now' => function ($time) { + 'from_now' => static function ($time) { $replacements = [ // year 'წელი' => 'წელიწადში', @@ -93,7 +93,7 @@ return [ return $time; }, - 'after' => function ($time) { + 'after' => static function ($time) { $replacements = [ // year 'წელი' => 'წლის', @@ -115,7 +115,7 @@ return [ return "$time შემდეგ"; }, - 'before' => function ($time) { + 'before' => static function ($time) { $replacements = [ // year 'წელი' => 'წლით', @@ -152,14 +152,14 @@ return [ 'calendar' => [ 'sameDay' => '[დღეს], LT[-ზე]', 'nextDay' => '[ხვალ], LT[-ზე]', - 'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) { + 'nextWeek' => static function (CarbonInterface $current, \Carbon\CarbonInterface $other) { return ($current->isSameWeek($other) ? '' : '[შემდეგ] ').'dddd, LT[-ზე]'; }, 'lastDay' => '[გუშინ], LT[-ზე]', 'lastWeek' => '[წინა] dddd, LT-ზე', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { if ($number === 0) { return $number; } @@ -184,7 +184,7 @@ return [ 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 1, 'list' => [', ', ' და '], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour >= 4) { if ($hour < 11) { return 'დილის'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kam.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kam.php index 0fc70d708..4d3a3b258 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kam.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kam.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Ĩyakwakya', 'Ĩyawĩoo'], 'weekdays' => ['Wa kyumwa', 'Wa kwambĩlĩlya', 'Wa kelĩ', 'Wa katatũ', 'Wa kana', 'Wa katano', 'Wa thanthatũ'], 'weekdays_short' => ['Wky', 'Wkw', 'Wkl', 'Wtũ', 'Wkn', 'Wtn', 'Wth'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ki.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ki.php index d86afc500..868fd61ae 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ki.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ki.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Kiroko', 'Hwaĩ-inĩ'], 'weekdays' => ['Kiumia', 'Njumatatũ', 'Njumaine', 'Njumatana', 'Aramithi', 'Njumaa', 'Njumamothi'], 'weekdays_short' => ['KMA', 'NTT', 'NMN', 'NMT', 'ART', 'NMA', 'NMM'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kk.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kk.php index 59fa9affb..23452dd2a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kk.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kk.php @@ -66,7 +66,7 @@ return [ 'lastWeek' => '[Өткен аптаның] dddd [сағат] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { static $suffixes = [ 0 => '-ші', 1 => '-ші', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kkj.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kkj.php index 6a1e77a85..f4cdb67e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kkj.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kkj.php @@ -10,4 +10,5 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kl_GL.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kl_GL.php index 4fed720a3..64c4ae9c7 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kl_GL.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kl_GL.php @@ -31,32 +31,32 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 1, - 'year' => '{1}ukioq :count|{0}:count ukiut|]1,Inf[ukiut :count', - 'a_year' => '{1}ukioq|{0}:count ukiut|]1,Inf[ukiut :count', - 'y' => '{1}:countyr|{0}:countyrs|]1,Inf[:countyrs', + 'year' => '{1}ukioq :count|{0}:count ukiut|[-Inf,Inf]ukiut :count', + 'a_year' => '{1}ukioq|{0}:count ukiut|[-Inf,Inf]ukiut :count', + 'y' => '{1}:countyr|{0}:countyrs|[-Inf,Inf]:countyrs', - 'month' => '{1}qaammat :count|{0}:count qaammatit|]1,Inf[qaammatit :count', - 'a_month' => '{1}qaammat|{0}:count qaammatit|]1,Inf[qaammatit :count', - 'm' => '{1}:countmo|{0}:countmos|]1,Inf[:countmos', + 'month' => '{1}qaammat :count|{0}:count qaammatit|[-Inf,Inf]qaammatit :count', + 'a_month' => '{1}qaammat|{0}:count qaammatit|[-Inf,Inf]qaammatit :count', + 'm' => '{1}:countmo|{0}:countmos|[-Inf,Inf]:countmos', - 'week' => '{1}:count sap. ak.|{0}:count sap. ak.|]1,Inf[:count sap. ak.', - 'a_week' => '{1}a sap. ak.|{0}:count sap. ak.|]1,Inf[:count sap. ak.', + 'week' => '{1}:count sap. ak.|{0}:count sap. ak.|[-Inf,Inf]:count sap. ak.', + 'a_week' => '{1}a sap. ak.|{0}:count sap. ak.|[-Inf,Inf]:count sap. ak.', 'w' => ':countw', - 'day' => '{1}:count ulloq|{0}:count ullut|]1,Inf[:count ullut', - 'a_day' => '{1}a ulloq|{0}:count ullut|]1,Inf[:count ullut', + 'day' => '{1}:count ulloq|{0}:count ullut|[-Inf,Inf]:count ullut', + 'a_day' => '{1}a ulloq|{0}:count ullut|[-Inf,Inf]:count ullut', 'd' => ':countd', - 'hour' => '{1}:count tiimi|{0}:count tiimit|]1,Inf[:count tiimit', - 'a_hour' => '{1}tiimi|{0}:count tiimit|]1,Inf[:count tiimit', + 'hour' => '{1}:count tiimi|{0}:count tiimit|[-Inf,Inf]:count tiimit', + 'a_hour' => '{1}tiimi|{0}:count tiimit|[-Inf,Inf]:count tiimit', 'h' => ':counth', - 'minute' => '{1}:count minutsi|{0}:count minutsit|]1,Inf[:count minutsit', - 'a_minute' => '{1}a minutsi|{0}:count minutsit|]1,Inf[:count minutsit', + 'minute' => '{1}:count minutsi|{0}:count minutsit|[-Inf,Inf]:count minutsit', + 'a_minute' => '{1}a minutsi|{0}:count minutsit|[-Inf,Inf]:count minutsit', 'min' => ':countm', - 'second' => '{1}:count sikunti|{0}:count sikuntit|]1,Inf[:count sikuntit', - 'a_second' => '{1}sikunti|{0}:count sikuntit|]1,Inf[:count sikuntit', + 'second' => '{1}:count sikunti|{0}:count sikuntit|[-Inf,Inf]:count sikuntit', + 'a_second' => '{1}sikunti|{0}:count sikuntit|[-Inf,Inf]:count sikuntit', 's' => ':counts', 'ago' => ':time matuma siorna', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kln.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kln.php index b9c39968b..de3f44fc5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kln.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kln.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['krn', 'koosk'], 'weekdays' => ['Kotisap', 'Kotaai', 'Koaeng’', 'Kosomok', 'Koang’wan', 'Komuut', 'Kolo'], 'weekdays_short' => ['Kts', 'Kot', 'Koo', 'Kos', 'Koa', 'Kom', 'Kol'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/km.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/km.php index da790ac85..570703e20 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/km.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/km.php @@ -17,19 +17,25 @@ * - Sovichet Tep */ return [ - 'year' => '{1}មួយឆ្នាំ|]1,Inf[:count ឆ្នាំ', + 'year' => ':count ឆ្នាំ', + 'a_year' => '{1}មួយឆ្នាំ|[-Inf,Inf]:count ឆ្នាំ', 'y' => ':count ឆ្នាំ', - 'month' => '{1}មួយខែ|]1,Inf[:count ខែ', + 'month' => ':count ខែ', + 'a_month' => '{1}មួយខែ|[-Inf,Inf]:count ខែ', 'm' => ':count ខែ', - 'week' => ':count សប្ដាហ៍', - 'w' => ':count សប្ដាហ៍', - 'day' => '{1}មួយថ្ងៃ|]1,Inf[:count ថ្ងៃ', + 'week' => ':count សប្តាហ៍', + 'w' => ':count សប្តាហ៍', + 'day' => ':count ថ្ងៃ', + 'a_day' => '{1}មួយថ្ងៃ|[-Inf,Inf]:count ថ្ងៃ', 'd' => ':count ថ្ងៃ', - 'hour' => '{1}មួយម៉ោង|]1,Inf[:count ម៉ោង', + 'hour' => ':count ម៉ោង', + 'a_hour' => '{1}មួយម៉ោង|[-Inf,Inf]:count ម៉ោង', 'h' => ':count ម៉ោង', - 'minute' => '{1}មួយនាទី|]1,Inf[:count នាទី', + 'minute' => ':count នាទី', + 'a_minute' => '{1}មួយនាទី|[-Inf,Inf]:count នាទី', 'min' => ':count នាទី', - 'second' => '{1}ប៉ុន្មានវិនាទី|]1,Inf[:count វិនាទី', + 'second' => ':count វិនាទី', + 'a_second' => '{0,1}ប៉ុន្មានវិនាទី|[-Inf,Inf]:count វិនាទី', 's' => ':count វិនាទី', 'ago' => ':timeមុន', 'from_now' => ':timeទៀត', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kn.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kn.php index 0d2ad08b4..51660e574 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kn.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kn.php @@ -17,13 +17,20 @@ * - rajeevnaikte */ return [ - 'year' => '{1}ಒಂದು ವರ್ಷ|]1,Inf[:count ವರ್ಷ', - 'month' => '{1}ಒಂದು ತಿಂಗಳು|]1,Inf[:count ತಿಂಗಳು', - 'week' => '{1}ಒಂದು ವಾರ|]1,Inf[:count ವಾರಗಳು', - 'day' => '{1}ಒಂದು ದಿನ|]1,Inf[:count ದಿನ', - 'hour' => '{1}ಒಂದು ಗಂಟೆ|]1,Inf[:count ಗಂಟೆ', - 'minute' => '{1}ಒಂದು ನಿಮಿಷ|]1,Inf[:count ನಿಮಿಷ', - 'second' => '{1}ಕೆಲವು ಕ್ಷಣಗಳು|]1,Inf[:count ಸೆಕೆಂಡುಗಳು', + 'year' => '{1}:count ವರ್ಷ|[-Inf,Inf]:count ವರ್ಷಗಳು', + 'a_year' => '{1}ಒಂದು ವರ್ಷ|[-Inf,Inf]:count ವರ್ಷಗಳು', + 'month' => ':count ತಿಂಗಳು', + 'a_month' => '{1}ಒಂದು ತಿಂಗಳು|[-Inf,Inf]:count ತಿಂಗಳು', + 'week' => '{1}:count ವಾರ|[-Inf,Inf]:count ವಾರಗಳು', + 'a_week' => '{1}ಒಂದು ವಾರ|[-Inf,Inf]:count ವಾರಗಳು', + 'day' => '{1}:count ದಿನ|[-Inf,Inf]:count ದಿನಗಳು', + 'a_day' => '{1}ಒಂದು ದಿನ|[-Inf,Inf]:count ದಿನಗಳು', + 'hour' => '{1}:count ಗಂಟೆ|[-Inf,Inf]:count ಗಂಟೆಗಳು', + 'a_hour' => '{1}ಒಂದು ಗಂಟೆ|[-Inf,Inf]:count ಗಂಟೆಗಳು', + 'minute' => '{1}:count ನಿಮಿಷ|[-Inf,Inf]:count ನಿಮಿಷಗಳು', + 'a_minute' => '{1}ಒಂದು ನಿಮಿಷ|[-Inf,Inf]:count ನಿಮಿಷಗಳು', + 'second' => '{0,1}:count ಸೆಕೆಂಡ್|[-Inf,Inf]:count ಸೆಕೆಂಡುಗಳು', + 'a_second' => '{0,1}ಕೆಲವು ಕ್ಷಣಗಳು|[-Inf,Inf]:count ಸೆಕೆಂಡುಗಳು', 'ago' => ':time ಹಿಂದೆ', 'from_now' => ':time ನಂತರ', 'diff_now' => 'ಈಗ', @@ -47,7 +54,7 @@ return [ 'sameElse' => 'L', ], 'ordinal' => ':numberನೇ', - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'ರಾತ್ರಿ'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ko.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ko.php index 4fa623765..8581b716e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ko.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ko.php @@ -22,25 +22,25 @@ */ return [ 'year' => ':count년', - 'a_year' => '{1}일년|]1,Inf[:count년', + 'a_year' => '{1}일년|[-Inf,Inf]:count년', 'y' => ':count년', 'month' => ':count개월', - 'a_month' => '{1}한달|]1,Inf[:count개월', + 'a_month' => '{1}한달|[-Inf,Inf]:count개월', 'm' => ':count개월', 'week' => ':count주', - 'a_week' => '{1}일주일|]1,Inf[:count 주', + 'a_week' => '{1}일주일|[-Inf,Inf]:count 주', 'w' => ':count주일', 'day' => ':count일', - 'a_day' => '{1}하루|]1,Inf[:count일', + 'a_day' => '{1}하루|[-Inf,Inf]:count일', 'd' => ':count일', 'hour' => ':count시간', - 'a_hour' => '{1}한시간|]1,Inf[:count시간', + 'a_hour' => '{1}한시간|[-Inf,Inf]:count시간', 'h' => ':count시간', 'minute' => ':count분', - 'a_minute' => '{1}일분|]1,Inf[:count분', + 'a_minute' => '{1}일분|[-Inf,Inf]:count분', 'min' => ':count분', 'second' => ':count초', - 'a_second' => '{1}몇초|]1,Inf[:count초', + 'a_second' => '{1}몇초|[-Inf,Inf]:count초', 's' => ':count초', 'ago' => ':time 전', 'from_now' => ':time 후', @@ -66,20 +66,13 @@ return [ 'lastWeek' => '지난주 dddd LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'd': - case 'D': - case 'DDD': - return $number.'일'; - case 'M': - return $number.'월'; - case 'w': - case 'W': - return $number.'주'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'd', 'D', 'DDD' => $number.'일', + 'M' => $number.'월', + 'w', 'W' => $number.'주', + default => $number, + }; }, 'meridiem' => ['오전', '오후'], 'months' => ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kok_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kok_IN.php index 92ba844c5..c6110d595 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kok_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/kok_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'], 'weekdays_short' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'], 'weekdays_min' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['म.पू.', 'म.नं.'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN.php index ce9d5d4ae..4ec598fd1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['آتهوار', 'ژءندروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'], 'weekdays_short' => ['آتهوار', 'ژءنتروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'], 'weekdays_min' => ['آتهوار', 'ژءنتروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['دوپھربرونھ', 'دوپھرپتھ'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN@devanagari.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN@devanagari.php index a2ae8b64f..0708f3ff1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN@devanagari.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ks_IN@devanagari.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['आथवार', 'चॅ़दुरवार', 'बोमवार', 'ब्वदवार', 'ब्रसवार', 'शोकुरवार', 'बटुवार'], 'weekdays_short' => ['आथ ', 'चॅ़दुर', 'बोम', 'ब्वद', 'ब्रस', 'शोकुर', 'बटु'], 'weekdays_min' => ['आथ ', 'चॅ़दुर', 'बोम', 'ब्वद', 'ब्रस', 'शोकुर', 'बटु'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ku.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ku.php index 189960c8a..074b07609 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ku.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ku.php @@ -14,20 +14,36 @@ * - Unicode, Inc. */ -return [ +return array_replace_recursive(require __DIR__.'/en.php', [ 'ago' => 'berî :time', 'from_now' => 'di :time de', 'after' => ':time piştî', 'before' => ':time berê', 'year' => ':count sal', + 'a_year' => ':count sal', + 'y' => ':count sal', 'year_ago' => ':count salê|:count salan', + 'y_ago' => ':count salê|:count salan', 'year_from_now' => 'salekê|:count salan', + 'y_from_now' => 'salekê|:count salan', 'month' => ':count meh', + 'a_month' => ':count meh', + 'm' => ':count meh', 'week' => ':count hefte', + 'a_week' => ':count hefte', + 'w' => ':count hefte', 'day' => ':count roj', + 'a_day' => ':count roj', + 'd' => ':count roj', 'hour' => ':count saet', + 'a_hour' => ':count saet', + 'h' => ':count saet', 'minute' => ':count deqîqe', + 'a_minute' => ':count deqîqe', + 'min' => ':count deqîqe', 'second' => ':count saniye', + 'a_second' => ':count saniye', + 's' => ':count saniye', 'months' => ['rêbendanê', 'reşemiyê', 'adarê', 'avrêlê', 'gulanê', 'pûşperê', 'tîrmehê', 'gelawêjê', 'rezberê', 'kewçêrê', 'sermawezê', 'berfanbarê'], 'months_standalone' => ['rêbendan', 'reşemî', 'adar', 'avrêl', 'gulan', 'pûşper', 'tîrmeh', 'gelawêj', 'rezber', 'kewçêr', 'sermawez', 'berfanbar'], 'months_short' => ['rêb', 'reş', 'ada', 'avr', 'gul', 'pûş', 'tîr', 'gel', 'rez', 'kew', 'ser', 'ber'], @@ -35,6 +51,7 @@ return [ 'weekdays_short' => ['yş', 'dş', 'sş', 'çş', 'pş', 'în', 'ş'], 'weekdays_min' => ['Y', 'D', 'S', 'Ç', 'P', 'Î', 'Ş'], 'list' => [', ', ' û '], + 'ordinal' => ':number', 'first_day_of_week' => 6, 'day_of_first_week_of_year' => 1, -]; +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ky.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ky.php index e0d1af103..2cb850395 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ky.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ky.php @@ -68,7 +68,7 @@ return [ 'lastWeek' => '[Өткен аптанын] dddd [күнү] [саат] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { static $suffixes = [ 0 => '-чү', 1 => '-чи', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lb.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lb.php index 7636655e3..72267b734 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lb.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lb.php @@ -60,15 +60,12 @@ return [ 'nextDay' => '[Muer um] LT', 'nextWeek' => 'dddd [um] LT', 'lastDay' => '[Gëschter um] LT', - 'lastWeek' => function (CarbonInterface $date) { + 'lastWeek' => static function (CarbonInterface $date) { // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule - switch ($date->dayOfWeek) { - case 2: - case 4: - return '[Leschten] dddd [um] LT'; - default: - return '[Leschte] dddd [um] LT'; - } + return match ($date->dayOfWeek) { + 2, 4 => '[Leschten] dddd [um] LT', + default => '[Leschte] dddd [um] LT', + }; }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lkt.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lkt.php index ae73a97b9..a5485fb38 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lkt.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lkt.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'month' => ':count haŋwí', // less reliable 'm' => ':count haŋwí', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lo.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lo.php index 48715f5c5..a5cc0242c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lo.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lo.php @@ -27,7 +27,8 @@ return [ 'h' => ':count ຊມ. ', 'minute' => ':count ນາທີ', 'min' => ':count ນທ. ', - 'second' => '{1}ບໍ່ເທົ່າໃດວິນາທີ|]1,Inf[:count ວິນາທີ', + 'second' => ':count ວິນາທີ', + 'a_second' => '{0,1}ບໍ່ເທົ່າໃດວິນາທີ|[-Inf,Inf]:count ວິນາທີ', 's' => ':count ວິ. ', 'ago' => ':timeຜ່ານມາ', 'from_now' => 'ອີກ :time', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc.php index 546e67916..31cfc844d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'minute' => ':count هنر', // less reliable 'min' => ':count هنر', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc_IQ.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc_IQ.php index d42f5e971..1ae546b04 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc_IQ.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lrc_IQ.php @@ -9,5 +9,4 @@ * file that was distributed with this source code. */ -return array_replace_recursive(require __DIR__.'/lrc.php', [ -]); +return require __DIR__.'/lrc.php'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lt.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lt.php index 7d1b6f743..207b817e0 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lt.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lt.php @@ -121,15 +121,12 @@ return [ 'lastWeek' => '[Paskutinį] dddd LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { - switch ($number) { - case 0: - return '0-is'; - case 3: - return '3-ias'; - default: - return "$number-as"; - } + 'ordinal' => static function ($number) { + return match ($number) { + 0 => '0-is', + 3 => '3-ias', + default => "$number-as", + }; }, 'meridiem' => ['priešpiet', 'popiet'], ]; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luo.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luo.php index b55af7318..5d6ec7c9a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luo.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luo.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['OD', 'OT'], 'weekdays' => ['Jumapil', 'Wuok Tich', 'Tich Ariyo', 'Tich Adek', 'Tich Ang’wen', 'Tich Abich', 'Ngeso'], 'weekdays_short' => ['JMP', 'WUT', 'TAR', 'TAD', 'TAN', 'TAB', 'NGS'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luy.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luy.php index 2b37e3e32..ab92e842a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luy.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/luy.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'weekdays' => ['Jumapiri', 'Jumatatu', 'Jumanne', 'Jumatano', 'Murwa wa Kanne', 'Murwa wa Katano', 'Jumamosi'], 'weekdays_short' => ['J2', 'J3', 'J4', 'J5', 'Al', 'Ij', 'J1'], 'weekdays_min' => ['J2', 'J3', 'J4', 'J5', 'Al', 'Ij', 'J1'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lv.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lv.php index d5cba7ca0..6ff355125 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lv.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lv.php @@ -47,40 +47,34 @@ use Carbon\CarbonInterface; $daysOfWeek = ['svētdiena', 'pirmdiena', 'otrdiena', 'trešdiena', 'ceturtdiena', 'piektdiena', 'sestdiena']; $daysOfWeekLocativum = ['svētdien', 'pirmdien', 'otrdien', 'trešdien', 'ceturtdien', 'piektdien', 'sestdien']; -$transformDiff = function ($input) { - return strtr($input, [ - // Nominative => "pirms/pēc" Dative - 'gads' => 'gada', - 'gadi' => 'gadiem', - 'gadu' => 'gadiem', - 'mēnesis' => 'mēneša', - 'mēneši' => 'mēnešiem', - 'mēnešu' => 'mēnešiem', - 'nedēļa' => 'nedēļas', - 'nedēļas' => 'nedēļām', - 'nedēļu' => 'nedēļām', - 'diena' => 'dienas', - 'dienas' => 'dienām', - 'dienu' => 'dienām', - 'stunda' => 'stundas', - 'stundas' => 'stundām', - 'stundu' => 'stundām', - 'minūte' => 'minūtes', - 'minūtes' => 'minūtēm', - 'minūšu' => 'minūtēm', - 'sekunde' => 'sekundes', - 'sekundes' => 'sekundēm', - 'sekunžu' => 'sekundēm', - ]); -}; +$transformDiff = static fn (string $input) => strtr($input, [ + // Nominative => "pirms/pēc" Dative + 'gads' => 'gada', + 'gadi' => 'gadiem', + 'gadu' => 'gadiem', + 'mēnesis' => 'mēneša', + 'mēneši' => 'mēnešiem', + 'mēnešu' => 'mēnešiem', + 'nedēļa' => 'nedēļas', + 'nedēļas' => 'nedēļām', + 'nedēļu' => 'nedēļām', + 'diena' => 'dienas', + 'dienas' => 'dienām', + 'dienu' => 'dienām', + 'stunda' => 'stundas', + 'stundas' => 'stundām', + 'stundu' => 'stundām', + 'minūte' => 'minūtes', + 'minūtes' => 'minūtēm', + 'minūšu' => 'minūtēm', + 'sekunde' => 'sekundes', + 'sekundes' => 'sekundēm', + 'sekunžu' => 'sekundēm', +]); return [ - 'ago' => function ($time) use ($transformDiff) { - return 'pirms '.$transformDiff($time); - }, - 'from_now' => function ($time) use ($transformDiff) { - return 'pēc '.$transformDiff($time); - }, + 'ago' => static fn (string $time) => 'pirms '.$transformDiff($time), + 'from_now' => static fn (string $time) => 'pēc '.$transformDiff($time), 'year' => '0 gadu|:count gads|:count gadi', 'y' => ':count g.', @@ -159,7 +153,7 @@ return [ 'calendar' => [ 'sameDay' => '[šodien] [plkst.] LT', 'nextDay' => '[rīt] [plkst.] LT', - 'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) use ($daysOfWeekLocativum) { + 'nextWeek' => static function (CarbonInterface $current, CarbonInterface $other) use ($daysOfWeekLocativum) { if ($current->week !== $other->week) { return '[nākošo] ['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT'; } @@ -167,7 +161,7 @@ return [ return '['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT'; }, 'lastDay' => '[vakar] [plkst.] LT', - 'lastWeek' => function (CarbonInterface $current) use ($daysOfWeekLocativum) { + 'lastWeek' => static function (CarbonInterface $current) use ($daysOfWeekLocativum) { return '[pagājušo] ['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT'; }, 'sameElse' => 'L', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lzh_TW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lzh_TW.php index 3b1493eef..771394e83 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lzh_TW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/lzh_TW.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['週日', '週一', '週二', '週三', '週四', '週五', '週六'], 'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'], 'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'alt_numbers' => ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '廿', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '卅', '卅一'], 'meridiem' => ['朝', '暮'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mag_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mag_IN.php index 193f67a7e..879776541 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mag_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mag_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'], 'weekdays_short' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'], 'weekdays_min' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mai_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mai_IN.php index 03049d458..3f9bba779 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mai_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mai_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रविदिन', 'सोमदिन', 'मंगलदिन', 'बुधदिन', 'बृहस्पतीदिन', 'शुक्रदिन', 'शनीदिन'], 'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पती', 'शुक्र', 'शनी'], 'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पती', 'शुक्र', 'शनी'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mas.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mas.php index cbd610c28..ba99156e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mas.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mas.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Ɛnkakɛnyá', 'Ɛndámâ'], 'weekdays' => ['Jumapílí', 'Jumatátu', 'Jumane', 'Jumatánɔ', 'Alaámisi', 'Jumáa', 'Jumamósi'], 'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mer.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mer.php index 2e14597fa..9b4ad3be9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mer.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mer.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['RŨ', 'ŨG'], 'weekdays' => ['Kiumia', 'Muramuko', 'Wairi', 'Wethatu', 'Wena', 'Wetano', 'Jumamosi'], 'weekdays_short' => ['KIU', 'MRA', 'WAI', 'WET', 'WEN', 'WTN', 'JUM'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mfe_MU.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mfe_MU.php index 2d27b4578..ef51ce7dc 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mfe_MU.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mfe_MU.php @@ -14,6 +14,7 @@ * - Samsung Electronics Co., Ltd. akhilesh.k@samsung.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'DD/MM/YY', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mgh.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mgh.php index 2a80960d7..a4b624c46 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mgh.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mgh.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['wichishu', 'mchochil’l'], 'weekdays' => ['Sabato', 'Jumatatu', 'Jumanne', 'Jumatano', 'Arahamisi', 'Ijumaa', 'Jumamosi'], 'weekdays_short' => ['Sab', 'Jtt', 'Jnn', 'Jtn', 'Ara', 'Iju', 'Jmo'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mk.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mk.php index d822de098..38fe6d046 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mk.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mk.php @@ -68,19 +68,13 @@ return [ 'nextDay' => '[Утре во] LT', 'nextWeek' => '[Во] dddd [во] LT', 'lastDay' => '[Вчера во] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - case 3: - case 6: - return '[Изминатата] dddd [во] LT'; - default: - return '[Изминатиот] dddd [во] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0, 3, 6 => '[Изминатата] dddd [во] LT', + default => '[Изминатиот] dddd [во] LT', }, 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { $lastDigit = $number % 10; $last2Digits = $number % 100; if ($number === 0) { diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ml.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ml.php index 1abd6c449..a35f96f50 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ml.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ml.php @@ -50,7 +50,7 @@ return [ 'lastWeek' => '[കഴിഞ്ഞ] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'രാത്രി'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mni_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mni_IN.php index 45d430ef9..4dc577c38 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mni_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mni_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['নোংমাইজিং', 'নিংথৌকাবা', 'লৈবাকপোকপা', 'য়ুমশকৈশা', 'শগোলশেন', 'ইরাই', 'থাংজ'], 'weekdays_short' => ['নোং', 'নিং', 'লৈবাক', 'য়ুম', 'শগোল', 'ইরা', 'থাং'], 'weekdays_min' => ['নোং', 'নিং', 'লৈবাক', 'য়ুম', 'শগোল', 'ইরা', 'থাং'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['এ.ম.', 'প.ম.'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mr.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mr.php index 4aaeafd0c..e57e6f514 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mr.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/mr.php @@ -57,7 +57,7 @@ return [ 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'रात्री'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ms.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ms.php index c9e80854f..fc53ab982 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ms.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ms.php @@ -21,29 +21,29 @@ */ return [ 'year' => ':count tahun', - 'a_year' => '{1}setahun|]1,Inf[:count tahun', + 'a_year' => '{1}setahun|[-Inf,Inf]:count tahun', 'y' => ':count tahun', 'month' => ':count bulan', - 'a_month' => '{1}sebulan|]1,Inf[:count bulan', + 'a_month' => '{1}sebulan|[-Inf,Inf]:count bulan', 'm' => ':count bulan', 'week' => ':count minggu', - 'a_week' => '{1}seminggu|]1,Inf[:count minggu', + 'a_week' => '{1}seminggu|[-Inf,Inf]:count minggu', 'w' => ':count minggu', 'day' => ':count hari', - 'a_day' => '{1}sehari|]1,Inf[:count hari', + 'a_day' => '{1}sehari|[-Inf,Inf]:count hari', 'd' => ':count hari', 'hour' => ':count jam', - 'a_hour' => '{1}sejam|]1,Inf[:count jam', + 'a_hour' => '{1}sejam|[-Inf,Inf]:count jam', 'h' => ':count jam', 'minute' => ':count minit', - 'a_minute' => '{1}seminit|]1,Inf[:count minit', + 'a_minute' => '{1}seminit|[-Inf,Inf]:count minit', 'min' => ':count minit', 'second' => ':count saat', - 'a_second' => '{1}beberapa saat|]1,Inf[:count saat', + 'a_second' => '{1}beberapa saat|[-Inf,Inf]:count saat', 'millisecond' => ':count milisaat', - 'a_millisecond' => '{1}semilisaat|]1,Inf[:count milliseconds', + 'a_millisecond' => '{1}semilisaat|[-Inf,Inf]:count milliseconds', 'microsecond' => ':count mikrodetik', - 'a_microsecond' => '{1}semikrodetik|]1,Inf[:count mikrodetik', + 'a_microsecond' => '{1}semikrodetik|[-Inf,Inf]:count mikrodetik', 's' => ':count saat', 'ago' => ':time yang lepas', 'from_now' => ':time dari sekarang', @@ -74,7 +74,7 @@ return [ 'lastWeek' => 'dddd [lepas pukul] LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 1) { return 'tengah malam'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/my.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/my.php index bbdfba401..fe0b252bd 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/my.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/my.php @@ -16,19 +16,25 @@ * - Nay Lin Aung */ return [ - 'year' => '{1}တစ်နှစ်|]1,Inf[:count နှစ်', + 'year' => ':count နှစ်', + 'a_year' => '{1}တစ်နှစ်|[-Inf,Inf]:count နှစ်', 'y' => ':count နှစ်', - 'month' => '{1}တစ်လ|]1,Inf[:count လ', + 'month' => ':count လ', + 'a_month' => '{1}တစ်လ|[-Inf,Inf]:count လ', 'm' => ':count လ', 'week' => ':count ပတ်', 'w' => ':count ပတ်', - 'day' => '{1}တစ်ရက်|]1,Inf[:count ရက်', + 'day' => ':count ရက်', + 'a_day' => '{1}တစ်ရက်|[-Inf,Inf]:count ရက်', 'd' => ':count ရက်', - 'hour' => '{1}တစ်နာရီ|]1,Inf[:count နာရီ', + 'hour' => ':count နာရီ', + 'a_hour' => '{1}တစ်နာရီ|[-Inf,Inf]:count နာရီ', 'h' => ':count နာရီ', - 'minute' => '{1}တစ်မိနစ်|]1,Inf[:count မိနစ်', + 'minute' => ':count မိနစ်', + 'a_minute' => '{1}တစ်မိနစ်|[-Inf,Inf]:count မိနစ်', 'min' => ':count မိနစ်', - 'second' => '{1}စက္ကန်.အနည်းငယ်|]1,Inf[:count စက္ကန့်', + 'second' => ':count စက္ကန့်', + 'a_second' => '{0,1}စက္ကန်.အနည်းငယ်|[-Inf,Inf]:count စက္ကန့်', 's' => ':count စက္ကန့်', 'ago' => 'လွန်ခဲ့သော :time က', 'from_now' => 'လာမည့် :time မှာ', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW.php index 5c50aa48d..4fc654816 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['禮拜日', '禮拜一', '禮拜二', '禮拜三', '禮拜四', '禮拜五', '禮拜六'], 'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'], 'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['頂晡', '下晡'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW@latin.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW@latin.php index 99ca2a425..5eecc63a8 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW@latin.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nan_TW@latin.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['lé-pài-ji̍t', 'pài-it', 'pài-jī', 'pài-saⁿ', 'pài-sì', 'pài-gō͘', 'pài-la̍k'], 'weekdays_short' => ['lp', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6'], 'weekdays_min' => ['lp', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['téng-po͘', 'ē-po͘'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nd.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nd.php index f75d9a714..d88633c27 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nd.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nd.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'weekdays' => ['Sonto', 'Mvulo', 'Sibili', 'Sithathu', 'Sine', 'Sihlanu', 'Mgqibelo'], 'weekdays_short' => ['Son', 'Mvu', 'Sib', 'Sit', 'Sin', 'Sih', 'Mgq'], 'weekdays_min' => ['Son', 'Mvu', 'Sib', 'Sit', 'Sin', 'Sih', 'Mgq'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ne.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ne.php index d4caf0e25..998d13f66 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ne.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ne.php @@ -55,7 +55,7 @@ return [ 'lastWeek' => '[गएको] dddd[,] LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 3) { return 'राति'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nhn_MX.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nhn_MX.php index 9db88a128..8d06d5092 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nhn_MX.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nhn_MX.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['teoilhuitl', 'ceilhuitl', 'omeilhuitl', 'yeilhuitl', 'nahuilhuitl', 'macuililhuitl', 'chicuaceilhuitl'], 'weekdays_short' => ['teo', 'cei', 'ome', 'yei', 'nau', 'mac', 'chi'], 'weekdays_min' => ['teo', 'cei', 'ome', 'yei', 'nau', 'mac', 'chi'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'month' => ':count metztli', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nl.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nl.php index 2d737703d..ccf192577 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nl.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nl.php @@ -69,7 +69,7 @@ return [ 'diff_after_tomorrow' => 'overmorgen', 'diff_before_yesterday' => 'eergisteren', 'period_recurrences' => ':count keer', - 'period_interval' => function (string $interval = '') { + 'period_interval' => static function (string $interval = '') { /** @var string $output */ $output = preg_replace('/^(een|één|1)\s+/u', '', $interval); @@ -97,7 +97,7 @@ return [ 'lastWeek' => '[afgelopen] dddd [om] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de'); }, 'months' => ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nr_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nr_ZA.php index f9a7be82e..509375982 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nr_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nr_ZA.php @@ -23,4 +23,5 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays_short' => ['Son', 'Mvu', 'Bil', 'Tha', 'Ne', 'Hla', 'Gqi'], 'weekdays_min' => ['Son', 'Mvu', 'Bil', 'Tha', 'Ne', 'Hla', 'Gqi'], 'day_of_first_week_of_year' => 1, + 'first_day_of_week' => 0, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nso_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nso_ZA.php index b08fe6dcd..93da1e78a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nso_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/nso_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['LaMorena', 'Mošupologo', 'Labobedi', 'Laboraro', 'Labone', 'Labohlano', 'Mokibelo'], 'weekdays_short' => ['Son', 'Moš', 'Bed', 'Rar', 'Ne', 'Hla', 'Mok'], 'weekdays_min' => ['Son', 'Moš', 'Bed', 'Rar', 'Ne', 'Hla', 'Mok'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count ngwaga', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/oc.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/oc.php index c9411d69d..858cf77be 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/oc.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/oc.php @@ -12,6 +12,7 @@ /* * Authors: * - Quentí + * - Quentin PAGÈS */ // @codeCoverageIgnoreStart use Symfony\Component\Translation\PluralizationRules; @@ -84,11 +85,11 @@ return [ 'weekdays' => ['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'], 'weekdays_short' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'], 'weekdays_min' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'], - 'ordinal' => function ($number, string $period = '') { + 'ordinal' => static function ($number, string $period = '') { $ordinal = [1 => 'èr', 2 => 'nd'][(int) $number] ?? 'en'; - // feminine for year, week, hour, minute, second - if (preg_match('/^[yYwWhHgGis]$/', $period)) { + // feminine for week, hour, minute, second + if (preg_match('/^[wWhHgGis]$/', $period)) { $ordinal .= 'a'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/om.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/om.php index b8d5a0b01..3c72dc9e5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/om.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/om.php @@ -27,6 +27,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Dilbata', 'Wiixata', 'Qibxata', 'Roobii', 'Kamiisa', 'Jimaata', 'Sanbata'], 'weekdays_short' => ['Dil', 'Wix', 'Qib', 'Rob', 'Kam', 'Jim', 'San'], 'weekdays_min' => ['Dil', 'Wix', 'Qib', 'Rob', 'Kam', 'Jim', 'San'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['WD', 'WB'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa.php index 48b203316..23c2f9e4c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa.php @@ -47,7 +47,7 @@ return [ 'lastWeek' => '[ਪਿਛਲੇ] dddd, LT', 'sameElse' => 'L', ], - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'ਰਾਤ'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa_PK.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa_PK.php index f9af11c60..494a87767 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa_PK.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pa_PK.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'], 'weekdays_short' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'], 'weekdays_min' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ص', 'ش'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pl.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pl.php index b72053549..35381f33a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pl.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pl.php @@ -82,32 +82,19 @@ return [ 'calendar' => [ 'sameDay' => '[Dziś o] LT', 'nextDay' => '[Jutro o] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[W niedzielę o] LT'; - case 2: - return '[We wtorek o] LT'; - case 3: - return '[W środę o] LT'; - case 6: - return '[W sobotę o] LT'; - default: - return '[W] dddd [o] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[W niedzielę o] LT', + 2 => '[We wtorek o] LT', + 3 => '[W środę o] LT', + 6 => '[W sobotę o] LT', + default => '[W] dddd [o] LT', }, 'lastDay' => '[Wczoraj o] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[W zeszłą niedzielę o] LT'; - case 3: - return '[W zeszłą środę o] LT'; - case 6: - return '[W zeszłą sobotę o] LT'; - default: - return '[W zeszły] dddd [o] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[W zeszłą niedzielę o] LT', + 3 => '[W zeszłą środę o] LT', + 6 => '[W zeszłą sobotę o] LT', + default => '[W zeszły] dddd [o] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pt.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pt.php index bb6359b14..85dbddccd 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pt.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/pt.php @@ -84,14 +84,9 @@ return [ 'nextDay' => '[Amanhã às] LT', 'nextWeek' => 'dddd [às] LT', 'lastDay' => '[Ontem às] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - case 6: - return '[Último] dddd [às] LT'; - default: - return '[Última] dddd [às] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0, 6 => '[Último] dddd [às] LT', + default => '[Última] dddd [às] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/quz_PE.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/quz_PE.php index d32291893..b047e5970 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/quz_PE.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/quz_PE.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['tuminku', 'lunis', 'martis', 'miyirkulis', 'juywis', 'wiyirnis', 'sawatu'], 'weekdays_short' => ['tum', 'lun', 'mar', 'miy', 'juy', 'wiy', 'saw'], 'weekdays_min' => ['tum', 'lun', 'mar', 'miy', 'juy', 'wiy', 'saw'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'minute' => ':count uchuy', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/raj_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/raj_IN.php index 7b4589cd3..4a9f0b9d3 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/raj_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/raj_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रविवार', 'सोमवार', 'मंगल्लवार', 'बुधवार', 'बृहस्पतिवार', 'शुक्रवार', 'शनिवार'], 'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'], 'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ru.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ru.php index 673b043b2..fe9607f46 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ru.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ru.php @@ -34,17 +34,16 @@ * - AlexWalkerson * - Vladislav UnsealedOne * - dima-bzz + * - Sergey Danilchenko */ use Carbon\CarbonInterface; -$transformDiff = function ($input) { - return strtr($input, [ - 'неделя' => 'неделю', - 'секунда' => 'секунду', - 'минута' => 'минуту', - ]); -}; +$transformDiff = static fn (string $input) => strtr($input, [ + 'неделя' => 'неделю', + 'секунда' => 'секунду', + 'минута' => 'минуту', +]); return [ 'year' => ':count год|:count года|:count лет', @@ -68,18 +67,15 @@ return [ 'second' => ':count секунда|:count секунды|:count секунд', 's' => ':count сек.', 'a_second' => '{1}несколько секунд|:count секунду|:count секунды|:count секунд', - 'ago' => function ($time) use ($transformDiff) { - return $transformDiff($time).' назад'; - }, - 'from_now' => function ($time) use ($transformDiff) { - return 'через '.$transformDiff($time); - }, - 'after' => function ($time) use ($transformDiff) { - return $transformDiff($time).' после'; - }, - 'before' => function ($time) use ($transformDiff) { - return $transformDiff($time).' до'; - }, + 'millisecond' => '{1}:count миллисекунда|:count миллисекунды|:count миллисекунд', + 'a_millisecond' => '{1}миллисекунда|:count миллисекунда|:count миллисекунды|:count миллисекунд', + 'ms' => ':count мс', + 'microsecond' => '{1}:count микросекунда|:count микросекунды|:count микросекунд', + 'a_microsecond' => '{1}микросекунда|:count микросекунда|:count микросекунды|:count микросекунд', + 'ago' => static fn (string $time) => $transformDiff($time).' назад', + 'from_now' => static fn (string $time) => 'через '.$transformDiff($time), + 'after' => static fn (string $time) => $transformDiff($time).' после', + 'before' => static fn (string $time) => $transformDiff($time).' до', 'diff_now' => 'только что', 'diff_today' => 'Сегодня,', 'diff_today_regexp' => 'Сегодня,?(?:\\s+в)?', @@ -100,7 +96,7 @@ return [ 'calendar' => [ 'sameDay' => '[Сегодня, в] LT', 'nextDay' => '[Завтра, в] LT', - 'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) { + 'nextWeek' => static function (CarbonInterface $current, \Carbon\CarbonInterface $other) { if ($current->week !== $other->week) { switch ($current->dayOfWeek) { case 0: @@ -123,7 +119,7 @@ return [ return '[В] dddd, [в] LT'; }, 'lastDay' => '[Вчера, в] LT', - 'lastWeek' => function (CarbonInterface $current, CarbonInterface $other) { + 'lastWeek' => static function (CarbonInterface $current, \Carbon\CarbonInterface $other) { if ($current->week !== $other->week) { switch ($current->dayOfWeek) { case 0: @@ -147,22 +143,15 @@ return [ }, 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'M': - case 'd': - case 'DDD': - return $number.'-й'; - case 'D': - return $number.'-го'; - case 'w': - case 'W': - return $number.'-я'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'M', 'd', 'DDD' => $number.'-й', + 'D' => $number.'-го', + 'w', 'W' => $number.'-я', + default => $number, + }; }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'ночи'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sa_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sa_IN.php index cfda9a636..f2489e8de 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sa_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sa_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['रविवासर:', 'सोमवासर:', 'मंगलवासर:', 'बुधवासर:', 'बृहस्पतिवासरः', 'शुक्रवासर', 'शनिवासर:'], 'weekdays_short' => ['रविः', 'सोम:', 'मंगल:', 'बुध:', 'बृहस्पतिः', 'शुक्र', 'शनि:'], 'weekdays_min' => ['रविः', 'सोम:', 'मंगल:', 'बुध:', 'बृहस्पतिः', 'शुक्र', 'शनि:'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/saq.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/saq.php index ff8bf6044..ca3f994d4 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/saq.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/saq.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['Tesiran', 'Teipa'], 'weekdays' => ['Mderot ee are', 'Mderot ee kuni', 'Mderot ee ong’wan', 'Mderot ee inet', 'Mderot ee ile', 'Mderot ee sapa', 'Mderot ee kwe'], 'weekdays_short' => ['Are', 'Kun', 'Ong', 'Ine', 'Ile', 'Sap', 'Kwe'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sat_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sat_IN.php index 632b1af6b..6c3608b2d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sat_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sat_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['सिंगेमाँहाँ', 'ओतेमाँहाँ', 'बालेमाँहाँ', 'सागुनमाँहाँ', 'सारदीमाँहाँ', 'जारुममाँहाँ', 'ञुहुममाँहाँ'], 'weekdays_short' => ['सिंगे', 'ओते', 'बाले', 'सागुन', 'सारदी', 'जारुम', 'ञुहुम'], 'weekdays_min' => ['सिंगे', 'ओते', 'बाले', 'सागुन', 'सारदी', 'जारुम', 'ञुहुम'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'month' => ':count ńindạ cando', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sd.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sd.php index 0022c5a9c..d91e4d852 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sd.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sd.php @@ -38,16 +38,22 @@ $weekdays = [ * Authors: * - Narain Sagar * - Sawood Alam - * - Narain Sagar */ return [ - 'year' => '{1}'.'هڪ سال'.'|:count '.'سال', - 'month' => '{1}'.'هڪ مهينو'.'|:count '.'مهينا', - 'week' => '{1}'.'ھڪ ھفتو'.'|:count '.'هفتا', - 'day' => '{1}'.'هڪ ڏينهن'.'|:count '.'ڏينهن', - 'hour' => '{1}'.'هڪ ڪلاڪ'.'|:count '.'ڪلاڪ', - 'minute' => '{1}'.'هڪ منٽ'.'|:count '.'منٽ', - 'second' => '{1}'.'چند سيڪنڊ'.'|:count '.'سيڪنڊ', + 'year' => ':count '.'سال', + 'a_year' => '{1}'.'هڪ سال'.'|:count '.'سال', + 'month' => ':count '.'مهينا', + 'a_month' => '{1}'.'هڪ مهينو'.'|:count '.'مهينا', + 'week' => ':count '.'هفتا', + 'a_week' => '{1}'.'ھڪ ھفتو'.'|:count '.'هفتا', + 'day' => ':count '.'ڏينهن', + 'a_day' => '{1}'.'هڪ ڏينهن'.'|:count '.'ڏينهن', + 'hour' => ':count '.'ڪلاڪ', + 'a_hour' => '{1}'.'هڪ ڪلاڪ'.'|:count '.'ڪلاڪ', + 'minute' => ':count '.'منٽ', + 'a_minute' => '{1}'.'هڪ منٽ'.'|:count '.'منٽ', + 'second' => ':count '.'سيڪنڊ', + 'a_second' => '{1}'.'چند سيڪنڊ'.'|:count '.'سيڪنڊ', 'ago' => ':time اڳ', 'from_now' => ':time پوء', 'diff_yesterday' => 'ڪالهه', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/seh.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/seh.php index babf9afb0..31b5aadea 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/seh.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/seh.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'weekdays' => ['Dimingu', 'Chiposi', 'Chipiri', 'Chitatu', 'Chinai', 'Chishanu', 'Sabudu'], 'weekdays_short' => ['Dim', 'Pos', 'Pir', 'Tat', 'Nai', 'Sha', 'Sab'], 'weekdays_min' => ['Dim', 'Pos', 'Pir', 'Tat', 'Nai', 'Sha', 'Sab'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sh.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sh.php index e03b50675..d65f90ec2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sh.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sh.php @@ -9,16 +9,6 @@ * file that was distributed with this source code. */ -// @codeCoverageIgnoreStart -use Symfony\Component\Translation\PluralizationRules; - -if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) { - PluralizationRules::set(static function ($number) { - return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - }, 'sh'); -} -// @codeCoverageIgnoreEnd - /* * Authors: * - Томица Кораћ diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shn_MM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shn_MM.php index f399acf0d..9eeba47fe 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shn_MM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shn_MM.php @@ -14,6 +14,7 @@ * - ubuntu Myanmar LoCo Team https://ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'OY MMM OD dddd', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shs_CA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shs_CA.php index 08d385e66..f41c34df6 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shs_CA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/shs_CA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sxetspesq̓t', 'Spetkesq̓t', 'Selesq̓t', 'Skellesq̓t', 'Smesesq̓t', 'Stselkstesq̓t', 'Stqmekstesq̓t'], 'weekdays_short' => ['Sxe', 'Spe', 'Sel', 'Ske', 'Sme', 'Sts', 'Stq'], 'weekdays_min' => ['Sxe', 'Spe', 'Sel', 'Ske', 'Sme', 'Sts', 'Stq'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count sqlélten', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/si.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/si.php index 636bf6914..7d14ca6c9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/si.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/si.php @@ -32,16 +32,16 @@ return [ 'second' => '{1}තත්පර 1|තත්පර :count', 'a_second' => '{1}තත්පර කිහිපයකට|තත්පර :count', 'ago' => ':time කට පෙර', - 'from_now' => function ($time) { - if (preg_match('/දින \d/u', $time)) { + 'from_now' => static function ($time) { + if (preg_match('/දින \d+/u', $time)) { return $time.' න්'; } return $time.' කින්'; }, 'before' => ':time කට පෙර', - 'after' => function ($time) { - if (preg_match('/දින \d/u', $time)) { + 'after' => static function ($time) { + if (preg_match('/දින \d+/u', $time)) { return $time.' න්'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sid_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sid_ET.php index 1296f9be7..5e9632d19 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sid_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sid_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sambata', 'Sanyo', 'Maakisanyo', 'Roowe', 'Hamuse', 'Arbe', 'Qidaame'], 'weekdays_short' => ['Sam', 'San', 'Mak', 'Row', 'Ham', 'Arb', 'Qid'], 'weekdays_min' => ['Sam', 'San', 'Mak', 'Row', 'Ham', 'Arb', 'Qid'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['soodo', 'hawwaro'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sk.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sk.php index f9702e960..051e93564 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sk.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sk.php @@ -32,6 +32,7 @@ * - Jakub ADAMEC * - Marek Adamický * - AlterwebStudio + * - Peter Kundis */ use Carbon\CarbonInterface; @@ -56,13 +57,15 @@ $ago = function ($time) { ]; $replacementsPlural = [ - '/\bhodiny\b/' => 'hodinami', - '/\bminúty\b/' => 'minútami', - '/\bsekundy\b/' => 'sekundami', + '/\b(?:hodiny|hodín)\b/' => 'hodinami', + '/\b(?:minúty|minút)\b/' => 'minútami', + '/\b(?:sekundy|sekúnd)\b/' => 'sekundami', + '/\bdeň\b/' => 'dňom', '/\bdni\b/' => 'dňami', - '/\btýždne\b/' => 'týždňami', - '/\bmesiace\b/' => 'mesiacmi', - '/\broky\b/' => 'rokmi', + '/\bdní\b/u' => 'dňami', + '/\b(?:týždne|týždňov)\b/' => 'týždňami', + '/\b(?:mesiace|mesiacov)\b/' => 'mesiacmi', + '/\b(?:roky|rokov)\b/' => 'rokmi', ]; foreach ($replacements + $replacementsPlural as $pattern => $replacement) { @@ -149,7 +152,9 @@ return [ 'weekdays' => ['nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota'], 'weekdays_short' => ['ned', 'pon', 'uto', 'str', 'štv', 'pia', 'sob'], 'weekdays_min' => ['ne', 'po', 'ut', 'st', 'št', 'pi', 'so'], - 'months' => ['január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'], + 'months' => ['januára', 'februára', 'marca', 'apríla', 'mája', 'júna', 'júla', 'augusta', 'septembra', 'októbra', 'novembra', 'decembra'], + 'months_standalone' => ['január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'], 'months_short' => ['jan', 'feb', 'mar', 'apr', 'máj', 'jún', 'júl', 'aug', 'sep', 'okt', 'nov', 'dec'], + 'months_regexp' => '/(DD?o?\.?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/', 'meridiem' => ['dopoludnia', 'popoludní'], ]; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sl.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sl.php index 1f1d1b338..012742e10 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sl.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sl.php @@ -99,7 +99,7 @@ return [ 'nextDay' => '[jutri ob] LT', 'nextWeek' => 'dddd [ob] LT', 'lastDay' => '[včeraj ob] LT', - 'lastWeek' => function (CarbonInterface $date) { + 'lastWeek' => static function (CarbonInterface $date) { switch ($date->dayOfWeek) { case 0: return '[preteklo] [nedeljo] [ob] LT'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sm_WS.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sm_WS.php index f06606871..1568af6ed 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sm_WS.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sm_WS.php @@ -14,6 +14,7 @@ * - Samsung Electronics Co., Ltd. akhilesh.k@samsung.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'DD/MM/YYYY', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sn.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sn.php index 4f25028a3..095936fc7 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sn.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sn.php @@ -10,6 +10,7 @@ */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'meridiem' => ['a', 'p'], 'weekdays' => ['Svondo', 'Muvhuro', 'Chipiri', 'Chitatu', 'China', 'Chishanu', 'Mugovera'], 'weekdays_short' => ['Svo', 'Muv', 'Chp', 'Cht', 'Chn', 'Chs', 'Mug'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/so.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/so.php index 578527197..78e487cc5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/so.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/so.php @@ -13,10 +13,10 @@ * Author: * - Abdifatah Abdilahi(@abdifatahz) */ -return [ +return array_replace_recursive(require __DIR__.'/en.php', [ 'year' => ':count sanad|:count sanadood', 'a_year' => 'sanad|:count sanadood', - 'y' => '{1}:countsn|{0}:countsns|]1,Inf[:countsn', + 'y' => '{1}:countsn|{0}:countsns|[-Inf,Inf]:countsn', 'month' => ':count bil|:count bilood', 'a_month' => 'bil|:count bilood', 'm' => ':countbil', @@ -71,4 +71,4 @@ return [ 'lastWeek' => '[Hore] dddd [Markay ahayd] LT', 'sameElse' => 'L', ], -]; +]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr.php index 68ba663aa..f1908a22f 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr.php @@ -26,7 +26,7 @@ return [ 'year' => ':count godina|:count godine|:count godina', 'y' => ':count g.', 'month' => ':count mesec|:count meseca|:count meseci', - 'm' => ':count mj.', + 'm' => ':count mes.', 'week' => ':count nedelja|:count nedelje|:count nedelja', 'w' => ':count ned.', 'day' => ':count dan|:count dana|:count dana', @@ -37,15 +37,16 @@ return [ 'min' => ':count min.', 'second' => ':count sekundu|:count sekunde|:count sekundi', 's' => ':count sek.', + 'ago' => 'pre :time', 'from_now' => 'za :time', 'after' => 'nakon :time', 'before' => 'pre :time', - 'year_from_now' => ':count godinu|:count godine|:count godina', 'year_ago' => ':count godinu|:count godine|:count godina', - 'week_from_now' => ':count nedelju|:count nedelje|:count nedelja', + 'year_from_now' => ':count godinu|:count godine|:count godina', 'week_ago' => ':count nedelju|:count nedelje|:count nedelja', + 'week_from_now' => ':count nedelju|:count nedelje|:count nedelja', 'diff_now' => 'upravo sada', 'diff_today' => 'danas', @@ -67,36 +68,21 @@ return [ 'calendar' => [ 'sameDay' => '[danas u] LT', 'nextDay' => '[sutra u] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[u nedelju u] LT'; - case 3: - return '[u sredu u] LT'; - case 6: - return '[u subotu u] LT'; - default: - return '[u] dddd [u] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[u nedelju u] LT', + 3 => '[u sredu u] LT', + 6 => '[u subotu u] LT', + default => '[u] dddd [u] LT', }, 'lastDay' => '[juče u] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[prošle nedelje u] LT'; - case 1: - return '[prošlog ponedeljka u] LT'; - case 2: - return '[prošlog utorka u] LT'; - case 3: - return '[prošle srede u] LT'; - case 4: - return '[prošlog četvrtka u] LT'; - case 5: - return '[prošlog petka u] LT'; - default: - return '[prošle subote u] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[prošle nedelje u] LT', + 1 => '[prošlog ponedeljka u] LT', + 2 => '[prošlog utorka u] LT', + 3 => '[prošle srede u] LT', + 4 => '[prošlog četvrtka u] LT', + 5 => '[prošlog petka u] LT', + default => '[prošle subote u] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php index 8becbc576..fe42d5abc 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php @@ -66,36 +66,21 @@ return [ 'calendar' => [ 'sameDay' => '[данас у] LT', 'nextDay' => '[сутра у] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[у недељу у] LT'; - case 3: - return '[у среду у] LT'; - case 6: - return '[у суботу у] LT'; - default: - return '[у] dddd [у] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[у недељу у] LT', + 3 => '[у среду у] LT', + 6 => '[у суботу у] LT', + default => '[у] dddd [у] LT', }, 'lastDay' => '[јуче у] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[прошле недеље у] LT'; - case 1: - return '[прошлог понедељка у] LT'; - case 2: - return '[прошлог уторка у] LT'; - case 3: - return '[прошле среде у] LT'; - case 4: - return '[прошлог четвртка у] LT'; - case 5: - return '[прошлог петка у] LT'; - default: - return '[прошле суботе у] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[прошле недеље у] LT', + 1 => '[прошлог понедељка у] LT', + 2 => '[прошлог уторка у] LT', + 3 => '[прошле среде у] LT', + 4 => '[прошлог четвртка у] LT', + 5 => '[прошлог петка у] LT', + default => '[прошле суботе у] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php index 28d22fd2c..e34f732a1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php @@ -72,36 +72,21 @@ return [ 'calendar' => [ 'sameDay' => '[данас у] LT', 'nextDay' => '[сутра у] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[у недељу у] LT'; - case 3: - return '[у среду у] LT'; - case 6: - return '[у суботу у] LT'; - default: - return '[у] dddd [у] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[у недељу у] LT', + 3 => '[у среду у] LT', + 6 => '[у суботу у] LT', + default => '[у] dddd [у] LT', }, 'lastDay' => '[јуче у] LT', - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[прошле недеље у] LT'; - case 1: - return '[прошлог понедељка у] LT'; - case 2: - return '[прошлог уторка у] LT'; - case 3: - return '[прошле среде у] LT'; - case 4: - return '[прошлог четвртка у] LT'; - case 5: - return '[прошлог петка у] LT'; - default: - return '[прошле суботе у] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[прошле недеље у] LT', + 1 => '[прошлог понедељка у] LT', + 2 => '[прошлог уторка у] LT', + 3 => '[прошле среде у] LT', + 4 => '[прошлог четвртка у] LT', + 5 => '[прошлог петка у] LT', + default => '[прошле суботе у] LT', }, 'sameElse' => 'L', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php index 5b8f2d062..811508018 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php @@ -40,35 +40,20 @@ return array_replace_recursive(require __DIR__.'/sr.php', [ 'diff_tomorrow' => 'sjutra', 'calendar' => [ 'nextDay' => '[sjutra u] LT', - 'nextWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[u nedjelju u] LT'; - case 3: - return '[u srijedu u] LT'; - case 6: - return '[u subotu u] LT'; - default: - return '[u] dddd [u] LT'; - } + 'nextWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[u nedjelju u] LT', + 3 => '[u srijedu u] LT', + 6 => '[u subotu u] LT', + default => '[u] dddd [u] LT', }, - 'lastWeek' => function (CarbonInterface $date) { - switch ($date->dayOfWeek) { - case 0: - return '[prošle nedjelje u] LT'; - case 1: - return '[prošle nedjelje u] LT'; - case 2: - return '[prošlog utorka u] LT'; - case 3: - return '[prošle srijede u] LT'; - case 4: - return '[prošlog četvrtka u] LT'; - case 5: - return '[prošlog petka u] LT'; - default: - return '[prošle subote u] LT'; - } + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0 => '[prošle nedjelje u] LT', + 1 => '[prošle nedjelje u] LT', + 2 => '[prošlog utorka u] LT', + 3 => '[prošle srijede u] LT', + 4 => '[prošlog četvrtka u] LT', + 5 => '[prošlog petka u] LT', + default => '[prošle subote u] LT', }, ], 'weekdays' => ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ss.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ss.php index 1c52c9bf6..0ec3e8f99 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ss.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ss.php @@ -46,7 +46,7 @@ return [ 'lastWeek' => 'dddd [leliphelile] [nga] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { $lastDigit = $number % 10; return $number.( @@ -55,7 +55,7 @@ return [ ) ); }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 11) { return 'ekuseni'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/st_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/st_ZA.php index 5bce7f20f..5eee2224c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/st_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/st_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sontaha', 'Mantaha', 'Labobedi', 'Laboraro', 'Labone', 'Labohlano', 'Moqebelo'], 'weekdays_short' => ['Son', 'Mma', 'Bed', 'Rar', 'Ne', 'Hla', 'Moq'], 'weekdays_min' => ['Son', 'Mma', 'Bed', 'Rar', 'Ne', 'Hla', 'Moq'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'week' => ':count Sontaha', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sv.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sv.php index 1706c7191..d7e0ddf28 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sv.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/sv.php @@ -66,7 +66,7 @@ return [ 'lastWeek' => '[I] dddd[s] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { $lastDigit = $number % 10; return $number.( diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ta.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ta.php index c1d89cbb3..c5dd68e79 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ta.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ta.php @@ -63,7 +63,7 @@ return [ 'sameElse' => 'L', ], 'ordinal' => ':numberவது', - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 2) { return ' யாமம்'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tcy_IN.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tcy_IN.php index 2ff20e0e6..f2bbf1037 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tcy_IN.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tcy_IN.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ಐಥಾರ', 'ಸೋಮಾರ', 'ಅಂಗರೆ', 'ಬುಧಾರ', 'ಗುರುವಾರ', 'ಶುಕ್ರರ', 'ಶನಿವಾರ'], 'weekdays_short' => ['ಐ', 'ಸೋ', 'ಅಂ', 'ಬು', 'ಗು', 'ಶು', 'ಶ'], 'weekdays_min' => ['ಐ', 'ಸೋ', 'ಅಂ', 'ಬು', 'ಗು', 'ಶು', 'ಶ'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ಕಾಂಡೆ', 'ಬಯ್ಯ'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/te.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/te.php index ac38218f3..52d4809e9 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/te.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/te.php @@ -61,7 +61,7 @@ return [ 'sameElse' => 'L', ], 'ordinal' => ':numberవ', - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'రాత్రి'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tg.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tg.php index b7df893c1..57b451352 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tg.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tg.php @@ -45,7 +45,7 @@ return [ 'lastWeek' => 'dddd[и] [ҳафтаи гузашта соати] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number) { + 'ordinal' => static function ($number) { if ($number === 0) { // special case for zero return "$number-ıncı"; } @@ -77,7 +77,7 @@ return [ return $number.($suffixes[$number] ?? $suffixes[$number % 10] ?? $suffixes[$number >= 100 ? 100 : -1] ?? ''); }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'шаб'; } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/th.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/th.php index 6397f6e46..78980d5c2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/th.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/th.php @@ -34,7 +34,7 @@ return [ 'minute' => ':count นาที', 'min' => ':count นาที', 'second' => ':count วินาที', - 'a_second' => '{1}ไม่กี่วินาที|]1,Inf[:count วินาที', + 'a_second' => '{1}ไม่กี่วินาที|[-Inf,Inf]:count วินาที', 's' => ':count วินาที', 'ago' => ':timeที่แล้ว', 'from_now' => 'อีก :time', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/the_NP.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/the_NP.php index 34da16278..cdb02b2ca 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/the_NP.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/the_NP.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['आइतबार', 'सोमबार', 'मंगलबार', 'बुधबार', 'बिहिबार', 'शुक्रबार', 'शनिबार'], 'weekdays_short' => ['आइत', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि'], 'weekdays_min' => ['आइत', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['पूर्वाह्न', 'अपराह्न'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ti_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ti_ET.php index 024217f2f..a8160698a 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ti_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ti_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ሰንበት', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'], 'weekdays_short' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'], 'weekdays_min' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ንጉሆ ሰዓተ', 'ድሕር ሰዓት'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tk_TM.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tk_TM.php index f949a4300..b1c487a07 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tk_TM.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tk_TM.php @@ -15,12 +15,10 @@ * - SuperManPHP * - Maksat Meredow (isadma) */ -$transformDiff = function ($input) { - return strtr($input, [ - 'sekunt' => 'sekunt', - 'hepde' => 'hepde', - ]); -}; +$transformDiff = static fn (string $input) => strtr($input, [ + 'sekunt' => 'sekunt', + 'hepde' => 'hepde', +]); return array_replace_recursive(require __DIR__.'/en.php', [ 'formats' => [ @@ -28,9 +26,9 @@ return array_replace_recursive(require __DIR__.'/en.php', [ ], 'months' => ['Ýanwar', 'Fewral', 'Mart', 'Aprel', 'Maý', 'Iýun', 'Iýul', 'Awgust', 'Sentýabr', 'Oktýabr', 'Noýabr', 'Dekabr'], 'months_short' => ['Ýan', 'Few', 'Mar', 'Apr', 'Maý', 'Iýn', 'Iýl', 'Awg', 'Sen', 'Okt', 'Noý', 'Dek'], - 'weekdays' => ['Duşenbe', 'Sişenbe', 'Çarşenbe', 'Penşenbe', 'Anna', 'Şenbe', 'Ýekşenbe'], - 'weekdays_short' => ['Duş', 'Siş', 'Çar', 'Pen', 'Ann', 'Şen', 'Ýek'], - 'weekdays_min' => ['Du', 'Si', 'Ça', 'Pe', 'An', 'Şe', 'Ýe'], + 'weekdays' => ['Ýekşenbe', 'Duşenbe', 'Sişenbe', 'Çarşenbe', 'Penşenbe', 'Anna', 'Şenbe'], + 'weekdays_short' => ['Ýek', 'Duş', 'Siş', 'Çar', 'Pen', 'Ann', 'Şen'], + 'weekdays_min' => ['Ýe', 'Du', 'Si', 'Ça', 'Pe', 'An', 'Şe'], 'first_day_of_week' => 1, 'day_of_first_week_of_year' => 1, @@ -62,16 +60,8 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 's' => ':count sekunt', 'a_second' => ':count sekunt', - 'ago' => function ($time) use ($transformDiff) { - return $transformDiff($time).' ozal'; - }, - 'from_now' => function ($time) use ($transformDiff) { - return $transformDiff($time).' soňra'; - }, - 'after' => function ($time) use ($transformDiff) { - return $transformDiff($time).' soň'; - }, - 'before' => function ($time) use ($transformDiff) { - return $transformDiff($time).' öň'; - }, + 'ago' => static fn (string $time) => $transformDiff($time).' ozal', + 'from_now' => static fn (string $time) => $transformDiff($time).' soňra', + 'after' => static fn (string $time) => $transformDiff($time).' soň', + 'before' => static fn (string $time) => $transformDiff($time).' öň', ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tlh.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tlh.php index fbf9e6f72..4ecf2446c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tlh.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tlh.php @@ -23,7 +23,7 @@ return [ 'hour' => '{1}wa’ rep|:count rep', 'minute' => '{1}wa’ tup|:count tup', 'second' => '{1}puS lup|:count lup', - 'ago' => function ($time) { + 'ago' => static function ($time) { $output = strtr($time, [ 'jaj' => 'Hu’', 'jar' => 'wen', @@ -32,7 +32,7 @@ return [ return $output === $time ? "$time ret" : $output; }, - 'from_now' => function ($time) { + 'from_now' => static function ($time) { $output = strtr($time, [ 'jaj' => 'leS', 'jar' => 'waQ', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tn_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tn_ZA.php index aada7db58..e3df8f68e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tn_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tn_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['laTshipi', 'Mosupologo', 'Labobedi', 'Laboraro', 'Labone', 'Labotlhano', 'Lamatlhatso'], 'weekdays_short' => ['Tsh', 'Mos', 'Bed', 'Rar', 'Ne', 'Tlh', 'Mat'], 'weekdays_min' => ['Tsh', 'Mos', 'Bed', 'Rar', 'Ne', 'Tlh', 'Mat'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => 'dingwaga di le :count', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/to_TO.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/to_TO.php index 335c69a85..ce713edba 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/to_TO.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/to_TO.php @@ -14,6 +14,7 @@ * - International Components for Unicode akhilesh.k@samsung.com */ return array_replace_recursive(require __DIR__.'/en.php', [ + 'first_day_of_week' => 0, 'formats' => [ 'L' => 'dddd DD MMM YYYY', ], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tpi_PG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tpi_PG.php index 5f58c44c0..721b625b5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tpi_PG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tpi_PG.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sande', 'Mande', 'Tunde', 'Trinde', 'Fonde', 'Fraide', 'Sarere'], 'weekdays_short' => ['San', 'Man', 'Tun', 'Tri', 'Fon', 'Fra', 'Sar'], 'weekdays_min' => ['San', 'Man', 'Tun', 'Tri', 'Fon', 'Fra', 'Sar'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['biknait', 'apinun'], diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tr.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tr.php index f5d9f4cc5..0cb3aade4 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tr.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/tr.php @@ -23,25 +23,25 @@ */ return [ 'year' => ':count yıl', - 'a_year' => '{1}bir yıl|]1,Inf[:count yıl', + 'a_year' => '{1}bir yıl|[-Inf,Inf]:count yıl', 'y' => ':county', 'month' => ':count ay', - 'a_month' => '{1}bir ay|]1,Inf[:count ay', + 'a_month' => '{1}bir ay|[-Inf,Inf]:count ay', 'm' => ':countay', 'week' => ':count hafta', - 'a_week' => '{1}bir hafta|]1,Inf[:count hafta', + 'a_week' => '{1}bir hafta|[-Inf,Inf]:count hafta', 'w' => ':counth', 'day' => ':count gün', - 'a_day' => '{1}bir gün|]1,Inf[:count gün', + 'a_day' => '{1}bir gün|[-Inf,Inf]:count gün', 'd' => ':countg', 'hour' => ':count saat', - 'a_hour' => '{1}bir saat|]1,Inf[:count saat', + 'a_hour' => '{1}bir saat|[-Inf,Inf]:count saat', 'h' => ':countsa', 'minute' => ':count dakika', - 'a_minute' => '{1}bir dakika|]1,Inf[:count dakika', + 'a_minute' => '{1}bir dakika|[-Inf,Inf]:count dakika', 'min' => ':countdk', 'second' => ':count saniye', - 'a_second' => '{1}birkaç saniye|]1,Inf[:count saniye', + 'a_second' => '{1}birkaç saniye|[-Inf,Inf]:count saniye', 's' => ':countsn', 'ago' => ':time önce', 'from_now' => ':time sonra', @@ -71,7 +71,7 @@ return [ 'lastWeek' => '[geçen] dddd [saat] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { + 'ordinal' => static function ($number, $period) { switch ($period) { case 'd': case 'D': diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ts_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ts_ZA.php index 37a24ec49..327134551 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ts_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ts_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Sonto', 'Musumbhunuku', 'Ravumbirhi', 'Ravunharhu', 'Ravumune', 'Ravuntlhanu', 'Mugqivela'], 'weekdays_short' => ['Son', 'Mus', 'Bir', 'Har', 'Ne', 'Tlh', 'Mug'], 'weekdays_min' => ['Son', 'Mus', 'Bir', 'Har', 'Ne', 'Tlh', 'Mug'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => 'malembe ya :count', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ug.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ug.php index 259b99a48..12c9f8a67 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ug.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ug.php @@ -46,20 +46,14 @@ return [ 'lastWeek' => '[ئالدىنقى] dddd [سائەت] LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'd': - case 'D': - case 'DDD': - return $number.'-كۈنى'; - case 'w': - case 'W': - return $number.'-ھەپتە'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'd', 'D', 'DDD' => $number.'-كۈنى', + 'w', 'W' => $number.'-ھەپتە', + default => $number, + }; }, - 'meridiem' => function ($hour, $minute) { + 'meridiem' => static function ($hour, $minute) { $time = $hour * 100 + $minute; if ($time < 600) { return 'يېرىم كېچە'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/uk.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/uk.php index 4217d16ed..3bedd2ea2 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/uk.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/uk.php @@ -11,7 +11,7 @@ use Carbon\CarbonInterface; -$processHoursFunction = function (CarbonInterface $date, string $format) { +$processHoursFunction = static function (CarbonInterface $date, string $format) { return $format.'о'.($date->hour === 11 ? 'б' : '').'] LT'; }; @@ -130,52 +130,30 @@ return [ 'LLLL' => 'dddd, D MMMM YYYY, HH:mm', ], 'calendar' => [ - 'sameDay' => function (CarbonInterface $date) use ($processHoursFunction) { - return $processHoursFunction($date, '[Сьогодні '); - }, - 'nextDay' => function (CarbonInterface $date) use ($processHoursFunction) { - return $processHoursFunction($date, '[Завтра '); - }, - 'nextWeek' => function (CarbonInterface $date) use ($processHoursFunction) { - return $processHoursFunction($date, '[У] dddd ['); - }, - 'lastDay' => function (CarbonInterface $date) use ($processHoursFunction) { - return $processHoursFunction($date, '[Вчора '); - }, - 'lastWeek' => function (CarbonInterface $date) use ($processHoursFunction) { - switch ($date->dayOfWeek) { - case 0: - case 3: - case 5: - case 6: - return $processHoursFunction($date, '[Минулої] dddd ['); - default: - return $processHoursFunction($date, '[Минулого] dddd ['); - } + 'sameDay' => static fn (CarbonInterface $date) => $processHoursFunction($date, '[Сьогодні '), + 'nextDay' => static fn (CarbonInterface $date) => $processHoursFunction($date, '[Завтра '), + 'nextWeek' => static fn (CarbonInterface $date) => $processHoursFunction($date, '[У] dddd ['), + 'lastDay' => static fn (CarbonInterface $date) => $processHoursFunction($date, '[Вчора '), + 'lastWeek' => static fn (CarbonInterface $date) => match ($date->dayOfWeek) { + 0, 3, 5, 6 => $processHoursFunction($date, '[Минулої] dddd ['), + default => $processHoursFunction($date, '[Минулого] dddd ['), }, 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return $number.'-й'; - case 'D': - return $number.'-го'; - default: - return $number; - } + 'ordinal' => static fn ($number, $period) => match ($period) { + 'M', 'd', 'DDD', 'w', 'W' => $number.'-й', + 'D' => $number.'-го', + default => $number, }, - 'meridiem' => function ($hour) { + 'meridiem' => static function ($hour) { if ($hour < 4) { return 'ночі'; } + if ($hour < 12) { return 'ранку'; } + if ($hour < 17) { return 'дня'; } @@ -186,14 +164,14 @@ return [ 'months_standalone' => ['січень', 'лютий', 'березень', 'квітень', 'травень', 'червень', 'липень', 'серпень', 'вересень', 'жовтень', 'листопад', 'грудень'], 'months_short' => ['січ', 'лют', 'бер', 'кві', 'тра', 'чер', 'лип', 'сер', 'вер', 'жов', 'лис', 'гру'], 'months_regexp' => '/(D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/', - 'weekdays' => function (CarbonInterface $date, $format, $index) { + 'weekdays' => static function (CarbonInterface $date, $format, $index) { static $words = [ 'nominative' => ['неділя', 'понеділок', 'вівторок', 'середа', 'четвер', 'п’ятниця', 'субота'], 'accusative' => ['неділю', 'понеділок', 'вівторок', 'середу', 'четвер', 'п’ятницю', 'суботу'], 'genitive' => ['неділі', 'понеділка', 'вівторка', 'середи', 'четверга', 'п’ятниці', 'суботи'], ]; - $format = $format ?? ''; + $format ??= ''; $nounCase = preg_match('/(\[(В|в|У|у)\])\s+dddd/u', $format) ? 'accusative' : ( diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/unm_US.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/unm_US.php index fa5c374e3..161a1ec88 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/unm_US.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/unm_US.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['kentuwei', 'manteke', 'tusteke', 'lelai', 'tasteke', 'pelaiteke', 'sateteke'], 'weekdays_short' => ['ken', 'man', 'tus', 'lel', 'tas', 'pel', 'sat'], 'weekdays_min' => ['ken', 'man', 'tus', 'lel', 'tas', 'pel', 'sat'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, // Too unreliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ur.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ur.php index dc16c2c35..ac960f3f4 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ur.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ur.php @@ -46,15 +46,22 @@ $weekdays = [ * - hafezdivandari * - Hossein Jabbari * - nimamo + * - Usman Zahid */ return [ - 'year' => 'ایک سال|:count سال', - 'month' => 'ایک ماہ|:count ماہ', - 'week' => ':count ہفتے', - 'day' => 'ایک دن|:count دن', - 'hour' => 'ایک گھنٹہ|:count گھنٹے', - 'minute' => 'ایک منٹ|:count منٹ', - 'second' => 'چند سیکنڈ|:count سیکنڈ', + 'year' => ':count '.'سال', + 'a_year' => 'ایک سال|:count سال', + 'month' => ':count '.'ماہ', + 'a_month' => 'ایک ماہ|:count ماہ', + 'week' => ':count '.'ہفتے', + 'day' => ':count '.'دن', + 'a_day' => 'ایک دن|:count دن', + 'hour' => ':count '.'گھنٹے', + 'a_hour' => 'ایک گھنٹہ|:count گھنٹے', + 'minute' => ':count '.'منٹ', + 'a_minute' => 'ایک منٹ|:count منٹ', + 'second' => ':count '.'سیکنڈ', + 'a_second' => 'چند سیکنڈ|:count سیکنڈ', 'ago' => ':time قبل', 'from_now' => ':time بعد', 'after' => ':time بعد', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ve_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ve_ZA.php index 5eb2b9128..d401d9f24 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ve_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/ve_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['Swondaha', 'Musumbuluwo', 'Ḽavhuvhili', 'Ḽavhuraru', 'Ḽavhuṋa', 'Ḽavhuṱanu', 'Mugivhela'], 'weekdays_short' => ['Swo', 'Mus', 'Vhi', 'Rar', 'ṋa', 'Ṱan', 'Mug'], 'weekdays_min' => ['Swo', 'Mus', 'Vhi', 'Rar', 'ṋa', 'Ṱan', 'Mug'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, // Too unreliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/wal_ET.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/wal_ET.php index a4e619a87..e862f2c59 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/wal_ET.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/wal_ET.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['ወጋ', 'ሳይኖ', 'ማቆሳኛ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ'], 'weekdays_short' => ['ወጋ ', 'ሳይኖ', 'ማቆሳ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ '], 'weekdays_min' => ['ወጋ ', 'ሳይኖ', 'ማቆሳ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ '], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'meridiem' => ['ማለዶ', 'ቃማ'], ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/xh_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/xh_ZA.php index 910f8311e..009153c7b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/xh_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/xh_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['iCawa', 'uMvulo', 'lwesiBini', 'lwesiThathu', 'ulweSine', 'lwesiHlanu', 'uMgqibelo'], 'weekdays_short' => ['Caw', 'Mvu', 'Bin', 'Tha', 'Sin', 'Hla', 'Mgq'], 'weekdays_min' => ['Caw', 'Mvu', 'Bin', 'Tha', 'Sin', 'Hla', 'Mgq'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count ihlobo', // less reliable diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yi_US.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yi_US.php index f764d36f6..f2dec331d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yi_US.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yi_US.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['זונטיק', 'מאָנטיק', 'דינסטיק', 'מיטװאָך', 'דאָנערשטיק', 'פֿרײַטיק', 'שבת'], 'weekdays_short' => ['זונ\'', 'מאָנ\'', 'דינ\'', 'מיט\'', 'דאָנ\'', 'פֿרײַ\'', 'שבת'], 'weekdays_min' => ['זונ\'', 'מאָנ\'', 'דינ\'', 'מיט\'', 'דאָנ\'', 'פֿרײַ\'', 'שבת'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => ':count יאר', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yuw_PG.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yuw_PG.php index b99ad2e8e..8a1ccf981 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yuw_PG.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/yuw_PG.php @@ -22,5 +22,6 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['sönda', 'mönda', 'sinda', 'mitiwö', 'sogipbono', 'nenggo', 'söndanggie'], 'weekdays_short' => ['sön', 'mön', 'sin', 'mit', 'soi', 'nen', 'sab'], 'weekdays_min' => ['sön', 'mön', 'sin', 'mit', 'soi', 'nen', 'sab'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, ]); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hans.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hans.php index 9b91785e1..8d8d9d771 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hans.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hans.php @@ -37,7 +37,7 @@ return [ 'minute' => ':count:optional-space分钟', 'min' => ':count:optional-space分钟', 'second' => ':count:optional-space秒', - 'a_second' => '{1}几秒|]1,Inf[:count:optional-space秒', + 'a_second' => '{1}几秒|[-Inf,Inf]:count:optional-space秒', 's' => ':count:optional-space秒', 'ago' => ':time前', 'from_now' => ':time后', @@ -63,22 +63,15 @@ return [ 'lastWeek' => '[上]ddddLT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'd': - case 'D': - case 'DDD': - return $number.'日'; - case 'M': - return $number.'月'; - case 'w': - case 'W': - return $number.'周'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'd', 'D', 'DDD' => $number.'日', + 'M' => $number.'月', + 'w', 'W' => $number.'周', + default => $number, + }; }, - 'meridiem' => function ($hour, $minute) { + 'meridiem' => static function ($hour, $minute) { $time = $hour * 100 + $minute; if ($time < 600) { return '凌晨'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hant.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hant.php index a27b61093..e34db01c1 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hant.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zh_Hant.php @@ -39,7 +39,7 @@ return [ 'minute' => ':count:optional-space分鐘', 'min' => ':count:optional-space分鐘', 'second' => ':count:optional-space秒', - 'a_second' => '{1}幾秒|]1,Inf[:count:optional-space秒', + 'a_second' => '{1}幾秒|[-Inf,Inf]:count:optional-space秒', 's' => ':count:optional-space秒', 'ago' => ':time前', 'from_now' => ':time後', @@ -65,22 +65,15 @@ return [ 'lastWeek' => '[上]dddd LT', 'sameElse' => 'L', ], - 'ordinal' => function ($number, $period) { - switch ($period) { - case 'd': - case 'D': - case 'DDD': - return $number.'日'; - case 'M': - return $number.'月'; - case 'w': - case 'W': - return $number.'周'; - default: - return $number; - } + 'ordinal' => static function ($number, $period) { + return match ($period) { + 'd', 'D', 'DDD' => $number.'日', + 'M' => $number.'月', + 'w', 'W' => $number.'周', + default => $number, + }; }, - 'meridiem' => function ($hour, $minute) { + 'meridiem' => static function ($hour, $minute) { $time = $hour * 100 + $minute; if ($time < 600) { return '凌晨'; diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zu_ZA.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zu_ZA.php index 6bfb72f0a..b1e8bc0b5 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zu_ZA.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Lang/zu_ZA.php @@ -22,6 +22,7 @@ return array_replace_recursive(require __DIR__.'/en.php', [ 'weekdays' => ['iSonto', 'uMsombuluko', 'uLwesibili', 'uLwesithathu', 'uLwesine', 'uLwesihlanu', 'uMgqibelo'], 'weekdays_short' => ['Son', 'Mso', 'Bil', 'Tha', 'Sin', 'Hla', 'Mgq'], 'weekdays_min' => ['Son', 'Mso', 'Bil', 'Tha', 'Sin', 'Hla', 'Mgq'], + 'first_day_of_week' => 0, 'day_of_first_week_of_year' => 1, 'year' => 'kweminyaka engu-:count', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Language.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Language.php index 1fb5bafdc..6197e8b00 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Language.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Language.php @@ -1,5 +1,7 @@ names) { - $this->names = static::all()[$this->code] ?? [ - 'isoName' => $this->code, - 'nativeName' => $this->code, - ]; - } + $this->names ??= static::all()[$this->code] ?? [ + 'isoName' => $this->code, + 'nativeName' => $this->code, + ]; return $this->names; } /** * Returns the original locale ID. - * - * @return string */ public function getId(): string { @@ -135,8 +100,6 @@ class Language implements JsonSerializable /** * Returns the code of the locale "en"/"fr". - * - * @return string */ public function getCode(): string { @@ -145,8 +108,6 @@ class Language implements JsonSerializable /** * Returns the variant code such as cyrl/latn. - * - * @return string|null */ public function getVariant(): ?string { @@ -155,8 +116,6 @@ class Language implements JsonSerializable /** * Returns the variant such as Cyrillic/Latin. - * - * @return string|null */ public function getVariantName(): ?string { @@ -173,8 +132,6 @@ class Language implements JsonSerializable /** * Returns the region part of the locale. - * - * @return string|null */ public function getRegion(): ?string { @@ -184,7 +141,8 @@ class Language implements JsonSerializable /** * Returns the region name for the current language. * - * @return string|null + * ⚠ ISO 3166-2 short name provided with no warranty, should not + * be used for any purpose to show official state names. */ public function getRegionName(): ?string { @@ -193,24 +151,18 @@ class Language implements JsonSerializable /** * Returns the long ISO language name. - * - * @return string */ public function getFullIsoName(): string { - if (!$this->isoName) { - $this->isoName = $this->getNames()['isoName']; - } + $this->isoName ??= $this->getNames()['isoName']; return $this->isoName; } /** * Set the ISO language name. - * - * @param string $isoName */ - public function setIsoName(string $isoName): self + public function setIsoName(string $isoName): static { $this->isoName = $isoName; @@ -219,24 +171,18 @@ class Language implements JsonSerializable /** * Return the full name of the language in this language. - * - * @return string */ public function getFullNativeName(): string { - if (!$this->nativeName) { - $this->nativeName = $this->getNames()['nativeName']; - } + $this->nativeName ??= $this->getNames()['nativeName']; return $this->nativeName; } /** * Set the name of the language in this language. - * - * @param string $nativeName */ - public function setNativeName(string $nativeName): self + public function setNativeName(string $nativeName): static { $this->nativeName = $nativeName; @@ -245,8 +191,6 @@ class Language implements JsonSerializable /** * Returns the short ISO language name. - * - * @return string */ public function getIsoName(): string { @@ -257,8 +201,6 @@ class Language implements JsonSerializable /** * Get the short name of the language in this language. - * - * @return string */ public function getNativeName(): string { @@ -269,10 +211,8 @@ class Language implements JsonSerializable /** * Get a string with short ISO name, region in parentheses if applicable, variant in parentheses if applicable. - * - * @return string */ - public function getIsoDescription() + public function getIsoDescription(): string { $region = $this->getRegionName(); $variant = $this->getVariantName(); @@ -282,10 +222,8 @@ class Language implements JsonSerializable /** * Get a string with short native name, region in parentheses if applicable, variant in parentheses if applicable. - * - * @return string */ - public function getNativeDescription() + public function getNativeDescription(): string { $region = $this->getRegionName(); $variant = $this->getVariantName(); @@ -295,10 +233,8 @@ class Language implements JsonSerializable /** * Get a string with long ISO name, region in parentheses if applicable, variant in parentheses if applicable. - * - * @return string */ - public function getFullIsoDescription() + public function getFullIsoDescription(): string { $region = $this->getRegionName(); $variant = $this->getVariantName(); @@ -308,10 +244,8 @@ class Language implements JsonSerializable /** * Get a string with long native name, region in parentheses if applicable, variant in parentheses if applicable. - * - * @return string */ - public function getFullNativeDescription() + public function getFullNativeDescription(): string { $region = $this->getRegionName(); $variant = $this->getVariantName(); @@ -321,21 +255,16 @@ class Language implements JsonSerializable /** * Returns the original locale ID. - * - * @return string */ - public function __toString() + public function __toString(): string { return $this->getId(); } /** * Get a string with short ISO name, region in parentheses if applicable, variant in parentheses if applicable. - * - * @return string */ - #[ReturnTypeWillChange] - public function jsonSerialize() + public function jsonSerialize(): string { return $this->getIsoDescription(); } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php index 84e241e3e..76fc24a15 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php @@ -1,5 +1,7 @@ appGetter = $appGetter; @@ -40,9 +45,15 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider $this->localeGetter = $localeGetter; } + public function setFallbackLocaleGetter(?callable $fallbackLocaleGetter): void + { + $this->fallbackLocaleGetter = $fallbackLocaleGetter; + } + public function boot() { $this->updateLocale(); + $this->updateFallbackLocale(); if (!$this->app->bound('events')) { return; @@ -79,7 +90,34 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider try { $root = Date::getFacadeRoot(); $root->setLocale($locale); - } catch (Throwable $e) { + } catch (Throwable) { + // Non Carbon class in use in Date facade + } + } + } + + public function updateFallbackLocale() + { + $locale = $this->getFallbackLocale(); + + if ($locale === null) { + return; + } + + Carbon::setFallbackLocale($locale); + CarbonImmutable::setFallbackLocale($locale); + CarbonPeriod::setFallbackLocale($locale); + CarbonInterval::setFallbackLocale($locale); + + if (class_exists(IlluminateCarbon::class) && method_exists(IlluminateCarbon::class, 'setFallbackLocale')) { + IlluminateCarbon::setFallbackLocale($locale); + } + + if (class_exists(Date::class)) { + try { + $root = Date::getFacadeRoot(); + $root->setFallbackLocale($locale); + } catch (Throwable) { // @codeCoverageIgnore // Non Carbon class in use in Date facade } } @@ -104,6 +142,19 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider return $app ? $app->getLocale() : null; } + protected function getFallbackLocale() + { + if ($this->fallbackLocaleGetter) { + return ($this->fallbackLocaleGetter)(); + } + + $app = $this->getApp(); + + return $app && method_exists($app, 'getFallbackLocale') + ? $app->getFallbackLocale() + : $this->getGlobalApp('translator')?->getFallback(); + } + protected function getApp() { if ($this->appGetter) { diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/List/languages.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/List/languages.php index 5b5d9a1e7..557787753 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/List/languages.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/List/languages.php @@ -1,5 +1,7 @@ 'Andorra', @@ -41,7 +68,7 @@ return [ 'BL' => 'Saint Barthélemy', 'BM' => 'Bermuda', 'BN' => 'Brunei Darussalam', - 'BO' => 'Bolivia (Plurinational State of)', + 'BO' => 'Bolivia', 'BQ' => 'Bonaire, Sint Eustatius and Saba', 'BR' => 'Brazil', 'BS' => 'Bahamas', @@ -84,8 +111,8 @@ return [ 'ET' => 'Ethiopia', 'FI' => 'Finland', 'FJ' => 'Fiji', - 'FK' => 'Falkland Islands (Malvinas)', - 'FM' => 'Micronesia (Federated States of)', + 'FK' => 'Falkland Islands', + 'FM' => 'Micronesia', 'FO' => 'Faroe Islands', 'FR' => 'France', 'GA' => 'Gabon', @@ -120,7 +147,7 @@ return [ 'IN' => 'India', 'IO' => 'British Indian Ocean Territory', 'IQ' => 'Iraq', - 'IR' => 'Iran (Islamic Republic of)', + 'IR' => 'Iran', 'IS' => 'Iceland', 'IT' => 'Italy', 'JE' => 'Jersey', @@ -151,12 +178,12 @@ return [ 'LY' => 'Libya', 'MA' => 'Morocco', 'MC' => 'Monaco', - 'MD' => 'Moldova, Republic of', + 'MD' => 'Moldova', 'ME' => 'Montenegro', 'MF' => 'Saint Martin (French part)', 'MG' => 'Madagascar', 'MH' => 'Marshall Islands', - 'MK' => 'Macedonia, the former Yugoslav Republic of', + 'MK' => 'North Macedonia', 'ML' => 'Mali', 'MM' => 'Myanmar', 'MN' => 'Mongolia', @@ -195,7 +222,7 @@ return [ 'PM' => 'Saint Pierre and Miquelon', 'PN' => 'Pitcairn', 'PR' => 'Puerto Rico', - 'PS' => 'Palestine, State of', + 'PS' => 'Palestine', 'PT' => 'Portugal', 'PW' => 'Palau', 'PY' => 'Paraguay', @@ -240,8 +267,8 @@ return [ 'TR' => 'Turkey', 'TT' => 'Trinidad and Tobago', 'TV' => 'Tuvalu', - 'TW' => 'Taiwan, Province of China', - 'TZ' => 'Tanzania, United Republic of', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania', 'UA' => 'Ukraine', 'UG' => 'Uganda', 'UM' => 'United States Minor Outlying Islands', @@ -250,7 +277,7 @@ return [ 'UZ' => 'Uzbekistan', 'VA' => 'Holy See', 'VC' => 'Saint Vincent and the Grenadines', - 'VE' => 'Venezuela (Bolivarian Republic of)', + 'VE' => 'Venezuela', 'VG' => 'Virgin Islands (British)', 'VI' => 'Virgin Islands (U.S.)', 'VN' => 'Viet Nam', diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php index c05480876..64b5d9768 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php @@ -1,5 +1,7 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use Carbon\Exceptions\InvalidFormatException; + +enum Month: int +{ + // Using constants is only safe starting from PHP 8.2 + case January = 1; // CarbonInterface::JANUARY + case February = 2; // CarbonInterface::FEBRUARY + case March = 3; // CarbonInterface::MARCH + case April = 4; // CarbonInterface::APRIL + case May = 5; // CarbonInterface::MAY + case June = 6; // CarbonInterface::JUNE + case July = 7; // CarbonInterface::JULY + case August = 8; // CarbonInterface::AUGUST + case September = 9; // CarbonInterface::SEPTEMBER + case October = 10; // CarbonInterface::OCTOBER + case November = 11; // CarbonInterface::NOVEMBER + case December = 12; // CarbonInterface::DECEMBER + + public static function int(self|int|null $value): ?int + { + return $value instanceof self ? $value->value : $value; + } + + public static function fromNumber(int $number): self + { + $month = $number % CarbonInterface::MONTHS_PER_YEAR; + + return self::from($month + ($month < 1 ? CarbonInterface::MONTHS_PER_YEAR : 0)); + } + + public static function fromName(string $name, ?string $locale = null): self + { + try { + return self::from(CarbonImmutable::parseFromLocale("$name 1", $locale)->month); + } catch (InvalidFormatException $exception) { + // Possibly current language expect a dot after short name, but it's missing + if ($locale !== null && !mb_strlen($name) < 4 && !str_ends_with($name, '.')) { + try { + return self::from(CarbonImmutable::parseFromLocale("$name. 1", $locale)->month); + } catch (InvalidFormatException $e) { + // Throw previous error + } + } + + throw $exception; + } + } + + public function ofTheYear(CarbonImmutable|int|null $now = null): CarbonImmutable + { + if (\is_int($now)) { + return CarbonImmutable::create($now, $this->value); + } + + $modifier = $this->name.' 1st'; + + return $now?->modify($modifier) ?? new CarbonImmutable($modifier); + } + + public function locale(string $locale, ?CarbonImmutable $now = null): CarbonImmutable + { + return $this->ofTheYear($now)->locale($locale); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php deleted file mode 100644 index fde67b36a..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php +++ /dev/null @@ -1,286 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -use Closure; -use InvalidArgumentException; -use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter as AdapterReflectionParameter; -use PHPStan\BetterReflection\Reflection\Adapter\ReflectionType as AdapterReflectionType; -use PHPStan\BetterReflection\Reflection\ReflectionClass as BetterReflectionClass; -use PHPStan\BetterReflection\Reflection\ReflectionFunction as BetterReflectionFunction; -use PHPStan\BetterReflection\Reflection\ReflectionParameter as BetterReflectionParameter; -use PHPStan\Reflection\Php\BuiltinMethodReflection; -use PHPStan\TrinaryLogic; -use ReflectionClass; -use ReflectionFunction; -use ReflectionMethod; -use ReflectionParameter; -use ReflectionType; -use stdClass; -use Throwable; - -abstract class AbstractMacro implements BuiltinMethodReflection -{ - /** - * The reflection function/method. - * - * @var ReflectionFunction|ReflectionMethod - */ - protected $reflectionFunction; - - /** - * The class name. - * - * @var class-string - */ - private $className; - - /** - * The method name. - * - * @var string - */ - private $methodName; - - /** - * The parameters. - * - * @var ReflectionParameter[] - */ - private $parameters; - - /** - * The is static. - * - * @var bool - */ - private $static = false; - - /** - * Macro constructor. - * - * @param class-string $className - * @param string $methodName - * @param callable $macro - */ - public function __construct(string $className, string $methodName, $macro) - { - $this->className = $className; - $this->methodName = $methodName; - $rawReflectionFunction = \is_array($macro) - ? new ReflectionMethod($macro[0], $macro[1]) - : new ReflectionFunction($macro); - $this->reflectionFunction = self::hasModernParser() - ? $this->getReflectionFunction($macro) - : $rawReflectionFunction; // @codeCoverageIgnore - $this->parameters = array_map( - function ($parameter) { - if ($parameter instanceof BetterReflectionParameter) { - return new AdapterReflectionParameter($parameter); - } - - return $parameter; // @codeCoverageIgnore - }, - $this->reflectionFunction->getParameters() - ); - - if ($rawReflectionFunction->isClosure()) { - try { - $closure = $rawReflectionFunction->getClosure(); - $boundClosure = Closure::bind($closure, new stdClass()); - $this->static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null); - } catch (Throwable $e) { - $this->static = true; - } - } - } - - private function getReflectionFunction($spec) - { - if (\is_array($spec) && \count($spec) === 2 && \is_string($spec[1])) { - \assert($spec[1] !== ''); - - if (\is_object($spec[0])) { - return BetterReflectionClass::createFromInstance($spec[0]) - ->getMethod($spec[1]); - } - - return BetterReflectionClass::createFromName($spec[0]) - ->getMethod($spec[1]); - } - - if (\is_string($spec)) { - return BetterReflectionFunction::createFromName($spec); - } - - if ($spec instanceof Closure) { - return BetterReflectionFunction::createFromClosure($spec); - } - - throw new InvalidArgumentException('Could not create reflection from the spec given'); // @codeCoverageIgnore - } - - /** - * {@inheritdoc} - */ - public function getDeclaringClass(): ReflectionClass - { - return new ReflectionClass($this->className); - } - - /** - * {@inheritdoc} - */ - public function isPrivate(): bool - { - return false; - } - - /** - * {@inheritdoc} - */ - public function isPublic(): bool - { - return true; - } - - /** - * {@inheritdoc} - */ - public function isFinal(): bool - { - return false; - } - - /** - * {@inheritdoc} - */ - public function isInternal(): bool - { - return false; - } - - /** - * {@inheritdoc} - */ - public function isAbstract(): bool - { - return false; - } - - /** - * {@inheritdoc} - */ - public function isStatic(): bool - { - return $this->static; - } - - /** - * {@inheritdoc} - */ - public function getDocComment(): ?string - { - return $this->reflectionFunction->getDocComment() ?: null; - } - - /** - * {@inheritdoc} - */ - public function getName(): string - { - return $this->methodName; - } - - /** - * {@inheritdoc} - */ - public function getParameters(): array - { - return $this->parameters; - } - - /** - * {@inheritdoc} - */ - public function getReturnType(): ?ReflectionType - { - $type = $this->reflectionFunction->getReturnType(); - - if ($type instanceof ReflectionType) { - return $type; // @codeCoverageIgnore - } - - return self::adaptType($type); - } - - /** - * {@inheritdoc} - */ - public function isDeprecated(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean( - $this->reflectionFunction->isDeprecated() || - preg_match('/@deprecated/i', $this->getDocComment() ?: '') - ); - } - - /** - * {@inheritdoc} - */ - public function isVariadic(): bool - { - return $this->reflectionFunction->isVariadic(); - } - - /** - * {@inheritdoc} - */ - public function getPrototype(): BuiltinMethodReflection - { - return $this; - } - - public function getTentativeReturnType(): ?ReflectionType - { - return null; - } - - public function returnsByReference(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - private static function adaptType($type) - { - $method = method_exists(AdapterReflectionType::class, 'fromTypeOrNull') - ? 'fromTypeOrNull' - : 'fromReturnTypeOrNull'; // @codeCoverageIgnore - - return AdapterReflectionType::$method($type); - } - - private static function hasModernParser(): bool - { - static $modernParser = null; - - if ($modernParser !== null) { - return $modernParser; - } - - $modernParser = method_exists(AdapterReflectionType::class, 'fromTypeOrNull'); - - return $modernParser; - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/Macro.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/Macro.php deleted file mode 100644 index de3e51f6a..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/Macro.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -use PHPStan\BetterReflection\Reflection\Adapter; -use PHPStan\Reflection\Php\BuiltinMethodReflection; -use ReflectionMethod; - -$method = new ReflectionMethod(BuiltinMethodReflection::class, 'getReflection'); - -require $method->hasReturnType() && $method->getReturnType()->getName() === Adapter\ReflectionMethod::class - ? __DIR__.'/../../../lazy/Carbon/PHPStan/AbstractMacroStatic.php' - : __DIR__.'/../../../lazy/Carbon/PHPStan/AbstractMacroBuiltin.php'; - -$method = new ReflectionMethod(BuiltinMethodReflection::class, 'getFileName'); - -require $method->hasReturnType() - ? __DIR__.'/../../../lazy/Carbon/PHPStan/MacroStrongType.php' - : __DIR__.'/../../../lazy/Carbon/PHPStan/MacroWeakType.php'; - -final class Macro extends LazyMacro -{ -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php index 2cd6fce54..7327586a6 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php @@ -1,5 +1,7 @@ scanner = new MacroScanner($reflectionProvider); - $this->methodReflectionFactory = $methodReflectionFactory; + $this->reflectionProvider = $reflectionProvider; + $this->closureTypeFactory = $closureTypeFactory; } /** @@ -55,7 +63,17 @@ final class MacroExtension implements MethodsClassReflectionExtension */ public function hasMethod(ClassReflection $classReflection, string $methodName): bool { - return $this->scanner->hasMethod($classReflection->getName(), $methodName); + if ( + $classReflection->getName() !== CarbonInterface::class && + !$classReflection->isSubclassOf(CarbonInterface::class) + ) { + return false; + } + + $className = $classReflection->getName(); + + return \is_callable([$className, 'hasMacro']) && + $className::hasMacro($methodName); } /** @@ -63,26 +81,57 @@ final class MacroExtension implements MethodsClassReflectionExtension */ public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection { - $builtinMacro = $this->scanner->getMethod($classReflection->getName(), $methodName); - $supportAssertions = class_exists(Assertions::class); + $macros = FactoryImmutable::getDefaultInstance()->getSettings()['macros'] ?? []; + $macro = $macros[$methodName] ?? throw new InvalidArgumentException("Macro '$methodName' not found"); + $static = false; + $final = false; + $deprecated = false; + $docComment = null; - return $this->methodReflectionFactory->create( + if (\is_array($macro) && \count($macro) === 2 && \is_string($macro[1])) { + \assert($macro[1] !== ''); + + $reflection = new ReflectionMethod($macro[0], $macro[1]); + $closure = \is_object($macro[0]) ? $reflection->getClosure($macro[0]) : $reflection->getClosure(); + + $static = $reflection->isStatic(); + $final = $reflection->isFinal(); + $deprecated = $reflection->isDeprecated(); + $docComment = $reflection->getDocComment() ?: null; + } elseif (\is_string($macro)) { + $reflection = new ReflectionFunction($macro); + $closure = $reflection->getClosure(); + $deprecated = $reflection->isDeprecated(); + $docComment = $reflection->getDocComment() ?: null; + } elseif ($macro instanceof Closure) { + $closure = $macro; + + try { + $boundClosure = Closure::bind($closure, new stdClass()); + $static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null); + } catch (Throwable) { + $static = true; + } + + $reflection = new ReflectionFunction($macro); + $deprecated = $reflection->isDeprecated(); + $docComment = $reflection->getDocComment() ?: null; + } + + if (!isset($closure)) { + throw new InvalidArgumentException('Could not create reflection from the spec given'); // @codeCoverageIgnore + } + + $closureType = $this->closureTypeFactory->fromClosureObject($closure); + + return new MacroMethodReflection( $classReflection, - null, - $builtinMacro, - $classReflection->getActiveTemplateTypeMap(), - [], - TypehintHelper::decideTypeFromReflection($builtinMacro->getReturnType()), - null, - null, - $builtinMacro->isDeprecated()->yes(), - $builtinMacro->isInternal(), - $builtinMacro->isFinal(), - $supportAssertions ? null : $builtinMacro->getDocComment(), - $supportAssertions ? Assertions::createEmpty() : null, - null, - $builtinMacro->getDocComment(), - [] + $methodName, + $closureType, + $static, + $final, + $deprecated, + $docComment, ); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroMethodReflection.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroMethodReflection.php new file mode 100644 index 000000000..b710f5492 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroMethodReflection.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\PHPStan; + +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\TrinaryLogic; +use PHPStan\Type\Type; + +use function preg_match; + +class MacroMethodReflection implements MethodReflection +{ + private ClassReflection $declaringClass; + private string $methodName; + private ParametersAcceptor $macroClosureType; + private bool $static; + private bool $final; + private bool $deprecated; + private ?string $docComment; + + public function __construct( + ClassReflection $declaringClass, + string $methodName, + ParametersAcceptor $macroClosureType, + bool $static, + bool $final, + bool $deprecated, + ?string $docComment + ) { + $this->declaringClass = $declaringClass; + $this->methodName = $methodName; + $this->macroClosureType = $macroClosureType; + $this->static = $static; + $this->final = $final; + $this->deprecated = $deprecated; + $this->docComment = $docComment; + } + + public function getDeclaringClass(): ClassReflection + { + return $this->declaringClass; + } + + public function isStatic(): bool + { + return $this->static; + } + + public function isPrivate(): bool + { + return false; + } + + public function isPublic(): bool + { + return true; + } + + public function getDocComment(): ?string + { + return $this->docComment; + } + + public function getName(): string + { + return $this->methodName; + } + + public function getPrototype(): \PHPStan\Reflection\ClassMemberReflection + { + return $this; + } + + public function getVariants(): array + { + return [$this->macroClosureType]; + } + + public function isDeprecated(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean( + $this->deprecated || + preg_match('/@deprecated/i', $this->getDocComment() ?: '') + ); + } + + public function getDeprecatedDescription(): ?string + { + return null; + } + + public function isFinal(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->final); + } + + public function isInternal(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + + public function getThrowType(): ?Type + { + return null; + } + + public function hasSideEffects(): TrinaryLogic + { + return TrinaryLogic::createMaybe(); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php deleted file mode 100644 index eb8957d4d..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\PHPStan; - -use Carbon\CarbonInterface; -use PHPStan\Reflection\ReflectionProvider; -use ReflectionClass; -use ReflectionException; - -final class MacroScanner -{ - /** - * @var \PHPStan\Reflection\ReflectionProvider - */ - private $reflectionProvider; - - /** - * MacroScanner constructor. - * - * @param \PHPStan\Reflection\ReflectionProvider $reflectionProvider - */ - public function __construct(ReflectionProvider $reflectionProvider) - { - $this->reflectionProvider = $reflectionProvider; - } - - /** - * Return true if the given pair class-method is a Carbon macro. - * - * @param class-string $className - * @param string $methodName - * - * @return bool - */ - public function hasMethod(string $className, string $methodName): bool - { - $classReflection = $this->reflectionProvider->getClass($className); - - if ( - $classReflection->getName() !== CarbonInterface::class && - !$classReflection->isSubclassOf(CarbonInterface::class) - ) { - return false; - } - - return \is_callable([$className, 'hasMacro']) && - $className::hasMacro($methodName); - } - - /** - * Return the Macro for a given pair class-method. - * - * @param class-string $className - * @param string $methodName - * - * @throws ReflectionException - * - * @return Macro - */ - public function getMethod(string $className, string $methodName): Macro - { - $reflectionClass = new ReflectionClass($className); - $property = $reflectionClass->getProperty('globalMacros'); - - $property->setAccessible(true); - $macro = $property->getValue()[$methodName]; - - return new Macro( - $className, - $methodName, - $macro - ); - } -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Boundaries.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Boundaries.php index 71bbb7230..b21b9c54e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Boundaries.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Boundaries.php @@ -1,5 +1,7 @@ startOfWeek(Carbon::SUNDAY) . "\n"; * ``` * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week * * @return static */ - public function startOfWeek($weekStartsAt = null) + public function startOfWeek(WeekDay|int|null $weekStartsAt = null): static { - return $this->subDays((7 + $this->dayOfWeek - ($weekStartsAt ?? $this->firstWeekDay)) % 7)->startOfDay(); + return $this + ->subDays( + (static::DAYS_PER_WEEK + $this->dayOfWeek - (WeekDay::int($weekStartsAt) ?? $this->firstWeekDay)) % + static::DAYS_PER_WEEK, + ) + ->startOfDay(); } /** @@ -286,13 +295,18 @@ trait Boundaries * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek(Carbon::SATURDAY) . "\n"; * ``` * - * @param int $weekEndsAt optional start allow you to specify the day of week to use to end the week + * @param WeekDay|int|null $weekEndsAt optional end allow you to specify the day of week to use to end the week * * @return static */ - public function endOfWeek($weekEndsAt = null) + public function endOfWeek(WeekDay|int|null $weekEndsAt = null): static { - return $this->addDays((7 - $this->dayOfWeek + ($weekEndsAt ?? $this->lastWeekDay)) % 7)->endOfDay(); + return $this + ->addDays( + (static::DAYS_PER_WEEK - $this->dayOfWeek + (WeekDay::int($weekEndsAt) ?? $this->lastWeekDay)) % + static::DAYS_PER_WEEK, + ) + ->endOfDay(); } /** @@ -302,10 +316,8 @@ trait Boundaries * ``` * echo Carbon::parse('2018-07-25 12:45:16')->startOfHour(); * ``` - * - * @return static */ - public function startOfHour() + public function startOfHour(): static { return $this->setTime($this->hour, 0, 0, 0); } @@ -317,10 +329,8 @@ trait Boundaries * ``` * echo Carbon::parse('2018-07-25 12:45:16')->endOfHour(); * ``` - * - * @return static */ - public function endOfHour() + public function endOfHour(): static { return $this->setTime($this->hour, static::MINUTES_PER_HOUR - 1, static::SECONDS_PER_MINUTE - 1, static::MICROSECONDS_PER_SECOND - 1); } @@ -332,10 +342,8 @@ trait Boundaries * ``` * echo Carbon::parse('2018-07-25 12:45:16')->startOfMinute(); * ``` - * - * @return static */ - public function startOfMinute() + public function startOfMinute(): static { return $this->setTime($this->hour, $this->minute, 0, 0); } @@ -347,10 +355,8 @@ trait Boundaries * ``` * echo Carbon::parse('2018-07-25 12:45:16')->endOfMinute(); * ``` - * - * @return static */ - public function endOfMinute() + public function endOfMinute(): static { return $this->setTime($this->hour, $this->minute, static::SECONDS_PER_MINUTE - 1, static::MICROSECONDS_PER_SECOND - 1); } @@ -364,10 +370,8 @@ trait Boundaries * ->startOfSecond() * ->format('H:i:s.u'); * ``` - * - * @return static */ - public function startOfSecond() + public function startOfSecond(): static { return $this->setTime($this->hour, $this->minute, $this->second, 0); } @@ -381,32 +385,59 @@ trait Boundaries * ->endOfSecond() * ->format('H:i:s.u'); * ``` - * - * @return static */ - public function endOfSecond() + public function endOfSecond(): static { return $this->setTime($this->hour, $this->minute, $this->second, static::MICROSECONDS_PER_SECOND - 1); } + /** + * Modify to start of current millisecond, microseconds such as 12345 become 123000 + * + * @example + * ``` + * echo Carbon::parse('2018-07-25 12:45:16.334455') + * ->startOfSecond() + * ->format('H:i:s.u'); + * ``` + */ + public function startOfMillisecond(): static + { + $millisecond = (int) floor($this->micro / 1000); + + return $this->setTime($this->hour, $this->minute, $this->second, $millisecond * 1000); + } + + /** + * Modify to end of current millisecond, microseconds such as 12345 become 123999 + * + * @example + * ``` + * echo Carbon::parse('2018-07-25 12:45:16.334455') + * ->endOfSecond() + * ->format('H:i:s.u'); + * ``` + */ + public function endOfMillisecond(): static + { + $millisecond = (int) floor($this->micro / 1000); + + return $this->setTime($this->hour, $this->minute, $this->second, $millisecond * 1000 + 999); + } + /** * Modify to start of current given unit. * * @example * ``` * echo Carbon::parse('2018-07-25 12:45:16.334455') - * ->startOf('month') - * ->endOf('week', Carbon::FRIDAY); + * ->startOf(Unit::Month) + * ->endOf(Unit::Week, Carbon::FRIDAY); * ``` - * - * @param string $unit - * @param array $params - * - * @return static */ - public function startOf($unit, ...$params) + public function startOf(Unit|string $unit, mixed ...$params): static { - $ucfUnit = ucfirst(static::singularUnit($unit)); + $ucfUnit = ucfirst($unit instanceof Unit ? $unit->value : static::singularUnit($unit)); $method = "startOf$ucfUnit"; if (!method_exists($this, $method)) { throw new UnknownUnitException($unit); @@ -421,18 +452,13 @@ trait Boundaries * @example * ``` * echo Carbon::parse('2018-07-25 12:45:16.334455') - * ->startOf('month') - * ->endOf('week', Carbon::FRIDAY); + * ->startOf(Unit::Month) + * ->endOf(Unit::Week, Carbon::FRIDAY); * ``` - * - * @param string $unit - * @param array $params - * - * @return static */ - public function endOf($unit, ...$params) + public function endOf(Unit|string $unit, mixed ...$params): static { - $ucfUnit = ucfirst(static::singularUnit($unit)); + $ucfUnit = ucfirst($unit instanceof Unit ? $unit->value : static::singularUnit($unit)); $method = "endOf$ucfUnit"; if (!method_exists($this, $method)) { throw new UnknownUnitException($unit); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Cast.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Cast.php index 5f7c7c011..4c00e42cc 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Cast.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Cast.php @@ -1,5 +1,7 @@ $className The $className::instance() method will be called to cast the current object. + * + * @return T */ - public function cast(string $className) + public function cast(string $className): mixed { if (!method_exists($className, 'instance')) { if (is_a($className, DateTimeInterface::class, true)) { - return new $className($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone()); + return $className::createFromFormat('U.u', $this->rawFormat('U.u')) + ->setTimezone($this->getTimezone()); } throw new InvalidCastException("$className has not the instance() method needed to cast the date."); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Comparison.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Comparison.php index daee19cc9..53e54deae 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Comparison.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Comparison.php @@ -1,5 +1,7 @@ eq('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see equalTo() - * - * @return bool */ - public function eq($date): bool + public function eq(DateTimeInterface|string $date): bool { return $this->equalTo($date); } @@ -68,16 +73,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->equalTo(Carbon::parse('2018-07-25 12:45:16')); // true * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function equalTo($date): bool + public function equalTo(DateTimeInterface|string $date): bool { - $this->discourageNull($date); - $this->discourageBoolean($date); - return $this == $this->resolveCarbon($date); } @@ -91,13 +89,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see notEqualTo() - * - * @return bool */ - public function ne($date): bool + public function ne(DateTimeInterface|string $date): bool { return $this->notEqualTo($date); } @@ -111,12 +105,8 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->notEqualTo(Carbon::parse('2018-07-25 12:45:16')); // false * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function notEqualTo($date): bool + public function notEqualTo(DateTimeInterface|string $date): bool { return !$this->equalTo($date); } @@ -131,13 +121,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThan() - * - * @return bool */ - public function gt($date): bool + public function gt(DateTimeInterface|string $date): bool { return $this->greaterThan($date); } @@ -151,16 +137,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:16'); // false * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function greaterThan($date): bool + public function greaterThan(DateTimeInterface|string $date): bool { - $this->discourageNull($date); - $this->discourageBoolean($date); - return $this > $this->resolveCarbon($date); } @@ -174,13 +153,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThan() - * - * @return bool */ - public function isAfter($date): bool + public function isAfter(DateTimeInterface|string $date): bool { return $this->greaterThan($date); } @@ -195,13 +170,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:17'); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see greaterThanOrEqualTo() - * - * @return bool */ - public function gte($date): bool + public function gte(DateTimeInterface|string $date): bool { return $this->greaterThanOrEqualTo($date); } @@ -215,16 +186,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:16'); // true * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:17'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function greaterThanOrEqualTo($date): bool + public function greaterThanOrEqualTo(DateTimeInterface|string $date): bool { - $this->discourageNull($date); - $this->discourageBoolean($date); - return $this >= $this->resolveCarbon($date); } @@ -238,13 +202,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThan() - * - * @return bool */ - public function lt($date): bool + public function lt(DateTimeInterface|string $date): bool { return $this->lessThan($date); } @@ -258,16 +218,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:16'); // false * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function lessThan($date): bool + public function lessThan(DateTimeInterface|string $date): bool { - $this->discourageNull($date); - $this->discourageBoolean($date); - return $this < $this->resolveCarbon($date); } @@ -281,13 +234,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThan() - * - * @return bool */ - public function isBefore($date): bool + public function isBefore(DateTimeInterface|string $date): bool { return $this->lessThan($date); } @@ -302,13 +251,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:17'); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * * @see lessThanOrEqualTo() - * - * @return bool */ - public function lte($date): bool + public function lte(DateTimeInterface|string $date): bool { return $this->lessThanOrEqualTo($date); } @@ -322,16 +267,9 @@ trait Comparison * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:16'); // true * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:17'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date - * - * @return bool */ - public function lessThanOrEqualTo($date): bool + public function lessThanOrEqualTo(DateTimeInterface|string $date): bool { - $this->discourageNull($date); - $this->discourageBoolean($date); - return $this <= $this->resolveCarbon($date); } @@ -350,13 +288,9 @@ trait Comparison * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01', false); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * @param bool $equal Indicates if an equal to comparison should be done - * - * @return bool + * @param bool $equal Indicates if an equal to comparison should be done */ - public function between($date1, $date2, $equal = true): bool + public function between(DateTimeInterface|string $date1, DateTimeInterface|string $date2, bool $equal = true): bool { $date1 = $this->resolveCarbon($date1); $date2 = $this->resolveCarbon($date2); @@ -381,13 +315,8 @@ trait Comparison * Carbon::parse('2018-07-25')->betweenIncluded('2018-08-01', '2018-08-20'); // false * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-25', '2018-08-01'); // true * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * - * @return bool */ - public function betweenIncluded($date1, $date2): bool + public function betweenIncluded(DateTimeInterface|string $date1, DateTimeInterface|string $date2): bool { return $this->between($date1, $date2, true); } @@ -401,13 +330,8 @@ trait Comparison * Carbon::parse('2018-07-25')->betweenExcluded('2018-08-01', '2018-08-20'); // false * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-25', '2018-08-01'); // false * ``` - * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * - * @return bool */ - public function betweenExcluded($date1, $date2): bool + public function betweenExcluded(DateTimeInterface|string $date1, DateTimeInterface|string $date2): bool { return $this->between($date1, $date2, false); } @@ -423,13 +347,9 @@ trait Comparison * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01', false); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1 - * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2 - * @param bool $equal Indicates if an equal to comparison should be done - * - * @return bool + * @param bool $equal Indicates if an equal to comparison should be done */ - public function isBetween($date1, $date2, $equal = true): bool + public function isBetween(DateTimeInterface|string $date1, DateTimeInterface|string $date2, bool $equal = true): bool { return $this->between($date1, $date2, $equal); } @@ -442,10 +362,8 @@ trait Comparison * Carbon::parse('2019-07-14')->isWeekday(); // false * Carbon::parse('2019-07-15')->isWeekday(); // true * ``` - * - * @return bool */ - public function isWeekday() + public function isWeekday(): bool { return !$this->isWeekend(); } @@ -458,12 +376,14 @@ trait Comparison * Carbon::parse('2019-07-14')->isWeekend(); // true * Carbon::parse('2019-07-15')->isWeekend(); // false * ``` - * - * @return bool */ - public function isWeekend() + public function isWeekend(): bool { - return \in_array($this->dayOfWeek, static::$weekendDays, true); + return \in_array( + $this->dayOfWeek, + $this->transmitFactory(static fn () => static::getWeekendDays()), + true, + ); } /** @@ -474,12 +394,12 @@ trait Comparison * Carbon::yesterday()->isYesterday(); // true * Carbon::tomorrow()->isYesterday(); // false * ``` - * - * @return bool */ - public function isYesterday() + public function isYesterday(): bool { - return $this->toDateString() === static::yesterday($this->getTimezone())->toDateString(); + return $this->toDateString() === $this->transmitFactory( + fn () => static::yesterday($this->getTimezone())->toDateString(), + ); } /** @@ -490,10 +410,8 @@ trait Comparison * Carbon::today()->isToday(); // true * Carbon::tomorrow()->isToday(); // false * ``` - * - * @return bool */ - public function isToday() + public function isToday(): bool { return $this->toDateString() === $this->nowWithSameTz()->toDateString(); } @@ -506,12 +424,12 @@ trait Comparison * Carbon::tomorrow()->isTomorrow(); // true * Carbon::yesterday()->isTomorrow(); // false * ``` - * - * @return bool */ - public function isTomorrow() + public function isTomorrow(): bool { - return $this->toDateString() === static::tomorrow($this->getTimezone())->toDateString(); + return $this->toDateString() === $this->transmitFactory( + fn () => static::tomorrow($this->getTimezone())->toDateString(), + ); } /** @@ -522,10 +440,8 @@ trait Comparison * Carbon::now()->addHours(5)->isFuture(); // true * Carbon::now()->subHours(5)->isFuture(); // false * ``` - * - * @return bool */ - public function isFuture() + public function isFuture(): bool { return $this->greaterThan($this->nowWithSameTz()); } @@ -538,14 +454,42 @@ trait Comparison * Carbon::now()->subHours(5)->isPast(); // true * Carbon::now()->addHours(5)->isPast(); // false * ``` - * - * @return bool */ - public function isPast() + public function isPast(): bool { return $this->lessThan($this->nowWithSameTz()); } + /** + * Determines if the instance is now or in the future, ie. greater (after) than or equal to now. + * + * @example + * ``` + * Carbon::now()->isNowOrFuture(); // true + * Carbon::now()->addHours(5)->isNowOrFuture(); // true + * Carbon::now()->subHours(5)->isNowOrFuture(); // false + * ``` + */ + public function isNowOrFuture(): bool + { + return $this->greaterThanOrEqualTo($this->nowWithSameTz()); + } + + /** + * Determines if the instance is now or in the past, ie. less (before) than or equal to now. + * + * @example + * ``` + * Carbon::now()->isNowOrPast(); // true + * Carbon::now()->subHours(5)->isNowOrPast(); // true + * Carbon::now()->addHours(5)->isNowOrPast(); // false + * ``` + */ + public function isNowOrPast(): bool + { + return $this->lessThanOrEqualTo($this->nowWithSameTz()); + } + /** * Determines if the instance is a leap year. * @@ -554,10 +498,8 @@ trait Comparison * Carbon::parse('2020-01-01')->isLeapYear(); // true * Carbon::parse('2019-01-01')->isLeapYear(); // false * ``` - * - * @return bool */ - public function isLeapYear() + public function isLeapYear(): bool { return $this->rawFormat('L') === '1'; } @@ -577,12 +519,10 @@ trait Comparison * ``` * * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates - * - * @return bool */ - public function isLongYear() + public function isLongYear(): bool { - return static::create($this->year, 12, 28, 0, 0, 0, $this->tz)->weekOfYear === 53; + return static::create($this->year, 12, 28, 0, 0, 0, $this->tz)->weekOfYear === static::WEEKS_PER_YEAR + 1; } /** @@ -598,10 +538,8 @@ trait Comparison * ``` * * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates - * - * @return bool */ - public function isLongIsoYear() + public function isLongIsoYear(): bool { return static::create($this->isoWeekYear, 12, 28, 0, 0, 0, $this->tz)->weekOfYear === 53; } @@ -615,12 +553,10 @@ trait Comparison * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-06-14')); // false * ``` * - * @param string $format date formats to compare. - * @param \Carbon\Carbon|\DateTimeInterface|string|null $date instance to compare with or null to use current day. - * - * @return bool + * @param string $format date formats to compare. + * @param DateTimeInterface|string $date instance to compare with or null to use current day. */ - public function isSameAs($format, $date = null) + public function isSameAs(string $format, DateTimeInterface|string $date): bool { return $this->rawFormat($format) === $this->resolveCarbon($date)->rawFormat($format); } @@ -634,19 +570,27 @@ trait Comparison * Carbon::parse('2018-12-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // false * ``` * - * @param string $unit singular unit string - * @param \Carbon\Carbon|\DateTimeInterface|null $date instance to compare with or null to use current day. + * @param string $unit singular unit string + * @param DateTimeInterface|string $date instance to compare with or null to use current day. * * @throws BadComparisonUnitException * * @return bool */ - public function isSameUnit($unit, $date = null) + public function isSameUnit(string $unit, DateTimeInterface|string $date): bool { + if ($unit === /* @call isSameUnit */ 'quarter') { + $other = $this->resolveCarbon($date); + + return $other->year === $this->year && $other->quarter === $this->quarter; + } + $units = [ // @call isSameUnit 'year' => 'Y', // @call isSameUnit + 'month' => 'Y-n', + // @call isSameUnit 'week' => 'o-W', // @call isSameUnit 'day' => 'Y-m-d', @@ -657,6 +601,10 @@ trait Comparison // @call isSameUnit 'second' => 'Y-m-d H:i:s', // @call isSameUnit + 'milli' => 'Y-m-d H:i:s.v', + // @call isSameUnit + 'millisecond' => 'Y-m-d H:i:s.v', + // @call isSameUnit 'micro' => 'Y-m-d H:i:s.u', // @call isSameUnit 'microsecond' => 'Y-m-d H:i:s.u', @@ -670,7 +618,7 @@ trait Comparison return $this->resolveCarbon($date)->$unit === $this->$unit; } - if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) { + if ($this->isLocalStrictModeEnabled()) { throw new BadComparisonUnitException($unit); } @@ -689,12 +637,10 @@ trait Comparison * @param string $unit The unit to test. * * @throws BadMethodCallException - * - * @return bool */ - public function isCurrentUnit($unit) + public function isCurrentUnit(string $unit): bool { - return $this->{'isSame'.ucfirst($unit)}(); + return $this->{'isSame'.ucfirst($unit)}('now'); } /** @@ -708,12 +654,12 @@ trait Comparison * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01'), false); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|string|null $date The instance to compare with or null to use current day. - * @param bool $ofSameYear Check if it is the same month in the same year. + * @param DateTimeInterface|string $date The instance to compare with or null to use current day. + * @param bool $ofSameYear Check if it is the same month in the same year. * * @return bool */ - public function isSameQuarter($date = null, $ofSameYear = true) + public function isSameQuarter(DateTimeInterface|string $date, bool $ofSameYear = true): bool { $date = $this->resolveCarbon($date); @@ -731,12 +677,12 @@ trait Comparison * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01'), false); // true * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date. - * @param bool $ofSameYear Check if it is the same month in the same year. + * @param DateTimeInterface|string $date The instance to compare with or null to use the current date. + * @param bool $ofSameYear Check if it is the same month in the same year. * * @return bool */ - public function isSameMonth($date = null, $ofSameYear = true) + public function isSameMonth(DateTimeInterface|string $date, bool $ofSameYear = true): bool { return $this->isSameAs($ofSameYear ? 'Y-m' : 'm', $date); } @@ -752,11 +698,11 @@ trait Comparison * Carbon::parse('2019-07-17')->isDayOfWeek('Friday'); // false * ``` * - * @param int $dayOfWeek + * @param int|string $dayOfWeek * * @return bool */ - public function isDayOfWeek($dayOfWeek) + public function isDayOfWeek($dayOfWeek): bool { if (\is_string($dayOfWeek) && \defined($constant = static::class.'::'.strtoupper($dayOfWeek))) { $dayOfWeek = \constant($constant); @@ -776,13 +722,13 @@ trait Comparison * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-06')); // false * ``` * - * @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day. + * @param DateTimeInterface|string|null $date The instance to compare with or null to use current day. * * @return bool */ - public function isBirthday($date = null) + public function isBirthday(DateTimeInterface|string|null $date = null): bool { - return $this->isSameAs('md', $date); + return $this->isSameAs('md', $date ?? 'now'); } /** @@ -796,14 +742,148 @@ trait Comparison * Carbon::parse('2019-03-31')->isLastOfMonth(); // true * Carbon::parse('2019-04-30')->isLastOfMonth(); // true * ``` - * - * @return bool */ - public function isLastOfMonth() + public function isLastOfMonth(): bool { return $this->day === $this->daysInMonth; } + /** + * Check if the instance is start of a given unit (tolerating a given interval). + * + * @example + * ``` + * // Check if a date-time is the first 15 minutes of the hour it's in + * Carbon::parse('2019-02-28 20:13:00')->isStartOfUnit(Unit::Hour, '15 minutes'); // true + * ``` + */ + public function isStartOfUnit( + Unit $unit, + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + mixed ...$params, + ): bool { + $interval ??= match ($unit) { + Unit::Day, Unit::Hour, Unit::Minute, Unit::Second, Unit::Millisecond, Unit::Microsecond => Unit::Microsecond, + default => Unit::Day, + }; + + $startOfUnit = $this->avoidMutation()->startOf($unit, ...$params); + $startOfUnitDateTime = $startOfUnit->rawFormat('Y-m-d H:i:s.u'); + $maximumDateTime = $startOfUnit + ->add($interval instanceof Unit ? '1 '.$interval->value : $interval) + ->rawFormat('Y-m-d H:i:s.u'); + + if ($maximumDateTime < $startOfUnitDateTime) { + return false; + } + + return $this->rawFormat('Y-m-d H:i:s.u') < $maximumDateTime; + } + + /** + * Check if the instance is end of a given unit (tolerating a given interval). + * + * @example + * ``` + * // Check if a date-time is the last 15 minutes of the hour it's in + * Carbon::parse('2019-02-28 20:13:00')->isEndOfUnit(Unit::Hour, '15 minutes'); // false + * ``` + */ + public function isEndOfUnit( + Unit $unit, + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + mixed ...$params, + ): bool { + $interval ??= match ($unit) { + Unit::Day, Unit::Hour, Unit::Minute, Unit::Second, Unit::Millisecond, Unit::Microsecond => Unit::Microsecond, + default => Unit::Day, + }; + + $endOfUnit = $this->avoidMutation()->endOf($unit, ...$params); + $endOfUnitDateTime = $endOfUnit->rawFormat('Y-m-d H:i:s.u'); + $minimumDateTime = $endOfUnit + ->sub($interval instanceof Unit ? '1 '.$interval->value : $interval) + ->rawFormat('Y-m-d H:i:s.u'); + + if ($minimumDateTime > $endOfUnitDateTime) { + return false; + } + + return $this->rawFormat('Y-m-d H:i:s.u') > $minimumDateTime; + } + + /** + * Determines if the instance is start of millisecond (first microsecond by default but interval can be customized). + */ + public function isStartOfMillisecond( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Millisecond, $interval); + } + + /** + * Determines if the instance is end of millisecond (last microsecond by default but interval can be customized). + */ + public function isEndOfMillisecond( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Millisecond, $interval); + } + + /** + * Determines if the instance is start of second (first microsecond by default but interval can be customized). + */ + public function isStartOfSecond( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Second, $interval); + } + + /** + * Determines if the instance is end of second (last microsecond by default but interval can be customized). + */ + public function isEndOfSecond( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Second, $interval); + } + + /** + * Determines if the instance is start of minute (first microsecond by default but interval can be customized). + */ + public function isStartOfMinute( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Minute, $interval); + } + + /** + * Determines if the instance is end of minute (last microsecond by default but interval can be customized). + */ + public function isEndOfMinute( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Minute, $interval); + } + + /** + * Determines if the instance is start of hour (first microsecond by default but interval can be customized). + */ + public function isStartOfHour( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Hour, $interval); + } + + /** + * Determines if the instance is end of hour (last microsecond by default but interval can be customized). + */ + public function isEndOfHour( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Hour, $interval); + } + /** * Check if the instance is start of day / midnight. * @@ -816,12 +896,47 @@ trait Comparison * Carbon::parse('2019-02-28 00:00:00.000012')->isStartOfDay(true); // false * ``` * - * @param bool $checkMicroseconds check time at microseconds precision - * - * @return bool + * @param bool $checkMicroseconds check time at microseconds precision + * @param Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval if an interval is specified it will be used as precision + * for instance with "15 minutes", it checks if current date-time + * is in the last 15 minutes of the day, with Unit::Hour, it + * checks if it's in the last hour of the day. */ - public function isStartOfDay($checkMicroseconds = false) - { + public function isStartOfDay( + Unit|DateInterval|Closure|CarbonConverterInterface|string|bool $checkMicroseconds = false, + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + if ($checkMicroseconds === true) { + @trigger_error( + "Since 3.8.0, it's deprecated to use \$checkMicroseconds.\n". + "It will be removed in 4.0.0.\n". + "Instead, you should use either isStartOfDay(interval: Unit::Microsecond) or isStartOfDay(interval: Unit::Second)\n". + 'And you can now use any custom interval as precision, such as isStartOfDay(interval: "15 minutes")', + \E_USER_DEPRECATED, + ); + } + + if ($interval === null && !\is_bool($checkMicroseconds)) { + $interval = $checkMicroseconds; + } + + if ($interval !== null) { + if ($interval instanceof Unit) { + $interval = '1 '.$interval->value; + } + + $date = $this->rawFormat('Y-m-d'); + $time = $this->rawFormat('H:i:s.u'); + $maximum = $this->avoidMutation()->startOfDay()->add($interval); + $maximumDate = $maximum->rawFormat('Y-m-d'); + + if ($date === $maximumDate) { + return $time < $maximum->rawFormat('H:i:s.u'); + } + + return $maximumDate > $date; + } + /* @var CarbonInterface $this */ return $checkMicroseconds ? $this->rawFormat('H:i:s.u') === '00:00:00.000000' @@ -842,18 +957,191 @@ trait Comparison * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(true); // false * ``` * - * @param bool $checkMicroseconds check time at microseconds precision - * - * @return bool + * @param bool $checkMicroseconds check time at microseconds precision + * @param Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval if an interval is specified it will be used as precision + * for instance with "15 minutes", it checks if current date-time + * is in the last 15 minutes of the day, with Unit::Hour, it + * checks if it's in the last hour of the day. */ - public function isEndOfDay($checkMicroseconds = false) - { + public function isEndOfDay( + Unit|DateInterval|Closure|CarbonConverterInterface|string|bool $checkMicroseconds = false, + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + if ($checkMicroseconds === true) { + @trigger_error( + "Since 3.8.0, it's deprecated to use \$checkMicroseconds.\n". + "It will be removed in 4.0.0.\n". + "Instead, you should use either isEndOfDay(interval: Unit::Microsecond) or isEndOfDay(interval: Unit::Second)\n". + 'And you can now use any custom interval as precision, such as isEndOfDay(interval: "15 minutes")', + \E_USER_DEPRECATED, + ); + } + + if ($interval === null && !\is_bool($checkMicroseconds)) { + $interval = $checkMicroseconds; + } + + if ($interval !== null) { + $date = $this->rawFormat('Y-m-d'); + $time = $this->rawFormat('H:i:s.u'); + $minimum = $this->avoidMutation() + ->endOfDay() + ->sub($interval instanceof Unit ? '1 '.$interval->value : $interval); + $minimumDate = $minimum->rawFormat('Y-m-d'); + + if ($date === $minimumDate) { + return $time > $minimum->rawFormat('H:i:s.u'); + } + + return $minimumDate < $date; + } + /* @var CarbonInterface $this */ return $checkMicroseconds ? $this->rawFormat('H:i:s.u') === '23:59:59.999999' : $this->rawFormat('H:i:s') === '23:59:59'; } + /** + * Determines if the instance is start of week (first day by default but interval can be customized). + * + * @example + * ``` + * Carbon::parse('2024-08-31')->startOfWeek()->isStartOfWeek(); // true + * Carbon::parse('2024-08-31')->isStartOfWeek(); // false + * ``` + */ + public function isStartOfWeek( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + WeekDay|int|null $weekStartsAt = null, + ): bool { + return $this->isStartOfUnit(Unit::Week, $interval, $weekStartsAt); + } + + /** + * Determines if the instance is end of week (last day by default but interval can be customized). + * + * @example + * ``` + * Carbon::parse('2024-08-31')->endOfWeek()->isEndOfWeek(); // true + * Carbon::parse('2024-08-31')->isEndOfWeek(); // false + * ``` + */ + public function isEndOfWeek( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + WeekDay|int|null $weekEndsAt = null, + ): bool { + return $this->isEndOfUnit(Unit::Week, $interval, $weekEndsAt); + } + + /** + * Determines if the instance is start of month (first day by default but interval can be customized). + */ + public function isStartOfMonth( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Month, $interval); + } + + /** + * Determines if the instance is end of month (last day by default but interval can be customized). + */ + public function isEndOfMonth( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Month, $interval); + } + + /** + * Determines if the instance is start of quarter (first day by default but interval can be customized). + */ + public function isStartOfQuarter( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Quarter, $interval); + } + + /** + * Determines if the instance is end of quarter (last day by default but interval can be customized). + */ + public function isEndOfQuarter( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Quarter, $interval); + } + + /** + * Determines if the instance is start of year (first day by default but interval can be customized). + */ + public function isStartOfYear( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Year, $interval); + } + + /** + * Determines if the instance is end of year (last day by default but interval can be customized). + */ + public function isEndOfYear( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Year, $interval); + } + + /** + * Determines if the instance is start of decade (first day by default but interval can be customized). + */ + public function isStartOfDecade( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Decade, $interval); + } + + /** + * Determines if the instance is end of decade (last day by default but interval can be customized). + */ + public function isEndOfDecade( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Decade, $interval); + } + + /** + * Determines if the instance is start of century (first day by default but interval can be customized). + */ + public function isStartOfCentury( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Century, $interval); + } + + /** + * Determines if the instance is end of century (last day by default but interval can be customized). + */ + public function isEndOfCentury( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Century, $interval); + } + + /** + * Determines if the instance is start of millennium (first day by default but interval can be customized). + */ + public function isStartOfMillennium( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isStartOfUnit(Unit::Millennium, $interval); + } + + /** + * Determines if the instance is end of millennium (last day by default but interval can be customized). + */ + public function isEndOfMillennium( + Unit|DateInterval|Closure|CarbonConverterInterface|string|null $interval = null, + ): bool { + return $this->isEndOfUnit(Unit::Millennium, $interval); + } + /** * Check if the instance is start of day / midnight. * @@ -863,10 +1151,8 @@ trait Comparison * Carbon::parse('2019-02-28 00:00:00.999999')->isMidnight(); // true * Carbon::parse('2019-02-28 00:00:01')->isMidnight(); // false * ``` - * - * @return bool */ - public function isMidnight() + public function isMidnight(): bool { return $this->isStartOfDay(); } @@ -881,10 +1167,8 @@ trait Comparison * Carbon::parse('2019-02-28 12:00:00.999999')->isMidday(); // true * Carbon::parse('2019-02-28 12:00:01')->isMidday(); // false * ``` - * - * @return bool */ - public function isMidday() + public function isMidday(): bool { /* @var CarbonInterface $this */ return $this->rawFormat('G:i:s') === static::$midDayAt.':00:00'; @@ -898,19 +1182,10 @@ trait Comparison * Carbon::hasFormat('11:12:45', 'h:i:s'); // true * Carbon::hasFormat('13:12:45', 'h:i:s'); // false * ``` - * - * @param string $date - * @param string $format - * - * @return bool */ - public static function hasFormat($date, $format) + public static function hasFormat(string $date, string $format): bool { - // createFromFormat() is known to handle edge cases silently. - // E.g. "1975-5-1" (Y-n-j) will still be parsed correctly when "Y-m-d" is supplied as the format. - // To ensure we're really testing against our desired format, perform an additional regex validation. - - return self::matchFormatPattern((string) $date, preg_quote((string) $format, '/'), static::$regexFormats); + return FactoryImmutable::getInstance()->hasFormat($date, $format); } /** @@ -927,9 +1202,9 @@ trait Comparison * * @return bool */ - public static function hasFormatWithModifiers($date, $format): bool + public static function hasFormatWithModifiers(?string $date, string $format): bool { - return self::matchFormatPattern((string) $date, (string) $format, array_merge(static::$regexFormats, static::$regexFormatModifiers)); + return FactoryImmutable::getInstance()->hasFormatWithModifiers($date, $format); } /** @@ -941,21 +1216,20 @@ trait Comparison * Carbon::canBeCreatedFromFormat('11:12:45', 'h:i:s'); // true * Carbon::canBeCreatedFromFormat('13:12:45', 'h:i:s'); // false * ``` - * - * @param string $date - * @param string $format - * - * @return bool */ - public static function canBeCreatedFromFormat($date, $format) + public static function canBeCreatedFromFormat(?string $date, string $format): bool { + if ($date === null) { + return false; + } + try { // Try to create a DateTime object. Throws an InvalidArgumentException if the provided time string // doesn't match the format in any way. if (!static::rawCreateFromFormat($format, $date)) { return false; } - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { return false; } @@ -983,11 +1257,13 @@ trait Comparison * ``` * * @param string $tester day name, month name, hour, date, etc. as string - * - * @return bool */ - public function is(string $tester) + public function is(WeekDay|Month|string $tester): bool { + if ($tester instanceof BackedEnum) { + $tester = $tester->name; + } + $tester = trim($tester); if (preg_match('/^\d+$/', $tester)) { @@ -995,21 +1271,27 @@ trait Comparison } if (preg_match('/^(?:Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December)$/i', $tester)) { - return $this->isSameMonth(static::parse($tester), false); + return $this->isSameMonth( + $this->transmitFactory(static fn () => static::parse("$tester 1st")), + false, + ); } if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) { - return $this->isSameMonth(static::parse($tester)); + return $this->isSameMonth( + $this->transmitFactory(static fn () => static::parse($tester)), + ); } - if (preg_match('/^\d{1,2}-\d{1,2}$/', $tester)) { - return $this->isSameDay(static::parse($this->year.'-'.$tester)); + if (preg_match('/^(\d{1,2})-(\d{1,2})$/', $tester, $match)) { + return $this->month === (int) $match[1] && $this->day === (int) $match[2]; } $modifier = preg_replace('/(\d)h$/i', '$1:00', $tester); /* @var CarbonInterface $max */ - $median = static::parse('5555-06-15 12:30:30.555555')->modify($modifier); + $median = $this->transmitFactory(static fn () => static::parse('5555-06-15 12:30:30.555555')) + ->modify($modifier); $current = $this->avoidMutation(); /* @var CarbonInterface $other */ $other = $this->avoidMutation()->modify($modifier); @@ -1032,7 +1314,7 @@ trait Comparison if (preg_match( '/^(?:january|february|march|april|may|june|july|august|september|october|november|december)(?:\s+\d+)?$/i', - $tester + $tester, )) { return $current->startOfMonth()->eq($other->startOfMonth()); } @@ -1057,42 +1339,6 @@ trait Comparison return $current->eq($other); } - /** - * Checks if the (date)time string is in a given format with - * given list of pattern replacements. - * - * @example - * ``` - * Carbon::hasFormat('11:12:45', 'h:i:s'); // true - * Carbon::hasFormat('13:12:45', 'h:i:s'); // false - * ``` - * - * @param string $date - * @param string $format - * @param array $replacements - * - * @return bool - */ - private static function matchFormatPattern(string $date, string $format, array $replacements): bool - { - // Preg quote, but remove escaped backslashes since we'll deal with escaped characters in the format string. - $regex = str_replace('\\\\', '\\', $format); - // Replace not-escaped letters - $regex = preg_replace_callback( - '/(?endOfTime ?? false; } - - private function discourageNull($value): void - { - if ($value === null) { - @trigger_error("Since 2.61.0, it's deprecated to compare a date to null, meaning of such comparison is ambiguous and will no longer be possible in 3.0.0, you should explicitly pass 'now' or make an other check to eliminate null values.", \E_USER_DEPRECATED); - } - } - - private function discourageBoolean($value): void - { - if (\is_bool($value)) { - @trigger_error("Since 2.61.0, it's deprecated to compare a date to true or false, meaning of such comparison is ambiguous and will no longer be possible in 3.0.0, you should explicitly pass 'now' or make an other check to eliminate boolean values.", \E_USER_DEPRECATED); - } - } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Converter.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Converter.php index fff8a600a..764c5d4f0 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Converter.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Converter.php @@ -1,5 +1,7 @@ localFormatFunction ?: static::$formatFunction; + $function = $this->localFormatFunction + ?? $this->getFactory()->getSettings()['formatFunction'] + ?? static::$formatFunction; if (!$function) { return $this->rawFormat($format); @@ -64,12 +63,8 @@ trait Converter /** * @see https://php.net/manual/en/datetime.format.php - * - * @param string $format - * - * @return string */ - public function rawFormat($format) + public function rawFormat(string $format): string { return parent::format($format); } @@ -81,12 +76,12 @@ trait Converter * ``` * echo Carbon::now(); // Carbon instances can be cast to string * ``` - * - * @return string */ - public function __toString() + public function __toString(): string { - $format = $this->localToStringFormat ?? static::$toStringFormat; + $format = $this->localToStringFormat + ?? $this->getFactory()->getSettings()['toStringFormat'] + ?? null; return $format instanceof Closure ? $format($this) @@ -104,10 +99,8 @@ trait Converter * ``` * echo Carbon::now()->toDateString(); * ``` - * - * @return string */ - public function toDateString() + public function toDateString(): string { return $this->rawFormat('Y-m-d'); } @@ -119,10 +112,8 @@ trait Converter * ``` * echo Carbon::now()->toFormattedDateString(); * ``` - * - * @return string */ - public function toFormattedDateString() + public function toFormattedDateString(): string { return $this->rawFormat('M j, Y'); } @@ -134,8 +125,6 @@ trait Converter * ``` * echo Carbon::now()->toFormattedDayDateString(); * ``` - * - * @return string */ public function toFormattedDayDateString(): string { @@ -149,12 +138,8 @@ trait Converter * ``` * echo Carbon::now()->toTimeString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toTimeString($unitPrecision = 'second') + public function toTimeString(string $unitPrecision = 'second'): string { return $this->rawFormat(static::getTimeFormatByPrecision($unitPrecision)); } @@ -166,12 +151,8 @@ trait Converter * ``` * echo Carbon::now()->toDateTimeString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toDateTimeString($unitPrecision = 'second') + public function toDateTimeString(string $unitPrecision = 'second'): string { return $this->rawFormat('Y-m-d '.static::getTimeFormatByPrecision($unitPrecision)); } @@ -180,25 +161,16 @@ trait Converter * Return a format from H:i to H:i:s.u according to given unit precision. * * @param string $unitPrecision "minute", "second", "millisecond" or "microsecond" - * - * @return string */ - public static function getTimeFormatByPrecision($unitPrecision) + public static function getTimeFormatByPrecision(string $unitPrecision): string { - switch (static::singularUnit($unitPrecision)) { - case 'minute': - return 'H:i'; - case 'second': - return 'H:i:s'; - case 'm': - case 'millisecond': - return 'H:i:s.v'; - case 'µ': - case 'microsecond': - return 'H:i:s.u'; - } - - throw new UnitException('Precision unit expected among: minute, second, millisecond and microsecond.'); + return match (static::singularUnit($unitPrecision)) { + 'minute' => 'H:i', + 'second' => 'H:i:s', + 'm', 'millisecond' => 'H:i:s.v', + 'µ', 'microsecond' => 'H:i:s.u', + default => throw new UnitException('Precision unit expected among: minute, second, millisecond and microsecond.'), + }; } /** @@ -210,12 +182,8 @@ trait Converter * echo "\n"; * echo Carbon::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toDateTimeLocalString($unitPrecision = 'second') + public function toDateTimeLocalString(string $unitPrecision = 'second'): string { return $this->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision)); } @@ -227,10 +195,8 @@ trait Converter * ``` * echo Carbon::now()->toDayDateTimeString(); * ``` - * - * @return string */ - public function toDayDateTimeString() + public function toDayDateTimeString(): string { return $this->rawFormat('D, M j, Y g:i A'); } @@ -242,10 +208,8 @@ trait Converter * ``` * echo Carbon::now()->toAtomString(); * ``` - * - * @return string */ - public function toAtomString() + public function toAtomString(): string { return $this->rawFormat(DateTime::ATOM); } @@ -257,12 +221,10 @@ trait Converter * ``` * echo Carbon::now()->toCookieString(); * ``` - * - * @return string */ - public function toCookieString() + public function toCookieString(): string { - return $this->rawFormat(DateTime::COOKIE); + return $this->rawFormat(DateTimeInterface::COOKIE); } /** @@ -272,10 +234,8 @@ trait Converter * ``` * echo Carbon::now()->toIso8601String(); * ``` - * - * @return string */ - public function toIso8601String() + public function toIso8601String(): string { return $this->toAtomString(); } @@ -287,12 +247,10 @@ trait Converter * ``` * echo Carbon::now()->toRfc822String(); * ``` - * - * @return string */ - public function toRfc822String() + public function toRfc822String(): string { - return $this->rawFormat(DateTime::RFC822); + return $this->rawFormat(DateTimeInterface::RFC822); } /** @@ -302,12 +260,8 @@ trait Converter * ``` * echo Carbon::now()->toIso8601ZuluString(); * ``` - * - * @param string $unitPrecision - * - * @return string */ - public function toIso8601ZuluString($unitPrecision = 'second') + public function toIso8601ZuluString(string $unitPrecision = 'second'): string { return $this->avoidMutation() ->utc() @@ -321,12 +275,10 @@ trait Converter * ``` * echo Carbon::now()->toRfc850String(); * ``` - * - * @return string */ - public function toRfc850String() + public function toRfc850String(): string { - return $this->rawFormat(DateTime::RFC850); + return $this->rawFormat(DateTimeInterface::RFC850); } /** @@ -336,12 +288,10 @@ trait Converter * ``` * echo Carbon::now()->toRfc1036String(); * ``` - * - * @return string */ - public function toRfc1036String() + public function toRfc1036String(): string { - return $this->rawFormat(DateTime::RFC1036); + return $this->rawFormat(DateTimeInterface::RFC1036); } /** @@ -351,12 +301,10 @@ trait Converter * ``` * echo Carbon::now()->toRfc1123String(); * ``` - * - * @return string */ - public function toRfc1123String() + public function toRfc1123String(): string { - return $this->rawFormat(DateTime::RFC1123); + return $this->rawFormat(DateTimeInterface::RFC1123); } /** @@ -366,35 +314,24 @@ trait Converter * ``` * echo Carbon::now()->toRfc2822String(); * ``` - * - * @return string */ - public function toRfc2822String() + public function toRfc2822String(): string { - return $this->rawFormat(DateTime::RFC2822); + return $this->rawFormat(DateTimeInterface::RFC2822); } /** - * Format the instance as RFC3339 - * - * @param bool $extended + * Format the instance as RFC3339. * * @example * ``` * echo Carbon::now()->toRfc3339String() . "\n"; * echo Carbon::now()->toRfc3339String(true) . "\n"; * ``` - * - * @return string */ - public function toRfc3339String($extended = false) + public function toRfc3339String(bool $extended = false): string { - $format = DateTime::RFC3339; - if ($extended) { - $format = DateTime::RFC3339_EXTENDED; - } - - return $this->rawFormat($format); + return $this->rawFormat($extended ? DateTimeInterface::RFC3339_EXTENDED : DateTimeInterface::RFC3339); } /** @@ -404,12 +341,10 @@ trait Converter * ``` * echo Carbon::now()->toRssString(); * ``` - * - * @return string */ - public function toRssString() + public function toRssString(): string { - return $this->rawFormat(DateTime::RSS); + return $this->rawFormat(DateTimeInterface::RSS); } /** @@ -419,12 +354,10 @@ trait Converter * ``` * echo Carbon::now()->toW3cString(); * ``` - * - * @return string */ - public function toW3cString() + public function toW3cString(): string { - return $this->rawFormat(DateTime::W3C); + return $this->rawFormat(DateTimeInterface::W3C); } /** @@ -434,10 +367,8 @@ trait Converter * ``` * echo Carbon::now()->toRfc7231String(); * ``` - * - * @return string */ - public function toRfc7231String() + public function toRfc7231String(): string { return $this->avoidMutation() ->setTimezone('GMT') @@ -451,10 +382,8 @@ trait Converter * ``` * var_dump(Carbon::now()->toArray()); * ``` - * - * @return array */ - public function toArray() + public function toArray(): array { return [ 'year' => $this->year, @@ -479,25 +408,21 @@ trait Converter * ``` * var_dump(Carbon::now()->toObject()); * ``` - * - * @return object */ - public function toObject() + public function toObject(): object { return (object) $this->toArray(); } /** - * Returns english human readable complete date string. + * Returns english human-readable complete date string. * * @example * ``` * echo Carbon::now()->toString(); * ``` - * - * @return string */ - public function toString() + public function toString(): string { return $this->avoidMutation()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); } @@ -513,20 +438,18 @@ trait Converter * ``` * * @param bool $keepOffset Pass true to keep the date offset. Else forced to UTC. - * - * @return null|string */ - public function toISOString($keepOffset = false) + public function toISOString(bool $keepOffset = false): ?string { if (!$this->isValid()) { return null; } $yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY'; - $tzFormat = $keepOffset ? 'Z' : '[Z]'; + $timezoneFormat = $keepOffset ? 'Z' : '[Z]'; $date = $keepOffset ? $this : $this->avoidMutation()->utc(); - return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat"); + return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$timezoneFormat"); } /** @@ -536,10 +459,8 @@ trait Converter * ``` * echo Carbon::now('America/Toronto')->toJSON(); * ``` - * - * @return null|string */ - public function toJSON() + public function toJSON(): ?string { return $this->toISOString(); } @@ -551,12 +472,11 @@ trait Converter * ``` * var_dump(Carbon::now()->toDateTime()); * ``` - * - * @return DateTime */ - public function toDateTime() + public function toDateTime(): DateTime { - return new DateTime($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone()); + return DateTime::createFromFormat('U.u', $this->rawFormat('U.u')) + ->setTimezone($this->getTimezone()); } /** @@ -566,12 +486,11 @@ trait Converter * ``` * var_dump(Carbon::now()->toDateTimeImmutable()); * ``` - * - * @return DateTimeImmutable */ - public function toDateTimeImmutable() + public function toDateTimeImmutable(): DateTimeImmutable { - return new DateTimeImmutable($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone()); + return DateTimeImmutable::createFromFormat('U.u', $this->rawFormat('U.u')) + ->setTimezone($this->getTimezone()); } /** @@ -583,10 +502,8 @@ trait Converter * ``` * var_dump(Carbon::now()->toDate()); * ``` - * - * @return DateTime */ - public function toDate() + public function toDate(): DateTime { return $this->toDateTime(); } @@ -597,30 +514,32 @@ trait Converter * @param \DateTimeInterface|Carbon|CarbonImmutable|int|null $end period end date or recurrences count if int * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit * @param string|null $unit if specified, $interval must be an integer - * - * @return CarbonPeriod */ - public function toPeriod($end = null, $interval = null, $unit = null) + public function toPeriod($end = null, $interval = null, $unit = null): CarbonPeriod { if ($unit) { $interval = CarbonInterval::make("$interval ".static::pluralUnit($unit)); } - $period = ($this->isMutable() ? new CarbonPeriod() : new CarbonPeriodImmutable()) - ->setDateClass(static::class) - ->setStartDate($this); - - if ($interval) { - $period = $period->setDateInterval($interval); - } + $isDefaultInterval = !$interval; + $interval ??= CarbonInterval::day(); + $class = $this->isMutable() ? CarbonPeriod::class : CarbonPeriodImmutable::class; if (\is_int($end) || (\is_string($end) && ctype_digit($end))) { - $period = $period->setRecurrences($end); - } elseif ($end) { - $period = $period->setEndDate($end); + $end = (int) $end; } - return $period; + $end ??= 1; + + if (!\is_int($end)) { + $end = $this->resolveCarbon($end); + } + + return new $class( + raw: [$this, CarbonInterval::make($interval), $end], + dateClass: static::class, + isDefaultInterval: $isDefaultInterval, + ); } /** @@ -629,10 +548,8 @@ trait Converter * @param \DateTimeInterface|Carbon|CarbonImmutable|null $end period end date * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit * @param string|null $unit if specified, $interval must be an integer - * - * @return CarbonPeriod */ - public function range($end = null, $interval = null, $unit = null) + public function range($end = null, $interval = null, $unit = null): CarbonPeriod { return $this->toPeriod($end, $interval, $unit); } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Creator.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Creator.php index 0d611ea22..9509e5bad 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Creator.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Creator.php @@ -1,5 +1,7 @@ constructTimezoneFromDateTime($time, $tz)->format('Y-m-d H:i:s.u'); + public function __construct( + DateTimeInterface|WeekDay|Month|string|int|float|null $time = null, + DateTimeZone|string|int|null $timezone = null, + ) { + $this->initLocalFactory(); + + if ($time instanceof Month) { + $time = $time->name.' 1'; + } elseif ($time instanceof WeekDay) { + $time = $time->name; + } elseif ($time instanceof DateTimeInterface) { + $time = $this->constructTimezoneFromDateTime($time, $timezone)->format('Y-m-d H:i:s.u'); } - if (is_numeric($time) && (!\is_string($time) || !preg_match('/^\d{1,14}$/', $time))) { + if (\is_string($time) && str_starts_with($time, '@')) { + $time = static::createFromTimestampUTC(substr($time, 1))->format('Y-m-d\TH:i:s.uP'); + } elseif (is_numeric($time) && (!\is_string($time) || !preg_match('/^\d{1,14}$/', $time))) { $time = static::createFromTimestampUTC($time)->format('Y-m-d\TH:i:s.uP'); } - // If the class has a test now set and we are trying to create a now() + // If the class has a test now set, and we are trying to create a now() // instance then override as required - $isNow = empty($time) || $time === 'now'; + $isNow = \in_array($time, [null, '', 'now'], true); + $timezone = static::safeCreateDateTimeZone($timezone) ?? null; - if (method_exists(static::class, 'hasTestNow') && - method_exists(static::class, 'getTestNow') && - static::hasTestNow() && + if ( + ($this->clock || ( + method_exists(static::class, 'hasTestNow') && + method_exists(static::class, 'getTestNow') && + static::hasTestNow() + )) && ($isNow || static::hasRelativeKeywords($time)) ) { - static::mockConstructorParameters($time, $tz); - } - - // Work-around for PHP bug https://bugs.php.net/bug.php?id=67127 - if (!str_contains((string) .1, '.')) { - $locale = setlocale(LC_NUMERIC, '0'); // @codeCoverageIgnore - setlocale(LC_NUMERIC, 'C'); // @codeCoverageIgnore + $this->mockConstructorParameters($time, $timezone); } try { - parent::__construct($time ?: 'now', static::safeCreateDateTimeZone($tz) ?: null); + parent::__construct($time ?? 'now', $timezone); } catch (Exception $exception) { throw new InvalidFormatException($exception->getMessage(), 0, $exception); } $this->constructedObjectId = spl_object_hash($this); - if (isset($locale)) { - setlocale(LC_NUMERIC, $locale); // @codeCoverageIgnore - } - self::setLastErrors(parent::getLastErrors()); } /** * Get timezone from a datetime instance. - * - * @param DateTimeInterface $date - * @param DateTimeZone|string|null $tz - * - * @return DateTimeInterface */ - private function constructTimezoneFromDateTime(DateTimeInterface $date, &$tz) - { - if ($tz !== null) { - $safeTz = static::safeCreateDateTimeZone($tz); + private function constructTimezoneFromDateTime( + DateTimeInterface $date, + DateTimeZone|string|int|null &$timezone, + ): DateTimeInterface { + if ($timezone !== null) { + $safeTz = static::safeCreateDateTimeZone($timezone); if ($safeTz) { - return ($date instanceof DateTimeImmutable ? $date : clone $date)->setTimezone($safeTz); + $date = ($date instanceof DateTimeImmutable ? $date : clone $date)->setTimezone($safeTz); } return $date; } - $tz = $date->getTimezone(); + $timezone = $date->getTimezone(); return $date; } @@ -128,27 +132,22 @@ trait Creator /** * Update constructedObjectId on cloned. */ - public function __clone() + public function __clone(): void { $this->constructedObjectId = spl_object_hash($this); } /** * Create a Carbon instance from a DateTime one. - * - * @param DateTimeInterface $date - * - * @return static */ - public static function instance($date) + public static function instance(DateTimeInterface $date): static { if ($date instanceof static) { return clone $date; } - static::expectDateTime($date); - - $instance = new static($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); + $instance = parent::createFromFormat('U.u', $date->format('U.u')) + ->setTimezone($date->getTimezone()); if ($date instanceof CarbonInterface) { $settings = $date->getSettings(); @@ -170,35 +169,29 @@ trait Creator * as it allows you to do Carbon::parse('Monday next week')->fn() rather * than (new Carbon('Monday next week'))->fn(). * - * @param string|DateTimeInterface|null $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function rawParse($time = null, $tz = null) - { + public static function rawParse( + DateTimeInterface|WeekDay|Month|string|int|float|null $time, + DateTimeZone|string|int|null $timezone = null, + ): static { if ($time instanceof DateTimeInterface) { return static::instance($time); } try { - return new static($time, $tz); + return new static($time, $timezone); } catch (Exception $exception) { // @codeCoverageIgnoreStart try { - $date = @static::now($tz)->change($time); - } catch (DateMalformedStringException $ignoredException) { + $date = @static::now($timezone)->change($time); + } catch (DateMalformedStringException|InvalidFormatException) { $date = null; } // @codeCoverageIgnoreEnd - if (!$date) { - throw new InvalidFormatException("Could not parse '$time': ".$exception->getMessage(), 0, $exception); - } - - return $date; + return $date + ?? throw new InvalidFormatException("Could not parse '$time': ".$exception->getMessage(), 0, $exception); } } @@ -209,19 +202,16 @@ trait Creator * as it allows you to do Carbon::parse('Monday next week')->fn() rather * than (new Carbon('Monday next week'))->fn(). * - * @param string|DateTimeInterface|null $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function parse($time = null, $tz = null) - { + public static function parse( + DateTimeInterface|WeekDay|Month|string|int|float|null $time, + DateTimeZone|string|int|null $timezone = null, + ): static { $function = static::$parseFunction; if (!$function) { - return static::rawParse($time, $tz); + return static::rawParse($time, $timezone); } if (\is_string($function) && method_exists(static::class, $function)) { @@ -234,120 +224,75 @@ trait Creator /** * Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.). * - * @param string $time date/time string in the given language (may also contain English). - * @param string|null $locale if locale is null or not specified, current global locale will be - * used instead. - * @param DateTimeZone|string|null $tz optional timezone for the new instance. + * @param string $time date/time string in the given language (may also contain English). + * @param string|null $locale if locale is null or not specified, current global locale will be + * used instead. + * @param DateTimeZone|string|int|null $timezone optional timezone for the new instance. * * @throws InvalidFormatException - * - * @return static */ - public static function parseFromLocale($time, $locale = null, $tz = null) - { - return static::rawParse(static::translateTimeString($time, $locale, 'en'), $tz); + public static function parseFromLocale( + string $time, + ?string $locale = null, + DateTimeZone|string|int|null $timezone = null, + ): static { + return static::rawParse(static::translateTimeString($time, $locale, static::DEFAULT_LOCALE), $timezone); } /** * Get a Carbon instance for the current date and time. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function now($tz = null) + public static function now(DateTimeZone|string|int|null $timezone = null): static { - return new static(null, $tz); + return new static(null, $timezone); } /** * Create a Carbon instance for today. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function today($tz = null) + public static function today(DateTimeZone|string|int|null $timezone = null): static { - return static::rawParse('today', $tz); + return static::rawParse('today', $timezone); } /** * Create a Carbon instance for tomorrow. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function tomorrow($tz = null) + public static function tomorrow(DateTimeZone|string|int|null $timezone = null): static { - return static::rawParse('tomorrow', $tz); + return static::rawParse('tomorrow', $timezone); } /** * Create a Carbon instance for yesterday. - * - * @param DateTimeZone|string|null $tz - * - * @return static */ - public static function yesterday($tz = null) + public static function yesterday(DateTimeZone|string|int|null $timezone = null): static { - return static::rawParse('yesterday', $tz); + return static::rawParse('yesterday', $timezone); } - /** - * Create a Carbon instance for the greatest supported date. - * - * @return static - */ - public static function maxValue() - { - if (self::$PHPIntSize === 4) { - // 32 bit - return static::createFromTimestamp(PHP_INT_MAX); // @codeCoverageIgnore - } - - // 64 bit - return static::create(9999, 12, 31, 23, 59, 59); - } - - /** - * Create a Carbon instance for the lowest supported date. - * - * @return static - */ - public static function minValue() - { - if (self::$PHPIntSize === 4) { - // 32 bit - return static::createFromTimestamp(~PHP_INT_MAX); // @codeCoverageIgnore - } - - // 64 bit - return static::create(1, 1, 1, 0, 0, 0); - } - - private static function assertBetween($unit, $value, $min, $max) + private static function assertBetween($unit, $value, $min, $max): void { if (static::isStrictModeEnabled() && ($value < $min || $value > $max)) { throw new OutOfRangeException($unit, $min, $max, $value); } } - private static function createNowInstance($tz) + private static function createNowInstance($timezone) { if (!static::hasTestNow()) { - return static::now($tz); + return static::now($timezone); } $now = static::getTestNow(); if ($now instanceof Closure) { - return $now(static::now($tz)); + return $now(static::now($timezone)); } - return $now->avoidMutation()->tz($tz); + $now = $now->avoidMutation(); + + return $timezone === null ? $now : $now->setTimezone($timezone); } /** @@ -362,28 +307,30 @@ trait Creator * If $hour is not null then the default values for $minute and $second * will be 0. * - * @param DateTimeInterface|int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param DateTimeInterface|string|int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null) + public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null): ?static { + $month = self::monthToInt($month); + if ((\is_string($year) && !is_numeric($year)) || $year instanceof DateTimeInterface) { - return static::parse($year, $tz ?: (\is_string($month) || $month instanceof DateTimeZone ? $month : null)); + return static::parse($year, $timezone ?? (\is_string($month) || $month instanceof DateTimeZone ? $month : null)); } $defaults = null; - $getDefault = function ($unit) use ($tz, &$defaults) { + $getDefault = function ($unit) use ($timezone, &$defaults) { if ($defaults === null) { - $now = self::createNowInstance($tz); + $now = self::createNowInstance($timezone); $defaults = array_combine([ 'year', @@ -422,13 +369,13 @@ trait Creator } $second = ($second < 10 ? '0' : '').number_format($second, 6); - $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz); + $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', \sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $timezone); - if ($fixYear !== null) { + if ($instance && $fixYear !== null) { $instance = $instance->addYears($fixYear); } - return $instance; + return $instance ?? null; } /** @@ -446,20 +393,21 @@ trait Creator * If one of the set values is not valid, an InvalidDateException * will be thrown. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidDateException * - * @return static|false + * @return static|null */ - public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) + public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null): ?static { + $month = self::monthToInt($month); $fields = static::getRangesByUnit(); foreach ($fields as $field => $range) { @@ -468,11 +416,11 @@ trait Creator throw new InvalidDateException($field, $$field); } - return false; + return null; } } - $instance = static::create($year, $month, $day, $hour, $minute, $second, $tz); + $instance = static::create($year, $month, $day, $hour, $minute, $second, $timezone); foreach (array_reverse($fields) as $field => $range) { if ($$field !== null && (!\is_int($$field) || $$field !== $instance->$field)) { @@ -480,7 +428,7 @@ trait Creator throw new InvalidDateException($field, $$field); } - return false; + return null; } } @@ -492,25 +440,25 @@ trait Creator * * @see create() * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null): self + public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null): static { $initialStrictMode = static::isStrictModeEnabled(); static::useStrictMode(true); try { - $date = static::create($year, $month, $day, $hour, $minute, $second, $tz); + $date = static::create($year, $month, $day, $hour, $minute, $second, $timezone); } finally { static::useStrictMode($initialStrictMode); } @@ -521,114 +469,101 @@ trait Creator /** * Create a Carbon instance from just a date. The time portion is set to now. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createFromDate($year = null, $month = null, $day = null, $tz = null) + public static function createFromDate($year = null, $month = null, $day = null, $timezone = null) { - return static::create($year, $month, $day, null, null, null, $tz); + return static::create($year, $month, $day, null, null, null, $timezone); } /** * Create a Carbon instance from just a date. The time portion is set to midnight. * - * @param int|null $year - * @param int|null $month - * @param int|null $day - * @param DateTimeZone|string|null $tz + * @param int|null $year + * @param int|null $month + * @param int|null $day + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createMidnightDate($year = null, $month = null, $day = null, $tz = null) + public static function createMidnightDate($year = null, $month = null, $day = null, $timezone = null) { - return static::create($year, $month, $day, 0, 0, 0, $tz); + return static::create($year, $month, $day, 0, 0, 0, $timezone); } /** * Create a Carbon instance from just a time. The date portion is set to today. * - * @param int|null $hour - * @param int|null $minute - * @param int|null $second - * @param DateTimeZone|string|null $tz + * @param int|null $hour + * @param int|null $minute + * @param int|null $second + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * * @return static */ - public static function createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null) + public static function createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null): static { - return static::create(null, null, null, $hour, $minute, $second, $tz); + return static::create(null, null, null, $hour, $minute, $second, $timezone); } /** * Create a Carbon instance from a time string. The date portion is set to today. * - * @param string $time - * @param DateTimeZone|string|null $tz - * * @throws InvalidFormatException - * - * @return static */ - public static function createFromTimeString($time, $tz = null) + public static function createFromTimeString(string $time, DateTimeZone|string|int|null $timezone = null): static { - return static::today($tz)->setTimeFromTimeString($time); + return static::today($timezone)->setTimeFromTimeString($time); } - /** - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $originalTz - * - * @return DateTimeInterface|false - */ - private static function createFromFormatAndTimezone($format, $time, $originalTz) + private static function createFromFormatAndTimezone( + string $format, + string $time, + DateTimeZone|string|int|null $originalTimezone, + ): ?DateTimeInterface { + if ($originalTimezone === null) { + return parent::createFromFormat($format, $time) ?: null; + } + + $timezone = \is_int($originalTimezone) ? self::getOffsetTimezone($originalTimezone) : $originalTimezone; + + $timezone = static::safeCreateDateTimeZone($timezone, $originalTimezone); + + return parent::createFromFormat($format, $time, $timezone) ?: null; + } + + private static function getOffsetTimezone(int $offset): string { - // Work-around for https://bugs.php.net/bug.php?id=75577 - // @codeCoverageIgnoreStart - if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) { - $format = str_replace('.v', '.u', $format); - } - // @codeCoverageIgnoreEnd + $minutes = (int) ($offset * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE); - if ($originalTz === null) { - return parent::createFromFormat($format, (string) $time); - } - - $tz = \is_int($originalTz) - ? @timezone_name_from_abbr('', (int) ($originalTz * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE), 1) - : $originalTz; - - $tz = static::safeCreateDateTimeZone($tz, $originalTz); - - if ($tz === false) { - return false; - } - - return parent::createFromFormat($format, (string) $time, $tz); + return @timezone_name_from_abbr('', $minutes, 1) ?: throw new InvalidTimeZoneException( + "Invalid offset timezone $offset", + ); } /** * Create a Carbon instance from a specific format. * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function rawCreateFromFormat($format, $time, $tz = null) + public static function rawCreateFromFormat(string $format, string $time, $timezone = null): ?static { // Work-around for https://bugs.php.net/bug.php?id=80141 $format = preg_replace('/(?getTimezone(); + if ($timezone === null && !preg_match("/{$nonEscaped}[eOPT]/", $nonIgnored)) { + $timezone = clone $mock->getTimezone(); } $mock = $mock->copy(); @@ -676,7 +611,7 @@ trait Creator } // Regenerate date from the modified format to base result on the mocked instance instead of now. - $date = self::createFromFormatAndTimezone($format, $time, $tz); + $date = self::createFromFormatAndTimezone($format, $time, $timezone); } if ($date instanceof DateTimeInterface) { @@ -687,30 +622,43 @@ trait Creator } if (static::isStrictModeEnabled()) { - throw new InvalidFormatException(implode(PHP_EOL, $lastErrors['errors'])); + throw new InvalidFormatException(implode(PHP_EOL, (array) $lastErrors['errors'])); } - return false; + return null; } /** * Create a Carbon instance from a specific format. * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ #[ReturnTypeWillChange] - public static function createFromFormat($format, $time, $tz = null) + public static function createFromFormat($format, $time, $timezone = null): ?static { $function = static::$createFromFormatFunction; + // format is a single numeric unit + if (\is_int($time) && \in_array(ltrim($format, '!'), ['U', 'Y', 'y', 'X', 'x', 'm', 'n', 'd', 'j', 'w', 'W', 'H', 'h', 'G', 'g', 'i', 's', 'u', 'z', 'v'], true)) { + $time = (string) $time; + } + + if (!\is_string($time)) { + @trigger_error( + 'createFromFormat() $time parameter will only accept string or integer for 1-letter format representing a numeric unit in the next version', + \E_USER_DEPRECATED, + ); + $time = (string) $time; + } + if (!$function) { - return static::rawCreateFromFormat($format, $time, $tz); + return static::rawCreateFromFormat($format, $time, $timezone); } if (\is_string($function) && method_exists(static::class, $function)) { @@ -723,42 +671,45 @@ trait Creator /** * Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()). * - * @param string $format Datetime format - * @param string $time - * @param DateTimeZone|string|false|null $tz optional timezone - * @param string|null $locale locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use) - * @param \Symfony\Component\Translation\TranslatorInterface $translator optional custom translator to use for macro-formats + * @param string $format Datetime format + * @param string $time + * @param DateTimeZone|string|int|null $timezone optional timezone + * @param string|null $locale locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use) + * @param TranslatorInterface|null $translator optional custom translator to use for macro-formats * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null) - { + public static function createFromIsoFormat( + string $format, + string $time, + $timezone = null, + ?string $locale = CarbonInterface::DEFAULT_LOCALE, + ?TranslatorInterface $translator = null + ): ?static { $format = preg_replace_callback('/(? static::getTranslationMessageWith($translator, 'formats.LT', $locale, 'h:mm A'), - 'LTS' => static::getTranslationMessageWith($translator, 'formats.LTS', $locale, 'h:mm:ss A'), - 'L' => static::getTranslationMessageWith($translator, 'formats.L', $locale, 'MM/DD/YYYY'), - 'LL' => static::getTranslationMessageWith($translator, 'formats.LL', $locale, 'MMMM D, YYYY'), - 'LLL' => static::getTranslationMessageWith($translator, 'formats.LLL', $locale, 'MMMM D, YYYY h:mm A'), - 'LLLL' => static::getTranslationMessageWith($translator, 'formats.LLLL', $locale, 'dddd, MMMM D, YYYY h:mm A'), + 'LT' => static::getTranslationMessageWith($translator, 'formats.LT', $locale), + 'LTS' => static::getTranslationMessageWith($translator, 'formats.LTS', $locale), + 'L' => static::getTranslationMessageWith($translator, 'formats.L', $locale), + 'LL' => static::getTranslationMessageWith($translator, 'formats.LL', $locale), + 'LLL' => static::getTranslationMessageWith($translator, 'formats.LLL', $locale), + 'LLLL' => static::getTranslationMessageWith($translator, 'formats.LLLL', $locale), ]; } return $formats[$code] ?? preg_replace_callback( '/MMMM|MM|DD|dddd/', - function ($code) { - return mb_substr($code[0], 1); - }, - $formats[strtoupper($code)] ?? '' + static fn (array $code) => mb_substr($code[0], 1), + $formats[strtoupper($code)] ?? '', ); }, $format); @@ -859,28 +810,28 @@ trait Creator return $format; }, $format); - return static::rawCreateFromFormat($format, $time, $tz); + return static::rawCreateFromFormat($format, $time, $timezone); } /** * Create a Carbon instance from a specific format and a string in a given language. * - * @param string $format Datetime format - * @param string $locale - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime format + * @param string $locale + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromLocaleFormat($format, $locale, $time, $tz = null) + public static function createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null): ?static { $format = preg_replace_callback( '/(?:\\\\[a-zA-Z]|[bfkqCEJKQRV]){2,}/', static function (array $match) use ($locale): string { $word = str_replace('\\', '', $match[0]); - $translatedWord = static::translateTimeString($word, $locale, 'en'); + $translatedWord = static::translateTimeString($word, $locale, static::DEFAULT_LOCALE); return $word === $translatedWord ? $match[0] @@ -889,26 +840,26 @@ trait Creator $format ); - return static::rawCreateFromFormat($format, static::translateTimeString($time, $locale, 'en'), $tz); + return static::rawCreateFromFormat($format, static::translateTimeString($time, $locale, static::DEFAULT_LOCALE), $timezone); } /** * Create a Carbon instance from a specific ISO format and a string in a given language. * - * @param string $format Datetime ISO format - * @param string $locale - * @param string $time - * @param DateTimeZone|string|false|null $tz + * @param string $format Datetime ISO format + * @param string $locale + * @param string $time + * @param DateTimeZone|string|int|null $timezone * * @throws InvalidFormatException * - * @return static|false + * @return static|null */ - public static function createFromLocaleIsoFormat($format, $locale, $time, $tz = null) + public static function createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null): ?static { - $time = static::translateTimeString($time, $locale, 'en', CarbonInterface::TRANSLATE_MONTHS | CarbonInterface::TRANSLATE_DAYS | CarbonInterface::TRANSLATE_MERIDIEM); + $time = static::translateTimeString($time, $locale, static::DEFAULT_LOCALE, CarbonInterface::TRANSLATE_MONTHS | CarbonInterface::TRANSLATE_DAYS | CarbonInterface::TRANSLATE_MERIDIEM); - return static::createFromIsoFormat($format, $time, $tz, $locale); + return static::createFromIsoFormat($format, $time, $timezone, $locale); } /** @@ -923,7 +874,7 @@ trait Creator * * @return static|null */ - public static function make($var) + public static function make($var, DateTimeZone|string|null $timezone = null): ?static { if ($var instanceof DateTimeInterface) { return static::instance($var); @@ -938,7 +889,7 @@ trait Creator !preg_match('/^R\d/', $var) && preg_match('/[a-z\d]/i', $var) ) { - $date = static::parse($var); + $date = static::parse($var, $timezone); } } @@ -952,7 +903,7 @@ trait Creator * * @return void */ - private static function setLastErrors($lastErrors) + private static function setLastErrors($lastErrors): void { if (\is_array($lastErrors) || $lastErrors === false) { static::$lastErrors = \is_array($lastErrors) ? $lastErrors : [ @@ -966,12 +917,22 @@ trait Creator /** * {@inheritdoc} - * - * @return array */ - #[ReturnTypeWillChange] - public static function getLastErrors() + public static function getLastErrors(): array|false { - return static::$lastErrors; + return static::$lastErrors ?? false; + } + + private static function monthToInt(mixed $value, string $unit = 'month'): mixed + { + if ($value instanceof Month) { + if ($unit !== 'month') { + throw new UnitException("Month enum cannot be used to set $unit"); + } + + return Month::int($value); + } + + return $value; } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Date.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Date.php index 8ae5c1781..14b9abafa 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Date.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Date.php @@ -1,5 +1,7 @@ * + * @property string $localeDayOfWeek the day of week in current locale + * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale + * @property string $localeMonth the month in current locale + * @property string $shortLocaleMonth the abbreviated month in current locale * @property int $year * @property int $yearIso * @property int $month @@ -52,6 +62,7 @@ use Throwable; * @property int $second * @property int $micro * @property int $microsecond + * @property int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) * @property int|float|string $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English @@ -64,17 +75,90 @@ use Throwable; * @property int $isoWeek 1 through 53 * @property int $weekYear year according to week format * @property int $isoWeekYear year according to ISO week format - * @property int $dayOfYear 1 through 366 * @property int $age does a diffInYears() with default parameters * @property int $offset the timezone offset in seconds from UTC * @property int $offsetMinutes the timezone offset in minutes from UTC * @property int $offsetHours the timezone offset in hours from UTC * @property CarbonTimeZone $timezone the current timezone * @property CarbonTimeZone $tz alias of $timezone - * @property-read int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) - * @property-read int $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month + * @property int $centuryOfMillennium The value of the century starting from the beginning of the current millennium + * @property int $dayOfCentury The value of the day starting from the beginning of the current century + * @property int $dayOfDecade The value of the day starting from the beginning of the current decade + * @property int $dayOfMillennium The value of the day starting from the beginning of the current millennium + * @property int $dayOfMonth The value of the day starting from the beginning of the current month + * @property int $dayOfQuarter The value of the day starting from the beginning of the current quarter + * @property int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) + * @property int $dayOfYear 1 through 366 + * @property int $decadeOfCentury The value of the decade starting from the beginning of the current century + * @property int $decadeOfMillennium The value of the decade starting from the beginning of the current millennium + * @property int $hourOfCentury The value of the hour starting from the beginning of the current century + * @property int $hourOfDay The value of the hour starting from the beginning of the current day + * @property int $hourOfDecade The value of the hour starting from the beginning of the current decade + * @property int $hourOfMillennium The value of the hour starting from the beginning of the current millennium + * @property int $hourOfMonth The value of the hour starting from the beginning of the current month + * @property int $hourOfQuarter The value of the hour starting from the beginning of the current quarter + * @property int $hourOfWeek The value of the hour starting from the beginning of the current week + * @property int $hourOfYear The value of the hour starting from the beginning of the current year + * @property int $microsecondOfCentury The value of the microsecond starting from the beginning of the current century + * @property int $microsecondOfDay The value of the microsecond starting from the beginning of the current day + * @property int $microsecondOfDecade The value of the microsecond starting from the beginning of the current decade + * @property int $microsecondOfHour The value of the microsecond starting from the beginning of the current hour + * @property int $microsecondOfMillennium The value of the microsecond starting from the beginning of the current millennium + * @property int $microsecondOfMillisecond The value of the microsecond starting from the beginning of the current millisecond + * @property int $microsecondOfMinute The value of the microsecond starting from the beginning of the current minute + * @property int $microsecondOfMonth The value of the microsecond starting from the beginning of the current month + * @property int $microsecondOfQuarter The value of the microsecond starting from the beginning of the current quarter + * @property int $microsecondOfSecond The value of the microsecond starting from the beginning of the current second + * @property int $microsecondOfWeek The value of the microsecond starting from the beginning of the current week + * @property int $microsecondOfYear The value of the microsecond starting from the beginning of the current year + * @property int $millisecondOfCentury The value of the millisecond starting from the beginning of the current century + * @property int $millisecondOfDay The value of the millisecond starting from the beginning of the current day + * @property int $millisecondOfDecade The value of the millisecond starting from the beginning of the current decade + * @property int $millisecondOfHour The value of the millisecond starting from the beginning of the current hour + * @property int $millisecondOfMillennium The value of the millisecond starting from the beginning of the current millennium + * @property int $millisecondOfMinute The value of the millisecond starting from the beginning of the current minute + * @property int $millisecondOfMonth The value of the millisecond starting from the beginning of the current month + * @property int $millisecondOfQuarter The value of the millisecond starting from the beginning of the current quarter + * @property int $millisecondOfSecond The value of the millisecond starting from the beginning of the current second + * @property int $millisecondOfWeek The value of the millisecond starting from the beginning of the current week + * @property int $millisecondOfYear The value of the millisecond starting from the beginning of the current year + * @property int $minuteOfCentury The value of the minute starting from the beginning of the current century + * @property int $minuteOfDay The value of the minute starting from the beginning of the current day + * @property int $minuteOfDecade The value of the minute starting from the beginning of the current decade + * @property int $minuteOfHour The value of the minute starting from the beginning of the current hour + * @property int $minuteOfMillennium The value of the minute starting from the beginning of the current millennium + * @property int $minuteOfMonth The value of the minute starting from the beginning of the current month + * @property int $minuteOfQuarter The value of the minute starting from the beginning of the current quarter + * @property int $minuteOfWeek The value of the minute starting from the beginning of the current week + * @property int $minuteOfYear The value of the minute starting from the beginning of the current year + * @property int $monthOfCentury The value of the month starting from the beginning of the current century + * @property int $monthOfDecade The value of the month starting from the beginning of the current decade + * @property int $monthOfMillennium The value of the month starting from the beginning of the current millennium + * @property int $monthOfQuarter The value of the month starting from the beginning of the current quarter + * @property int $monthOfYear The value of the month starting from the beginning of the current year + * @property int $quarterOfCentury The value of the quarter starting from the beginning of the current century + * @property int $quarterOfDecade The value of the quarter starting from the beginning of the current decade + * @property int $quarterOfMillennium The value of the quarter starting from the beginning of the current millennium + * @property int $quarterOfYear The value of the quarter starting from the beginning of the current year + * @property int $secondOfCentury The value of the second starting from the beginning of the current century + * @property int $secondOfDay The value of the second starting from the beginning of the current day + * @property int $secondOfDecade The value of the second starting from the beginning of the current decade + * @property int $secondOfHour The value of the second starting from the beginning of the current hour + * @property int $secondOfMillennium The value of the second starting from the beginning of the current millennium + * @property int $secondOfMinute The value of the second starting from the beginning of the current minute + * @property int $secondOfMonth The value of the second starting from the beginning of the current month + * @property int $secondOfQuarter The value of the second starting from the beginning of the current quarter + * @property int $secondOfWeek The value of the second starting from the beginning of the current week + * @property int $secondOfYear The value of the second starting from the beginning of the current year + * @property int $weekOfCentury The value of the week starting from the beginning of the current century + * @property int $weekOfDecade The value of the week starting from the beginning of the current decade + * @property int $weekOfMillennium The value of the week starting from the beginning of the current millennium + * @property int $weekOfMonth 1 through 5 + * @property int $weekOfQuarter The value of the week starting from the beginning of the current quarter + * @property int $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property int $yearOfCentury The value of the year starting from the beginning of the current century + * @property int $yearOfDecade The value of the year starting from the beginning of the current decade + * @property int $yearOfMillennium The value of the year starting from the beginning of the current millennium * @property-read string $latinMeridiem "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark) * @property-read string $latinUpperMeridiem "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark) * @property-read string $timezoneAbbreviatedName the current timezone abbreviated name @@ -87,13 +171,10 @@ use Throwable; * @property-read string $meridiem lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language * @property-read string $upperMeridiem uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language * @property-read int $noZeroHour current hour from 1 to 24 - * @property-read int $weeksInYear 51 through 53 * @property-read int $isoWeeksInYear 51 through 53 - * @property-read int $weekOfMonth 1 through 5 * @property-read int $weekNumberInMonth 1 through 5 * @property-read int $firstWeekDay 0 through 6 * @property-read int $lastWeekDay 0 through 6 - * @property-read int $daysInYear 365 or 366 * @property-read int $quarter the quarter of this instance, 1 - 4 * @property-read int $decade the decade of this instance * @property-read int $century the century of this instance @@ -104,6 +185,84 @@ use Throwable; * @property-read string $timezoneName the current timezone name * @property-read string $tzName alias of $timezoneName * @property-read string $locale locale of the current instance + * @property-read int $centuriesInMillennium The number of centuries contained in the current millennium + * @property-read int $daysInCentury The number of days contained in the current century + * @property-read int $daysInDecade The number of days contained in the current decade + * @property-read int $daysInMillennium The number of days contained in the current millennium + * @property-read int $daysInMonth number of days in the given month + * @property-read int $daysInQuarter The number of days contained in the current quarter + * @property-read int $daysInWeek The number of days contained in the current week + * @property-read int $daysInYear 365 or 366 + * @property-read int $decadesInCentury The number of decades contained in the current century + * @property-read int $decadesInMillennium The number of decades contained in the current millennium + * @property-read int $hoursInCentury The number of hours contained in the current century + * @property-read int $hoursInDay The number of hours contained in the current day + * @property-read int $hoursInDecade The number of hours contained in the current decade + * @property-read int $hoursInMillennium The number of hours contained in the current millennium + * @property-read int $hoursInMonth The number of hours contained in the current month + * @property-read int $hoursInQuarter The number of hours contained in the current quarter + * @property-read int $hoursInWeek The number of hours contained in the current week + * @property-read int $hoursInYear The number of hours contained in the current year + * @property-read int $microsecondsInCentury The number of microseconds contained in the current century + * @property-read int $microsecondsInDay The number of microseconds contained in the current day + * @property-read int $microsecondsInDecade The number of microseconds contained in the current decade + * @property-read int $microsecondsInHour The number of microseconds contained in the current hour + * @property-read int $microsecondsInMillennium The number of microseconds contained in the current millennium + * @property-read int $microsecondsInMillisecond The number of microseconds contained in the current millisecond + * @property-read int $microsecondsInMinute The number of microseconds contained in the current minute + * @property-read int $microsecondsInMonth The number of microseconds contained in the current month + * @property-read int $microsecondsInQuarter The number of microseconds contained in the current quarter + * @property-read int $microsecondsInSecond The number of microseconds contained in the current second + * @property-read int $microsecondsInWeek The number of microseconds contained in the current week + * @property-read int $microsecondsInYear The number of microseconds contained in the current year + * @property-read int $millisecondsInCentury The number of milliseconds contained in the current century + * @property-read int $millisecondsInDay The number of milliseconds contained in the current day + * @property-read int $millisecondsInDecade The number of milliseconds contained in the current decade + * @property-read int $millisecondsInHour The number of milliseconds contained in the current hour + * @property-read int $millisecondsInMillennium The number of milliseconds contained in the current millennium + * @property-read int $millisecondsInMinute The number of milliseconds contained in the current minute + * @property-read int $millisecondsInMonth The number of milliseconds contained in the current month + * @property-read int $millisecondsInQuarter The number of milliseconds contained in the current quarter + * @property-read int $millisecondsInSecond The number of milliseconds contained in the current second + * @property-read int $millisecondsInWeek The number of milliseconds contained in the current week + * @property-read int $millisecondsInYear The number of milliseconds contained in the current year + * @property-read int $minutesInCentury The number of minutes contained in the current century + * @property-read int $minutesInDay The number of minutes contained in the current day + * @property-read int $minutesInDecade The number of minutes contained in the current decade + * @property-read int $minutesInHour The number of minutes contained in the current hour + * @property-read int $minutesInMillennium The number of minutes contained in the current millennium + * @property-read int $minutesInMonth The number of minutes contained in the current month + * @property-read int $minutesInQuarter The number of minutes contained in the current quarter + * @property-read int $minutesInWeek The number of minutes contained in the current week + * @property-read int $minutesInYear The number of minutes contained in the current year + * @property-read int $monthsInCentury The number of months contained in the current century + * @property-read int $monthsInDecade The number of months contained in the current decade + * @property-read int $monthsInMillennium The number of months contained in the current millennium + * @property-read int $monthsInQuarter The number of months contained in the current quarter + * @property-read int $monthsInYear The number of months contained in the current year + * @property-read int $quartersInCentury The number of quarters contained in the current century + * @property-read int $quartersInDecade The number of quarters contained in the current decade + * @property-read int $quartersInMillennium The number of quarters contained in the current millennium + * @property-read int $quartersInYear The number of quarters contained in the current year + * @property-read int $secondsInCentury The number of seconds contained in the current century + * @property-read int $secondsInDay The number of seconds contained in the current day + * @property-read int $secondsInDecade The number of seconds contained in the current decade + * @property-read int $secondsInHour The number of seconds contained in the current hour + * @property-read int $secondsInMillennium The number of seconds contained in the current millennium + * @property-read int $secondsInMinute The number of seconds contained in the current minute + * @property-read int $secondsInMonth The number of seconds contained in the current month + * @property-read int $secondsInQuarter The number of seconds contained in the current quarter + * @property-read int $secondsInWeek The number of seconds contained in the current week + * @property-read int $secondsInYear The number of seconds contained in the current year + * @property-read int $weeksInCentury The number of weeks contained in the current century + * @property-read int $weeksInDecade The number of weeks contained in the current decade + * @property-read int $weeksInMillennium The number of weeks contained in the current millennium + * @property-read int $weeksInMonth The number of weeks contained in the current month + * @property-read int $weeksInQuarter The number of weeks contained in the current quarter + * @property-read int $weeksInYear 51 through 53 + * @property-read int $yearsInCentury The number of years contained in the current century + * @property-read int $yearsInDecade The number of years contained in the current decade + * @property-read int $yearsInMillennium The number of years contained in the current millennium * * @method bool isUtc() Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) * @method bool isLocal() Check if the current instance has non-UTC timezone. @@ -116,64 +275,72 @@ use Throwable; * @method bool isThursday() Checks if the instance day is thursday. * @method bool isFriday() Checks if the instance day is friday. * @method bool isSaturday() Checks if the instance day is saturday. - * @method bool isSameYear(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameYear(DateTimeInterface|string $date) Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentYear() Checks if the instance is in the same year as the current moment. * @method bool isNextYear() Checks if the instance is in the same year as the current moment next year. * @method bool isLastYear() Checks if the instance is in the same year as the current moment last year. - * @method bool isSameWeek(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. - * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. - * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. - * @method bool isSameDay(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. - * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. - * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. - * @method bool isSameHour(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. - * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. - * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. - * @method bool isSameMinute(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. - * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. - * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. - * @method bool isSameSecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. - * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. - * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. - * @method bool isSameMicro(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. - * @method bool isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). - * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. - * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. - * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. * @method bool isCurrentMonth() Checks if the instance is in the same month as the current moment. * @method bool isNextMonth() Checks if the instance is in the same month as the current moment next month. * @method bool isLastMonth() Checks if the instance is in the same month as the current moment last month. - * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. - * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. - * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. - * @method bool isSameDecade(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameWeek(DateTimeInterface|string $date) Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentWeek() Checks if the instance is in the same week as the current moment. + * @method bool isNextWeek() Checks if the instance is in the same week as the current moment next week. + * @method bool isLastWeek() Checks if the instance is in the same week as the current moment last week. + * @method bool isSameDay(DateTimeInterface|string $date) Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentDay() Checks if the instance is in the same day as the current moment. + * @method bool isNextDay() Checks if the instance is in the same day as the current moment next day. + * @method bool isLastDay() Checks if the instance is in the same day as the current moment last day. + * @method bool isSameHour(DateTimeInterface|string $date) Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentHour() Checks if the instance is in the same hour as the current moment. + * @method bool isNextHour() Checks if the instance is in the same hour as the current moment next hour. + * @method bool isLastHour() Checks if the instance is in the same hour as the current moment last hour. + * @method bool isSameMinute(DateTimeInterface|string $date) Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMinute() Checks if the instance is in the same minute as the current moment. + * @method bool isNextMinute() Checks if the instance is in the same minute as the current moment next minute. + * @method bool isLastMinute() Checks if the instance is in the same minute as the current moment last minute. + * @method bool isSameSecond(DateTimeInterface|string $date) Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentSecond() Checks if the instance is in the same second as the current moment. + * @method bool isNextSecond() Checks if the instance is in the same second as the current moment next second. + * @method bool isLastSecond() Checks if the instance is in the same second as the current moment last second. + * @method bool isSameMilli(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMilli() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMilli() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMilli() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMillisecond(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillisecond() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMillisecond() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMillisecond() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMicro(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicro() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicro() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicro() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameMicrosecond(DateTimeInterface|string $date) Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMicrosecond() Checks if the instance is in the same microsecond as the current moment. + * @method bool isNextMicrosecond() Checks if the instance is in the same microsecond as the current moment next microsecond. + * @method bool isLastMicrosecond() Checks if the instance is in the same microsecond as the current moment last microsecond. + * @method bool isSameDecade(DateTimeInterface|string $date) Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentDecade() Checks if the instance is in the same decade as the current moment. * @method bool isNextDecade() Checks if the instance is in the same decade as the current moment next decade. * @method bool isLastDecade() Checks if the instance is in the same decade as the current moment last decade. - * @method bool isSameCentury(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameCentury(DateTimeInterface|string $date) Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentCentury() Checks if the instance is in the same century as the current moment. * @method bool isNextCentury() Checks if the instance is in the same century as the current moment next century. * @method bool isLastCentury() Checks if the instance is in the same century as the current moment last century. - * @method bool isSameMillennium(Carbon|DateTimeInterface|string|null $date = null) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). + * @method bool isSameMillennium(DateTimeInterface|string $date) Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone). * @method bool isCurrentMillennium() Checks if the instance is in the same millennium as the current moment. * @method bool isNextMillennium() Checks if the instance is in the same millennium as the current moment next millennium. * @method bool isLastMillennium() Checks if the instance is in the same millennium as the current moment last millennium. + * @method bool isCurrentQuarter() Checks if the instance is in the same quarter as the current moment. + * @method bool isNextQuarter() Checks if the instance is in the same quarter as the current moment next quarter. + * @method bool isLastQuarter() Checks if the instance is in the same quarter as the current moment last quarter. * @method CarbonInterface years(int $value) Set current instance year to the given value. * @method CarbonInterface year(int $value) Set current instance year to the given value. * @method CarbonInterface setYears(int $value) Set current instance year to the given value. * @method CarbonInterface setYear(int $value) Set current instance year to the given value. - * @method CarbonInterface months(int $value) Set current instance month to the given value. - * @method CarbonInterface month(int $value) Set current instance month to the given value. - * @method CarbonInterface setMonths(int $value) Set current instance month to the given value. - * @method CarbonInterface setMonth(int $value) Set current instance month to the given value. + * @method CarbonInterface months(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface month(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface setMonths(Month|int $value) Set current instance month to the given value. + * @method CarbonInterface setMonth(Month|int $value) Set current instance month to the given value. * @method CarbonInterface days(int $value) Set current instance day to the given value. * @method CarbonInterface day(int $value) Set current instance day to the given value. * @method CarbonInterface setDays(int $value) Set current instance day to the given value. @@ -206,241 +373,256 @@ use Throwable; * @method CarbonInterface microsecond(int $value) Set current instance microsecond to the given value. * @method CarbonInterface setMicroseconds(int $value) Set current instance microsecond to the given value. * @method CarbonInterface setMicrosecond(int $value) Set current instance microsecond to the given value. - * @method CarbonInterface addYears(int $value = 1) Add years (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addYear() Add one year to the instance (using date interval). - * @method CarbonInterface subYears(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subYear() Sub one year to the instance (using date interval). - * @method CarbonInterface addYearsWithOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addYearsWithOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subYearsWithOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subYearsWithOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addYearsWithoutOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsWithoutOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsWithoutOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsWithoutOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addYearsWithNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsWithNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsWithNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsWithNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addYearsNoOverflow(int $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addYearsNoOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subYearsNoOverflow(int $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subYearsNoOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonths(int $value = 1) Add months (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMonth() Add one month to the instance (using date interval). - * @method CarbonInterface subMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMonth() Sub one month to the instance (using date interval). - * @method CarbonInterface addMonthsWithOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addMonthsWithOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subMonthsWithOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subMonthsWithOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addMonthsWithoutOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsWithoutOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsWithoutOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsWithoutOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonthsWithNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsWithNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsWithNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsWithNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMonthsNoOverflow(int $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMonthsNoOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMonthsNoOverflow(int $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMonthsNoOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDays(int $value = 1) Add days (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addDay() Add one day to the instance (using date interval). - * @method CarbonInterface subDays(int $value = 1) Sub days (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subDay() Sub one day to the instance (using date interval). - * @method CarbonInterface addHours(int $value = 1) Add hours (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addHour() Add one hour to the instance (using date interval). - * @method CarbonInterface subHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subHour() Sub one hour to the instance (using date interval). - * @method CarbonInterface addMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMinute() Add one minute to the instance (using date interval). - * @method CarbonInterface subMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMinute() Sub one minute to the instance (using date interval). - * @method CarbonInterface addSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addSecond() Add one second to the instance (using date interval). - * @method CarbonInterface subSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subSecond() Sub one second to the instance (using date interval). - * @method CarbonInterface addMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMilli() Add one millisecond to the instance (using date interval). - * @method CarbonInterface subMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMilli() Sub one millisecond to the instance (using date interval). - * @method CarbonInterface addMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMillisecond() Add one millisecond to the instance (using date interval). - * @method CarbonInterface subMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMillisecond() Sub one millisecond to the instance (using date interval). - * @method CarbonInterface addMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMicro() Add one microsecond to the instance (using date interval). - * @method CarbonInterface subMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMicro() Sub one microsecond to the instance (using date interval). - * @method CarbonInterface addMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMicrosecond() Add one microsecond to the instance (using date interval). - * @method CarbonInterface subMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMicrosecond() Sub one microsecond to the instance (using date interval). - * @method CarbonInterface addMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addMillennium() Add one millennium to the instance (using date interval). - * @method CarbonInterface subMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subMillennium() Sub one millennium to the instance (using date interval). - * @method CarbonInterface addMillenniaWithOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addMillenniaWithOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subMillenniaWithOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subMillenniaWithOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addMillenniaWithoutOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaWithoutOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaWithoutOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaWithoutOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMillenniaWithNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaWithNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaWithNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaWithNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addMillenniaNoOverflow(int $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addMillenniaNoOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subMillenniaNoOverflow(int $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subMillenniaNoOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addCentury() Add one century to the instance (using date interval). - * @method CarbonInterface subCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subCentury() Sub one century to the instance (using date interval). - * @method CarbonInterface addCenturiesWithOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addCenturiesWithOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subCenturiesWithOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subCenturiesWithOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addCenturiesWithoutOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesWithoutOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesWithoutOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesWithoutOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturiesWithNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesWithNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesWithNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesWithNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addCenturiesNoOverflow(int $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addCenturiesNoOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subCenturiesNoOverflow(int $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subCenturiesNoOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addDecade() Add one decade to the instance (using date interval). - * @method CarbonInterface subDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subDecade() Sub one decade to the instance (using date interval). - * @method CarbonInterface addDecadesWithOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addDecadesWithOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subDecadesWithOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subDecadesWithOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addDecadesWithoutOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesWithoutOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesWithoutOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesWithoutOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecadesWithNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesWithNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesWithNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesWithNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addDecadesNoOverflow(int $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addDecadesNoOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subDecadesNoOverflow(int $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subDecadesNoOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addQuarter() Add one quarter to the instance (using date interval). - * @method CarbonInterface subQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subQuarter() Sub one quarter to the instance (using date interval). - * @method CarbonInterface addQuartersWithOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface addQuartersWithOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface subQuartersWithOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonInterface subQuartersWithOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. * @method CarbonInterface subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. - * @method CarbonInterface addQuartersWithoutOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersWithoutOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersWithoutOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersWithoutOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuartersWithNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersWithNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersWithNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersWithNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addQuartersNoOverflow(int $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface addQuartersNoOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface subQuartersNoOverflow(int $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonInterface subQuartersNoOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. * @method CarbonInterface subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. - * @method CarbonInterface addWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addWeek() Add one week to the instance (using date interval). - * @method CarbonInterface subWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subWeek() Sub one week to the instance (using date interval). - * @method CarbonInterface addWeekdays(int $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface addWeekdays(int|float $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). * @method CarbonInterface addWeekday() Add one weekday to the instance (using date interval). - * @method CarbonInterface subWeekdays(int $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonInterface subWeekdays(int|float $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). * @method CarbonInterface subWeekday() Sub one weekday to the instance (using date interval). - * @method CarbonInterface addRealMicros(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMicro() Add one microsecond to the instance (using timestamp). - * @method CarbonInterface subRealMicros(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMicro() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonInterface addRealMicroseconds(int $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMicrosecond() Add one microsecond to the instance (using timestamp). - * @method CarbonInterface subRealMicroseconds(int $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMicrosecond() Sub one microsecond to the instance (using timestamp). - * @method CarbonPeriod microsecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. - * @method CarbonInterface addRealMillis(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMilli() Add one millisecond to the instance (using timestamp). - * @method CarbonInterface subRealMillis(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMilli() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonInterface addRealMilliseconds(int $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMillisecond() Add one millisecond to the instance (using timestamp). - * @method CarbonInterface subRealMilliseconds(int $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMillisecond() Sub one millisecond to the instance (using timestamp). - * @method CarbonPeriod millisecondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. - * @method CarbonInterface addRealSeconds(int $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealSecond() Add one second to the instance (using timestamp). - * @method CarbonInterface subRealSeconds(int $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealSecond() Sub one second to the instance (using timestamp). - * @method CarbonPeriod secondsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. - * @method CarbonInterface addRealMinutes(int $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMinute() Add one minute to the instance (using timestamp). - * @method CarbonInterface subRealMinutes(int $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMinute() Sub one minute to the instance (using timestamp). - * @method CarbonPeriod minutesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. - * @method CarbonInterface addRealHours(int $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealHour() Add one hour to the instance (using timestamp). - * @method CarbonInterface subRealHours(int $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealHour() Sub one hour to the instance (using timestamp). - * @method CarbonPeriod hoursUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. - * @method CarbonInterface addRealDays(int $value = 1) Add days (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealDay() Add one day to the instance (using timestamp). - * @method CarbonInterface subRealDays(int $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealDay() Sub one day to the instance (using timestamp). - * @method CarbonPeriod daysUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. - * @method CarbonInterface addRealWeeks(int $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealWeek() Add one week to the instance (using timestamp). - * @method CarbonInterface subRealWeeks(int $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealWeek() Sub one week to the instance (using timestamp). - * @method CarbonPeriod weeksUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. - * @method CarbonInterface addRealMonths(int $value = 1) Add months (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMonth() Add one month to the instance (using timestamp). - * @method CarbonInterface subRealMonths(int $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMonth() Sub one month to the instance (using timestamp). - * @method CarbonPeriod monthsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. - * @method CarbonInterface addRealQuarters(int $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealQuarter() Add one quarter to the instance (using timestamp). - * @method CarbonInterface subRealQuarters(int $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealQuarter() Sub one quarter to the instance (using timestamp). - * @method CarbonPeriod quartersUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. - * @method CarbonInterface addRealYears(int $value = 1) Add years (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealYear() Add one year to the instance (using timestamp). - * @method CarbonInterface subRealYears(int $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealYear() Sub one year to the instance (using timestamp). - * @method CarbonPeriod yearsUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. - * @method CarbonInterface addRealDecades(int $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealDecade() Add one decade to the instance (using timestamp). - * @method CarbonInterface subRealDecades(int $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealDecade() Sub one decade to the instance (using timestamp). - * @method CarbonPeriod decadesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. - * @method CarbonInterface addRealCenturies(int $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealCentury() Add one century to the instance (using timestamp). - * @method CarbonInterface subRealCenturies(int $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealCentury() Sub one century to the instance (using timestamp). - * @method CarbonPeriod centuriesUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. - * @method CarbonInterface addRealMillennia(int $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface addRealMillennium() Add one millennium to the instance (using timestamp). - * @method CarbonInterface subRealMillennia(int $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). - * @method CarbonInterface subRealMillennium() Sub one millennium to the instance (using timestamp). - * @method CarbonPeriod millenniaUntil($endDate = null, int $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method CarbonInterface addUTCMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMicro() Add one microsecond to the instance (using timestamp). + * @method CarbonInterface subUTCMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMicro() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicros(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonInterface addUTCMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMicrosecond() Add one microsecond to the instance (using timestamp). + * @method CarbonInterface subUTCMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMicrosecond() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicroseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonInterface addUTCMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMilli() Add one millisecond to the instance (using timestamp). + * @method CarbonInterface subUTCMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMilli() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMillis(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonInterface addUTCMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMillisecond() Add one millisecond to the instance (using timestamp). + * @method CarbonInterface subUTCMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMillisecond() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMilliseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonInterface addUTCSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCSecond() Add one second to the instance (using timestamp). + * @method CarbonInterface subUTCSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCSecond() Sub one second to the instance (using timestamp). + * @method CarbonPeriod secondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. + * @method float diffInUTCSeconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of seconds. + * @method CarbonInterface addUTCMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMinute() Add one minute to the instance (using timestamp). + * @method CarbonInterface subUTCMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMinute() Sub one minute to the instance (using timestamp). + * @method CarbonPeriod minutesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. + * @method float diffInUTCMinutes(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of minutes. + * @method CarbonInterface addUTCHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCHour() Add one hour to the instance (using timestamp). + * @method CarbonInterface subUTCHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCHour() Sub one hour to the instance (using timestamp). + * @method CarbonPeriod hoursUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. + * @method float diffInUTCHours(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of hours. + * @method CarbonInterface addUTCDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCDay() Add one day to the instance (using timestamp). + * @method CarbonInterface subUTCDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCDay() Sub one day to the instance (using timestamp). + * @method CarbonPeriod daysUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. + * @method float diffInUTCDays(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of days. + * @method CarbonInterface addUTCWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCWeek() Add one week to the instance (using timestamp). + * @method CarbonInterface subUTCWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCWeek() Sub one week to the instance (using timestamp). + * @method CarbonPeriod weeksUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. + * @method float diffInUTCWeeks(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of weeks. + * @method CarbonInterface addUTCMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMonth() Add one month to the instance (using timestamp). + * @method CarbonInterface subUTCMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMonth() Sub one month to the instance (using timestamp). + * @method CarbonPeriod monthsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. + * @method float diffInUTCMonths(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of months. + * @method CarbonInterface addUTCQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCQuarter() Add one quarter to the instance (using timestamp). + * @method CarbonInterface subUTCQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCQuarter() Sub one quarter to the instance (using timestamp). + * @method CarbonPeriod quartersUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. + * @method float diffInUTCQuarters(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of quarters. + * @method CarbonInterface addUTCYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCYear() Add one year to the instance (using timestamp). + * @method CarbonInterface subUTCYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCYear() Sub one year to the instance (using timestamp). + * @method CarbonPeriod yearsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. + * @method float diffInUTCYears(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of years. + * @method CarbonInterface addUTCDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCDecade() Add one decade to the instance (using timestamp). + * @method CarbonInterface subUTCDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCDecade() Sub one decade to the instance (using timestamp). + * @method CarbonPeriod decadesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. + * @method float diffInUTCDecades(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of decades. + * @method CarbonInterface addUTCCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCCentury() Add one century to the instance (using timestamp). + * @method CarbonInterface subUTCCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCCentury() Sub one century to the instance (using timestamp). + * @method CarbonPeriod centuriesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. + * @method float diffInUTCCenturies(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of centuries. + * @method CarbonInterface addUTCMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface addUTCMillennium() Add one millennium to the instance (using timestamp). + * @method CarbonInterface subUTCMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonInterface subUTCMillennium() Sub one millennium to the instance (using timestamp). + * @method CarbonPeriod millenniaUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method float diffInUTCMillennia(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of millennia. * @method CarbonInterface roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method CarbonInterface roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. * @method CarbonInterface floorYear(float $precision = 1) Truncate the current instance year with given precision. @@ -521,6 +703,160 @@ use Throwable; * @method string longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) * @method string shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) * @method string longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.) + * @method int centuriesInMillennium() Return the number of centuries contained in the current millennium + * @method int|static centuryOfMillennium(?int $century = null) Return the value of the century starting from the beginning of the current millennium when called with no parameters, change the current century when called with an integer value + * @method int|static dayOfCentury(?int $day = null) Return the value of the day starting from the beginning of the current century when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfDecade(?int $day = null) Return the value of the day starting from the beginning of the current decade when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMillennium(?int $day = null) Return the value of the day starting from the beginning of the current millennium when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMonth(?int $day = null) Return the value of the day starting from the beginning of the current month when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfQuarter(?int $day = null) Return the value of the day starting from the beginning of the current quarter when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfWeek(?int $day = null) Return the value of the day starting from the beginning of the current week when called with no parameters, change the current day when called with an integer value + * @method int daysInCentury() Return the number of days contained in the current century + * @method int daysInDecade() Return the number of days contained in the current decade + * @method int daysInMillennium() Return the number of days contained in the current millennium + * @method int daysInMonth() Return the number of days contained in the current month + * @method int daysInQuarter() Return the number of days contained in the current quarter + * @method int daysInWeek() Return the number of days contained in the current week + * @method int daysInYear() Return the number of days contained in the current year + * @method int|static decadeOfCentury(?int $decade = null) Return the value of the decade starting from the beginning of the current century when called with no parameters, change the current decade when called with an integer value + * @method int|static decadeOfMillennium(?int $decade = null) Return the value of the decade starting from the beginning of the current millennium when called with no parameters, change the current decade when called with an integer value + * @method int decadesInCentury() Return the number of decades contained in the current century + * @method int decadesInMillennium() Return the number of decades contained in the current millennium + * @method int|static hourOfCentury(?int $hour = null) Return the value of the hour starting from the beginning of the current century when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDay(?int $hour = null) Return the value of the hour starting from the beginning of the current day when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDecade(?int $hour = null) Return the value of the hour starting from the beginning of the current decade when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMillennium(?int $hour = null) Return the value of the hour starting from the beginning of the current millennium when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMonth(?int $hour = null) Return the value of the hour starting from the beginning of the current month when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfQuarter(?int $hour = null) Return the value of the hour starting from the beginning of the current quarter when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfWeek(?int $hour = null) Return the value of the hour starting from the beginning of the current week when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfYear(?int $hour = null) Return the value of the hour starting from the beginning of the current year when called with no parameters, change the current hour when called with an integer value + * @method int hoursInCentury() Return the number of hours contained in the current century + * @method int hoursInDay() Return the number of hours contained in the current day + * @method int hoursInDecade() Return the number of hours contained in the current decade + * @method int hoursInMillennium() Return the number of hours contained in the current millennium + * @method int hoursInMonth() Return the number of hours contained in the current month + * @method int hoursInQuarter() Return the number of hours contained in the current quarter + * @method int hoursInWeek() Return the number of hours contained in the current week + * @method int hoursInYear() Return the number of hours contained in the current year + * @method int|static microsecondOfCentury(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current century when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDay(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current day when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDecade(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current decade when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfHour(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current hour when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillennium(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millennium when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillisecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millisecond when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMinute(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current minute when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMonth(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current month when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfQuarter(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current quarter when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfSecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current second when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfWeek(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current week when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfYear(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current year when called with no parameters, change the current microsecond when called with an integer value + * @method int microsecondsInCentury() Return the number of microseconds contained in the current century + * @method int microsecondsInDay() Return the number of microseconds contained in the current day + * @method int microsecondsInDecade() Return the number of microseconds contained in the current decade + * @method int microsecondsInHour() Return the number of microseconds contained in the current hour + * @method int microsecondsInMillennium() Return the number of microseconds contained in the current millennium + * @method int microsecondsInMillisecond() Return the number of microseconds contained in the current millisecond + * @method int microsecondsInMinute() Return the number of microseconds contained in the current minute + * @method int microsecondsInMonth() Return the number of microseconds contained in the current month + * @method int microsecondsInQuarter() Return the number of microseconds contained in the current quarter + * @method int microsecondsInSecond() Return the number of microseconds contained in the current second + * @method int microsecondsInWeek() Return the number of microseconds contained in the current week + * @method int microsecondsInYear() Return the number of microseconds contained in the current year + * @method int|static millisecondOfCentury(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current century when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDay(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current day when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDecade(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current decade when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfHour(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current hour when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMillennium(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current millennium when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMinute(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current minute when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMonth(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current month when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfQuarter(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current quarter when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfSecond(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current second when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfWeek(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current week when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfYear(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current year when called with no parameters, change the current millisecond when called with an integer value + * @method int millisecondsInCentury() Return the number of milliseconds contained in the current century + * @method int millisecondsInDay() Return the number of milliseconds contained in the current day + * @method int millisecondsInDecade() Return the number of milliseconds contained in the current decade + * @method int millisecondsInHour() Return the number of milliseconds contained in the current hour + * @method int millisecondsInMillennium() Return the number of milliseconds contained in the current millennium + * @method int millisecondsInMinute() Return the number of milliseconds contained in the current minute + * @method int millisecondsInMonth() Return the number of milliseconds contained in the current month + * @method int millisecondsInQuarter() Return the number of milliseconds contained in the current quarter + * @method int millisecondsInSecond() Return the number of milliseconds contained in the current second + * @method int millisecondsInWeek() Return the number of milliseconds contained in the current week + * @method int millisecondsInYear() Return the number of milliseconds contained in the current year + * @method int|static minuteOfCentury(?int $minute = null) Return the value of the minute starting from the beginning of the current century when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDay(?int $minute = null) Return the value of the minute starting from the beginning of the current day when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDecade(?int $minute = null) Return the value of the minute starting from the beginning of the current decade when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfHour(?int $minute = null) Return the value of the minute starting from the beginning of the current hour when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMillennium(?int $minute = null) Return the value of the minute starting from the beginning of the current millennium when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMonth(?int $minute = null) Return the value of the minute starting from the beginning of the current month when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfQuarter(?int $minute = null) Return the value of the minute starting from the beginning of the current quarter when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfWeek(?int $minute = null) Return the value of the minute starting from the beginning of the current week when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfYear(?int $minute = null) Return the value of the minute starting from the beginning of the current year when called with no parameters, change the current minute when called with an integer value + * @method int minutesInCentury() Return the number of minutes contained in the current century + * @method int minutesInDay() Return the number of minutes contained in the current day + * @method int minutesInDecade() Return the number of minutes contained in the current decade + * @method int minutesInHour() Return the number of minutes contained in the current hour + * @method int minutesInMillennium() Return the number of minutes contained in the current millennium + * @method int minutesInMonth() Return the number of minutes contained in the current month + * @method int minutesInQuarter() Return the number of minutes contained in the current quarter + * @method int minutesInWeek() Return the number of minutes contained in the current week + * @method int minutesInYear() Return the number of minutes contained in the current year + * @method int|static monthOfCentury(?int $month = null) Return the value of the month starting from the beginning of the current century when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfDecade(?int $month = null) Return the value of the month starting from the beginning of the current decade when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfMillennium(?int $month = null) Return the value of the month starting from the beginning of the current millennium when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfQuarter(?int $month = null) Return the value of the month starting from the beginning of the current quarter when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfYear(?int $month = null) Return the value of the month starting from the beginning of the current year when called with no parameters, change the current month when called with an integer value + * @method int monthsInCentury() Return the number of months contained in the current century + * @method int monthsInDecade() Return the number of months contained in the current decade + * @method int monthsInMillennium() Return the number of months contained in the current millennium + * @method int monthsInQuarter() Return the number of months contained in the current quarter + * @method int monthsInYear() Return the number of months contained in the current year + * @method int|static quarterOfCentury(?int $quarter = null) Return the value of the quarter starting from the beginning of the current century when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfDecade(?int $quarter = null) Return the value of the quarter starting from the beginning of the current decade when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfMillennium(?int $quarter = null) Return the value of the quarter starting from the beginning of the current millennium when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfYear(?int $quarter = null) Return the value of the quarter starting from the beginning of the current year when called with no parameters, change the current quarter when called with an integer value + * @method int quartersInCentury() Return the number of quarters contained in the current century + * @method int quartersInDecade() Return the number of quarters contained in the current decade + * @method int quartersInMillennium() Return the number of quarters contained in the current millennium + * @method int quartersInYear() Return the number of quarters contained in the current year + * @method int|static secondOfCentury(?int $second = null) Return the value of the second starting from the beginning of the current century when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDay(?int $second = null) Return the value of the second starting from the beginning of the current day when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDecade(?int $second = null) Return the value of the second starting from the beginning of the current decade when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfHour(?int $second = null) Return the value of the second starting from the beginning of the current hour when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMillennium(?int $second = null) Return the value of the second starting from the beginning of the current millennium when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMinute(?int $second = null) Return the value of the second starting from the beginning of the current minute when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMonth(?int $second = null) Return the value of the second starting from the beginning of the current month when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfQuarter(?int $second = null) Return the value of the second starting from the beginning of the current quarter when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfWeek(?int $second = null) Return the value of the second starting from the beginning of the current week when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfYear(?int $second = null) Return the value of the second starting from the beginning of the current year when called with no parameters, change the current second when called with an integer value + * @method int secondsInCentury() Return the number of seconds contained in the current century + * @method int secondsInDay() Return the number of seconds contained in the current day + * @method int secondsInDecade() Return the number of seconds contained in the current decade + * @method int secondsInHour() Return the number of seconds contained in the current hour + * @method int secondsInMillennium() Return the number of seconds contained in the current millennium + * @method int secondsInMinute() Return the number of seconds contained in the current minute + * @method int secondsInMonth() Return the number of seconds contained in the current month + * @method int secondsInQuarter() Return the number of seconds contained in the current quarter + * @method int secondsInWeek() Return the number of seconds contained in the current week + * @method int secondsInYear() Return the number of seconds contained in the current year + * @method int|static weekOfCentury(?int $week = null) Return the value of the week starting from the beginning of the current century when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfDecade(?int $week = null) Return the value of the week starting from the beginning of the current decade when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMillennium(?int $week = null) Return the value of the week starting from the beginning of the current millennium when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMonth(?int $week = null) Return the value of the week starting from the beginning of the current month when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfQuarter(?int $week = null) Return the value of the week starting from the beginning of the current quarter when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfYear(?int $week = null) Return the value of the week starting from the beginning of the current year when called with no parameters, change the current week when called with an integer value + * @method int weeksInCentury() Return the number of weeks contained in the current century + * @method int weeksInDecade() Return the number of weeks contained in the current decade + * @method int weeksInMillennium() Return the number of weeks contained in the current millennium + * @method int weeksInMonth() Return the number of weeks contained in the current month + * @method int weeksInQuarter() Return the number of weeks contained in the current quarter + * @method int|static yearOfCentury(?int $year = null) Return the value of the year starting from the beginning of the current century when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfDecade(?int $year = null) Return the value of the year starting from the beginning of the current decade when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfMillennium(?int $year = null) Return the value of the year starting from the beginning of the current millennium when called with no parameters, change the current year when called with an integer value + * @method int yearsInCentury() Return the number of years contained in the current century + * @method int yearsInDecade() Return the number of years contained in the current decade + * @method int yearsInMillennium() Return the number of years contained in the current millennium * * */ @@ -566,13 +902,6 @@ trait Date CarbonInterface::SATURDAY => 'Saturday', ]; - /** - * Will UTF8 encoding be used to print localized date/time ? - * - * @var bool - */ - protected static $utf8 = false; - /** * List of unit and magic methods associated as doc-comments. * @@ -614,37 +943,32 @@ trait Date /** * Creates a DateTimeZone from a string, DateTimeZone or integer offset. * - * @param DateTimeZone|string|int|null $object original value to get CarbonTimeZone from it. - * @param DateTimeZone|string|int|null $objectDump dump of the object for error messages. + * @param DateTimeZone|string|int|false|null $object original value to get CarbonTimeZone from it. + * @param DateTimeZone|string|int|false|null $objectDump dump of the object for error messages. * * @throws InvalidTimeZoneException * - * @return CarbonTimeZone|false + * @return CarbonTimeZone|null */ - protected static function safeCreateDateTimeZone($object, $objectDump = null) - { + protected static function safeCreateDateTimeZone( + DateTimeZone|string|int|false|null $object, + DateTimeZone|string|int|false|null $objectDump = null, + ): ?CarbonTimeZone { return CarbonTimeZone::instance($object, $objectDump); } /** * Get the TimeZone associated with the Carbon instance (as CarbonTimeZone). * - * @return CarbonTimeZone - * * @link https://php.net/manual/en/datetime.gettimezone.php */ - #[ReturnTypeWillChange] - public function getTimezone() + public function getTimezone(): CarbonTimeZone { - return CarbonTimeZone::instance(parent::getTimezone()); + return $this->transmitFactory(fn () => CarbonTimeZone::instance(parent::getTimezone())); } /** * List of minimum and maximums for each unit. - * - * @param int $daysInMonth - * - * @return array */ protected static function getRangesByUnit(int $daysInMonth = 31): array { @@ -694,7 +1018,7 @@ trait Date * * @return static */ - public function avoidMutation(): self + public function avoidMutation(): static { if ($this instanceof DateTimeImmutable) { return $this; @@ -708,79 +1032,11 @@ trait Date * * @return static */ - public function nowWithSameTz() + public function nowWithSameTz(): static { - return static::now($this->getTimezone()); - } + $timezone = $this->getTimezone(); - /** - * Throws an exception if the given object is not a DateTime and does not implement DateTimeInterface. - * - * @param mixed $date - * @param string|array $other - * - * @throws InvalidTypeException - */ - protected static function expectDateTime($date, $other = []) - { - $message = 'Expected '; - foreach ((array) $other as $expect) { - $message .= "$expect, "; - } - - if (!$date instanceof DateTime && !$date instanceof DateTimeInterface) { - throw new InvalidTypeException( - $message.'DateTime or DateTimeInterface, '. - (\is_object($date) ? \get_class($date) : \gettype($date)).' given' - ); - } - } - - /** - * Return the Carbon instance passed through, a now instance in the same timezone - * if null given or parse the input if string given. - * - * @param Carbon|DateTimeInterface|string|null $date - * - * @return static - */ - protected function resolveCarbon($date = null) - { - if (!$date) { - return $this->nowWithSameTz(); - } - - if (\is_string($date)) { - return static::parse($date, $this->getTimezone()); - } - - static::expectDateTime($date, ['null', 'string']); - - return $date instanceof self ? $date : static::instance($date); - } - - /** - * Return the Carbon instance passed through, a now instance in UTC - * if null given or parse the input if string given (using current timezone - * then switching to UTC). - * - * @param Carbon|DateTimeInterface|string|null $date - * - * @return static - */ - protected function resolveUTC($date = null): self - { - if (!$date) { - return static::now('UTC'); - } - - if (\is_string($date)) { - return static::parse($date, $this->getTimezone())->utc(); - } - - static::expectDateTime($date, ['null', 'string']); - - return $date instanceof self ? $date : static::instance($date)->utc(); + return $this->getClock()?->nowAs(static::class, $timezone) ?? static::now($timezone); } /** @@ -809,37 +1065,51 @@ trait Date /////////////////////////////////////////////////////////////////// /** - * Get a part of the Carbon object - * - * @param string $name + * Get a part of the Carbon object. * * @throws UnknownGetterException * * @return string|int|bool|DateTimeZone|null */ - public function __get($name) + public function __get(string $name): mixed { return $this->get($name); } /** - * Get a part of the Carbon object - * - * @param string $name + * Get a part of the Carbon object. * * @throws UnknownGetterException * - * @return string|int|bool|DateTimeZone|null + * @return string|int|bool|DateTimeZone */ - public function get($name) + public function get(Unit|string $name): mixed { + static $localizedFormats = [ + // @property string the day of week in current locale + 'localeDayOfWeek' => 'dddd', + // @property string the abbreviated day of week in current locale + 'shortLocaleDayOfWeek' => 'ddd', + // @property string the month in current locale + 'localeMonth' => 'MMMM', + // @property string the abbreviated month in current locale + 'shortLocaleMonth' => 'MMM', + ]; + + $name = Unit::toName($name); + + if (isset($localizedFormats[$name])) { + return $this->isoFormat($localizedFormats[$name]); + } + static $formats = [ // @property int 'year' => 'Y', // @property int 'yearIso' => 'o', + // @--property-read int + // @--property-write Month|int // @property int - // @call isSameUnit 'month' => 'n', // @property int 'day' => 'j', @@ -853,11 +1123,11 @@ trait Date 'micro' => 'u', // @property int 'microsecond' => 'u', - // @property-read int 0 (for Sunday) through 6 (for Saturday) + // @property int 0 (for Sunday) through 6 (for Saturday) 'dayOfWeek' => 'w', - // @property-read int 1 (for Monday) through 7 (for Sunday) + // @property int 1 (for Monday) through 7 (for Sunday) 'dayOfWeekIso' => 'N', - // @property-read int ISO-8601 week number of year, weeks starting on Monday + // @property int ISO-8601 week number of year, weeks starting on Monday 'weekOfYear' => 'W', // @property-read int number of days in the given month 'daysInMonth' => 't', @@ -875,30 +1145,6 @@ trait Date 'englishMonth' => 'F', // @property string the abbreviated month in English 'shortEnglishMonth' => 'M', - // @property string the day of week in current locale LC_TIME - // @deprecated - // reason: It uses OS language package and strftime() which is deprecated since PHP 8.1. - // replacement: Use ->isoFormat('MMM') instead. - // since: 2.55.0 - 'localeDayOfWeek' => '%A', - // @property string the abbreviated day of week in current locale LC_TIME - // @deprecated - // reason: It uses OS language package and strftime() which is deprecated since PHP 8.1. - // replacement: Use ->isoFormat('dddd') instead. - // since: 2.55.0 - 'shortLocaleDayOfWeek' => '%a', - // @property string the month in current locale LC_TIME - // @deprecated - // reason: It uses OS language package and strftime() which is deprecated since PHP 8.1. - // replacement: Use ->isoFormat('ddd') instead. - // since: 2.55.0 - 'localeMonth' => '%B', - // @property string the abbreviated month in current locale LC_TIME - // @deprecated - // reason: It uses OS language package and strftime() which is deprecated since PHP 8.1. - // replacement: Use ->isoFormat('MMMM') instead. - // since: 2.55.0 - 'shortLocaleMonth' => '%b', // @property-read string $timezoneAbbreviatedName the current timezone abbreviated name 'timezoneAbbreviatedName' => 'T', // @property-read string $tzAbbrName alias of $timezoneAbbreviatedName @@ -907,9 +1153,7 @@ trait Date switch (true) { case isset($formats[$name]): - $format = $formats[$name]; - $method = str_starts_with($format, '%') ? 'formatLocalized' : 'rawFormat'; - $value = $this->$method($format); + $value = $this->rawFormat($formats[$name]); return is_numeric($value) ? (int) $value : $value; @@ -969,7 +1213,7 @@ trait Date case $name === 'isoWeeksInYear': return $this->isoWeeksInYear(); - // @property-read int 1 through 5 + // @property int 1 through 5 case $name === 'weekOfMonth': return (int) ceil($this->day / static::DAYS_PER_WEEK); @@ -979,11 +1223,11 @@ trait Date // @property-read int 0 through 6 case $name === 'firstWeekDay': - return $this->localTranslator ? ($this->getTranslationMessage('first_day_of_week') ?? 0) : static::getWeekStartsAt(); + return (int) $this->getTranslationMessage('first_day_of_week'); // @property-read int 0 through 6 case $name === 'lastWeekDay': - return $this->localTranslator ? (($this->getTranslationMessage('first_day_of_week') ?? 0) + static::DAYS_PER_WEEK - 1) % static::DAYS_PER_WEEK : static::getWeekEndsAt(); + return $this->transmitFactory(fn () => static::weekRotate((int) $this->getTranslationMessage('first_day_of_week'), -1)); // @property int 1 through 366 case $name === 'dayOfYear': @@ -991,14 +1235,13 @@ trait Date // @property-read int 365 or 366 case $name === 'daysInYear': - return $this->isLeapYear() ? 366 : 365; + return static::DAYS_PER_YEAR + ($this->isLeapYear() ? 1 : 0); // @property int does a diffInYears() with default parameters case $name === 'age': - return $this->diffInYears(); + return (int) $this->diffInYears(); // @property-read int the quarter of this instance, 1 - 4 - // @call isSameUnit case $name === 'quarter': return (int) ceil($this->month / static::MONTHS_PER_QUARTER); @@ -1012,6 +1255,7 @@ trait Date case $name === 'century': $factor = 1; $year = $this->year; + if ($year < 0) { $year = -$year; $factor = -1; @@ -1024,6 +1268,7 @@ trait Date case $name === 'millennium': $factor = 1; $year = $this->year; + if ($year < 0) { $year = -$year; $factor = -1; @@ -1055,10 +1300,14 @@ trait Date case $name === 'utc': return $this->getOffset() === 0; + // @--property-write DateTimeZone|string|int $timezone the current timezone + // @--property-write DateTimeZone|string|int $tz alias of $timezone + // @--property-read CarbonTimeZone $timezone the current timezone + // @--property-read CarbonTimeZone $tz alias of $timezone // @property CarbonTimeZone $timezone the current timezone // @property CarbonTimeZone $tz alias of $timezone case $name === 'timezone' || $name === 'tz': - return CarbonTimeZone::instance($this->getTimezone()); + return $this->getTimezone(); // @property-read string $timezoneName the current timezone name // @property-read string $tzName alias of $timezoneName @@ -1069,6 +1318,26 @@ trait Date case $name === 'locale': return $this->getTranslatorLocale(); + case preg_match('/^([a-z]{2,})(In|Of)([A-Z][a-z]+)$/', $name, $match): + [, $firstUnit, $operator, $secondUnit] = $match; + + try { + $start = $this->avoidMutation()->startOf($secondUnit); + $value = $operator === 'Of' + ? (\in_array($firstUnit, [ + // Unit with indexes starting at 1 (other units start at 0) + 'day', + 'week', + 'month', + 'quarter', + ], true) ? 1 : 0) + floor($start->diffInUnit($firstUnit, $this)) + : round($start->diffInUnit($firstUnit, $start->avoidMutation()->add($secondUnit, 1))); + + return (int) $value; + } catch (UnknownUnitException) { + // default to macro + } + default: $macro = $this->getLocalMacro('get'.ucfirst($name)); @@ -1091,7 +1360,7 @@ trait Date { try { $this->__get($name); - } catch (UnknownGetterException | ReflectionException $e) { + } catch (UnknownGetterException | ReflectionException) { return false; } @@ -1120,19 +1389,16 @@ trait Date } /** - * Set a part of the Carbon object - * - * @param string|array $name - * @param string|int|DateTimeZone $value + * Set a part of the Carbon object. * * @throws ImmutableException|UnknownSetterException * * @return $this */ - public function set($name, $value = null) + public function set(Unit|array|string $name, DateTimeZone|Month|string|int|float|null $value = null): static { if ($this->isImmutable()) { - throw new ImmutableException(sprintf('%s class', static::class)); + throw new ImmutableException(\sprintf('%s class', static::class)); } if (\is_array($name)) { @@ -1143,6 +1409,8 @@ trait Date return $this; } + $name = Unit::toName($name); + switch ($name) { case 'milliseconds': case 'millisecond': @@ -1175,7 +1443,7 @@ trait Date case 'minute': case 'second': [$year, $month, $day, $hour, $minute, $second] = array_map('intval', explode('-', $this->rawFormat('Y-n-j-G-i-s'))); - $$name = $value; + $$name = self::monthToInt($value, $name); $this->setDateTime($year, $month, $day, $hour, $minute, $second); break; @@ -1205,6 +1473,16 @@ trait Date break; + case 'dayOfWeek': + $this->addDays($value - $this->dayOfWeek); + + break; + + case 'dayOfWeekIso': + $this->addDays($value - $this->dayOfWeekIso); + + break; + case 'timestamp': $this->setTimestamp($value); @@ -1232,6 +1510,32 @@ trait Date break; default: + if (preg_match('/^([a-z]{2,})Of([A-Z][a-z]+)$/', $name, $match)) { + [, $firstUnit, $secondUnit] = $match; + + try { + $start = $this->avoidMutation()->startOf($secondUnit); + $currentValue = (\in_array($firstUnit, [ + // Unit with indexes starting at 1 (other units start at 0) + 'day', + 'week', + 'month', + 'quarter', + ], true) ? 1 : 0) + (int) floor($start->diffInUnit($firstUnit, $this)); + + // We check $value a posteriori to give precedence to UnknownUnitException + if (!\is_int($value)) { + throw new UnitException("->$name expects integer value"); + } + + $this->addUnit($firstUnit, $value - $currentValue); + + break; + } catch (UnknownUnitException) { + // default to macro + } + } + $macro = $this->getLocalMacro('set'.ucfirst($name)); if ($macro) { @@ -1240,7 +1544,7 @@ trait Date break; } - if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) { + if ($this->isLocalStrictModeEnabled()) { throw new UnknownSetterException($name); } @@ -1250,37 +1554,18 @@ trait Date return $this; } - protected function getTranslatedFormByRegExp($baseKey, $keySuffix, $context, $subKey, $defaultValue) - { - $key = $baseKey.$keySuffix; - $standaloneKey = "{$key}_standalone"; - $baseTranslation = $this->getTranslationMessage($key); - - if ($baseTranslation instanceof Closure) { - return $baseTranslation($this, $context, $subKey) ?: $defaultValue; - } - - if ( - $this->getTranslationMessage("$standaloneKey.$subKey") && - (!$context || (($regExp = $this->getTranslationMessage("{$baseKey}_regexp")) && !preg_match($regExp, $context))) - ) { - $key = $standaloneKey; - } - - return $this->getTranslationMessage("$key.$subKey", null, $defaultValue); - } - /** * Get the translation of the current week day name (with context for languages with multiple forms). * * @param string|null $context whole format string * @param string $keySuffix "", "_short" or "_min" * @param string|null $defaultValue default value if translation missing - * - * @return string */ - public function getTranslatedDayName($context = null, $keySuffix = '', $defaultValue = null) - { + public function getTranslatedDayName( + ?string $context = null, + string $keySuffix = '', + ?string $defaultValue = null, + ): string { return $this->getTranslatedFormByRegExp('weekdays', $keySuffix, $context, $this->dayOfWeek, $defaultValue ?: $this->englishDayOfWeek); } @@ -1288,10 +1573,8 @@ trait Date * Get the translation of the current short week day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedShortDayName($context = null) + public function getTranslatedShortDayName(?string $context = null): string { return $this->getTranslatedDayName($context, '_short', $this->shortEnglishDayOfWeek); } @@ -1300,10 +1583,8 @@ trait Date * Get the translation of the current abbreviated week day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedMinDayName($context = null) + public function getTranslatedMinDayName(?string $context = null): string { return $this->getTranslatedDayName($context, '_min', $this->shortEnglishDayOfWeek); } @@ -1314,11 +1595,12 @@ trait Date * @param string|null $context whole format string * @param string $keySuffix "" or "_short" * @param string|null $defaultValue default value if translation missing - * - * @return string */ - public function getTranslatedMonthName($context = null, $keySuffix = '', $defaultValue = null) - { + public function getTranslatedMonthName( + ?string $context = null, + string $keySuffix = '', + ?string $defaultValue = null, + ): string { return $this->getTranslatedFormByRegExp('months', $keySuffix, $context, $this->month - 1, $defaultValue ?: $this->englishMonth); } @@ -1326,10 +1608,8 @@ trait Date * Get the translation of the current short month day name (with context for languages with multiple forms). * * @param string|null $context whole format string - * - * @return string */ - public function getTranslatedShortMonthName($context = null) + public function getTranslatedShortMonthName(?string $context = null): string { return $this->getTranslatedMonthName($context, '_short', $this->shortEnglishMonth); } @@ -1337,11 +1617,17 @@ trait Date /** * Get/set the day of year. * + * @template T of int|null + * * @param int|null $value new value for day of year if using as setter. * + * @psalm-param T $value + * * @return static|int + * + * @psalm-return (T is int ? static : int) */ - public function dayOfYear($value = null) + public function dayOfYear(?int $value = null): static|int { $dayOfYear = $this->dayOfYear; @@ -1351,11 +1637,9 @@ trait Date /** * Get/set the weekday from 0 (Sunday) to 6 (Saturday). * - * @param int|null $value new value for weekday if using as setter. - * - * @return static|int + * @param WeekDay|int|null $value new value for weekday if using as setter. */ - public function weekday($value = null) + public function weekday(WeekDay|int|null $value = null): static|int { if ($value === null) { return $this->dayOfWeek; @@ -1364,36 +1648,32 @@ trait Date $firstDay = (int) ($this->getTranslationMessage('first_day_of_week') ?? 0); $dayOfWeek = ($this->dayOfWeek + 7 - $firstDay) % 7; - return $this->addDays((($value + 7 - $firstDay) % 7) - $dayOfWeek); + return $this->addDays(((WeekDay::int($value) + 7 - $firstDay) % 7) - $dayOfWeek); } /** * Get/set the ISO weekday from 1 (Monday) to 7 (Sunday). * - * @param int|null $value new value for weekday if using as setter. - * - * @return static|int + * @param WeekDay|int|null $value new value for weekday if using as setter. */ - public function isoWeekday($value = null) + public function isoWeekday(WeekDay|int|null $value = null): static|int { $dayOfWeekIso = $this->dayOfWeekIso; - return $value === null ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso); + return $value === null ? $dayOfWeekIso : $this->addDays(WeekDay::int($value) - $dayOfWeekIso); } /** * Return the number of days since the start of the week (using the current locale or the first parameter * if explicitly given). * - * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, - * if not provided, start of week is inferred from the locale - * (Sunday for en_US, Monday for de_DE, etc.) - * - * @return int + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, + * if not provided, start of week is inferred from the locale + * (Sunday for en_US, Monday for de_DE, etc.) */ - public function getDaysFromStartOfWeek(int $weekStartsAt = null): int + public function getDaysFromStartOfWeek(WeekDay|int|null $weekStartsAt = null): int { - $firstDay = (int) ($weekStartsAt ?? $this->getTranslationMessage('first_day_of_week') ?? 0); + $firstDay = (int) (WeekDay::int($weekStartsAt) ?? $this->getTranslationMessage('first_day_of_week') ?? 0); return ($this->dayOfWeek + 7 - $firstDay) % 7; } @@ -1402,16 +1682,14 @@ trait Date * Set the day (keeping the current time) to the start of the week + the number of days passed as the first * parameter. First day of week is driven by the locale unless explicitly set with the second parameter. * - * @param int $numberOfDays number of days to add after the start of the current week - * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, - * if not provided, start of week is inferred from the locale - * (Sunday for en_US, Monday for de_DE, etc.) - * - * @return static + * @param int $numberOfDays number of days to add after the start of the current week + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week, + * if not provided, start of week is inferred from the locale + * (Sunday for en_US, Monday for de_DE, etc.) */ - public function setDaysFromStartOfWeek(int $numberOfDays, int $weekStartsAt = null) + public function setDaysFromStartOfWeek(int $numberOfDays, WeekDay|int|null $weekStartsAt = null): static { - return $this->addDays($numberOfDays - $this->getDaysFromStartOfWeek($weekStartsAt)); + return $this->addDays($numberOfDays - $this->getDaysFromStartOfWeek(WeekDay::int($weekStartsAt))); } /** @@ -1420,21 +1698,21 @@ trait Date * @param string $valueUnit unit name to modify * @param int $value new value for the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function setUnitNoOverflow($valueUnit, $value, $overflowUnit) + public function setUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static { try { - $original = $this->avoidMutation(); + $start = $this->avoidMutation()->startOf($overflowUnit); + $end = $this->avoidMutation()->endOf($overflowUnit); /** @var static $date */ $date = $this->$valueUnit($value); - $end = $original->avoidMutation()->endOf($overflowUnit); - $start = $original->avoidMutation()->startOf($overflowUnit); + if ($date < $start) { - $date = $date->setDateTimeFrom($start); - } elseif ($date > $end) { - $date = $date->setDateTimeFrom($end); + return $date->mutateIfMutable($start); + } + + if ($date > $end) { + return $date->mutateIfMutable($end); } return $date; @@ -1449,10 +1727,8 @@ trait Date * @param string $valueUnit unit name to modify * @param int $value amount to add to the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function addUnitNoOverflow($valueUnit, $value, $overflowUnit) + public function addUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static { return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit + $value, $overflowUnit); } @@ -1463,24 +1739,18 @@ trait Date * @param string $valueUnit unit name to modify * @param int $value amount to subtract to the input unit * @param string $overflowUnit unit name to not overflow - * - * @return static */ - public function subUnitNoOverflow($valueUnit, $value, $overflowUnit) + public function subUnitNoOverflow(string $valueUnit, int $value, string $overflowUnit): static { return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit - $value, $overflowUnit); } /** * Returns the minutes offset to UTC if no arguments passed, else set the timezone with given minutes shift passed. - * - * @param int|null $minuteOffset - * - * @return int|static */ - public function utcOffset(int $minuteOffset = null) + public function utcOffset(?int $minuteOffset = null): static|int { - if (\func_num_args() < 1) { + if ($minuteOffset === null) { return $this->offsetMinutes; } @@ -1491,97 +1761,63 @@ trait Date * Set the date with gregorian year, month and day numbers. * * @see https://php.net/manual/en/datetime.setdate.php - * - * @param int $year - * @param int $month - * @param int $day - * - * @return static */ - #[ReturnTypeWillChange] - public function setDate($year, $month, $day) + public function setDate(int $year, int $month, int $day): static { - return parent::setDate((int) $year, (int) $month, (int) $day); + return parent::setDate($year, $month, $day); } /** * Set a date according to the ISO 8601 standard - using weeks and day offsets rather than specific dates. * * @see https://php.net/manual/en/datetime.setisodate.php - * - * @param int $year - * @param int $week - * @param int $day - * - * @return static */ - #[ReturnTypeWillChange] - public function setISODate($year, $week, $day = 1) + public function setISODate(int $year, int $week, int $day = 1): static { - return parent::setISODate((int) $year, (int) $week, (int) $day); + return parent::setISODate($year, $week, $day); } /** * Set the date and time all together. - * - * @param int $year - * @param int $month - * @param int $day - * @param int $hour - * @param int $minute - * @param int $second - * @param int $microseconds - * - * @return static */ - public function setDateTime($year, $month, $day, $hour, $minute, $second = 0, $microseconds = 0) - { - return $this->setDate($year, $month, $day)->setTime((int) $hour, (int) $minute, (int) $second, (int) $microseconds); + public function setDateTime( + int $year, + int $month, + int $day, + int $hour, + int $minute, + int $second = 0, + int $microseconds = 0, + ): static { + return $this->setDate($year, $month, $day)->setTime($hour, $minute, $second, $microseconds); } /** * Resets the current time of the DateTime object to a different time. * * @see https://php.net/manual/en/datetime.settime.php - * - * @param int $hour - * @param int $minute - * @param int $second - * @param int $microseconds - * - * @return static */ - #[ReturnTypeWillChange] - public function setTime($hour, $minute, $second = 0, $microseconds = 0) + public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0): static { - return parent::setTime((int) $hour, (int) $minute, (int) $second, (int) $microseconds); + return parent::setTime($hour, $minute, $second, $microseconds); } /** * Set the instance's timestamp. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $unixTimestamp - * - * @return static */ - #[ReturnTypeWillChange] - public function setTimestamp($unixTimestamp) + public function setTimestamp(float|int|string $timestamp): static { - [$timestamp, $microseconds] = self::getIntegerAndDecimalParts($unixTimestamp); + [$seconds, $microseconds] = self::getIntegerAndDecimalParts($timestamp); - return parent::setTimestamp((int) $timestamp)->setMicroseconds((int) $microseconds); + return parent::setTimestamp((int) $seconds)->setMicroseconds((int) $microseconds); } /** * Set the time by time string. - * - * @param string $time - * - * @return static */ - public function setTimeFromTimeString($time) + public function setTimeFromTimeString(string $time): static { if (!str_contains($time, ':')) { $time .= ':0'; @@ -1592,12 +1828,8 @@ trait Date /** * @alias setTimezone - * - * @param DateTimeZone|string $value - * - * @return static */ - public function timezone($value) + public function timezone(DateTimeZone|string|int $value): static { return $this->setTimezone($value); } @@ -1605,13 +1837,11 @@ trait Date /** * Set the timezone or returns the timezone name if no arguments passed. * - * @param DateTimeZone|string $value - * - * @return static|string + * @return ($value is null ? string : static) */ - public function tz($value = null) + public function tz(DateTimeZone|string|int|null $value = null): static|string { - if (\func_num_args() < 1) { + if ($value === null) { return $this->tzName; } @@ -1620,31 +1850,16 @@ trait Date /** * Set the instance's timezone from a string or object. - * - * @param DateTimeZone|string $value - * - * @return static */ - #[ReturnTypeWillChange] - public function setTimezone($value) + public function setTimezone(DateTimeZone|string|int $timeZone): static { - $tz = static::safeCreateDateTimeZone($value); - - if ($tz === false && !self::isStrictModeEnabled()) { - $tz = new CarbonTimeZone(); - } - - return parent::setTimezone($tz); + return parent::setTimezone(static::safeCreateDateTimeZone($timeZone)); } /** * Set the instance's timezone from a string or object and add/subtract the offset difference. - * - * @param DateTimeZone|string $value - * - * @return static */ - public function shiftTimezone($value) + public function shiftTimezone(DateTimeZone|string $value): static { $dateTimeString = $this->format('Y-m-d H:i:s.u'); @@ -1655,22 +1870,16 @@ trait Date /** * Set the instance's timezone to UTC. - * - * @return static */ - public function utc() + public function utc(): static { return $this->setTimezone('UTC'); } /** * Set the year, month, and date for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date now if null - * - * @return static */ - public function setDateFrom($date = null) + public function setDateFrom(DateTimeInterface|string $date): static { $date = $this->resolveCarbon($date); @@ -1679,12 +1888,8 @@ trait Date /** * Set the hour, minute, second and microseconds for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date now if null - * - * @return static */ - public function setTimeFrom($date = null) + public function setTimeFrom(DateTimeInterface|string $date): static { $date = $this->resolveCarbon($date); @@ -1693,12 +1898,8 @@ trait Date /** * Set the date and time for this instance to that of the passed instance. - * - * @param Carbon|DateTimeInterface $date - * - * @return static */ - public function setDateTimeFrom($date = null) + public function setDateTimeFrom(DateTimeInterface|string $date): static { $date = $this->resolveCarbon($date); @@ -1706,11 +1907,9 @@ trait Date } /** - * Get the days of the week - * - * @return array + * Get the days of the week. */ - public static function getDays() + public static function getDays(): array { return static::$days; } @@ -1719,85 +1918,37 @@ trait Date /////////////////////// WEEK SPECIAL DAYS ///////////////////////// /////////////////////////////////////////////////////////////////// - private static function getFirstDayOfWeek(): int + /** + * Get the first day of week. + * + * @return int + */ + public static function getWeekStartsAt(?string $locale = null): int { return (int) static::getTranslationMessageWith( - static::getTranslator(), - 'first_day_of_week' + $locale ? Translator::get($locale) : static::getTranslator(), + 'first_day_of_week', ); } /** - * Get the first day of week + * Get the last day of week. + * + * @param string $locale local to consider the last day of week. * * @return int */ - public static function getWeekStartsAt() + public static function getWeekEndsAt(?string $locale = null): int { - if (static::$weekStartsAt === static::WEEK_DAY_AUTO) { - return self::getFirstDayOfWeek(); - } - - return static::$weekStartsAt; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the - * 'first_day_of_week' locale setting to change the start of week according to current locale - * selected and implicitly the end of week. - * - * Set the first day of week - * - * @param int|string $day week start day (or 'auto' to get the first day of week from Carbon::getLocale() culture). - * - * @return void - */ - public static function setWeekStartsAt($day) - { - static::$weekStartsAt = $day === static::WEEK_DAY_AUTO ? $day : max(0, (7 + $day) % 7); - } - - /** - * Get the last day of week - * - * @return int - */ - public static function getWeekEndsAt() - { - if (static::$weekStartsAt === static::WEEK_DAY_AUTO) { - return (int) (static::DAYS_PER_WEEK - 1 + self::getFirstDayOfWeek()) % static::DAYS_PER_WEEK; - } - - return static::$weekEndsAt; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek - * or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the - * start of week according to current locale selected and implicitly the end of week. - * - * Set the last day of week - * - * @param int|string $day week end day (or 'auto' to get the day before the first day of week - * from Carbon::getLocale() culture). - * - * @return void - */ - public static function setWeekEndsAt($day) - { - static::$weekEndsAt = $day === static::WEEK_DAY_AUTO ? $day : max(0, (7 + $day) % 7); + return static::weekRotate(static::getWeekStartsAt($locale), -1); } /** * Get weekend days - * - * @return array */ - public static function getWeekendDays() + public static function getWeekendDays(): array { - return static::$weekendDays; + return FactoryImmutable::getInstance()->getWeekendDays(); } /** @@ -1822,24 +1973,18 @@ trait Date * ``` * * Set weekend days - * - * @param array $days - * - * @return void */ - public static function setWeekendDays($days) + public static function setWeekendDays(array $days): void { - static::$weekendDays = $days; + FactoryImmutable::getDefaultInstance()->setWeekendDays($days); } /** * Determine if a time string will produce a relative date. * - * @param string $time - * * @return bool true if time match a relative date, false if absolute or invalid time string */ - public static function hasRelativeKeywords($time) + public static function hasRelativeKeywords(?string $time): bool { if (!$time || strtotime($time) === false) { return false; @@ -1857,68 +2002,20 @@ trait Date /////////////////////// STRING FORMATTING ///////////////////////// /////////////////////////////////////////////////////////////////// - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use UTF-8 language packages on every machine. - * - * Set if UTF8 will be used for localized date/time. - * - * @param bool $utf8 - */ - public static function setUtf8($utf8) - { - static::$utf8 = $utf8; - } - - /** - * Format the instance with the current locale. You can set the current - * locale using setlocale() https://php.net/setlocale. - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat() instead. - * Deprecated since 2.55.0 - * - * @param string $format - * - * @return string - */ - public function formatLocalized($format) - { - // Check for Windows to find and replace the %e modifier correctly. - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - $format = preg_replace('#(?toDateTimeString()); - $formatted = ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) - ? strftime($format, $time) - : @strftime($format, $time); - - return static::$utf8 - ? ( - \function_exists('mb_convert_encoding') - ? mb_convert_encoding($formatted, 'UTF-8', mb_list_encodings()) - : utf8_encode($formatted) - ) - : $formatted; - } - /** * Returns list of locale formats for ISO formatting. * * @param string|null $locale current locale used if null - * - * @return array */ - public function getIsoFormats($locale = null) + public function getIsoFormats(?string $locale = null): array { return [ - 'LT' => $this->getTranslationMessage('formats.LT', $locale, 'h:mm A'), - 'LTS' => $this->getTranslationMessage('formats.LTS', $locale, 'h:mm:ss A'), - 'L' => $this->getTranslationMessage('formats.L', $locale, 'MM/DD/YYYY'), - 'LL' => $this->getTranslationMessage('formats.LL', $locale, 'MMMM D, YYYY'), - 'LLL' => $this->getTranslationMessage('formats.LLL', $locale, 'MMMM D, YYYY h:mm A'), - 'LLLL' => $this->getTranslationMessage('formats.LLLL', $locale, 'dddd, MMMM D, YYYY h:mm A'), + 'LT' => $this->getTranslationMessage('formats.LT', $locale), + 'LTS' => $this->getTranslationMessage('formats.LTS', $locale), + 'L' => $this->getTranslationMessage('formats.L', $locale), + 'LL' => $this->getTranslationMessage('formats.LL', $locale), + 'LLL' => $this->getTranslationMessage('formats.LLL', $locale), + 'LLLL' => $this->getTranslationMessage('formats.LLLL', $locale), 'l' => $this->getTranslationMessage('formats.l', $locale), 'll' => $this->getTranslationMessage('formats.ll', $locale), 'lll' => $this->getTranslationMessage('formats.lll', $locale), @@ -1930,10 +2027,8 @@ trait Date * Returns list of calendar formats for ISO formatting. * * @param string|null $locale current locale used if null - * - * @return array */ - public function getCalendarFormats($locale = null) + public function getCalendarFormats(?string $locale = null): array { return [ 'sameDay' => $this->getTranslationMessage('calendar.sameDay', $locale, '[Today at] LT'), @@ -1947,129 +2042,108 @@ trait Date /** * Returns list of locale units for ISO formatting. - * - * @return array */ - public static function getIsoUnits() + public static function getIsoUnits(): array { static $units = null; - if ($units === null) { - $units = [ - 'OD' => ['getAltNumber', ['day']], - 'OM' => ['getAltNumber', ['month']], - 'OY' => ['getAltNumber', ['year']], - 'OH' => ['getAltNumber', ['hour']], - 'Oh' => ['getAltNumber', ['h']], - 'Om' => ['getAltNumber', ['minute']], - 'Os' => ['getAltNumber', ['second']], - 'D' => 'day', - 'DD' => ['rawFormat', ['d']], - 'Do' => ['ordinal', ['day', 'D']], - 'd' => 'dayOfWeek', - 'dd' => function (CarbonInterface $date, $originalFormat = null) { - return $date->getTranslatedMinDayName($originalFormat); - }, - 'ddd' => function (CarbonInterface $date, $originalFormat = null) { - return $date->getTranslatedShortDayName($originalFormat); - }, - 'dddd' => function (CarbonInterface $date, $originalFormat = null) { - return $date->getTranslatedDayName($originalFormat); - }, - 'DDD' => 'dayOfYear', - 'DDDD' => ['getPaddedUnit', ['dayOfYear', 3]], - 'DDDo' => ['ordinal', ['dayOfYear', 'DDD']], - 'e' => ['weekday', []], - 'E' => 'dayOfWeekIso', - 'H' => ['rawFormat', ['G']], - 'HH' => ['rawFormat', ['H']], - 'h' => ['rawFormat', ['g']], - 'hh' => ['rawFormat', ['h']], - 'k' => 'noZeroHour', - 'kk' => ['getPaddedUnit', ['noZeroHour']], - 'hmm' => ['rawFormat', ['gi']], - 'hmmss' => ['rawFormat', ['gis']], - 'Hmm' => ['rawFormat', ['Gi']], - 'Hmmss' => ['rawFormat', ['Gis']], - 'm' => 'minute', - 'mm' => ['rawFormat', ['i']], - 'a' => 'meridiem', - 'A' => 'upperMeridiem', - 's' => 'second', - 'ss' => ['getPaddedUnit', ['second']], - 'S' => function (CarbonInterface $date) { - return (string) floor($date->micro / 100000); - }, - 'SS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro / 10000), 2, '0', STR_PAD_LEFT); - }, - 'SSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro / 1000), 3, '0', STR_PAD_LEFT); - }, - 'SSSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro / 100), 4, '0', STR_PAD_LEFT); - }, - 'SSSSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro / 10), 5, '0', STR_PAD_LEFT); - }, - 'SSSSSS' => ['getPaddedUnit', ['micro', 6]], - 'SSSSSSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro * 10), 7, '0', STR_PAD_LEFT); - }, - 'SSSSSSSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro * 100), 8, '0', STR_PAD_LEFT); - }, - 'SSSSSSSSS' => function (CarbonInterface $date) { - return str_pad((string) floor($date->micro * 1000), 9, '0', STR_PAD_LEFT); - }, - 'M' => 'month', - 'MM' => ['rawFormat', ['m']], - 'MMM' => function (CarbonInterface $date, $originalFormat = null) { - $month = $date->getTranslatedShortMonthName($originalFormat); - $suffix = $date->getTranslationMessage('mmm_suffix'); - if ($suffix && $month !== $date->monthName) { - $month .= $suffix; - } + $units ??= [ + 'OD' => ['getAltNumber', ['day']], + 'OM' => ['getAltNumber', ['month']], + 'OY' => ['getAltNumber', ['year']], + 'OH' => ['getAltNumber', ['hour']], + 'Oh' => ['getAltNumber', ['h']], + 'Om' => ['getAltNumber', ['minute']], + 'Os' => ['getAltNumber', ['second']], + 'D' => 'day', + 'DD' => ['rawFormat', ['d']], + 'Do' => ['ordinal', ['day', 'D']], + 'd' => 'dayOfWeek', + 'dd' => static fn (CarbonInterface $date, $originalFormat = null) => $date->getTranslatedMinDayName( + $originalFormat, + ), + 'ddd' => static fn (CarbonInterface $date, $originalFormat = null) => $date->getTranslatedShortDayName( + $originalFormat, + ), + 'dddd' => static fn (CarbonInterface $date, $originalFormat = null) => $date->getTranslatedDayName( + $originalFormat, + ), + 'DDD' => 'dayOfYear', + 'DDDD' => ['getPaddedUnit', ['dayOfYear', 3]], + 'DDDo' => ['ordinal', ['dayOfYear', 'DDD']], + 'e' => ['weekday', []], + 'E' => 'dayOfWeekIso', + 'H' => ['rawFormat', ['G']], + 'HH' => ['rawFormat', ['H']], + 'h' => ['rawFormat', ['g']], + 'hh' => ['rawFormat', ['h']], + 'k' => 'noZeroHour', + 'kk' => ['getPaddedUnit', ['noZeroHour']], + 'hmm' => ['rawFormat', ['gi']], + 'hmmss' => ['rawFormat', ['gis']], + 'Hmm' => ['rawFormat', ['Gi']], + 'Hmmss' => ['rawFormat', ['Gis']], + 'm' => 'minute', + 'mm' => ['rawFormat', ['i']], + 'a' => 'meridiem', + 'A' => 'upperMeridiem', + 's' => 'second', + 'ss' => ['getPaddedUnit', ['second']], + 'S' => static fn (CarbonInterface $date) => (string) floor($date->micro / 100000), + 'SS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro / 10000, 2), + 'SSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro / 1000, 3), + 'SSSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro / 100, 4), + 'SSSSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro / 10, 5), + 'SSSSSS' => ['getPaddedUnit', ['micro', 6]], + 'SSSSSSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro * 10, 7), + 'SSSSSSSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro * 100, 8), + 'SSSSSSSSS' => static fn (CarbonInterface $date) => self::floorZeroPad($date->micro * 1000, 9), + 'M' => 'month', + 'MM' => ['rawFormat', ['m']], + 'MMM' => static function (CarbonInterface $date, $originalFormat = null) { + $month = $date->getTranslatedShortMonthName($originalFormat); + $suffix = $date->getTranslationMessage('mmm_suffix'); + if ($suffix && $month !== $date->monthName) { + $month .= $suffix; + } - return $month; - }, - 'MMMM' => function (CarbonInterface $date, $originalFormat = null) { - return $date->getTranslatedMonthName($originalFormat); - }, - 'Mo' => ['ordinal', ['month', 'M']], - 'Q' => 'quarter', - 'Qo' => ['ordinal', ['quarter', 'M']], - 'G' => 'isoWeekYear', - 'GG' => ['getPaddedUnit', ['isoWeekYear']], - 'GGG' => ['getPaddedUnit', ['isoWeekYear', 3]], - 'GGGG' => ['getPaddedUnit', ['isoWeekYear', 4]], - 'GGGGG' => ['getPaddedUnit', ['isoWeekYear', 5]], - 'g' => 'weekYear', - 'gg' => ['getPaddedUnit', ['weekYear']], - 'ggg' => ['getPaddedUnit', ['weekYear', 3]], - 'gggg' => ['getPaddedUnit', ['weekYear', 4]], - 'ggggg' => ['getPaddedUnit', ['weekYear', 5]], - 'W' => 'isoWeek', - 'WW' => ['getPaddedUnit', ['isoWeek']], - 'Wo' => ['ordinal', ['isoWeek', 'W']], - 'w' => 'week', - 'ww' => ['getPaddedUnit', ['week']], - 'wo' => ['ordinal', ['week', 'w']], - 'x' => ['valueOf', []], - 'X' => 'timestamp', - 'Y' => 'year', - 'YY' => ['rawFormat', ['y']], - 'YYYY' => ['getPaddedUnit', ['year', 4]], - 'YYYYY' => ['getPaddedUnit', ['year', 5]], - 'YYYYYY' => function (CarbonInterface $date) { - return ($date->year < 0 ? '' : '+').$date->getPaddedUnit('year', 6); - }, - 'z' => ['rawFormat', ['T']], - 'zz' => 'tzName', - 'Z' => ['getOffsetString', []], - 'ZZ' => ['getOffsetString', ['']], - ]; - } + return $month; + }, + 'MMMM' => static fn (CarbonInterface $date, $originalFormat = null) => $date->getTranslatedMonthName( + $originalFormat, + ), + 'Mo' => ['ordinal', ['month', 'M']], + 'Q' => 'quarter', + 'Qo' => ['ordinal', ['quarter', 'M']], + 'G' => 'isoWeekYear', + 'GG' => ['getPaddedUnit', ['isoWeekYear']], + 'GGG' => ['getPaddedUnit', ['isoWeekYear', 3]], + 'GGGG' => ['getPaddedUnit', ['isoWeekYear', 4]], + 'GGGGG' => ['getPaddedUnit', ['isoWeekYear', 5]], + 'g' => 'weekYear', + 'gg' => ['getPaddedUnit', ['weekYear']], + 'ggg' => ['getPaddedUnit', ['weekYear', 3]], + 'gggg' => ['getPaddedUnit', ['weekYear', 4]], + 'ggggg' => ['getPaddedUnit', ['weekYear', 5]], + 'W' => 'isoWeek', + 'WW' => ['getPaddedUnit', ['isoWeek']], + 'Wo' => ['ordinal', ['isoWeek', 'W']], + 'w' => 'week', + 'ww' => ['getPaddedUnit', ['week']], + 'wo' => ['ordinal', ['week', 'w']], + 'x' => ['valueOf', []], + 'X' => 'timestamp', + 'Y' => 'year', + 'YY' => ['rawFormat', ['y']], + 'YYYY' => ['getPaddedUnit', ['year', 4]], + 'YYYYY' => ['getPaddedUnit', ['year', 5]], + 'YYYYYY' => static fn (CarbonInterface $date) => ($date->year < 0 ? '' : '+'). + $date->getPaddedUnit('year', 6), + 'z' => ['rawFormat', ['T']], + 'zz' => 'tzName', + 'Z' => ['getOffsetString', []], + 'ZZ' => ['getOffsetString', ['']], + ]; return $units; } @@ -2081,21 +2155,14 @@ trait Date * @param int $length Length of the output (2 by default) * @param string $padString String to use for padding ("0" by default) * @param int $padType Side(s) to pad (STR_PAD_LEFT by default) - * - * @return string */ - public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = STR_PAD_LEFT) + public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = STR_PAD_LEFT): string { return ($this->$unit < 0 ? '-' : '').str_pad((string) abs($this->$unit), $length, $padString, $padType); } /** * Return a property with its ordinal. - * - * @param string $key - * @param string|null $period - * - * @return string */ public function ordinal(string $key, ?string $period = null): string { @@ -2112,13 +2179,11 @@ trait Date * Return the meridiem of the current time in the current locale. * * @param bool $isLower if true, returns lowercase variant if available in the current locale. - * - * @return string */ public function meridiem(bool $isLower = false): string { $hour = $this->hour; - $index = $hour < 12 ? 0 : 1; + $index = $hour < static::HOURS_PER_DAY / 2 ? 0 : 1; if ($isLower) { $key = 'meridiem.'.($index + 2); @@ -2152,27 +2217,22 @@ trait Date * Returns the alternative number for a given date property if available in the current locale. * * @param string $key date property - * - * @return string */ public function getAltNumber(string $key): string { - return $this->translateNumber(\strlen($key) > 1 ? $this->$key : $this->rawFormat('h')); + return $this->translateNumber((int) (\strlen($key) > 1 ? $this->$key : $this->rawFormat($key))); } /** * Format in the current language using ISO replacement patterns. * - * @param string $format * @param string|null $originalFormat provide context if a chunk has been passed alone - * - * @return string */ public function isoFormat(string $format, ?string $originalFormat = null): string { $result = ''; $length = mb_strlen($format); - $originalFormat = $originalFormat ?: $format; + $originalFormat ??= $format; $inEscaped = false; $formats = null; $units = null; @@ -2214,10 +2274,8 @@ trait Date $code = $match[0]; $sequence = $formats[$code] ?? preg_replace_callback( '/MMMM|MM|DD|dddd/', - function ($code) { - return mb_substr($code[0], 1); - }, - $formats[strtoupper($code)] ?? '' + static fn ($code) => mb_substr($code[0], 1), + $formats[strtoupper($code)] ?? '', ); $rest = mb_substr($format, $i + mb_strlen($code)); $format = mb_substr($format, 0, $i).$sequence.$rest; @@ -2239,7 +2297,7 @@ trait Date } elseif (\is_array($sequence)) { try { $sequence = $this->{$sequence[0]}(...$sequence[1]); - } catch (ReflectionException | InvalidArgumentException | BadMethodCallException $e) { + } catch (ReflectionException | InvalidArgumentException | BadMethodCallException) { $sequence = ''; } } elseif (\is_string($sequence)) { @@ -2260,59 +2318,51 @@ trait Date /** * List of replacements from date() format to isoFormat(). - * - * @return array */ - public static function getFormatsToIsoReplacements() + public static function getFormatsToIsoReplacements(): array { static $replacements = null; - if ($replacements === null) { - $replacements = [ - 'd' => true, - 'D' => 'ddd', - 'j' => true, - 'l' => 'dddd', - 'N' => true, - 'S' => function ($date) { - $day = $date->rawFormat('j'); - - return str_replace((string) $day, '', $date->isoFormat('Do')); - }, - 'w' => true, - 'z' => true, - 'W' => true, - 'F' => 'MMMM', - 'm' => true, - 'M' => 'MMM', - 'n' => true, - 't' => true, - 'L' => true, - 'o' => true, - 'Y' => true, - 'y' => true, - 'a' => 'a', - 'A' => 'A', - 'B' => true, - 'g' => true, - 'G' => true, - 'h' => true, - 'H' => true, - 'i' => true, - 's' => true, - 'u' => true, - 'v' => true, - 'E' => true, - 'I' => true, - 'O' => true, - 'P' => true, - 'Z' => true, - 'c' => true, - 'r' => true, - 'U' => true, - 'T' => true, - ]; - } + $replacements ??= [ + 'd' => true, + 'D' => 'ddd', + 'j' => true, + 'l' => 'dddd', + 'N' => true, + 'S' => static fn ($date) => str_replace((string) $date->rawFormat('j'), '', $date->isoFormat('Do')), + 'w' => true, + 'z' => true, + 'W' => true, + 'F' => 'MMMM', + 'm' => true, + 'M' => 'MMM', + 'n' => true, + 't' => true, + 'L' => true, + 'o' => true, + 'Y' => true, + 'y' => true, + 'a' => 'a', + 'A' => 'A', + 'B' => true, + 'g' => true, + 'G' => true, + 'h' => true, + 'H' => true, + 'i' => true, + 's' => true, + 'u' => true, + 'v' => true, + 'E' => true, + 'I' => true, + 'O' => true, + 'P' => true, + 'Z' => true, + 'c' => true, + 'r' => true, + 'U' => true, + 'T' => true, + ]; return $replacements; } @@ -2320,10 +2370,6 @@ trait Date /** * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php) * but translate words whenever possible (months, day names, etc.) using the current locale. - * - * @param string $format - * - * @return string */ public function translatedFormat(string $format): string { @@ -2405,33 +2451,18 @@ trait Date * like "-12:00". * * @param string $separator string to place between hours and minutes (":" by default) - * - * @return string */ - public function getOffsetString($separator = ':') + public function getOffsetString(string $separator = ':'): string { $second = $this->getOffset(); $symbol = $second < 0 ? '-' : '+'; $minute = abs($second) / static::SECONDS_PER_MINUTE; - $hour = str_pad((string) floor($minute / static::MINUTES_PER_HOUR), 2, '0', STR_PAD_LEFT); - $minute = str_pad((string) (((int) $minute) % static::MINUTES_PER_HOUR), 2, '0', STR_PAD_LEFT); + $hour = self::floorZeroPad($minute / static::MINUTES_PER_HOUR, 2); + $minute = self::floorZeroPad(((int) $minute) % static::MINUTES_PER_HOUR, 2); return "$symbol$hour$separator$minute"; } - protected static function executeStaticCallable($macro, ...$parameters) - { - return static::bindMacroContext(null, function () use (&$macro, &$parameters) { - if ($macro instanceof Closure) { - $boundMacro = @Closure::bind($macro, null, static::class); - - return ($boundMacro ?: $macro)(...$parameters); - } - - return $macro(...$parameters); - }); - } - /** * Dynamically handle calls to the class. * @@ -2439,48 +2470,61 @@ trait Date * @param array $parameters parameters list * * @throws BadMethodCallException - * - * @return mixed */ - public static function __callStatic($method, $parameters) + public static function __callStatic(string $method, array $parameters): mixed { if (!static::hasMacro($method)) { foreach (static::getGenericMacros() as $callback) { try { return static::executeStaticCallable($callback, $method, ...$parameters); - } catch (BadMethodCallException $exception) { + } catch (BadMethodCallException) { continue; } } + if (static::isStrictModeEnabled()) { - throw new UnknownMethodException(sprintf('%s::%s', static::class, $method)); + throw new UnknownMethodException(\sprintf('%s::%s', static::class, $method)); } return null; } - return static::executeStaticCallable(static::$globalMacros[$method], ...$parameters); + return static::executeStaticCallable(static::getMacro($method), ...$parameters); } /** * Set specified unit to new given value. * - * @param string $unit year, month, day, hour, minute, second or microsecond - * @param int $value new value for given unit - * - * @return static + * @param string $unit year, month, day, hour, minute, second or microsecond + * @param Month|int $value new value for given unit */ - public function setUnit($unit, $value = null) + public function setUnit(string $unit, Month|int|float|null $value = null): static { + if (\is_float($value)) { + $int = (int) $value; + + if ((float) $int !== $value) { + throw new InvalidArgumentException( + "$unit cannot be changed to float value $value, integer expected", + ); + } + + $value = $int; + } + $unit = static::singularUnit($unit); + $value = self::monthToInt($value, $unit); $dateUnits = ['year', 'month', 'day']; + if (\in_array($unit, $dateUnits)) { - return $this->setDate(...array_map(function ($name) use ($unit, $value) { - return (int) ($name === $unit ? $value : $this->$name); - }, $dateUnits)); + return $this->setDate(...array_map( + fn ($name) => (int) ($name === $unit ? $value : $this->$name), + $dateUnits, + )); } $units = ['hour', 'minute', 'second', 'micro']; + if ($unit === 'millisecond' || $unit === 'milli') { $value *= 1000; $unit = 'micro'; @@ -2488,80 +2532,49 @@ trait Date $unit = 'micro'; } - return $this->setTime(...array_map(function ($name) use ($unit, $value) { - return (int) ($name === $unit ? $value : $this->$name); - }, $units)); + return $this->setTime(...array_map( + fn ($name) => (int) ($name === $unit ? $value : $this->$name), + $units, + )); } /** * Returns standardized singular of a given singular/plural unit name (in English). - * - * @param string $unit - * - * @return string */ public static function singularUnit(string $unit): string { $unit = rtrim(mb_strtolower($unit), 's'); - if ($unit === 'centurie') { - return 'century'; - } - - if ($unit === 'millennia') { - return 'millennium'; - } - - return $unit; + return match ($unit) { + 'centurie' => 'century', + 'millennia' => 'millennium', + default => $unit, + }; } /** * Returns standardized plural of a given singular/plural unit name (in English). - * - * @param string $unit - * - * @return string */ public static function pluralUnit(string $unit): string { $unit = rtrim(strtolower($unit), 's'); - if ($unit === 'century') { - return 'centuries'; - } - - if ($unit === 'millennium' || $unit === 'millennia') { - return 'millennia'; - } - - return "{$unit}s"; + return match ($unit) { + 'century' => 'centuries', + 'millennium', 'millennia' => 'millennia', + default => "{$unit}s", + }; } - protected function executeCallable($macro, ...$parameters) + public static function sleep(int|float $seconds): void { - if ($macro instanceof Closure) { - $boundMacro = @$macro->bindTo($this, static::class) ?: @$macro->bindTo(null, static::class); + if (static::hasTestNow()) { + static::setTestNow(static::getTestNow()->avoidMutation()->addSeconds($seconds)); - return ($boundMacro ?: $macro)(...$parameters); + return; } - return $macro(...$parameters); - } - - protected function executeCallableWithContext($macro, ...$parameters) - { - return static::bindMacroContext($this, function () use (&$macro, &$parameters) { - return $this->executeCallable($macro, ...$parameters); - }); - } - - protected static function getGenericMacros() - { - foreach (static::$globalGenericMacros as $list) { - foreach ($list as $macro) { - yield $macro; - } - } + (new NativeClock('UTC'))->sleep($seconds); } /** @@ -2571,10 +2584,192 @@ trait Date * @param array $parameters parameters list * * @throws UnknownMethodException|BadMethodCallException|ReflectionException|Throwable - * - * @return mixed */ - public function __call($method, $parameters) + public function __call(string $method, array $parameters): mixed + { + $unit = rtrim($method, 's'); + + return $this->callDiffAlias($unit, $parameters) + ?? $this->callHumanDiffAlias($unit, $parameters) + ?? $this->callRoundMethod($unit, $parameters) + ?? $this->callIsMethod($unit, $parameters) + ?? $this->callModifierMethod($unit, $parameters) + ?? $this->callPeriodMethod($method, $parameters) + ?? $this->callGetOrSetMethod($method, $parameters) + ?? $this->callMacroMethod($method, $parameters); + } + + /** + * Return the Carbon instance passed through, a now instance in the same timezone + * if null given or parse the input if string given. + */ + protected function resolveCarbon(DateTimeInterface|string|null $date): self + { + if (!$date) { + return $this->nowWithSameTz(); + } + + if (\is_string($date)) { + return $this->transmitFactory(fn () => static::parse($date, $this->getTimezone())); + } + + return $date instanceof self ? $date : $this->transmitFactory(static fn () => static::instance($date)); + } + + protected static function weekRotate(int $day, int $rotation): int + { + return (static::DAYS_PER_WEEK + $rotation % static::DAYS_PER_WEEK + $day) % static::DAYS_PER_WEEK; + } + + protected function executeCallable(callable $macro, ...$parameters) + { + if ($macro instanceof Closure) { + $boundMacro = @$macro->bindTo($this, static::class) ?: @$macro->bindTo(null, static::class); + + return \call_user_func_array($boundMacro ?: $macro, $parameters); + } + + return \call_user_func_array($macro, $parameters); + } + + protected function executeCallableWithContext(callable $macro, ...$parameters) + { + return static::bindMacroContext($this, function () use (&$macro, &$parameters) { + return $this->executeCallable($macro, ...$parameters); + }); + } + + protected function getAllGenericMacros(): Generator + { + yield from $this->localGenericMacros ?? []; + yield from $this->transmitFactory(static fn () => static::getGenericMacros()); + } + + protected static function getGenericMacros(): Generator + { + foreach ((FactoryImmutable::getInstance()->getSettings()['genericMacros'] ?? []) as $list) { + foreach ($list as $macro) { + yield $macro; + } + } + } + + protected static function executeStaticCallable(callable $macro, ...$parameters) + { + return static::bindMacroContext(null, function () use (&$macro, &$parameters) { + if ($macro instanceof Closure) { + $boundMacro = @Closure::bind($macro, null, static::class); + + return \call_user_func_array($boundMacro ?: $macro, $parameters); + } + + return \call_user_func_array($macro, $parameters); + }); + } + + protected function getTranslatedFormByRegExp($baseKey, $keySuffix, $context, $subKey, $defaultValue) + { + $key = $baseKey.$keySuffix; + $standaloneKey = "{$key}_standalone"; + $baseTranslation = $this->getTranslationMessage($key); + + if ($baseTranslation instanceof Closure) { + return $baseTranslation($this, $context, $subKey) ?: $defaultValue; + } + + if ( + $this->getTranslationMessage("$standaloneKey.$subKey") && + (!$context || (($regExp = $this->getTranslationMessage("{$baseKey}_regexp")) && !preg_match($regExp, $context))) + ) { + $key = $standaloneKey; + } + + return $this->getTranslationMessage("$key.$subKey", null, $defaultValue); + } + + private function callGetOrSetMethod(string $method, array $parameters): mixed + { + if (preg_match('/^([a-z]{2,})(In|Of)([A-Z][a-z]+)$/', $method)) { + $localStrictModeEnabled = $this->localStrictModeEnabled; + $this->localStrictModeEnabled = true; + + try { + return $this->callGetOrSet($method, $parameters[0] ?? null); + } catch (UnknownGetterException|UnknownSetterException|ImmutableException) { + // continue to macro + } finally { + $this->localStrictModeEnabled = $localStrictModeEnabled; + } + } + + return null; + } + + private function callGetOrSet(string $name, mixed $value): mixed + { + if ($value !== null) { + if (\is_string($value) || \is_int($value) || \is_float($value) || $value instanceof DateTimeZone || $value instanceof Month) { + return $this->set($name, $value); + } + + return null; + } + + return $this->get($name); + } + + private function getUTCUnit(string $unit): ?string + { + if (str_starts_with($unit, 'Real')) { + return substr($unit, 4); + } + + if (str_starts_with($unit, 'UTC')) { + return substr($unit, 3); + } + + return null; + } + + private function callDiffAlias(string $method, array $parameters): mixed + { + if (preg_match('/^(diff|floatDiff)In(Real|UTC|Utc)?(.+)$/', $method, $match)) { + $mode = strtoupper($match[2] ?? ''); + $betterMethod = $match[1] === 'floatDiff' ? str_replace('floatDiff', 'diff', $method) : null; + + if ($mode === 'REAL') { + $mode = 'UTC'; + $betterMethod = str_replace($match[2], 'UTC', $betterMethod ?? $method); + } + + if ($betterMethod) { + @trigger_error( + "Use the method $betterMethod instead to make it more explicit about what it does.\n". + 'On next major version, "float" prefix will be removed (as all diff are now returning floating numbers)'. + ' and "Real" methods will be removed in favor of "UTC" because what it actually does is to convert both'. + ' dates to UTC timezone before comparison, while by default it does it only if both dates don\'t have'. + ' exactly the same timezone (Note: 2 timezones with the same offset but different names are considered'. + " different as it's not safe to assume they will always have the same offset).", + \E_USER_DEPRECATED, + ); + } + + $unit = self::pluralUnit($match[3]); + $diffMethod = 'diffIn'.ucfirst($unit); + + if (\in_array($unit, ['days', 'weeks', 'months', 'quarters', 'years'])) { + $parameters['utc'] = ($mode === 'UTC'); + } + + if (method_exists($this, $diffMethod)) { + return $this->$diffMethod(...$parameters); + } + } + + return null; + } + + private function callHumanDiffAlias(string $method, array $parameters): ?string { $diffSizes = [ // @mode diffForHumans @@ -2595,7 +2790,7 @@ trait Date $sizePattern = implode('|', array_keys($diffSizes)); $syntaxPattern = implode('|', array_keys($diffSyntaxModes)); - if (preg_match("/^(?$sizePattern)(?$syntaxPattern)DiffForHumans$/", $method, $match)) { + if (preg_match("/^(?$sizePattern)(?$syntaxPattern)DiffForHuman$/", $method, $match)) { $dates = array_filter($parameters, function ($parameter) { return $parameter instanceof DateTimeInterface; }); @@ -2610,38 +2805,73 @@ trait Date return $this->diffForHumans($other, $diffSyntaxModes[$match['syntax']], $diffSizes[$match['size']], ...$parameters); } - $roundedValue = $this->callRoundMethod($method, $parameters); + return null; + } - if ($roundedValue !== null) { - return $roundedValue; + private function callIsMethod(string $unit, array $parameters): ?bool + { + if (!str_starts_with($unit, 'is')) { + return null; } - $unit = rtrim($method, 's'); + $word = substr($unit, 2); - if (str_starts_with($unit, 'is')) { - $word = substr($unit, 2); + if (\in_array($word, static::$days, true)) { + return $this->isDayOfWeek($word); + } - if (\in_array($word, static::$days, true)) { - return $this->isDayOfWeek($word); - } + return match ($word) { + // @call is Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) + 'Utc', 'UTC' => $this->utc, + // @call is Check if the current instance has non-UTC timezone. + 'Local' => $this->local, + // @call is Check if the current instance is a valid date. + 'Valid' => $this->year !== 0, + // @call is Check if the current instance is in a daylight saving time. + 'DST' => $this->dst, + default => $this->callComparatorMethod($word, $parameters), + }; + } - switch ($word) { - // @call is Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.) - case 'Utc': - case 'UTC': - return $this->utc; - // @call is Check if the current instance has non-UTC timezone. - case 'Local': - return $this->local; - // @call is Check if the current instance is a valid date. - case 'Valid': - return $this->year !== 0; - // @call is Check if the current instance is in a daylight saving time. - case 'DST': - return $this->dst; + private function callComparatorMethod(string $unit, array $parameters): ?bool + { + $start = substr($unit, 0, 4); + $factor = -1; + + if ($start === 'Last') { + $start = 'Next'; + $factor = 1; + } + + if ($start === 'Next') { + $lowerUnit = strtolower(substr($unit, 4)); + + if (static::isModifiableUnit($lowerUnit)) { + return $this->avoidMutation()->addUnit($lowerUnit, $factor, false)->isSameUnit($lowerUnit, ...($parameters ?: ['now'])); } } + if ($start === 'Same') { + try { + return $this->isSameUnit(strtolower(substr($unit, 4)), ...$parameters); + } catch (BadComparisonUnitException) { + // Try next + } + } + + if (str_starts_with($unit, 'Current')) { + try { + return $this->isCurrentUnit(strtolower(substr($unit, 7))); + } catch (BadComparisonUnitException | BadMethodCallException) { + // Try next + } + } + + return null; + } + + private function callModifierMethod(string $unit, array $parameters): ?static + { $action = substr($unit, 0, 3); $overflow = null; @@ -2655,11 +2885,12 @@ trait Date if ($action === 'add' || $action === 'sub') { $unit = substr($unit, 3); + $utcUnit = $this->getUTCUnit($unit); - if (str_starts_with($unit, 'Real')) { - $unit = static::singularUnit(substr($unit, 4)); + if ($utcUnit) { + $unit = static::singularUnit($utcUnit); - return $this->{"{$action}RealUnit"}($unit, ...$parameters); + return $this->{"{$action}UTCUnit"}($unit, ...$parameters); } if (preg_match('/^(Month|Quarter|Year|Decade|Century|Centurie|Millennium|Millennia)s?(No|With|Without|WithNo)Overflow$/', $unit, $match)) { @@ -2674,38 +2905,11 @@ trait Date return $this->{"{$action}Unit"}($unit, $this->getMagicParameter($parameters, 0, 'value', 1), $overflow); } - $sixFirstLetters = substr($unit, 0, 6); - $factor = -1; - - if ($sixFirstLetters === 'isLast') { - $sixFirstLetters = 'isNext'; - $factor = 1; - } - - if ($sixFirstLetters === 'isNext') { - $lowerUnit = strtolower(substr($unit, 6)); - - if (static::isModifiableUnit($lowerUnit)) { - return $this->copy()->addUnit($lowerUnit, $factor, false)->isSameUnit($lowerUnit, ...$parameters); - } - } - - if ($sixFirstLetters === 'isSame') { - try { - return $this->isSameUnit(strtolower(substr($unit, 6)), ...$parameters); - } catch (BadComparisonUnitException $exception) { - // Try next - } - } - - if (str_starts_with($unit, 'isCurrent')) { - try { - return $this->isCurrentUnit(strtolower(substr($unit, 9))); - } catch (BadComparisonUnitException | BadMethodCallException $exception) { - // Try next - } - } + return null; + } + private function callPeriodMethod(string $method, array $parameters): ?CarbonPeriod + { if (str_ends_with($method, 'Until')) { try { $unit = static::singularUnit(substr($method, 0, -5)); @@ -2715,26 +2919,29 @@ trait Date $this->getMagicParameter($parameters, 1, 'factor', 1), $unit ); - } catch (InvalidArgumentException $exception) { + } catch (InvalidArgumentException) { // Try macros } } + return null; + } + + private function callMacroMethod(string $method, array $parameters): mixed + { return static::bindMacroContext($this, function () use (&$method, &$parameters) { $macro = $this->getLocalMacro($method); if (!$macro) { - foreach ([$this->localGenericMacros ?: [], static::getGenericMacros()] as $list) { - foreach ($list as $callback) { - try { - return $this->executeCallable($callback, $method, ...$parameters); - } catch (BadMethodCallException $exception) { - continue; - } + foreach ($this->getAllGenericMacros() as $callback) { + try { + return $this->executeCallable($callback, $method, ...$parameters); + } catch (BadMethodCallException) { + continue; } } - if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) { + if ($this->isLocalStrictModeEnabled()) { throw new UnknownMethodException($method); } @@ -2744,4 +2951,23 @@ trait Date return $this->executeCallable($macro, ...$parameters); }); } + + private static function floorZeroPad(int|float $value, int $length): string + { + return str_pad((string) floor($value), $length, '0', STR_PAD_LEFT); + } + + /** + * @template T of CarbonInterface + * + * @param T $date + * + * @return T + */ + private function mutateIfMutable(CarbonInterface $date): CarbonInterface + { + return $this instanceof DateTimeImmutable + ? $date + : $this->modify('@'.$date->rawFormat('U.u'))->setTimezone($date->getTimezone()); + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedPeriodProperties.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedPeriodProperties.php new file mode 100644 index 000000000..71660c3a8 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedPeriodProperties.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\Traits; + +use Carbon\CarbonInterface; +use Carbon\CarbonInterval; + +trait DeprecatedPeriodProperties +{ + /** + * Period start in PHP < 8.2. + * + * @var CarbonInterface + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period start. + */ + public $start; + + /** + * Period end in PHP < 8.2. + * + * @var CarbonInterface|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period end. + */ + public $end; + + /** + * Period current iterated date in PHP < 8.2. + * + * @var CarbonInterface|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period current iterated date. + */ + public $current; + + /** + * Period interval in PHP < 8.2. + * + * @var CarbonInterval|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period interval. + */ + public $interval; + + /** + * Period recurrences in PHP < 8.2. + * + * @var int|float|null + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period recurrences. + */ + public $recurrences; + + /** + * Period start included option in PHP < 8.2. + * + * @var bool + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period start included option. + */ + public $include_start_date; + + /** + * Period end included option in PHP < 8.2. + * + * @var bool + * + * @deprecated PHP 8.2 this property is no longer in sync with the actual period end included option. + */ + public $include_end_date; +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedProperties.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedProperties.php deleted file mode 100644 index 5acc6f5c7..000000000 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/DeprecatedProperties.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon\Traits; - -trait DeprecatedProperties -{ - /** - * the day of week in current locale LC_TIME - * - * @var string - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat('MMM') instead. - * Deprecated since 2.55.0 - */ - public $localeDayOfWeek; - - /** - * the abbreviated day of week in current locale LC_TIME - * - * @var string - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat('dddd') instead. - * Deprecated since 2.55.0 - */ - public $shortLocaleDayOfWeek; - - /** - * the month in current locale LC_TIME - * - * @var string - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat('ddd') instead. - * Deprecated since 2.55.0 - */ - public $localeMonth; - - /** - * the abbreviated month in current locale LC_TIME - * - * @var string - * - * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1. - * Use ->isoFormat('MMMM') instead. - * Deprecated since 2.55.0 - */ - public $shortLocaleMonth; -} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Difference.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Difference.php index ab5b65d23..db5fe1d27 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Difference.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Difference.php @@ -1,5 +1,7 @@ s !== 0 || $diff->i !== 0 || $diff->h !== 0 || $diff->d !== 0 || $diff->m !== 0 || $diff->y !== 0) { - $diff->f = (round($diff->f * 1000000) + 1000000) / 1000000; - $diff->s--; - - if ($diff->s < 0) { - $diff->s += 60; - $diff->i--; - - if ($diff->i < 0) { - $diff->i += 60; - $diff->h--; - - if ($diff->h < 0) { - $diff->h += 24; - $diff->d--; - - if ($diff->d < 0) { - $diff->d += 30; - $diff->m--; - - if ($diff->m < 0) { - $diff->m += 12; - $diff->y--; - } - } - } - } - } - - return; - } - - $diff->f *= -1; - $diff->invert(); - } - - /** - * @param DateInterval $diff - * @param bool $absolute - * - * @return CarbonInterval - */ - protected static function fixDiffInterval(DateInterval $diff, $absolute, array $skip = []) - { - $diff = CarbonInterval::instance($diff, $skip); - - // Work-around for https://bugs.php.net/bug.php?id=77145 - // @codeCoverageIgnoreStart - if ($diff->f > 0 && $diff->y === -1 && $diff->m === 11 && $diff->d >= 27 && $diff->h === 23 && $diff->i === 59 && $diff->s === 59) { - $diff->y = 0; - $diff->m = 0; - $diff->d = 0; - $diff->h = 0; - $diff->i = 0; - $diff->s = 0; - $diff->f = (1000000 - round($diff->f * 1000000)) / 1000000; - $diff->invert(); - } elseif ($diff->f < 0) { - static::fixNegativeMicroseconds($diff); - } - // @codeCoverageIgnoreEnd - - if ($absolute && $diff->invert) { - $diff->invert(); - } - - return $diff; - } - /** * Get the difference as a DateInterval instance. * Return relative interval (negative if $absolute flag is not set to true and the given date is before @@ -120,8 +45,7 @@ trait Difference * * @return DateInterval */ - #[ReturnTypeWillChange] - public function diff($date = null, $absolute = false) + public function diffAsDateInterval($date = null, bool $absolute = false): DateInterval { $other = $this->resolveCarbon($date); @@ -129,13 +53,11 @@ trait Difference // It was initially introduced for https://bugs.php.net/bug.php?id=80998 // The very specific case of 80998 was fixed in PHP 8.1beta3, but it introduced 81458 // So we still need to keep this for now - // @codeCoverageIgnoreStart - if (version_compare(PHP_VERSION, '8.1.0-dev', '>=') && $other->tz !== $this->tz) { - $other = $other->avoidMutation()->tz($this->tz); + if ($other->tz !== $this->tz) { + $other = $other->avoidMutation()->setTimezone($this->tz); } - // @codeCoverageIgnoreEnd - return parent::diff($other, (bool) $absolute); + return parent::diff($other, $absolute); } /** @@ -148,9 +70,49 @@ trait Difference * * @return CarbonInterval */ - public function diffAsCarbonInterval($date = null, $absolute = true, array $skip = []) + public function diffAsCarbonInterval($date = null, bool $absolute = false, array $skip = []): CarbonInterval { - return static::fixDiffInterval($this->diff($this->resolveCarbon($date), $absolute), $absolute, $skip); + return CarbonInterval::diff($this, $this->resolveCarbon($date), $absolute, $skip) + ->setLocalTranslator($this->getLocalTranslator()); + } + + /** + * @alias diffAsCarbonInterval + * + * Get the difference as a DateInterval instance. + * Return relative interval (negative if $absolute flag is not set to true and the given date is before + * current one). + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * + * @return CarbonInterval + */ + public function diff($date = null, bool $absolute = false, array $skip = []): CarbonInterval + { + return $this->diffAsCarbonInterval($date, $absolute, $skip); + } + + /** + * @param Unit|string $unit microsecond, millisecond, second, minute, + * hour, day, week, month, quarter, year, + * century, millennium + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInUnit(Unit|string $unit, $date = null, bool $absolute = false, bool $utc = false): float + { + $unit = static::pluralUnit($unit instanceof Unit ? $unit->value : rtrim($unit, 'z')); + $method = 'diffIn'.$unit; + + if (!method_exists($this, $method)) { + throw new UnknownUnitException($unit); + } + + return $this->$method($date, $absolute, $utc); } /** @@ -158,82 +120,165 @@ trait Difference * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInYears($date = null, $absolute = true) + public function diffInYears($date = null, bool $absolute = false, bool $utc = false): float { - return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%y'); - } + $start = $this; + $end = $this->resolveCarbon($date); - /** - * Get the difference in quarters rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInQuarters($date = null, $absolute = true) - { - return (int) ($this->diffInMonths($date, $absolute) / static::MONTHS_PER_QUARTER); - } - - /** - * Get the difference in months rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInMonths($date = null, $absolute = true) - { - $date = $this->resolveCarbon($date)->avoidMutation()->tz($this->tz); - - [$yearStart, $monthStart, $dayStart] = explode('-', $this->format('Y-m-dHisu')); - [$yearEnd, $monthEnd, $dayEnd] = explode('-', $date->format('Y-m-dHisu')); - - $diff = (((int) $yearEnd) - ((int) $yearStart)) * static::MONTHS_PER_YEAR + - ((int) $monthEnd) - ((int) $monthStart); - - if ($diff > 0) { - $diff -= ($dayStart > $dayEnd ? 1 : 0); - } elseif ($diff < 0) { - $diff += ($dayStart < $dayEnd ? 1 : 0); + if ($utc) { + $start = $start->avoidMutation()->utc(); + $end = $end->avoidMutation()->utc(); } - return $absolute ? abs($diff) : $diff; + $ascending = ($start <= $end); + $sign = $absolute || $ascending ? 1 : -1; + + if (!$ascending) { + [$start, $end] = [$end, $start]; + } + + $yearsDiff = (int) $start->diff($end, $absolute)->format('%r%y'); + /** @var Carbon|CarbonImmutable $floorEnd */ + $floorEnd = $start->avoidMutation()->addYears($yearsDiff); + + if ($floorEnd >= $end) { + return $sign * $yearsDiff; + } + + /** @var Carbon|CarbonImmutable $ceilEnd */ + $ceilEnd = $start->avoidMutation()->addYears($yearsDiff + 1); + + $daysToFloor = $floorEnd->diffInDays($end); + $daysToCeil = $end->diffInDays($ceilEnd); + + return $sign * ($yearsDiff + $daysToFloor / ($daysToCeil + $daysToFloor)); } /** - * Get the difference in weeks rounded down. + * Get the difference in quarters. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInWeeks($date = null, $absolute = true) + public function diffInQuarters($date = null, bool $absolute = false, bool $utc = false): float { - return (int) ($this->diffInDays($date, $absolute) / static::DAYS_PER_WEEK); + return $this->diffInMonths($date, $absolute, $utc) / static::MONTHS_PER_QUARTER; } /** - * Get the difference in days rounded down. + * Get the difference in months. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) * - * @return int + * @return float */ - public function diffInDays($date = null, $absolute = true) + public function diffInMonths($date = null, bool $absolute = false, bool $utc = false): float { - return $this->getIntervalDayDiff($this->diff($this->resolveCarbon($date), $absolute)); + $start = $this; + $end = $this->resolveCarbon($date); + + // Compare using UTC + if ($utc || ($end->timezoneName !== $start->timezoneName)) { + $start = $start->avoidMutation()->utc(); + $end = $end->avoidMutation()->utc(); + } + + [$yearStart, $monthStart, $dayStart] = explode('-', $start->format('Y-m-dHisu')); + [$yearEnd, $monthEnd, $dayEnd] = explode('-', $end->format('Y-m-dHisu')); + + $monthsDiff = (((int) $yearEnd) - ((int) $yearStart)) * static::MONTHS_PER_YEAR + + ((int) $monthEnd) - ((int) $monthStart); + + if ($monthsDiff > 0) { + $monthsDiff -= ($dayStart > $dayEnd ? 1 : 0); + } elseif ($monthsDiff < 0) { + $monthsDiff += ($dayStart < $dayEnd ? 1 : 0); + } + + $ascending = ($start <= $end); + $sign = $absolute || $ascending ? 1 : -1; + $monthsDiff = abs($monthsDiff); + + if (!$ascending) { + [$start, $end] = [$end, $start]; + } + + /** @var Carbon|CarbonImmutable $floorEnd */ + $floorEnd = $start->avoidMutation()->addMonths($monthsDiff); + + if ($floorEnd >= $end) { + return $sign * $monthsDiff; + } + + /** @var Carbon|CarbonImmutable $ceilEnd */ + $ceilEnd = $start->avoidMutation()->addMonths($monthsDiff + 1); + + $daysToFloor = $floorEnd->diffInDays($end); + $daysToCeil = $end->diffInDays($ceilEnd); + + return $sign * ($monthsDiff + $daysToFloor / ($daysToCeil + $daysToFloor)); } /** - * Get the difference in days using a filter closure rounded down. + * Get the difference in weeks. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInWeeks($date = null, bool $absolute = false, bool $utc = false): float + { + return $this->diffInDays($date, $absolute, $utc) / static::DAYS_PER_WEEK; + } + + /** + * Get the difference in days. + * + * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date + * @param bool $absolute Get the absolute of the difference + * @param bool $utc Always convert dates to UTC before comparing (if not set, it will do it only if timezones are different) + * + * @return float + */ + public function diffInDays($date = null, bool $absolute = false, bool $utc = false): float + { + $date = $this->resolveCarbon($date); + $current = $this; + + // Compare using UTC + if ($utc || ($date->timezoneName !== $current->timezoneName)) { + $date = $date->avoidMutation()->utc(); + $current = $current->avoidMutation()->utc(); + } + + $negative = ($date < $current); + [$start, $end] = $negative ? [$date, $current] : [$current, $date]; + $interval = $start->diffAsDateInterval($end); + $daysA = $this->getIntervalDayDiff($interval); + $floorEnd = $start->avoidMutation()->addDays($daysA); + $daysB = $daysA + ($floorEnd <= $end ? 1 : -1); + $ceilEnd = $start->avoidMutation()->addDays($daysB); + $microsecondsBetween = $floorEnd->diffInMicroseconds($ceilEnd); + $microsecondsToEnd = $floorEnd->diffInMicroseconds($end); + + return ($negative && !$absolute ? -1 : 1) + * ($daysA * ($microsecondsBetween - $microsecondsToEnd) + $daysB * $microsecondsToEnd) + / $microsecondsBetween; + } + + /** + * Get the difference in days using a filter closure. * * @param Closure $callback * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date @@ -241,13 +286,13 @@ trait Difference * * @return int */ - public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true) + public function diffInDaysFiltered(Closure $callback, $date = null, bool $absolute = false): int { return $this->diffFiltered(CarbonInterval::day(), $callback, $date, $absolute); } /** - * Get the difference in hours using a filter closure rounded down. + * Get the difference in hours using a filter closure. * * @param Closure $callback * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date @@ -255,7 +300,7 @@ trait Difference * * @return int */ - public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true) + public function diffInHoursFiltered(Closure $callback, $date = null, bool $absolute = false): int { return $this->diffFiltered(CarbonInterval::hour(), $callback, $date, $absolute); } @@ -270,7 +315,7 @@ trait Difference * * @return int */ - public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true) + public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, bool $absolute = false): int { $start = $this; $end = $this->resolveCarbon($date); @@ -289,109 +334,76 @@ trait Difference } /** - * Get the difference in weekdays rounded down. + * Get the difference in weekdays. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * * @return int */ - public function diffInWeekdays($date = null, $absolute = true) + public function diffInWeekdays($date = null, bool $absolute = false): int { - return $this->diffInDaysFiltered(static function (CarbonInterface $date) { - return $date->isWeekday(); - }, $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), $absolute); + return $this->diffInDaysFiltered( + static fn (CarbonInterface $date) => $date->isWeekday(), + $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), + $absolute, + ); } /** - * Get the difference in weekend days using a filter rounded down. + * Get the difference in weekend days using a filter. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * * @return int */ - public function diffInWeekendDays($date = null, $absolute = true) + public function diffInWeekendDays($date = null, bool $absolute = false): int { - return $this->diffInDaysFiltered(static function (CarbonInterface $date) { - return $date->isWeekend(); - }, $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), $absolute); + return $this->diffInDaysFiltered( + static fn (CarbonInterface $date) => $date->isWeekend(), + $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), + $absolute, + ); } /** - * Get the difference in hours rounded down. + * Get the difference in hours. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInHours($date = null, $absolute = true) + public function diffInHours($date = null, bool $absolute = false): float { - return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR); + return $this->diffInMinutes($date, $absolute) / static::MINUTES_PER_HOUR; } /** - * Get the difference in hours rounded down using timestamps. + * Get the difference in minutes. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInRealHours($date = null, $absolute = true) + public function diffInMinutes($date = null, bool $absolute = false): float { - return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR); + return $this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE; } /** - * Get the difference in minutes rounded down. + * Get the difference in seconds. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInMinutes($date = null, $absolute = true) + public function diffInSeconds($date = null, bool $absolute = false): float { - return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE); - } - - /** - * Get the difference in minutes rounded down using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMinutes($date = null, $absolute = true) - { - return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE); - } - - /** - * Get the difference in seconds rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInSeconds($date = null, $absolute = true) - { - $diff = $this->diff($date); - - if ($diff->days === 0) { - $diff = static::fixDiffInterval($diff, $absolute); - } - - $value = (((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) + - $diff->h) * static::MINUTES_PER_HOUR + - $diff->i) * static::SECONDS_PER_MINUTE + - $diff->s; - - return $absolute || !$diff->invert ? $value : -$value; + return $this->diffInMilliseconds($date, $absolute) / static::MILLISECONDS_PER_SECOND; } /** @@ -400,58 +412,9 @@ trait Difference * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * - * @return int + * @return float */ - public function diffInMicroseconds($date = null, $absolute = true) - { - $diff = $this->diff($date); - $value = (int) round(((((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) + - $diff->h) * static::MINUTES_PER_HOUR + - $diff->i) * static::SECONDS_PER_MINUTE + - ($diff->f + $diff->s)) * static::MICROSECONDS_PER_SECOND); - - return $absolute || !$diff->invert ? $value : -$value; - } - - /** - * Get the difference in milliseconds rounded down. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInMilliseconds($date = null, $absolute = true) - { - return (int) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND); - } - - /** - * Get the difference in seconds using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealSeconds($date = null, $absolute = true) - { - /** @var CarbonInterface $date */ - $date = $this->resolveCarbon($date); - $value = $date->getTimestamp() - $this->getTimestamp(); - - return $absolute ? abs($value) : $value; - } - - /** - * Get the difference in microseconds using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMicroseconds($date = null, $absolute = true) + public function diffInMicroseconds($date = null, bool $absolute = false): float { /** @var CarbonInterface $date */ $date = $this->resolveCarbon($date); @@ -462,319 +425,36 @@ trait Difference } /** - * Get the difference in milliseconds rounded down using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return int - */ - public function diffInRealMilliseconds($date = null, $absolute = true) - { - return (int) ($this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND); - } - - /** - * Get the difference in seconds as float (microsecond-precision). + * Get the difference in milliseconds. * * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date * @param bool $absolute Get the absolute of the difference * * @return float */ - public function floatDiffInSeconds($date = null, $absolute = true) + public function diffInMilliseconds($date = null, bool $absolute = false): float { - return (float) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND); - } - - /** - * Get the difference in minutes as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInMinutes($date = null, $absolute = true) - { - return $this->floatDiffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE; - } - - /** - * Get the difference in hours as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInHours($date = null, $absolute = true) - { - return $this->floatDiffInMinutes($date, $absolute) / static::MINUTES_PER_HOUR; - } - - /** - * Get the difference in days as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInDays($date = null, $absolute = true) - { - $hoursDiff = $this->floatDiffInHours($date, $absolute); - $interval = $this->diff($date, $absolute); - - if ($interval->y === 0 && $interval->m === 0 && $interval->d === 0) { - return $hoursDiff / static::HOURS_PER_DAY; - } - - $daysDiff = $this->getIntervalDayDiff($interval); - - return $daysDiff + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY; - } - - /** - * Get the difference in weeks as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInWeeks($date = null, $absolute = true) - { - return $this->floatDiffInDays($date, $absolute) / static::DAYS_PER_WEEK; - } - - /** - * Get the difference in months as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInMonths($date = null, $absolute = true) - { - $start = $this; - $end = $this->resolveCarbon($date); - $ascending = ($start <= $end); - $sign = $absolute || $ascending ? 1 : -1; - if (!$ascending) { - [$start, $end] = [$end, $start]; - } - $monthsDiff = $start->diffInMonths($end); - /** @var Carbon|CarbonImmutable $floorEnd */ - $floorEnd = $start->avoidMutation()->addMonths($monthsDiff); - - if ($floorEnd >= $end) { - return $sign * $monthsDiff; - } - - /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */ - $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth(); - - if ($startOfMonthAfterFloorEnd > $end) { - return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth); - } - - return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInDays($end) / $end->daysInMonth); - } - - /** - * Get the difference in year as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInYears($date = null, $absolute = true) - { - $start = $this; - $end = $this->resolveCarbon($date); - $ascending = ($start <= $end); - $sign = $absolute || $ascending ? 1 : -1; - if (!$ascending) { - [$start, $end] = [$end, $start]; - } - $yearsDiff = $start->diffInYears($end); - /** @var Carbon|CarbonImmutable $floorEnd */ - $floorEnd = $start->avoidMutation()->addYears($yearsDiff); - - if ($floorEnd >= $end) { - return $sign * $yearsDiff; - } - - /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */ - $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear(); - - if ($startOfYearAfterFloorEnd > $end) { - return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear); - } - - return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInDays($end) / $end->daysInYear); - } - - /** - * Get the difference in seconds as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealSeconds($date = null, $absolute = true) - { - return $this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND; - } - - /** - * Get the difference in minutes as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealMinutes($date = null, $absolute = true) - { - return $this->floatDiffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE; - } - - /** - * Get the difference in hours as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealHours($date = null, $absolute = true) - { - return $this->floatDiffInRealMinutes($date, $absolute) / static::MINUTES_PER_HOUR; - } - - /** - * Get the difference in days as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealDays($date = null, $absolute = true) - { - $date = $this->resolveUTC($date); - $utc = $this->avoidMutation()->utc(); - $hoursDiff = $utc->floatDiffInRealHours($date, $absolute); - - return ($hoursDiff < 0 ? -1 : 1) * $utc->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY; - } - - /** - * Get the difference in weeks as float (microsecond-precision). - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealWeeks($date = null, $absolute = true) - { - return $this->floatDiffInRealDays($date, $absolute) / static::DAYS_PER_WEEK; - } - - /** - * Get the difference in months as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealMonths($date = null, $absolute = true) - { - $start = $this; - $end = $this->resolveCarbon($date); - $ascending = ($start <= $end); - $sign = $absolute || $ascending ? 1 : -1; - if (!$ascending) { - [$start, $end] = [$end, $start]; - } - $monthsDiff = $start->diffInMonths($end); - /** @var Carbon|CarbonImmutable $floorEnd */ - $floorEnd = $start->avoidMutation()->addMonths($monthsDiff); - - if ($floorEnd >= $end) { - return $sign * $monthsDiff; - } - - /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */ - $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth(); - - if ($startOfMonthAfterFloorEnd > $end) { - return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth); - } - - return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInMonth); - } - - /** - * Get the difference in year as float (microsecond-precision) using timestamps. - * - * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date - * @param bool $absolute Get the absolute of the difference - * - * @return float - */ - public function floatDiffInRealYears($date = null, $absolute = true) - { - $start = $this; - $end = $this->resolveCarbon($date); - $ascending = ($start <= $end); - $sign = $absolute || $ascending ? 1 : -1; - if (!$ascending) { - [$start, $end] = [$end, $start]; - } - $yearsDiff = $start->diffInYears($end); - /** @var Carbon|CarbonImmutable $floorEnd */ - $floorEnd = $start->avoidMutation()->addYears($yearsDiff); - - if ($floorEnd >= $end) { - return $sign * $yearsDiff; - } - - /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */ - $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear(); - - if ($startOfYearAfterFloorEnd > $end) { - return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear); - } - - return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInYear); + return $this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND; } /** * The number of seconds since midnight. * - * @return int + * @return float */ - public function secondsSinceMidnight() + public function secondsSinceMidnight(): float { - return $this->diffInSeconds($this->avoidMutation()->startOfDay()); + return $this->diffInSeconds($this->copy()->startOfDay(), true); } /** * The number of seconds until 23:59:59. * - * @return int + * @return float */ - public function secondsUntilEndOfDay() + public function secondsUntilEndOfDay(): float { - return $this->diffInSeconds($this->avoidMutation()->endOfDay()); + return $this->diffInSeconds($this->copy()->endOfDay(), true); } /** @@ -790,41 +470,44 @@ trait Difference * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . "\n"; * ``` * - * @param Carbon|\DateTimeInterface|string|array|null $other if array passed, will be used as parameters array, see $syntax below; - * if null passed, now will be used as comparison reference; - * if any other type, it will be converted to date and used as reference. - * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contains: - * - 'syntax' entry (see below) - * - 'short' entry (see below) - * - 'parts' entry (see below) - * - 'options' entry (see below) - * - 'skip' entry, list of units to skip (array of strings or a single string, - * ` it can be the unit name (singular or plural) or its shortcut - * ` (y, m, w, d, h, min, s, ms, µs). - * - 'aUnit' entry, prefer "an hour" over "1 hour" if true - * - 'join' entry determines how to join multiple parts of the string - * ` - if $join is a string, it's used as a joiner glue - * ` - if $join is a callable/closure, it get the list of string and should return a string - * ` - if $join is an array, the first item will be the default glue, and the second item - * ` will be used instead of the glue for the last item - * ` - if $join is true, it will be guessed from the locale ('list' translation file entry) - * ` - if $join is missing, a space will be used as glue - * - 'other' entry (see above) - * - 'minimumUnit' entry determines the smallest unit of time to display can be long or - * ` short form of the units, e.g. 'hour' or 'h' (default value: s) - * if int passed, it add modifiers: - * Possible values: - * - CarbonInterface::DIFF_ABSOLUTE no modifiers - * - CarbonInterface::DIFF_RELATIVE_TO_NOW add ago/from now modifier - * - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier - * Default value: CarbonInterface::DIFF_ABSOLUTE - * @param bool $short displays short format of time units - * @param int $parts maximum number of parts to display (default value: 1: single unit) - * @param int $options human diff options - * - * @return string + * @param Carbon|DateTimeInterface|string|array|null $other if array passed, will be used as parameters array, see $syntax below; + * if null passed, now will be used as comparison reference; + * if any other type, it will be converted to date and used as reference. + * @param int|array $syntax if array passed, parameters will be extracted from it, the array may contains: + * ⦿ 'syntax' entry (see below) + * ⦿ 'short' entry (see below) + * ⦿ 'parts' entry (see below) + * ⦿ 'options' entry (see below) + * ⦿ 'skip' entry, list of units to skip (array of strings or a single string, + * ` it can be the unit name (singular or plural) or its shortcut + * ` (y, m, w, d, h, min, s, ms, µs). + * ⦿ 'aUnit' entry, prefer "an hour" over "1 hour" if true + * ⦿ 'altNumbers' entry, use alternative numbers if available + * ` (from the current language if true is passed, from the given language(s) + * ` if array or string is passed) + * ⦿ 'join' entry determines how to join multiple parts of the string + * ` - if $join is a string, it's used as a joiner glue + * ` - if $join is a callable/closure, it get the list of string and should return a string + * ` - if $join is an array, the first item will be the default glue, and the second item + * ` will be used instead of the glue for the last item + * ` - if $join is true, it will be guessed from the locale ('list' translation file entry) + * ` - if $join is missing, a space will be used as glue + * ⦿ 'other' entry (see above) + * ⦿ 'minimumUnit' entry determines the smallest unit of time to display can be long or + * ` short form of the units, e.g. 'hour' or 'h' (default value: s) + * ⦿ 'locale' language in which the diff should be output (has no effect if 'translator' key is set) + * ⦿ 'translator' a custom translator to use to translator the output. + * if int passed, it adds modifiers: + * Possible values: + * - CarbonInterface::DIFF_ABSOLUTE no modifiers + * - CarbonInterface::DIFF_RELATIVE_TO_NOW add ago/from now modifier + * - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier + * Default value: CarbonInterface::DIFF_ABSOLUTE + * @param bool $short displays short format of time units + * @param int $parts maximum number of parts to display (default value: 1: single unit) + * @param int $options human diff options */ - public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null) + public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null): string { /* @var CarbonInterface $this */ if (\is_array($other)) { @@ -834,19 +517,22 @@ trait Difference } $intSyntax = &$syntax; + if (\is_array($syntax)) { $syntax['syntax'] = $syntax['syntax'] ?? null; $intSyntax = &$syntax['syntax']; } + $intSyntax = (int) ($intSyntax ?? static::DIFF_RELATIVE_AUTO); $intSyntax = $intSyntax === static::DIFF_RELATIVE_AUTO && $other === null ? static::DIFF_RELATIVE_TO_NOW : $intSyntax; $parts = min(7, max(1, (int) $parts)); $skip = \is_array($syntax) ? ($syntax['skip'] ?? []) : []; + $options ??= $this->localHumanDiffOptions ?? $this->transmitFactory( + static fn () => static::getHumanDiffOptions(), + ); - return $this->diffAsCarbonInterval($other, false, (array) $skip) - ->setLocalTranslator($this->getLocalTranslator()) - ->forHumans($syntax, (bool) $short, $parts, $options ?? $this->localHumanDiffOptions ?? static::getHumanDiffOptions()); + return $this->diff($other, skip: (array) $skip)->forHumans($syntax, (bool) $short, $parts, $options); } /** @@ -1107,22 +793,21 @@ trait Difference } /** - * Get the difference in a human readable format in the current locale from current instance to an other + * Get the difference in a human-readable format in the current locale from current instance to another * instance given (or now if null given). * * @return string */ - public function timespan($other = null, $timezone = null) + public function timespan($other = null, $timezone = null): string { - if (!$other instanceof DateTimeInterface) { - $other = static::parse($other, $timezone); + if (\is_string($other)) { + $other = $this->transmitFactory(static fn () => static::parse($other, $timezone)); } return $this->diffForHumans($other, [ 'join' => ', ', 'syntax' => CarbonInterface::DIFF_ABSOLUTE, - 'options' => CarbonInterface::NO_ZERO_DIFF, - 'parts' => -1, + 'parts' => INF, ]); } @@ -1144,12 +829,12 @@ trait Difference /** @var CarbonInterface $other */ $other = $this->resolveCarbon($referenceTime)->avoidMutation()->setTimezone($this->getTimezone())->startOfDay(); $diff = $other->diffInDays($current, false); - $format = $diff < -6 ? 'sameElse' : ( + $format = $diff <= -static::DAYS_PER_WEEK ? 'sameElse' : ( $diff < -1 ? 'lastWeek' : ( $diff < 0 ? 'lastDay' : ( $diff < 1 ? 'sameDay' : ( $diff < 2 ? 'nextDay' : ( - $diff < 7 ? 'nextWeek' : 'sameElse' + $diff < static::DAYS_PER_WEEK ? 'nextWeek' : 'sameElse' ) ) ) @@ -1165,18 +850,6 @@ trait Difference private function getIntervalDayDiff(DateInterval $interval): int { - $daysDiff = (int) $interval->format('%a'); - $sign = $interval->format('%r') === '-' ? -1 : 1; - - if (\is_int($interval->days) && - $interval->y === 0 && - $interval->m === 0 && - version_compare(PHP_VERSION, '8.1.0-dev', '<') && - abs($interval->d - $daysDiff) === 1 - ) { - $daysDiff = abs($interval->d); // @codeCoverageIgnore - } - - return $daysDiff * $sign; + return (int) $interval->format('%r%a'); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php index f069c280d..e27c7bab7 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php @@ -1,5 +1,7 @@ forHumans(['locale' => 'en']); } if (\is_string($precision) && preg_match('/^\s*(?\d+)?\s*(?\w+)(?\W.*)?$/', $precision, $match)) { diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalStep.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalStep.php index 82d7c3264..2eaf9845d 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalStep.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/IntervalStep.php @@ -1,5 +1,7 @@ resolveCarbon($dateTime); if ($this->step) { - return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->avoidMutation(), $negated)); + $carbonDate = Callback::parameter($this->step, $carbonDate->avoidMutation()); + + return $carbonDate->modify(($this->step)($carbonDate, $negated)->format('Y-m-d H:i:s.u e O')); } if ($negated) { @@ -77,12 +82,8 @@ trait IntervalStep /** * Convert DateTimeImmutable instance to CarbonImmutable instance and DateTime instance to Carbon instance. - * - * @param DateTimeInterface $dateTime - * - * @return Carbon|CarbonImmutable */ - private function resolveCarbon(DateTimeInterface $dateTime) + private function resolveCarbon(DateTimeInterface $dateTime): Carbon|CarbonImmutable { if ($dateTime instanceof DateTimeImmutable) { return CarbonImmutable::instance($dateTime); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/LocalFactory.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/LocalFactory.php new file mode 100644 index 000000000..a03985498 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/LocalFactory.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\Traits; + +use Carbon\Factory; +use Carbon\FactoryImmutable; +use Carbon\WrapperClock; +use Closure; + +/** + * Remember the factory that was the current at the creation of the object. + */ +trait LocalFactory +{ + /** + * The clock that generated the current instance (or FactoryImmutable::getDefaultInstance() if none) + */ + private ?WrapperClock $clock = null; + + public function getClock(): ?WrapperClock + { + return $this->clock; + } + + private function initLocalFactory(): void + { + $this->clock = FactoryImmutable::getCurrentClock(); + } + + /** + * Trigger the given action using the local factory of the object, so it will be transmitted + * to any object also using this trait and calling initLocalFactory() in its constructor. + * + * @template T + * + * @param Closure(): T $action + * + * @return T + */ + private function transmitFactory(Closure $action): mixed + { + $previousClock = FactoryImmutable::getCurrentClock(); + FactoryImmutable::setCurrentClock($this->clock); + + try { + return $action(); + } finally { + FactoryImmutable::setCurrentClock($previousClock); + } + } + + private function getFactory(): Factory + { + return $this->getClock()?->getFactory() ?? FactoryImmutable::getDefaultInstance(); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Localization.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Localization.php index 46aff113e..8da7a17a3 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Localization.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Localization.php @@ -1,5 +1,7 @@ settings() method. - * @see settings - * - * @param int $humanDiffOptions - */ - public static function setHumanDiffOptions($humanDiffOptions) - { - static::$humanDiffOptions = $humanDiffOptions; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @see settings - * - * @param int $humanDiffOption - */ - public static function enableHumanDiffOption($humanDiffOption) - { - static::$humanDiffOptions = static::getHumanDiffOptions() | $humanDiffOption; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @see settings - * - * @param int $humanDiffOption - */ - public static function disableHumanDiffOption($humanDiffOption) - { - static::$humanDiffOptions = static::getHumanDiffOptions() & ~$humanDiffOption; - } - - /** - * Return default humanDiff() options (merged flags as integer). - * - * @return int - */ - public static function getHumanDiffOptions() - { - return static::$humanDiffOptions; - } - - /** - * Get the default translator instance in use. - * - * @return \Symfony\Component\Translation\TranslatorInterface - */ - public static function getTranslator() - { - return static::translator(); - } - - /** - * Set the default translator instance to use. - * - * @param \Symfony\Component\Translation\TranslatorInterface $translator - * - * @return void - */ - public static function setTranslator(TranslatorInterface $translator) - { - static::$translator = $translator; - } + protected ?TranslatorInterface $localTranslator = null; /** * Return true if the current instance has its own translator. - * - * @return bool */ - public function hasLocalTranslator() + public function hasLocalTranslator(): bool { return isset($this->localTranslator); } /** * Get the translator of the current instance or the default if none set. - * - * @return \Symfony\Component\Translation\TranslatorInterface */ - public function getLocalTranslator() + public function getLocalTranslator(): TranslatorInterface { - return $this->localTranslator ?: static::translator(); + return $this->localTranslator ?? $this->transmitFactory(static fn () => static::getTranslator()); } /** * Set the translator for the current instance. - * - * @param \Symfony\Component\Translation\TranslatorInterface $translator - * - * @return $this */ - public function setLocalTranslator(TranslatorInterface $translator) + public function setLocalTranslator(TranslatorInterface $translator): self { $this->localTranslator = $translator; @@ -167,19 +67,19 @@ trait Localization /** * Returns raw translation message for a given key. * - * @param \Symfony\Component\Translation\TranslatorInterface $translator the translator to use - * @param string $key key to find - * @param string|null $locale current locale used if null - * @param string|null $default default value if translation returns the key + * @param TranslatorInterface|null $translator the translator to use + * @param string $key key to find + * @param string|null $locale current locale used if null + * @param string|null $default default value if translation returns the key * - * @return string + * @return string|Closure|null */ public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) { if (!($translator instanceof TranslatorBagInterface && $translator instanceof TranslatorInterface)) { throw new InvalidTypeException( 'Translator does not implement '.TranslatorInterface::class.' and '.TranslatorBagInterface::class.'. '. - (\is_object($translator) ? \get_class($translator) : \gettype($translator)).' has been given.' + (\is_object($translator) ? \get_class($translator) : \gettype($translator)).' has been given.', ); } @@ -195,25 +95,25 @@ trait Localization /** * Returns raw translation message for a given key. * - * @param string $key key to find - * @param string|null $locale current locale used if null - * @param string|null $default default value if translation returns the key - * @param \Symfony\Component\Translation\TranslatorInterface $translator an optional translator to use + * @param string $key key to find + * @param string|null $locale current locale used if null + * @param string|null $default default value if translation returns the key + * @param TranslatorInterface $translator an optional translator to use * * @return string */ public function getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null) { - return static::getTranslationMessageWith($translator ?: $this->getLocalTranslator(), $key, $locale, $default); + return static::getTranslationMessageWith($translator ?? $this->getLocalTranslator(), $key, $locale, $default); } /** * Translate using translation string or callback available. * - * @param \Symfony\Component\Translation\TranslatorInterface $translator - * @param string $key - * @param array $parameters - * @param null $number + * @param TranslatorInterface $translator an optional translator to use + * @param string $key key to find + * @param array $parameters replacement parameters + * @param int|float|null $number number if plural * * @return string */ @@ -231,32 +131,31 @@ trait Localization $parameters[':count'] = $parameters['%count%']; } - // @codeCoverageIgnoreStart - $choice = $translator instanceof ContractsTranslatorInterface - ? $translator->trans($key, $parameters) - : $translator->transChoice($key, $number, $parameters); - // @codeCoverageIgnoreEnd - - return (string) $choice; + return (string) $translator->trans($key, $parameters); } /** * Translate using translation string or callback available. * - * @param string $key - * @param array $parameters - * @param string|int|float|null $number - * @param \Symfony\Component\Translation\TranslatorInterface|null $translator - * @param bool $altNumbers + * @param string $key key to find + * @param array $parameters replacement parameters + * @param string|int|float|null $number number if plural + * @param TranslatorInterface|null $translator an optional translator to use + * @param bool $altNumbers pass true to use alternative numbers * * @return string */ - public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string - { - $translation = static::translateWith($translator ?: $this->getLocalTranslator(), $key, $parameters, $number); + public function translate( + string $key, + array $parameters = [], + string|int|float|null $number = null, + ?TranslatorInterface $translator = null, + bool $altNumbers = false, + ): string { + $translation = static::translateWith($translator ?? $this->getLocalTranslator(), $key, $parameters, $number); if ($number !== null && $altNumbers) { - return str_replace($number, $this->translateNumber($number), $translation); + return str_replace((string) $number, $this->translateNumber((int) $number), $translation); } return $translation; @@ -328,11 +227,15 @@ trait Localization * * @return string */ - public static function translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL) - { + public static function translateTimeString( + string $timeString, + ?string $from = null, + ?string $to = null, + int $mode = CarbonInterface::TRANSLATE_ALL, + ): string { // Fallback source and destination locales $from = $from ?: static::getLocale(); - $to = $to ?: 'en'; + $to = $to ?: CarbonInterface::DEFAULT_LOCALE; if ($from === $to) { return $timeString; @@ -379,10 +282,10 @@ trait Localization } $$translationKey = array_merge( - $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($months, 12, $timeString) : [], - $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($messages['months_short'] ?? [], 12, $timeString) : [], - $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($weekdays, 7, $timeString) : [], - $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($messages['weekdays_short'] ?? [], 7, $timeString) : [], + $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($months, static::MONTHS_PER_YEAR, $timeString) : [], + $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($messages['months_short'] ?? [], static::MONTHS_PER_YEAR, $timeString) : [], + $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($weekdays, static::DAYS_PER_WEEK, $timeString) : [], + $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($messages['weekdays_short'] ?? [], static::DAYS_PER_WEEK, $timeString) : [], $mode & CarbonInterface::TRANSLATE_DIFF ? static::translateWordsByKeys([ 'diff_now', 'diff_today', @@ -402,11 +305,11 @@ trait Localization ], $messages, $key) : [], $mode & CarbonInterface::TRANSLATE_MERIDIEM ? array_map(function ($hour) use ($meridiem) { if (\is_array($meridiem)) { - return $meridiem[$hour < 12 ? 0 : 1]; + return $meridiem[$hour < static::HOURS_PER_DAY / 2 ? 0 : 1]; } return $meridiem($hour, 0, false); - }, range(0, 23)) : [] + }, range(0, 23)) : [], ); } @@ -424,14 +327,14 @@ trait Localization } /** - * Translate a time string from the current locale (`$date->locale()`) to an other. + * Translate a time string from the current locale (`$date->locale()`) to another one. * * @param string $timeString time string to translate * @param string|null $to output locale of the result returned ("en" by default) * * @return string */ - public function translateTimeStringTo($timeString, $to = null) + public function translateTimeStringTo(string $timeString, ?string $to = null): string { return static::translateTimeString($timeString, $this->getTranslatorLocale(), $to); } @@ -444,7 +347,7 @@ trait Localization * * @return $this|string */ - public function locale(string $locale = null, ...$fallbackLocales) + public function locale(?string $locale = null, string ...$fallbackLocales): static|string { if ($locale === null) { return $this->getTranslatorLocale(); @@ -476,22 +379,20 @@ trait Localization * * @return string */ - public static function getLocale() + public static function getLocale(): string { return static::getLocaleAwareTranslator()->getLocale(); } /** * Set the current translator locale and indicate if the source locale file exists. - * Pass 'auto' as locale to use closest language from the current LC_TIME locale. + * Pass 'auto' as locale to use the closest language to the current LC_TIME locale. * * @param string $locale locale ex. en - * - * @return bool */ - public static function setLocale($locale) + public static function setLocale(string $locale): void { - return static::getLocaleAwareTranslator()->setLocale($locale) !== false; + static::getLocaleAwareTranslator()->setLocale($locale); } /** @@ -501,7 +402,7 @@ trait Localization * * @param string $locale */ - public static function setFallbackLocale($locale) + public static function setFallbackLocale(string $locale): void { $translator = static::getTranslator(); @@ -513,7 +414,7 @@ trait Localization $translator->setMessages($preferredLocale, array_replace_recursive( $translator->getMessages()[$locale] ?? [], Translator::get($locale)->getMessages()[$locale] ?? [], - $translator->getMessages($preferredLocale) + $translator->getMessages($preferredLocale), )); } } @@ -523,10 +424,8 @@ trait Localization * Get the fallback locale. * * @see https://symfony.com/doc/current/components/translation.html#fallback-locales - * - * @return string|null */ - public static function getFallbackLocale() + public static function getFallbackLocale(): ?string { $translator = static::getTranslator(); @@ -546,10 +445,17 @@ trait Localization * * @return mixed */ - public static function executeWithLocale($locale, $func) + public static function executeWithLocale(string $locale, callable $func): mixed { $currentLocale = static::getLocale(); - $result = $func(static::setLocale($locale) ? static::getLocale() : false, static::translator()); + static::setLocale($locale); + $newLocale = static::getLocale(); + $result = $func( + $newLocale === 'en' && strtolower(substr((string) $locale, 0, 2)) !== 'en' + ? false + : $newLocale, + static::getTranslator(), + ); static::setLocale($currentLocale); return $result; @@ -563,7 +469,7 @@ trait Localization * * @return bool */ - public static function localeHasShortUnits($locale) + public static function localeHasShortUnits(string $locale): bool { return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) { return ($newLocale && (($y = static::translateWith($translator, 'y')) !== 'y' && $y !== static::translateWith($translator, 'year'))) || ( @@ -584,7 +490,7 @@ trait Localization * * @return bool */ - public static function localeHasDiffSyntax($locale) + public static function localeHasDiffSyntax(string $locale): bool { return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) { if (!$newLocale) { @@ -615,7 +521,7 @@ trait Localization * * @return bool */ - public static function localeHasDiffOneDayWords($locale) + public static function localeHasDiffOneDayWords(string $locale): bool { return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) { return $newLocale && @@ -633,7 +539,7 @@ trait Localization * * @return bool */ - public static function localeHasDiffTwoDayWords($locale) + public static function localeHasDiffTwoDayWords(string $locale): bool { return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) { return $newLocale && @@ -692,29 +598,11 @@ trait Localization return $languages; } - /** - * Initialize the default translator instance if necessary. - * - * @return \Symfony\Component\Translation\TranslatorInterface - */ - protected static function translator() - { - if (static::$translator === null) { - static::$translator = Translator::get(); - } - - return static::$translator; - } - /** * Get the locale of a given translator. * * If null or omitted, current local translator is used. * If no local translator is in use, current global translator is used. - * - * @param null $translator - * - * @return string|null */ protected function getTranslatorLocale($translator = null): ?string { @@ -724,7 +612,7 @@ trait Localization $translator = static::getLocaleAwareTranslator($translator); - return $translator ? $translator->getLocale() : null; + return $translator?->getLocale(); } /** @@ -737,7 +625,7 @@ trait Localization protected static function getLocaleAwareTranslator($translator = null) { if (\func_num_args() === 0) { - $translator = static::translator(); + $translator = static::getTranslator(); } if ($translator && !($translator instanceof LocaleAwareInterface || method_exists($translator, 'getLocale'))) { @@ -756,8 +644,8 @@ trait Localization private static function getFromCatalogue($translator, $catalogue, string $id, string $domain = 'messages') { return $translator instanceof TranslatorStrongTypeInterface - ? $translator->getFromCatalogue($catalogue, $id, $domain) // @codeCoverageIgnore - : $catalogue->get($id, $domain); + ? $translator->getFromCatalogue($catalogue, $id, $domain) + : $catalogue->get($id, $domain); // @codeCoverageIgnore } /** @@ -771,7 +659,11 @@ trait Localization { $word = str_replace([':count', '%count', ':time'], '', $word); $word = strtr($word, ['’' => "'"]); - $word = preg_replace('/({\d+(,(\d+|Inf))?}|[\[\]]\d+(,(\d+|Inf))?[\[\]])/', '', $word); + $word = preg_replace( + '/\{(?:-?\d+(?:\.\d+)?|-?Inf)(?:,(?:-?\d+|-?Inf))?}|[\[\]](?:-?\d+(?:\.\d+)?|-?Inf)(?:,(?:-?\d+|-?Inf))?[\[\]]/', + '', + $word, + ); return trim($word); } @@ -800,7 +692,7 @@ trait Localization return $key === 'to' ? self::cleanWordFromTranslationString(end($parts)) - : '(?:'.implode('|', array_map([static::class, 'cleanWordFromTranslationString'], $parts)).')'; + : '(?:'.implode('|', array_map(static::cleanWordFromTranslationString(...), $parts)).')'; }, $keys); } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Macro.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Macro.php index 92b6c9d86..978c1994b 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Macro.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Macro.php @@ -1,5 +1,7 @@ hours(11)->userFormat(); * ``` * - * @param string $name - * @param object|callable $macro - * - * @return void + * @param-closure-this static $macro */ - public static function macro($name, $macro) + public static function macro(string $name, ?callable $macro): void { - static::$globalMacros[$name] = $macro; + FactoryImmutable::getDefaultInstance()->macro($name, $macro); } /** * Remove all macros and generic macros. */ - public static function resetMacros() + public static function resetMacros(): void { - static::$globalMacros = []; - static::$globalGenericMacros = []; + FactoryImmutable::getDefaultInstance()->resetMacros(); } /** * Register a custom macro. * - * @param object|callable $macro - * @param int $priority marco with higher priority is tried first + * @param callable $macro + * @param int $priority marco with higher priority is tried first * * @return void */ - public static function genericMacro($macro, $priority = 0) + public static function genericMacro(callable $macro, int $priority = 0): void { - if (!isset(static::$globalGenericMacros[$priority])) { - static::$globalGenericMacros[$priority] = []; - krsort(static::$globalGenericMacros, SORT_NUMERIC); - } - - static::$globalGenericMacros[$priority][] = $macro; + FactoryImmutable::getDefaultInstance()->genericMacro($macro, $priority); } /** @@ -93,44 +76,36 @@ trait Macro * * @return bool */ - public static function hasMacro($name) + public static function hasMacro(string $name): bool { - return isset(static::$globalMacros[$name]); + return FactoryImmutable::getInstance()->hasMacro($name); } /** * Get the raw callable macro registered globally for a given name. - * - * @param string $name - * - * @return callable|null */ - public static function getMacro($name) + public static function getMacro(string $name): ?callable { - return static::$globalMacros[$name] ?? null; + return FactoryImmutable::getInstance()->getMacro($name); } /** * Checks if macro is registered globally or locally. - * - * @param string $name - * - * @return bool */ - public function hasLocalMacro($name) + public function hasLocalMacro(string $name): bool { - return ($this->localMacros && isset($this->localMacros[$name])) || static::hasMacro($name); + return ($this->localMacros && isset($this->localMacros[$name])) || $this->transmitFactory( + static fn () => static::hasMacro($name), + ); } /** * Get the raw callable macro registered globally or locally for a given name. - * - * @param string $name - * - * @return callable|null */ - public function getLocalMacro($name) + public function getLocalMacro(string $name): ?callable { - return ($this->localMacros ?? [])[$name] ?? static::getMacro($name); + return ($this->localMacros ?? [])[$name] ?? $this->transmitFactory( + static fn () => static::getMacro($name), + ); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/MagicParameter.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/MagicParameter.php index 310a44d0c..d6595f186 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/MagicParameter.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/MagicParameter.php @@ -1,5 +1,7 @@ getMethods( - ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED + ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED, ); foreach ($methods as $method) { @@ -89,16 +83,15 @@ trait Mixin continue; } - $method->setAccessible(true); + $macro = $method->invoke($mixin); - static::macro($method->name, $method->invoke($mixin)); + if (\is_callable($macro)) { + static::macro($method->name, $macro); + } } } - /** - * @param string $trait - */ - private static function loadMixinTrait($trait) + private static function loadMixinTrait(string $trait): void { $context = eval(self::getAnonymousClassCodeForTrait($trait)); $className = \get_class($context); @@ -114,7 +107,7 @@ trait Mixin try { // @ is required to handle error if not converted into exceptions $closure = @$closureBase->bindTo($context); - } catch (Throwable $throwable) { // @codeCoverageIgnore + } catch (Throwable) { // @codeCoverageIgnore $closure = $closureBase; // @codeCoverageIgnore } @@ -167,7 +160,7 @@ trait Mixin } } - private static function getAnonymousClassCodeForTrait(string $trait) + private static function getAnonymousClassCodeForTrait(string $trait): string { return 'return new class() extends '.static::class.' {use '.$trait.';};'; } @@ -185,15 +178,8 @@ trait Mixin /** * Stack a Carbon context from inside calls of self::this() and execute a given action. - * - * @param static|null $context - * @param callable $callable - * - * @throws Throwable - * - * @return mixed */ - protected static function bindMacroContext($context, callable $callable) + protected static function bindMacroContext(?self $context, callable $callable): mixed { static::$macroContextStack[] = $context; @@ -206,20 +192,16 @@ trait Mixin /** * Return the current context from inside a macro callee or a null if static. - * - * @return static|null */ - protected static function context() + protected static function context(): ?static { return end(static::$macroContextStack) ?: null; } /** * Return the current context from inside a macro callee or a new one if static. - * - * @return static */ - protected static function this() + protected static function this(): static { return end(static::$macroContextStack) ?: new static(); } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Modifiers.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Modifiers.php index 39343d8fa..7fc0f9f6c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Modifiers.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Modifiers.php @@ -1,5 +1,7 @@ change( - 'next '.(\is_string($modifier) ? $modifier : static::$days[$modifier]) + 'next '.(\is_string($modifier) ? $modifier : static::$days[$modifier]), ); } @@ -157,7 +160,7 @@ trait Modifiers * * @param string|int|null $modifier * - * @return static|false + * @return static */ public function previous($modifier = null) { @@ -166,7 +169,7 @@ trait Modifiers } return $this->change( - 'last '.(\is_string($modifier) ? $modifier : static::$days[$modifier]) + 'last '.(\is_string($modifier) ? $modifier : static::$days[$modifier]), ); } @@ -341,7 +344,7 @@ trait Modifiers */ public function average($date = null) { - return $this->addRealMicroseconds((int) ($this->diffInRealMicroseconds($this->resolveCarbon($date), false) / 2)); + return $this->addRealMicroseconds((int) ($this->diffInMicroseconds($this->resolveCarbon($date), false) / 2)); } /** @@ -354,7 +357,7 @@ trait Modifiers */ public function closest($date1, $date2) { - return $this->diffInRealMicroseconds($date1) < $this->diffInRealMicroseconds($date2) ? $date1 : $date2; + return $this->diffInMicroseconds($date1, true) < $this->diffInMicroseconds($date2, true) ? $date1 : $date2; } /** @@ -367,7 +370,7 @@ trait Modifiers */ public function farthest($date1, $date2) { - return $this->diffInRealMicroseconds($date1) > $this->diffInRealMicroseconds($date2) ? $date1 : $date2; + return $this->diffInMicroseconds($date1, true) > $this->diffInMicroseconds($date2, true) ? $date1 : $date2; } /** @@ -431,12 +434,13 @@ trait Modifiers * * @see https://php.net/manual/en/datetime.modify.php * - * @return static|false + * @return static */ #[ReturnTypeWillChange] public function modify($modify) { - return parent::modify((string) $modify); + return parent::modify((string) $modify) + ?: throw new InvalidFormatException('Could not modify with: '.var_export($modify, true)); } /** @@ -451,7 +455,7 @@ trait Modifiers * * @param string $modifier * - * @return static|false + * @return static */ public function change($modifier) { diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Mutability.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Mutability.php index 561c867d0..9f45f5859 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Mutability.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Mutability.php @@ -1,5 +1,7 @@ - */ - protected static $regexFormats = [ - 'd' => '(3[01]|[12][0-9]|0[1-9])', - 'D' => '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)', - 'j' => '([123][0-9]|[1-9])', - 'l' => '([a-zA-Z]{2,})', - 'N' => '([1-7])', - 'S' => '(st|nd|rd|th)', - 'w' => '([0-6])', - 'z' => '(36[0-5]|3[0-5][0-9]|[12][0-9]{2}|[1-9]?[0-9])', - 'W' => '(5[012]|[1-4][0-9]|0?[1-9])', - 'F' => '([a-zA-Z]{2,})', - 'm' => '(1[012]|0[1-9])', - 'M' => '([a-zA-Z]{3})', - 'n' => '(1[012]|[1-9])', - 't' => '(2[89]|3[01])', - 'L' => '(0|1)', - 'o' => '([1-9][0-9]{0,4})', - 'Y' => '([1-9]?[0-9]{4})', - 'y' => '([0-9]{2})', - 'a' => '(am|pm)', - 'A' => '(AM|PM)', - 'B' => '([0-9]{3})', - 'g' => '(1[012]|[1-9])', - 'G' => '(2[0-3]|1?[0-9])', - 'h' => '(1[012]|0[1-9])', - 'H' => '(2[0-3]|[01][0-9])', - 'i' => '([0-5][0-9])', - 's' => '([0-5][0-9])', - 'u' => '([0-9]{1,6})', - 'v' => '([0-9]{1,3})', - 'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\/[a-zA-Z]*)', - 'I' => '(0|1)', - 'O' => '([+-](1[0123]|0[0-9])[0134][05])', - 'P' => '([+-](1[0123]|0[0-9]):[0134][05])', - 'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])', - 'T' => '([a-zA-Z]{1,5})', - 'Z' => '(-?[1-5]?[0-9]{1,4})', - 'U' => '([0-9]*)', - - // The formats below are combinations of the above formats. - 'c' => '(([1-9]?[0-9]{4})-(1[012]|0[1-9])-(3[01]|[12][0-9]|0[1-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])[+-](1[012]|0[0-9]):([0134][05]))', // Y-m-dTH:i:sP - 'r' => '(([a-zA-Z]{3}), ([123][0-9]|0[1-9]) ([a-zA-Z]{3}) ([1-9]?[0-9]{4}) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]) [+-](1[012]|0[0-9])([0134][05]))', // D, d M Y H:i:s O - ]; - - /** - * Format modifiers (such as available in createFromFormat) regex patterns. - * - * @var array - */ - protected static $regexFormatModifiers = [ - '*' => '.+', - ' ' => '[ ]', - '#' => '[;:\\/.,()-]', - '?' => '([^a]|[a])', - '!' => '', - '|' => '', - '+' => '', - ]; - - /** - * Indicates if months should be calculated with overflow. - * Global setting. - * - * @var bool - */ - protected static $monthsOverflow = true; - - /** - * Indicates if years should be calculated with overflow. - * Global setting. - * - * @var bool - */ - protected static $yearsOverflow = true; - - /** - * Indicates if the strict mode is in use. - * Global setting. - * - * @var bool - */ - protected static $strictModeEnabled = true; - - /** - * Function to call instead of format. - * - * @var string|callable|null - */ - protected static $formatFunction; - - /** - * Function to call instead of createFromFormat. - * - * @var string|callable|null - */ - protected static $createFromFormatFunction; - - /** - * Function to call instead of parse. - * - * @var string|callable|null - */ - protected static $parseFunction; - /** * Indicates if months should be calculated with overflow. * Specific setting. - * - * @var bool|null */ - protected $localMonthsOverflow; + protected ?bool $localMonthsOverflow = null; /** * Indicates if years should be calculated with overflow. * Specific setting. - * - * @var bool|null */ - protected $localYearsOverflow; + protected ?bool $localYearsOverflow = null; /** * Indicates if the strict mode is in use. * Specific setting. - * - * @var bool|null */ - protected $localStrictModeEnabled; + protected ?bool $localStrictModeEnabled = null; /** * Options for diffForHumans and forHumans methods. - * - * @var bool|null */ - protected $localHumanDiffOptions; + protected ?int $localHumanDiffOptions = null; /** * Format to use on string cast. * - * @var string|null + * @var string|callable|null */ - protected $localToStringFormat; + protected $localToStringFormat = null; /** * Format to use on JSON serialization. * - * @var string|null + * @var string|callable|null */ - protected $localSerializer; + protected $localSerializer = null; /** * Instance-specific macros. - * - * @var array|null */ - protected $localMacros; + protected ?array $localMacros = null; /** * Instance-specific generic macros. - * - * @var array|null */ - protected $localGenericMacros; + protected ?array $localGenericMacros = null; /** * Function to call instead of format. * * @var string|callable|null */ - protected $localFormatFunction; - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * @see settings - * - * Enable the strict mode (or disable with passing false). - * - * @param bool $strictModeEnabled - */ - public static function useStrictMode($strictModeEnabled = true) - { - static::$strictModeEnabled = $strictModeEnabled; - } - - /** - * Returns true if the strict mode is globally in use, false else. - * (It can be overridden in specific instances.) - * - * @return bool - */ - public static function isStrictModeEnabled() - { - return static::$strictModeEnabled; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @see settings - * - * Indicates if months should be calculated with overflow. - * - * @param bool $monthsOverflow - * - * @return void - */ - public static function useMonthsOverflow($monthsOverflow = true) - { - static::$monthsOverflow = $monthsOverflow; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @see settings - * - * Reset the month overflow behavior. - * - * @return void - */ - public static function resetMonthsOverflow() - { - static::$monthsOverflow = true; - } - - /** - * Get the month overflow global behavior (can be overridden in specific instances). - * - * @return bool - */ - public static function shouldOverflowMonths() - { - return static::$monthsOverflow; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @see settings - * - * Indicates if years should be calculated with overflow. - * - * @param bool $yearsOverflow - * - * @return void - */ - public static function useYearsOverflow($yearsOverflow = true) - { - static::$yearsOverflow = $yearsOverflow; - } - - /** - * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. - * You should rather use the ->settings() method. - * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants - * are available for quarters, years, decade, centuries, millennia (singular and plural forms). - * @see settings - * - * Reset the month overflow behavior. - * - * @return void - */ - public static function resetYearsOverflow() - { - static::$yearsOverflow = true; - } - - /** - * Get the month overflow global behavior (can be overridden in specific instances). - * - * @return bool - */ - public static function shouldOverflowYears() - { - return static::$yearsOverflow; - } + protected $localFormatFunction = null; /** * Set specific options. @@ -364,7 +102,7 @@ trait Options * * @return $this|static */ - public function settings(array $settings) + public function settings(array $settings): static { $this->localStrictModeEnabled = $settings['strictMode'] ?? null; $this->localMonthsOverflow = $settings['monthOverflow'] ?? null; @@ -384,6 +122,8 @@ trait Options } $this->locale(...$locales); + } elseif (isset($settings['translator']) && property_exists($this, 'localTranslator')) { + $this->localTranslator = $settings['translator']; } if (isset($settings['innerTimezone'])) { @@ -399,10 +139,8 @@ trait Options /** * Returns current local settings. - * - * @return array */ - public function getSettings() + public function getSettings(): array { $settings = []; $map = [ @@ -432,16 +170,14 @@ trait Options /** * Show truthy properties on var_dump(). - * - * @return array */ - public function __debugInfo() + public function __debugInfo(): array { $infos = array_filter(get_object_vars($this), static function ($var) { return $var; }); - foreach (['dumpProperties', 'constructedObjectId', 'constructed'] as $property) { + foreach (['dumpProperties', 'constructedObjectId', 'constructed', 'originalInput'] as $property) { if (isset($infos[$property])) { unset($infos[$property]); } @@ -449,21 +185,31 @@ trait Options $this->addExtraDebugInfos($infos); + foreach (["\0*\0", ''] as $prefix) { + $key = $prefix.'carbonRecurrences'; + + if (\array_key_exists($key, $infos)) { + $infos['recurrences'] = $infos[$key]; + unset($infos[$key]); + } + } + return $infos; } - protected function addExtraDebugInfos(&$infos): void + protected function isLocalStrictModeEnabled(): bool + { + return $this->localStrictModeEnabled + ?? $this->transmitFactory(static fn () => static::isStrictModeEnabled()); + } + + protected function addExtraDebugInfos(array &$infos): void { if ($this instanceof DateTimeInterface) { try { - if (!isset($infos['date'])) { - $infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT); - } - - if (!isset($infos['timezone'])) { - $infos['timezone'] = $this->tzName; - } - } catch (Throwable $exception) { + $infos['date'] ??= $this->format(CarbonInterface::MOCK_DATETIME_FORMAT); + $infos['timezone'] ??= $this->tzName ?? $this->timezoneSetting ?? $this->timezone ?? null; + } catch (Throwable) { // noop } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Rounding.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Rounding.php index 85ff5a711..4239c6689 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Rounding.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Rounding.php @@ -1,5 +1,7 @@ [static::YEARS_PER_MILLENNIUM, 'year'], @@ -113,7 +114,7 @@ trait Rounding } $changes[$unit] = round( - $minimum + ($fraction ? $fraction * $function(($this->$unit - $minimum) / $fraction) : 0) + $minimum + ($fraction ? $fraction * $function(($this->$unit - $minimum) / $fraction) : 0), ); // Cannot use modulo as it lose double precision @@ -140,63 +141,40 @@ trait Rounding /** * Truncate the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int $precision - * - * @return CarbonInterface */ - public function floorUnit($unit, $precision = 1) + public function floorUnit(string $unit, DateInterval|string|float|int $precision = 1): static { return $this->roundUnit($unit, $precision, 'floor'); } /** * Ceil the current instance at the given unit with given precision if specified. - * - * @param string $unit - * @param float|int $precision - * - * @return CarbonInterface */ - public function ceilUnit($unit, $precision = 1) + public function ceilUnit(string $unit, DateInterval|string|float|int $precision = 1): static { return $this->roundUnit($unit, $precision, 'ceil'); } /** * Round the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * @param string $function - * - * @return CarbonInterface */ - public function round($precision = 1, $function = 'round') + public function round(DateInterval|string|float|int $precision = 1, callable|string $function = 'round'): static { return $this->roundWith($precision, $function); } /** * Round the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * - * @return CarbonInterface */ - public function floor($precision = 1) + public function floor(DateInterval|string|float|int $precision = 1): static { return $this->round($precision, 'floor'); } /** * Ceil the current instance second with given precision if specified. - * - * @param float|int|string|\DateInterval|null $precision - * - * @return CarbonInterface */ - public function ceil($precision = 1) + public function ceil(DateInterval|string|float|int $precision = 1): static { return $this->round($precision, 'ceil'); } @@ -204,26 +182,22 @@ trait Rounding /** * Round the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function roundWeek($weekStartsAt = null) + public function roundWeek(WeekDay|int|null $weekStartsAt = null): static { return $this->closest( $this->avoidMutation()->floorWeek($weekStartsAt), - $this->avoidMutation()->ceilWeek($weekStartsAt) + $this->avoidMutation()->ceilWeek($weekStartsAt), ); } /** * Truncate the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function floorWeek($weekStartsAt = null) + public function floorWeek(WeekDay|int|null $weekStartsAt = null): static { return $this->startOfWeek($weekStartsAt); } @@ -231,11 +205,9 @@ trait Rounding /** * Ceil the current instance week. * - * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week - * - * @return CarbonInterface + * @param WeekDay|int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week */ - public function ceilWeek($weekStartsAt = null) + public function ceilWeek(WeekDay|int|null $weekStartsAt = null): static { if ($this->isMutable()) { $startOfWeek = $this->avoidMutation()->startOfWeek($weekStartsAt); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Serialization.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Serialization.php index c1d5c5e13..1cb5c824c 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Serialization.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Serialization.php @@ -1,5 +1,7 @@ [Carbon::class, CarbonImmutable::class]]); + * ``` + * + * @param \Stringable|string $value + * @param array $options example: ['allowed_classes' => [CarbonImmutable::class]] * * @throws InvalidFormatException * * @return static */ - public static function fromSerialized($value) + public static function fromSerialized($value, array $options = []): static { - $instance = @unserialize((string) $value); + $instance = @unserialize((string) $value, $options); if (!$instance instanceof static) { throw new InvalidFormatException("Invalid serialized value: $value"); @@ -103,7 +107,7 @@ trait Serialization * @return static */ #[ReturnTypeWillChange] - public static function __set_state($dump) + public static function __set_state($dump): static { if (\is_string($dump)) { return static::parse($dump); @@ -148,9 +152,9 @@ trait Serialization // @codeCoverageIgnoreStart if (isset($this->timezone_type, $this->timezone, $this->date)) { return [ - 'date' => $this->date ?? null, + 'date' => $this->date, 'timezone_type' => $this->timezone_type, - 'timezone' => $this->timezone ?? null, + 'timezone' => $this->dumpTimezone($this->timezone), ]; } // @codeCoverageIgnoreEnd @@ -164,9 +168,10 @@ trait Serialization // @codeCoverageIgnoreStart if (\extension_loaded('msgpack') && isset($this->constructedObjectId)) { + $timezone = $this->timezone ?? null; $export['dumpDateProperties'] = [ 'date' => $this->format('Y-m-d H:i:s.u'), - 'timezone' => serialize($this->timezone ?? null), + 'timezone' => $this->dumpTimezone($timezone), ]; } // @codeCoverageIgnoreEnd @@ -182,11 +187,8 @@ trait Serialization * Set locale if specified on unserialize() called. * * Only used by PHP < 7.4. - * - * @return void */ - #[ReturnTypeWillChange] - public function __wakeup() + public function __wakeup(): void { if (parent::class && method_exists(parent::class, '__wakeup')) { // @codeCoverageIgnoreStart @@ -196,8 +198,8 @@ trait Serialization try { // FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later. ['date' => $date, 'timezone' => $timezone] = $this->dumpDateProperties; - parent::__construct($date, unserialize($timezone)); - } catch (Throwable $ignoredException) { + parent::__construct($date, $timezone); + } catch (Throwable) { throw $exception; } } @@ -218,8 +220,6 @@ trait Serialization * Set locale if specified on unserialize() called. * * Only used by PHP >= 7.4. - * - * @return void */ public function __unserialize(array $data): void { @@ -234,8 +234,8 @@ trait Serialization try { // FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later. ['date' => $date, 'timezone' => $timezone] = $data['dumpDateProperties']; - $this->__construct($date, unserialize($timezone)); - } catch (Throwable $ignoredException) { + $this->__construct($date, $timezone); + } catch (Throwable) { throw $exception; } } @@ -248,13 +248,12 @@ trait Serialization /** * Prepare the object for JSON serialization. - * - * @return array|string */ - #[ReturnTypeWillChange] - public function jsonSerialize() + public function jsonSerialize(): mixed { - $serializer = $this->localSerializer ?? static::$serializer; + $serializer = $this->localSerializer + ?? $this->getFactory()->getSettings()['toJsonFormat'] + ?? null; if ($serializer) { return \is_string($serializer) @@ -270,14 +269,10 @@ trait Serialization * You should rather transform Carbon object before the serialization. * * JSON serialize all Carbon instances using the given callback. - * - * @param callable $callback - * - * @return void */ - public static function serializeUsing($callback) + public static function serializeUsing(string|callable|null $format): void { - static::$serializer = $callback; + FactoryImmutable::getDefaultInstance()->serializeUsing($format); } /** @@ -287,7 +282,7 @@ trait Serialization * var_export($date) * get_object_vars($date) */ - public function cleanupDumpProperties() + public function cleanupDumpProperties(): self { // @codeCoverageIgnoreStart if (PHP_VERSION < 8.2) { @@ -312,9 +307,10 @@ trait Serialization } if (isset($this->constructedObjectId)) { + $timezone = $this->timezone ?? null; $this->dumpDateProperties = [ 'date' => $this->format('Y-m-d H:i:s.u'), - 'timezone' => serialize($this->timezone ?? null), + 'timezone' => $this->dumpTimezone($timezone), ]; $properties[] = 'dumpDateProperties'; @@ -323,4 +319,10 @@ trait Serialization return $properties; // @codeCoverageIgnoreEnd } + + /** @codeCoverageIgnore */ + private function dumpTimezone(mixed $timezone): mixed + { + return $timezone instanceof DateTimeZone ? $timezone->getName() : $timezone; + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticLocalization.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticLocalization.php new file mode 100644 index 000000000..cb1e9e601 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticLocalization.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\Traits; + +use Carbon\FactoryImmutable; +use Symfony\Contracts\Translation\TranslatorInterface; + +/** + * Static config for localization. + */ +trait StaticLocalization +{ + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * @see settings + */ + public static function setHumanDiffOptions(int $humanDiffOptions): void + { + FactoryImmutable::getDefaultInstance()->setHumanDiffOptions($humanDiffOptions); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * @see settings + */ + public static function enableHumanDiffOption(int $humanDiffOption): void + { + FactoryImmutable::getDefaultInstance()->enableHumanDiffOption($humanDiffOption); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * @see settings + */ + public static function disableHumanDiffOption(int $humanDiffOption): void + { + FactoryImmutable::getDefaultInstance()->disableHumanDiffOption($humanDiffOption); + } + + /** + * Return default humanDiff() options (merged flags as integer). + */ + public static function getHumanDiffOptions(): int + { + return FactoryImmutable::getInstance()->getHumanDiffOptions(); + } + + /** + * Set the default translator instance to use. + * + * @param TranslatorInterface $translator + * + * @return void + */ + public static function setTranslator(TranslatorInterface $translator): void + { + FactoryImmutable::getDefaultInstance()->setTranslator($translator); + } + + /** + * Initialize the default translator instance if necessary. + */ + public static function getTranslator(): TranslatorInterface + { + return FactoryImmutable::getInstance()->getTranslator(); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticOptions.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticOptions.php new file mode 100644 index 000000000..44dd284e1 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/StaticOptions.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon\Traits; + +use Carbon\FactoryImmutable; + +/** + * Options related to a static variable. + */ +trait StaticOptions +{ + /////////////////////////////////////////////////////////////////// + ///////////// Behavior customization for sub-classes ////////////// + /////////////////////////////////////////////////////////////////// + + /** + * Function to call instead of format. + * + * @var string|callable|null + */ + protected static $formatFunction; + + /** + * Function to call instead of createFromFormat. + * + * @var string|callable|null + */ + protected static $createFromFormatFunction; + + /** + * Function to call instead of parse. + * + * @var string|callable|null + */ + protected static $parseFunction; + + /////////////////////////////////////////////////////////////////// + ///////////// Use default factory for static options ////////////// + /////////////////////////////////////////////////////////////////// + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * @see settings + * + * Enable the strict mode (or disable with passing false). + * + * @param bool $strictModeEnabled + */ + public static function useStrictMode(bool $strictModeEnabled = true): void + { + FactoryImmutable::getDefaultInstance()->useStrictMode($strictModeEnabled); + } + + /** + * Returns true if the strict mode is globally in use, false else. + * (It can be overridden in specific instances.) + * + * @return bool + */ + public static function isStrictModeEnabled(): bool + { + return FactoryImmutable::getInstance()->isStrictModeEnabled(); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants + * are available for quarters, years, decade, centuries, millennia (singular and plural forms). + * @see settings + * + * Indicates if months should be calculated with overflow. + * + * @param bool $monthsOverflow + * + * @return void + */ + public static function useMonthsOverflow(bool $monthsOverflow = true): void + { + FactoryImmutable::getDefaultInstance()->useMonthsOverflow($monthsOverflow); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants + * are available for quarters, years, decade, centuries, millennia (singular and plural forms). + * @see settings + * + * Reset the month overflow behavior. + * + * @return void + */ + public static function resetMonthsOverflow(): void + { + FactoryImmutable::getDefaultInstance()->resetMonthsOverflow(); + } + + /** + * Get the month overflow global behavior (can be overridden in specific instances). + * + * @return bool + */ + public static function shouldOverflowMonths(): bool + { + return FactoryImmutable::getInstance()->shouldOverflowMonths(); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants + * are available for quarters, years, decade, centuries, millennia (singular and plural forms). + * @see settings + * + * Indicates if years should be calculated with overflow. + * + * @param bool $yearsOverflow + * + * @return void + */ + public static function useYearsOverflow(bool $yearsOverflow = true): void + { + FactoryImmutable::getDefaultInstance()->useYearsOverflow($yearsOverflow); + } + + /** + * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. + * You should rather use the ->settings() method. + * Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants + * are available for quarters, years, decade, centuries, millennia (singular and plural forms). + * @see settings + * + * Reset the month overflow behavior. + * + * @return void + */ + public static function resetYearsOverflow(): void + { + FactoryImmutable::getDefaultInstance()->resetYearsOverflow(); + } + + /** + * Get the month overflow global behavior (can be overridden in specific instances). + * + * @return bool + */ + public static function shouldOverflowYears(): bool + { + return FactoryImmutable::getInstance()->shouldOverflowYears(); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Test.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Test.php index f23c72e8f..c642dbdbf 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Test.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Test.php @@ -1,5 +1,7 @@ setTestNow($testNow); } /** @@ -87,29 +74,9 @@ trait Test * * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance */ - public static function setTestNowAndTimezone($testNow = null, $tz = null) + public static function setTestNowAndTimezone($testNow = null, $timezone = null): void { - if ($testNow) { - self::$testDefaultTimezone = self::$testDefaultTimezone ?? date_default_timezone_get(); - } - - $useDateInstanceTimezone = $testNow instanceof DateTimeInterface; - - if ($useDateInstanceTimezone) { - self::setDefaultTimezone($testNow->getTimezone()->getName(), $testNow); - } - - static::setTestNow($testNow); - - if (!$useDateInstanceTimezone) { - $now = static::getMockedTestNow(\func_num_args() === 1 ? null : $tz); - $tzName = $now ? $now->tzName : null; - self::setDefaultTimezone($tzName ?? self::$testDefaultTimezone ?? 'UTC', $now); - } - - if (!$testNow) { - self::$testDefaultTimezone = null; - } + FactoryImmutable::getDefaultInstance()->setTestNowAndTimezone($testNow, $timezone); } /** @@ -126,28 +93,20 @@ trait Test * * @return T */ - public static function withTestNow($testNow, $callback) + public static function withTestNow(mixed $testNow, callable $callback): mixed { - static::setTestNow($testNow); - - try { - $result = $callback(); - } finally { - static::setTestNow(); - } - - return $result; + return FactoryImmutable::getDefaultInstance()->withTestNow($testNow, $callback); } /** * Get the Carbon instance (real or mock) to be returned when a "now" * instance is created. * - * @return Closure|static the current instance used for testing + * @return Closure|CarbonInterface|null the current instance used for testing */ - public static function getTestNow() + public static function getTestNow(): Closure|CarbonInterface|null { - return static::$testNow; + return FactoryImmutable::getInstance()->getTestNow(); } /** @@ -156,73 +115,71 @@ trait Test * * @return bool true if there is a test instance, otherwise false */ - public static function hasTestNow() + public static function hasTestNow(): bool { - return static::getTestNow() !== null; + return FactoryImmutable::getInstance()->hasTestNow(); } /** * Get the mocked date passed in setTestNow() and if it's a Closure, execute it. - * - * @param string|\DateTimeZone $tz - * - * @return \Carbon\CarbonImmutable|\Carbon\Carbon|null */ - protected static function getMockedTestNow($tz) + protected static function getMockedTestNow(DateTimeZone|string|int|null $timezone): ?CarbonInterface { - $testNow = static::getTestNow(); + $testNow = FactoryImmutable::getInstance()->handleTestNowClosure(static::getTestNow(), $timezone); - if ($testNow instanceof Closure) { - $realNow = new DateTimeImmutable('now'); - $testNow = $testNow(static::parse( - $realNow->format('Y-m-d H:i:s.u'), - $tz ?: $realNow->getTimezone() - )); + if ($testNow === null) { + return null; } - /* @var \Carbon\CarbonImmutable|\Carbon\Carbon|null $testNow */ - return $testNow instanceof CarbonInterface - ? $testNow->avoidMutation()->tz($tz) - : $testNow; + $testNow = $testNow->avoidMutation(); + + return $timezone ? $testNow->setTimezone($timezone) : $testNow; } - protected static function mockConstructorParameters(&$time, $tz) + private function mockConstructorParameters(&$time, ?CarbonTimeZone $timezone): void { - /** @var \Carbon\CarbonImmutable|\Carbon\Carbon $testInstance */ - $testInstance = clone static::getMockedTestNow($tz); + $clock = $this->clock?->unwrap(); + $now = $clock instanceof Factory + ? $clock->getTestNow() + : $this->nowFromClock($timezone); + $testInstance = $now ?? self::getMockedTestNowClone($timezone); + + if (!$testInstance) { + return; + } + + if ($testInstance instanceof DateTimeInterface) { + $testInstance = $testInstance->setTimezone($timezone ?? date_default_timezone_get()); + } if (static::hasRelativeKeywords($time)) { $testInstance = $testInstance->modify($time); } + $factory = $this->getClock()?->unwrap(); + + if (!($factory instanceof Factory)) { + $factory = FactoryImmutable::getInstance(); + } + + $testInstance = $factory->handleTestNowClosure($testInstance, $timezone); + $time = $testInstance instanceof self ? $testInstance->rawFormat(static::MOCK_DATETIME_FORMAT) : $testInstance->format(static::MOCK_DATETIME_FORMAT); } - private static function setDefaultTimezone($timezone, DateTimeInterface $date = null) + private function getMockedTestNowClone($timezone): CarbonInterface|self|null { - $previous = null; - $success = false; + $mock = static::getMockedTestNow($timezone); - try { - $success = date_default_timezone_set($timezone); - } catch (Throwable $exception) { - $previous = $exception; - } + return $mock ? clone $mock : null; + } - if (!$success) { - $suggestion = @CarbonTimeZone::create($timezone)->toRegionName($date); + private function nowFromClock(?CarbonTimeZone $timezone): ?DateTimeImmutable + { + $now = $this->clock?->now(); - throw new InvalidArgumentException( - "Timezone ID '$timezone' is invalid". - ($suggestion && $suggestion !== $timezone ? ", did you mean '$suggestion'?" : '.')."\n". - "It must be one of the IDs from DateTimeZone::listIdentifiers(),\n". - 'For the record, hours/minutes offset are relevant only for a particular moment, '. - 'but not as a default timezone.', - 0, - $previous - ); - } + return $now && $timezone ? $now->setTimezone($timezone) : null; } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Timestamp.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Timestamp.php index 88a465c93..dab448dec 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Timestamp.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Timestamp.php @@ -1,5 +1,7 @@ setTimezone($tz); + #[\ReturnTypeWillChange] + public static function createFromTimestamp( + float|int|string $timestamp, + DateTimeZone|string|int|null $timezone = null, + ): static { + $date = static::createFromTimestampUTC($timestamp); + + return $timezone === null ? $date : $date->setTimezone($timezone); } /** - * Create a Carbon instance from an timestamp keeping the timezone to UTC. + * Create a Carbon instance from a timestamp keeping the timezone to UTC. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $timestamp - * - * @return static */ - public static function createFromTimestampUTC($timestamp) + public static function createFromTimestampUTC(float|int|string $timestamp): static { [$integer, $decimal] = self::getIntegerAndDecimalParts($timestamp); $delta = floor($decimal / static::MICROSECONDS_PER_SECOND); @@ -60,7 +60,7 @@ trait Timestamp * * @return static */ - public static function createFromTimestampMsUTC($timestamp) + public static function createFromTimestampMsUTC($timestamp): static { [$milliseconds, $microseconds] = self::getIntegerAndDecimalParts($timestamp, 3); $sign = $milliseconds < 0 || ($milliseconds === 0.0 && $microseconds < 0) ? -1 : 1; @@ -68,9 +68,9 @@ trait Timestamp $microseconds = $sign * abs($microseconds) + static::MICROSECONDS_PER_MILLISECOND * ($milliseconds % static::MILLISECONDS_PER_SECOND); $seconds = $sign * floor($milliseconds / static::MILLISECONDS_PER_SECOND); $delta = floor($microseconds / static::MICROSECONDS_PER_SECOND); - $seconds += $delta; + $seconds = (int) ($seconds + $delta); $microseconds -= $delta * static::MICROSECONDS_PER_SECOND; - $microseconds = str_pad($microseconds, 6, '0', STR_PAD_LEFT); + $microseconds = str_pad((string) (int) $microseconds, 6, '0', STR_PAD_LEFT); return static::rawCreateFromFormat('U u', "$seconds $microseconds"); } @@ -79,30 +79,24 @@ trait Timestamp * Create a Carbon instance from a timestamp in milliseconds. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $timestamp - * @param \DateTimeZone|string|null $tz - * - * @return static */ - public static function createFromTimestampMs($timestamp, $tz = null) - { - return static::createFromTimestampMsUTC($timestamp) - ->setTimezone($tz); + public static function createFromTimestampMs( + float|int|string $timestamp, + DateTimeZone|string|int|null $timezone = null, + ): static { + $date = static::createFromTimestampMsUTC($timestamp); + + return $timezone === null ? $date : $date->setTimezone($timezone); } /** * Set the instance's timestamp. * * Timestamp input can be given as int, float or a string containing one or more numbers. - * - * @param float|int|string $unixTimestamp - * - * @return static */ - public function timestamp($unixTimestamp) + public function timestamp(float|int|string $timestamp): static { - return $this->setTimestamp($unixTimestamp); + return $this->setTimestamp($timestamp); } /** @@ -123,7 +117,7 @@ trait Timestamp * * @return float */ - public function getPreciseTimestamp($precision = 6) + public function getPreciseTimestamp($precision = 6): float { return round(((float) $this->rawFormat('Uu')) / pow(10, 6 - $precision)); } @@ -133,7 +127,7 @@ trait Timestamp * * @return float */ - public function valueOf() + public function valueOf(): float { return $this->getPreciseTimestamp(3); } @@ -143,7 +137,7 @@ trait Timestamp * * @return int */ - public function getTimestampMs() + public function getTimestampMs(): int { return (int) $this->getPreciseTimestamp(3); } @@ -155,7 +149,7 @@ trait Timestamp * * @return int */ - public function unix() + public function unix(): int { return $this->getTimestamp(); } @@ -172,7 +166,7 @@ trait Timestamp * * @return array 0-index is integer part, 1-index is decimal part digits */ - private static function getIntegerAndDecimalParts($numbers, $decimals = 6) + private static function getIntegerAndDecimalParts($numbers, $decimals = 6): array { if (\is_int($numbers) || \is_float($numbers)) { $numbers = number_format($numbers, $decimals, '.', ''); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/ToStringFormat.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/ToStringFormat.php index a81164f99..5f0b367f0 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/ToStringFormat.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/ToStringFormat.php @@ -1,5 +1,7 @@ resetToStringFormat(); } /** @@ -49,8 +45,8 @@ trait ToStringFormat * * @return void */ - public static function setToStringFormat($format) + public static function setToStringFormat(string|Closure|null $format): void { - static::$toStringFormat = $format; + FactoryImmutable::getDefaultInstance()->setToStringFormat($format); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Units.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Units.php index 5be14ec7e..595372142 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Units.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Units.php @@ -1,5 +1,7 @@ addUTCUnit($unit, $value); + } + + /** + * Add seconds to the instance using timestamp. Positive $value travels + * forward while negative $value travels into the past. + * + * @param string $unit + * @param int|float|null $value + * + * @return static + */ + public function addUTCUnit(string $unit, $value = 1): static + { + $value ??= 0; + switch ($unit) { - // @call addRealUnit + // @call addUTCUnit case 'micro': - // @call addRealUnit + // @call addUTCUnit case 'microsecond': /* @var CarbonInterface $this */ $diff = $this->microsecond + $value; @@ -51,95 +75,125 @@ trait Units $time += $seconds; $diff -= $seconds * static::MICROSECONDS_PER_SECOND; $microtime = str_pad((string) $diff, 6, '0', STR_PAD_LEFT); - $tz = $this->tz; + $timezone = $this->tz; - return $this->tz('UTC')->modify("@$time.$microtime")->tz($tz); + return $this->tz('UTC')->modify("@$time.$microtime")->setTimezone($timezone); - // @call addRealUnit + // @call addUTCUnit case 'milli': - // @call addRealUnit + // @call addUTCUnit case 'millisecond': - return $this->addRealUnit('microsecond', $value * static::MICROSECONDS_PER_MILLISECOND); + return $this->addUTCUnit('microsecond', $value * static::MICROSECONDS_PER_MILLISECOND); - // @call addRealUnit + // @call addUTCUnit case 'second': break; - // @call addRealUnit + // @call addUTCUnit case 'minute': $value *= static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'hour': $value *= static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'day': $value *= static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'week': $value *= static::DAYS_PER_WEEK * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'month': $value *= 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'quarter': $value *= static::MONTHS_PER_QUARTER * 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'year': $value *= 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'decade': $value *= static::YEARS_PER_DECADE * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'century': $value *= static::YEARS_PER_CENTURY * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; - // @call addRealUnit + // @call addUTCUnit case 'millennium': $value *= static::YEARS_PER_MILLENNIUM * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE; break; default: - if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) { + if ($this->isLocalStrictModeEnabled()) { throw new UnitException("Invalid unit for real timestamp add/sub: '$unit'"); } return $this; } - /* @var CarbonInterface $this */ - return $this->setTimestamp((int) ($this->getTimestamp() + $value)); + $seconds = (int) $value; + $microseconds = (int) round( + (abs($value) - abs($seconds)) * ($value < 0 ? -1 : 1) * static::MICROSECONDS_PER_SECOND, + ); + $date = $this->setTimestamp($this->getTimestamp() + $seconds); + + return $microseconds ? $date->addUTCUnit('microsecond', $microseconds) : $date; } - public function subRealUnit($unit, $value = 1) + /** + * @deprecated Prefer to use add subUTCUnit() which more accurately defines what it's doing. + * + * Subtract seconds to the instance using timestamp. Positive $value travels + * into the past while negative $value travels forward. + * + * @param string $unit + * @param int $value + * + * @return static + */ + public function subRealUnit($unit, $value = 1): static { - return $this->addRealUnit($unit, -$value); + return $this->addUTCUnit($unit, -$value); + } + + /** + * Subtract seconds to the instance using timestamp. Positive $value travels + * into the past while negative $value travels forward. + * + * @param string $unit + * @param int $value + * + * @return static + */ + public function subUTCUnit($unit, $value = 1): static + { + return $this->addUTCUnit($unit, -$value); } /** @@ -149,7 +203,7 @@ trait Units * * @return bool */ - public static function isModifiableUnit($unit) + public static function isModifiableUnit($unit): bool { static $modifiableUnits = [ // @call addUnit @@ -176,7 +230,7 @@ trait Units * * @return static */ - public function rawAdd(DateInterval $interval) + public function rawAdd(DateInterval $interval): static { return parent::add($interval); } @@ -188,25 +242,34 @@ trait Units * @example $date->add(15, 'days') * @example $date->add(CarbonInterval::days(4)) * - * @param string|DateInterval|Closure|CarbonConverterInterface $unit - * @param int $value - * @param bool|null $overflow + * @param Unit|string|DateInterval|Closure|CarbonConverterInterface $unit + * @param int|float $value + * @param bool|null $overflow * * @return static */ #[ReturnTypeWillChange] - public function add($unit, $value = 1, $overflow = null) + public function add($unit, $value = 1, ?bool $overflow = null): static { + $unit = Unit::toNameIfUnit($unit); + $value = Unit::toNameIfUnit($value); + if (\is_string($unit) && \func_num_args() === 1) { $unit = CarbonInterval::make($unit, [], true); } if ($unit instanceof CarbonConverterInterface) { - return $this->resolveCarbon($unit->convertDate($this, false)); + $unit = Closure::fromCallable([$unit, 'convertDate']); } if ($unit instanceof Closure) { - return $this->resolveCarbon($unit($this, false)); + $result = $this->resolveCarbon($unit($this, false)); + + if ($this !== $result && $this->isMutable()) { + return $this->modify($result->rawFormat('Y-m-d H:i:s.u e O')); + } + + return $result; } if ($unit instanceof DateInterval) { @@ -217,26 +280,22 @@ trait Units [$value, $unit] = [$unit, $value]; } - return $this->addUnit($unit, $value, $overflow); + return $this->addUnit((string) $unit, $value, $overflow); } /** * Add given units to the current instance. - * - * @param string $unit - * @param int $value - * @param bool|null $overflow - * - * @return static */ - public function addUnit($unit, $value = 1, $overflow = null) + public function addUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static { + $unit = Unit::toName($unit); + $originalArgs = \func_get_args(); $date = $this; if (!is_numeric($value) || !(float) $value) { - return $date->isMutable() ? $date : $date->avoidMutation(); + return $date->isMutable() ? $date : $date->copy(); } $unit = self::singularUnit($unit); @@ -253,12 +312,12 @@ trait Units } if ($unit === 'weekday') { - $weekendDays = static::getWeekendDays(); + $weekendDays = $this->transmitFactory(static fn () => static::getWeekendDays()); if ($weekendDays !== [static::SATURDAY, static::SUNDAY]) { $absoluteValue = abs($value); $sign = $value / max(1, $absoluteValue); - $weekDaysCount = 7 - min(6, \count(array_unique($weekendDays))); + $weekDaysCount = static::DAYS_PER_WEEK - min(static::DAYS_PER_WEEK - 1, \count(array_unique($weekendDays))); $weeks = floor($absoluteValue / $weekDaysCount); for ($diff = $absoluteValue % $weekDaysCount; $diff; $diff--) { @@ -286,67 +345,44 @@ trait Units $day = $date->day; } - $value = (int) $value; - if ($unit === 'milli' || $unit === 'millisecond') { $unit = 'microsecond'; $value *= static::MICROSECONDS_PER_MILLISECOND; } - // Work-around for bug https://bugs.php.net/bug.php?id=75642 - if ($unit === 'micro' || $unit === 'microsecond') { - $microseconds = $this->micro + $value; - $second = (int) floor($microseconds / static::MICROSECONDS_PER_SECOND); - $microseconds %= static::MICROSECONDS_PER_SECOND; - if ($microseconds < 0) { - $microseconds += static::MICROSECONDS_PER_SECOND; - } - $date = $date->microseconds($microseconds); - $unit = 'second'; - $value = $second; - } + $previousException = null; try { - $date = $date->modify("$value $unit"); + $date = self::rawAddUnit($date, $unit, $value); if (isset($timeString)) { - $date = $date->setTimeFromTimeString($timeString); - } elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date->day) { - $date = $date->modify('last day of previous month'); + $date = $date?->setTimeFromTimeString($timeString); + } elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date?->day) { + $date = $date?->modify('last day of previous month'); } - } catch (DateMalformedStringException $ignoredException) { // @codeCoverageIgnore - $date = null; // @codeCoverageIgnore + } catch (DateMalformedStringException|InvalidFormatException|UnsupportedUnitException $exception) { + $date = null; + $previousException = $exception; } - if (!$date) { - throw new UnitException('Unable to add unit '.var_export($originalArgs, true)); - } - - return $date; + return $date ?? throw new UnitException( + 'Unable to add unit '.var_export($originalArgs, true), + previous: $previousException, + ); } /** * Subtract given units to the current instance. - * - * @param string $unit - * @param int $value - * @param bool|null $overflow - * - * @return static */ - public function subUnit($unit, $value = 1, $overflow = null) + public function subUnit(Unit|string $unit, $value = 1, ?bool $overflow = null): static { return $this->addUnit($unit, -$value, $overflow); } /** * Call native PHP DateTime/DateTimeImmutable sub() method. - * - * @param DateInterval $interval - * - * @return static */ - public function rawSub(DateInterval $interval) + public function rawSub(DateInterval $interval): static { return parent::sub($interval); } @@ -358,25 +394,31 @@ trait Units * @example $date->sub(15, 'days') * @example $date->sub(CarbonInterval::days(4)) * - * @param string|DateInterval|Closure|CarbonConverterInterface $unit - * @param int $value - * @param bool|null $overflow + * @param Unit|string|DateInterval|Closure|CarbonConverterInterface $unit + * @param int|float $value + * @param bool|null $overflow * * @return static */ #[ReturnTypeWillChange] - public function sub($unit, $value = 1, $overflow = null) + public function sub($unit, $value = 1, ?bool $overflow = null): static { if (\is_string($unit) && \func_num_args() === 1) { $unit = CarbonInterval::make($unit, [], true); } if ($unit instanceof CarbonConverterInterface) { - return $this->resolveCarbon($unit->convertDate($this, true)); + $unit = Closure::fromCallable([$unit, 'convertDate']); } if ($unit instanceof Closure) { - return $this->resolveCarbon($unit($this, true)); + $result = $this->resolveCarbon($unit($this, true)); + + if ($this !== $result && $this->isMutable()) { + return $this->modify($result->rawFormat('Y-m-d H:i:s.u e O')); + } + + return $result; } if ($unit instanceof DateInterval) { @@ -387,7 +429,7 @@ trait Units [$value, $unit] = [$unit, $value]; } - return $this->addUnit($unit, -(float) $value, $overflow); + return $this->addUnit((string) $unit, -(float) $value, $overflow); } /** @@ -396,12 +438,12 @@ trait Units * @see sub() * * @param string|DateInterval $unit - * @param int $value + * @param int|float $value * @param bool|null $overflow * * @return static */ - public function subtract($unit, $value = 1, $overflow = null) + public function subtract($unit, $value = 1, ?bool $overflow = null): static { if (\is_string($unit) && \func_num_args() === 1) { $unit = CarbonInterval::make($unit, [], true); @@ -409,4 +451,19 @@ trait Units return $this->sub($unit, $value, $overflow); } + + private static function rawAddUnit(self $date, string $unit, int|float $value): ?static + { + try { + return $date->rawAdd( + CarbonInterval::fromString(abs($value)." $unit")->invert($value < 0), + ); + } catch (InvalidIntervalException $exception) { + try { + return $date->modify("$value $unit"); + } catch (InvalidFormatException) { + throw new UnsupportedUnitException($unit, previous: $exception); + } + } + } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Week.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Week.php index 6f1481456..0101d055e 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Week.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Traits/Week.php @@ -1,5 +1,7 @@ weekYear( $year, - $dayOfWeek ?? 1, - $dayOfYear ?? 4 + $dayOfWeek ?? static::MONDAY, + $dayOfYear ?? static::THURSDAY, ); } @@ -69,7 +73,7 @@ trait Week */ public function weekYear($year = null, $dayOfWeek = null, $dayOfYear = null) { - $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0; + $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? static::SUNDAY; $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1; if ($year !== null) { @@ -82,18 +86,16 @@ trait Week $week = $this->week(null, $dayOfWeek, $dayOfYear); $day = $this->dayOfWeek; $date = $this->year($year); - switch ($date->weekYear(null, $dayOfWeek, $dayOfYear) - $year) { - case 1: - $date = $date->subWeeks(26); - break; - case -1: - $date = $date->addWeeks(26); + $date = match ($date->weekYear(null, $dayOfWeek, $dayOfYear) - $year) { + CarbonInterval::POSITIVE => $date->subWeeks(static::WEEKS_PER_YEAR / 2), + CarbonInterval::NEGATIVE => $date->addWeeks(static::WEEKS_PER_YEAR / 2), + default => $date, + }; - break; - } - - $date = $date->addWeeks($week - $date->week(null, $dayOfWeek, $dayOfYear))->startOfWeek($dayOfWeek); + $date = $date + ->addWeeks($week - $date->week(null, $dayOfWeek, $dayOfYear)) + ->startOfWeek($dayOfWeek); if ($date->dayOfWeek === $day) { return $date; @@ -132,8 +134,8 @@ trait Week public function isoWeeksInYear($dayOfWeek = null, $dayOfYear = null) { return $this->weeksInYear( - $dayOfWeek ?? 1, - $dayOfYear ?? 4 + $dayOfWeek ?? static::MONDAY, + $dayOfYear ?? static::THURSDAY, ); } @@ -149,7 +151,7 @@ trait Week */ public function weeksInYear($dayOfWeek = null, $dayOfYear = null) { - $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0; + $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? static::SUNDAY; $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1; $year = $this->year; $start = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); @@ -163,7 +165,7 @@ trait Week $endDay += $this->daysInYear; } - return (int) round(($endDay - $startDay) / 7); + return (int) round(($endDay - $startDay) / static::DAYS_PER_WEEK); } /** @@ -187,12 +189,14 @@ trait Week return $date->addWeeks(round($week) - $this->week(null, $dayOfWeek, $dayOfYear)); } - $start = $date->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); - $end = $date->avoidMutation()->startOfWeek($dayOfWeek); + $start = $date->avoidMutation()->shiftTimezone('UTC')->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); + $end = $date->avoidMutation()->shiftTimezone('UTC')->startOfWeek($dayOfWeek); + if ($start > $end) { - $start = $start->subWeeks(26)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); + $start = $start->subWeeks(static::WEEKS_PER_YEAR / 2)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek); } - $week = (int) ($start->diffInDays($end) / 7 + 1); + + $week = (int) ($start->diffInDays($end) / static::DAYS_PER_WEEK + 1); return $week > $end->weeksInYear($dayOfWeek, $dayOfYear) ? 1 : $week; } @@ -212,8 +216,8 @@ trait Week { return $this->week( $week, - $dayOfWeek ?? 1, - $dayOfYear ?? 4 + $dayOfWeek ?? static::MONDAY, + $dayOfYear ?? static::THURSDAY, ); } } diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Translator.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Translator.php index 491c9e720..9f523b264 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Translator.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/Translator.php @@ -1,5 +1,7 @@ hasReturnType() diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorImmutable.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorImmutable.php index ce6b2f90a..ab9933e56 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorImmutable.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorImmutable.php @@ -1,5 +1,7 @@ constructed = true; @@ -29,24 +30,24 @@ class TranslatorImmutable extends Translator /** * @codeCoverageIgnore */ - public function setDirectories(array $directories) + public function setDirectories(array $directories): static { $this->disallowMutation(__METHOD__); return parent::setDirectories($directories); } - public function setLocale($locale) + public function setLocale($locale): void { $this->disallowMutation(__METHOD__); - return parent::setLocale($locale); + parent::setLocale($locale); } /** * @codeCoverageIgnore */ - public function setMessages($locale, $messages) + public function setMessages(string $locale, array $messages): static { $this->disallowMutation(__METHOD__); @@ -56,7 +57,7 @@ class TranslatorImmutable extends Translator /** * @codeCoverageIgnore */ - public function setTranslations($messages) + public function setTranslations(array $messages): static { $this->disallowMutation(__METHOD__); @@ -73,7 +74,7 @@ class TranslatorImmutable extends Translator parent::setConfigCacheFactory($configCacheFactory); } - public function resetMessages($locale = null) + public function resetMessages(?string $locale = null): bool { $this->disallowMutation(__METHOD__); @@ -83,7 +84,7 @@ class TranslatorImmutable extends Translator /** * @codeCoverageIgnore */ - public function setFallbackLocales(array $locales) + public function setFallbackLocales(array $locales): void { $this->disallowMutation(__METHOD__); diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorStrongTypeInterface.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorStrongTypeInterface.php index ef4dee8e2..54a798093 100644 --- a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorStrongTypeInterface.php +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/TranslatorStrongTypeInterface.php @@ -1,5 +1,7 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +enum Unit: string +{ + case Microsecond = 'microsecond'; + case Millisecond = 'millisecond'; + case Second = 'second'; + case Minute = 'minute'; + case Hour = 'hour'; + case Day = 'day'; + case Week = 'week'; + case Month = 'month'; + case Quarter = 'quarter'; + case Year = 'year'; + case Decade = 'decade'; + case Century = 'century'; + case Millennium = 'millennium'; + + public static function toName(self|string $unit): string + { + return $unit instanceof self ? $unit->value : $unit; + } + + /** @internal */ + public static function toNameIfUnit(mixed $unit): mixed + { + return $unit instanceof self ? $unit->value : $unit; + } + + public static function fromName(string $name, ?string $locale = null): self + { + if ($locale !== null) { + $messages = Translator::get($locale)->getMessages($locale) ?? []; + + if ($messages !== []) { + $lowerName = mb_strtolower($name); + + foreach (self::cases() as $unit) { + foreach (['', '_from_now', '_ago', '_after', '_before'] as $suffix) { + $message = $messages[$unit->value.$suffix] ?? null; + + if (\is_string($message)) { + $words = explode('|', mb_strtolower(preg_replace( + '/[{\[\]].+?[}\[\]]/', + '', + str_replace(':count', '', $message), + ))); + + foreach ($words as $word) { + if (trim($word) === $lowerName) { + return $unit; + } + } + } + } + } + } + } + + return self::from(CarbonImmutable::singularUnit($name)); + } + + public function singular(?string $locale = null): string + { + if ($locale !== null) { + return trim(Translator::get($locale)->trans($this->value, [ + '%count%' => 1, + ':count' => 1, + ]), "1 \n\r\t\v\0"); + } + + return $this->value; + } + + public function plural(?string $locale = null): string + { + if ($locale !== null) { + return trim(Translator::get($locale)->trans($this->value, [ + '%count%' => 9, + ':count' => 9, + ]), "9 \n\r\t\v\0"); + } + + return CarbonImmutable::pluralUnit($this->value); + } + + public function interval(int|float $value = 1): CarbonInterval + { + return CarbonInterval::fromString("$value $this->name"); + } + + public function locale(string $locale): CarbonInterval + { + return $this->interval()->locale($locale); + } + + public function toPeriod(...$params): CarbonPeriod + { + return $this->interval()->toPeriod(...$params); + } + + public function stepBy(mixed $interval, Unit|string|null $unit = null): CarbonPeriod + { + return $this->interval()->stepBy($interval, $unit); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WeekDay.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WeekDay.php new file mode 100644 index 000000000..69f69cebc --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WeekDay.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use Carbon\Exceptions\InvalidFormatException; + +enum WeekDay: int +{ + // Using constants is only safe starting from PHP 8.2 + case Sunday = 0; // CarbonInterface::SUNDAY + case Monday = 1; // CarbonInterface::MONDAY + case Tuesday = 2; // CarbonInterface::TUESDAY + case Wednesday = 3; // CarbonInterface::WEDNESDAY + case Thursday = 4; // CarbonInterface::THURSDAY + case Friday = 5; // CarbonInterface::FRIDAY + case Saturday = 6; // CarbonInterface::SATURDAY + + public static function int(self|int|null $value): ?int + { + return $value instanceof self ? $value->value : $value; + } + + public static function fromNumber(int $number): self + { + $day = $number % CarbonInterface::DAYS_PER_WEEK; + + return self::from($day + ($day < 0 ? CarbonInterface::DAYS_PER_WEEK : 0)); + } + + public static function fromName(string $name, ?string $locale = null): self + { + try { + return self::from(CarbonImmutable::parseFromLocale($name, $locale)->dayOfWeek); + } catch (InvalidFormatException $exception) { + // Possibly current language expect a dot after short name, but it's missing + if ($locale !== null && !mb_strlen($name) < 4 && !str_ends_with($name, '.')) { + try { + return self::from(CarbonImmutable::parseFromLocale($name.'.', $locale)->dayOfWeek); + } catch (InvalidFormatException) { + // Throw previous error + } + } + + throw $exception; + } + } + + public function next(?CarbonImmutable $now = null): CarbonImmutable + { + return $now?->modify($this->name) ?? new CarbonImmutable($this->name); + } + + public function locale(string $locale, ?CarbonImmutable $now = null): CarbonImmutable + { + return $this->next($now)->locale($locale); + } +} diff --git a/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WrapperClock.php b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WrapperClock.php new file mode 100644 index 000000000..7fb184fe5 --- /dev/null +++ b/lam/lib/3rdParty/composer/nesbot/carbon/src/Carbon/WrapperClock.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; +use DateTimeZone; +use Psr\Clock\ClockInterface as PsrClockInterface; +use RuntimeException; +use Symfony\Component\Clock\ClockInterface; + +final class WrapperClock implements ClockInterface +{ + public function __construct( + private PsrClockInterface|Factory|DateTimeInterface $currentClock, + ) { + } + + public function unwrap(): PsrClockInterface|Factory|DateTimeInterface + { + return $this->currentClock; + } + + public function getFactory(): Factory + { + if ($this->currentClock instanceof Factory) { + return $this->currentClock; + } + + if ($this->currentClock instanceof DateTime) { + $factory = new Factory(); + $factory->setTestNowAndTimezone($this->currentClock); + + return $factory; + } + + if ($this->currentClock instanceof DateTimeImmutable) { + $factory = new FactoryImmutable(); + $factory->setTestNowAndTimezone($this->currentClock); + + return $factory; + } + + $factory = new FactoryImmutable(); + $factory->setTestNowAndTimezone(fn () => $this->currentClock->now()); + + return $factory; + } + + private function nowRaw(): DateTimeInterface + { + if ($this->currentClock instanceof DateTimeInterface) { + return $this->currentClock; + } + + if ($this->currentClock instanceof Factory) { + return $this->currentClock->__call('now', []); + } + + return $this->currentClock->now(); + } + + public function now(): DateTimeImmutable + { + $now = $this->nowRaw(); + + return $now instanceof DateTimeImmutable + ? $now + : new CarbonImmutable($now); + } + + /** + * @template T of CarbonInterface + * + * @param class-string $class + * + * @return T + */ + public function nowAs(string $class, DateTimeZone|string|int|null $timezone = null): CarbonInterface + { + $now = $this->nowRaw(); + $date = $now instanceof $class ? $now : $class::instance($now); + + return $timezone === null ? $date : $date->setTimezone($timezone); + } + + public function nowAsCarbon(DateTimeZone|string|int|null $timezone = null): CarbonInterface + { + $now = $this->nowRaw(); + + return $now instanceof CarbonInterface + ? ($timezone === null ? $now : $now->setTimezone($timezone)) + : $this->dateAsCarbon($now, $timezone); + } + + private function dateAsCarbon(DateTimeInterface $date, DateTimeZone|string|int|null $timezone): CarbonInterface + { + return $date instanceof DateTimeImmutable + ? new CarbonImmutable($date, $timezone) + : new Carbon($date, $timezone); + } + + public function sleep(float|int $seconds): void + { + if ($seconds === 0 || $seconds === 0.0) { + return; + } + + if ($seconds < 0) { + throw new RuntimeException('Expected positive number of seconds, '.$seconds.' given'); + } + + if ($this->currentClock instanceof DateTimeInterface) { + $this->currentClock = $this->addSeconds($this->currentClock, $seconds); + + return; + } + + if ($this->currentClock instanceof ClockInterface) { + $this->currentClock->sleep($seconds); + + return; + } + + $this->currentClock = $this->addSeconds($this->currentClock->now(), $seconds); + } + + public function withTimeZone(DateTimeZone|string $timezone): static + { + if ($this->currentClock instanceof ClockInterface) { + return new self($this->currentClock->withTimeZone($timezone)); + } + + $now = $this->currentClock instanceof DateTimeInterface + ? $this->currentClock + : $this->currentClock->now(); + + if (!($now instanceof DateTimeImmutable)) { + $now = clone $now; + } + + if (\is_string($timezone)) { + $timezone = new DateTimeZone($timezone); + } + + return new self($now->setTimezone($timezone)); + } + + private function addSeconds(DateTimeInterface $date, float|int $seconds): DateTimeInterface + { + $secondsPerHour = CarbonInterface::SECONDS_PER_MINUTE * CarbonInterface::MINUTES_PER_HOUR; + $hours = number_format( + floor($seconds / $secondsPerHour), + thousands_separator: '', + ); + $microseconds = number_format( + ($seconds - $hours * $secondsPerHour) * CarbonInterface::MICROSECONDS_PER_SECOND, + thousands_separator: '', + ); + + if (!($date instanceof DateTimeImmutable)) { + $date = clone $date; + } + + if ($hours !== '0') { + $date = $date->modify("$hours hours"); + } + + if ($microseconds !== '0') { + $date = $date->modify("$microseconds microseconds"); + } + + return $date; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/README.md b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/README.md index d2572e91c..211f0dc9f 100644 --- a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/README.md +++ b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/README.md @@ -1,6 +1,7 @@ # Constant-Time Encoding [![Build Status](https://github.com/paragonie/constant_time_encoding/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/constant_time_encoding/actions) +[![Static Analysis](https://github.com/paragonie/constant_time_encoding/actions/workflows/psalm.yml/badge.svg)](https://github.com/paragonie/constant_time_encoding/actions) [![Latest Stable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/stable)](https://packagist.org/packages/paragonie/constant_time_encoding) [![Latest Unstable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/unstable)](https://packagist.org/packages/paragonie/constant_time_encoding) [![License](https://poser.pugx.org/paragonie/constant_time_encoding/license)](https://packagist.org/packages/paragonie/constant_time_encoding) @@ -22,10 +23,13 @@ Our fork offers the following enhancements: ## PHP Version Requirements -Version 2 of this library should work on **PHP 7** or newer. For PHP 5 -support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x). +Version 3 of this library should work on **PHP 8** or newer. -If you are adding this as a dependency to a project intended to work on both PHP 5 and PHP 7, please set the required version to `^1|^2` instead of just `^1` or `^2`. +Version 2 of this library should work on **PHP 7** or newer. See [the v2.x branch](https://github.com/paragonie/constant_time_encoding/tree/v2.x). + +For PHP 5 support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x). + +If you are adding this as a dependency to a project intended to work on PHP 5 through 8.4, please set the required version to `^1|^2|^3`. ## How to Install diff --git a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/composer.json b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/composer.json index 2fe9717ad..5023095b4 100644 --- a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/composer.json +++ b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/composer.json @@ -37,11 +37,11 @@ "source": "https://github.com/paragonie/constant_time_encoding" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" }, "autoload": { "psr-4": { diff --git a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/src/Binary.php b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/src/Binary.php index 5368e4bba..a958f2f7c 100644 --- a/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/src/Binary.php +++ b/lam/lib/3rdParty/composer/paragonie/constant_time_encoding/src/Binary.php @@ -75,7 +75,7 @@ abstract class Binary #[\SensitiveParameter] string $str, int $start = 0, - $length = null + ?int $length = null ): string { if ($length === 0) { return ''; diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/LICENSE b/lam/lib/3rdParty/composer/paragonie/sodium_compat/LICENSE new file mode 100644 index 000000000..5729115bf --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/LICENSE @@ -0,0 +1,16 @@ +ISC License + +Copyright (c) 2016-2024, Paragon Initiative Enterprises +Copyright (c) 2013-2019, Frank Denis + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/README.md b/lam/lib/3rdParty/composer/paragonie/sodium_compat/README.md new file mode 100644 index 000000000..99461fb54 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/README.md @@ -0,0 +1,368 @@ +# Sodium Compat + +[![Build Status](https://github.com/paragonie/sodium_compat/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/sodium_compat/actions) +[![Psalm Status](https://github.com/paragonie/sodium_compat/actions/workflows/psalm.yml/badge.svg)](https://github.com/paragonie/sodium_compat/actions) +[![Latest Stable Version](https://poser.pugx.org/paragonie/sodium_compat/v/stable)](https://packagist.org/packages/paragonie/sodium_compat) +[![Latest Unstable Version](https://poser.pugx.org/paragonie/sodium_compat/v/unstable)](https://packagist.org/packages/paragonie/sodium_compat) +[![License](https://poser.pugx.org/paragonie/sodium_compat/license)](https://packagist.org/packages/paragonie/sodium_compat) +[![Downloads](https://img.shields.io/packagist/dt/paragonie/sodium_compat.svg)](https://packagist.org/packages/paragonie/sodium_compat) + +Sodium Compat is a pure PHP polyfill for the Sodium cryptography library +(libsodium), a core extension in PHP 7.2.0+ and otherwise [available in PECL](https://pecl.php.net/package/libsodium). + +If you have the PHP extension installed, Sodium Compat will opportunistically +and transparently use the PHP extension instead of our implementation. + +## Major Versions and Branches + +sodium_compat v1.21.0 was the last v1.x release from the master branch. From now +on, all future releases that support PHP 5.2 - 8.0 and 32-bit integers will be +[in the `v1.x` branch](https://github.com/paragonie/sodium_compat/tree/v1.x). + +Newer versions of sodium_compat (i.e., v2.0.0) will continue to live in the master +branch, unless a new major version is needed. The goal of this work is to improve +code readability and performance, while reducing boilerplate code. + +When in doubt, refer to the README file in [the master branch](https://github.com/paragonie/sodium_compat/blob/master/README.md) +for the latest in version information. + +### Which version should I use? + +| sodium_compat version | PHP versions supported | 32-bit support? | Branch | +|-----------------------|------------------------|-----------------|---------------------------------------------------------------| +| `v1.x.y` | 5.2.4 - LATEST | YES | [v1.x](https://github.com/paragonie/sodium_compat/tree/v1.x) | +| `v2.x.y` | 8.1 - LATEST | NO | **master** | + +If you need 32-bit PHP support (`PHP_INT_SIZE == 4`), continue using sodium_compat v1.x. +If you want improved performance and smaller dependencies, use v2.x. + +We recommend libraries and frameworks set a Composer version constraint as follows: + +```javascript +{ + "require": { + /* ... */ + "paragonie/sodium_compat": ">= 1" + /* ... */ + } +} +``` + +Applications should, conversely, specify the actual version that matters to them +and their deployments. + +## IMPORTANT! + +This cryptography library has not been formally audited by an independent third +party that specializes in cryptography or cryptanalysis. + +If you require such an audit before you can use sodium_compat in your projects +and have the funds for such an audit, please open an issue or contact +`security at paragonie dot com` so we can help get the ball rolling. + +However, sodium_compat has been adopted by high profile open source projects, +such as [Joomla!](https://github.com/joomla/joomla-cms/blob/459d74686d2a638ec51149d7c44ddab8075852be/composer.json#L40) +and [Magento](https://github.com/magento/magento2/blob/8fd89cfdf52c561ac0ca7bc20fd38ef688e201b0/composer.json#L44). +Furthermore, sodium_compat was developed by Paragon Initiative Enterprises, a +company that *specializes* in secure PHP development and PHP cryptography, and +has been informally reviewed by many other security experts who also specialize +in PHP. + +If you'd like to learn more about the defensive security measures we've taken +to prevent sodium_compat from being a source of vulnerability in your systems, +please read [*Cryptographically Secure PHP Development*](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development). + +# Installing Sodium Compat + +If you're using Composer: + +```bash +composer require paragonie/sodium_compat +``` + +### Install From Source + +If you're not using Composer, download a [release tarball](https://github.com/paragonie/sodium_compat/releases) +(which should be signed with [our GnuPG public key](https://paragonie.com/static/gpg-public-key.txt)), extract +its contents, then include our `autoload.php` script in your project. + +```php + + gpg --fingerprint 7F52D5C61D1255C731362E826B97A1C2826404DA + if [ $? -ne 0 ]; then + echo -e "\033[31mCould not download PGP public key for verification\033[0m" + exit 1 + fi +fi + +# Verifying the PHP Archive +gpg --verify sodium-compat.phar.sig sodium-compat.phar +``` + +Now, simply include this .phar file in your application. + +```php +execute(); +} else { + // Defer to a cron job or other sort of asynchronous process + $process->enqueue(); +} +``` + +## Documentation + +First, you'll want to read the [Libsodium Quick Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use). +It aims to answer, "Which function should I use for [common problem]?". + +If you don't find the answers in the Quick Reference page, check out +[*Using Libsodium in PHP Projects*](https://paragonie.com/book/pecl-libsodium). + +Finally, the [official libsodium documentation](https://download.libsodium.org/doc/) +(which was written for the C library, not the PHP library) also contains a lot of +insightful technical information you may find helpful. + +## API Coverage + +**Recommended reading:** [Libsodium Quick Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use) + +* Mainline NaCl Features + * `crypto_auth()` + * `crypto_auth_verify()` + * `crypto_box()` + * `crypto_box_open()` + * `crypto_scalarmult()` + * `crypto_secretbox()` + * `crypto_secretbox_open()` + * `crypto_sign()` + * `crypto_sign_open()` +* PECL Libsodium Features + * `crypto_aead_aegis128l_encrypt()` + * `crypto_aead_aegis128l_decrypt()` + * `crypto_aead_aegis256_encrypt()` + * `crypto_aead_aegis256_decrypt()` + * `crypto_aead_aes256gcm_encrypt()` + * `crypto_aead_aes256gcm_decrypt()` + * `crypto_aead_chacha20poly1305_encrypt()` + * `crypto_aead_chacha20poly1305_decrypt()` + * `crypto_aead_chacha20poly1305_ietf_encrypt()` + * `crypto_aead_chacha20poly1305_ietf_decrypt()` + * `crypto_aead_xchacha20poly1305_ietf_encrypt()` + * `crypto_aead_xchacha20poly1305_ietf_decrypt()` + * `crypto_box_xchacha20poly1305()` + * `crypto_box_xchacha20poly1305_open()` + * `crypto_box_seal()` + * `crypto_box_seal_open()` + * `crypto_generichash()` + * `crypto_generichash_init()` + * `crypto_generichash_update()` + * `crypto_generichash_final()` + * `crypto_kx()` + * `crypto_secretbox_xchacha20poly1305()` + * `crypto_secretbox_xchacha20poly1305_open()` + * `crypto_shorthash()` + * `crypto_sign_detached()` + * `crypto_sign_ed25519_pk_to_curve25519()` + * `crypto_sign_ed25519_sk_to_curve25519()` + * `crypto_sign_verify_detached()` + * For advanced users only: + * `crypto_core_ristretto255_add()` + * `crypto_core_ristretto255_from_hash()` + * `crypto_core_ristretto255_is_valid_point()` + * `crypto_core_ristretto255_random()` + * `crypto_core_ristretto255_scalar_add()` + * `crypto_core_ristretto255_scalar_complement()` + * `crypto_core_ristretto255_scalar_invert()` + * `crypto_core_ristretto255_scalar_mul()` + * `crypto_core_ristretto255_scalar_negate()` + * `crypto_core_ristretto255_scalar_random()` + * `crypto_core_ristretto255_scalar_reduce()` + * `crypto_core_ristretto255_scalar_sub()` + * `crypto_core_ristretto255_sub()` + * `crypto_scalarmult_ristretto255_base()` + * `crypto_scalarmult_ristretto255()` + * `crypto_stream()` + * `crypto_stream_keygen()` + * `crypto_stream_xor()` + * `crypto_stream_xchacha20()` + * `crypto_stream_xchacha20_keygen()` + * `crypto_stream_xchacha20_xor()` + * `crypto_stream_xchacha20_xor_ic()` + * Other utilities (e.g. `crypto_*_keypair()`) + * `add()` + * `base642bin()` + * `bin2base64()` + * `bin2hex()` + * `hex2bin()` + * `crypto_kdf_derive_from_key()` + * `crypto_kx_client_session_keys()` + * `crypto_kx_server_session_keys()` + * `crypto_secretstream_xchacha20poly1305_init_push()` + * `crypto_secretstream_xchacha20poly1305_push()` + * `crypto_secretstream_xchacha20poly1305_init_pull()` + * `crypto_secretstream_xchacha20poly1305_pull()` + * `crypto_secretstream_xchacha20poly1305_rekey()` + * `pad()` + * `unpad()` + +### Cryptography Primitives Provided + +* **X25519** - Elliptic Curve Diffie Hellman over Curve25519 +* **Ed25519** - Edwards curve Digital Signature Algorithm over Curve25519 +* **Xsalsa20** - Extended-nonce Salsa20 stream cipher +* **ChaCha20** - Stream cipher +* **Xchacha20** - Extended-nonce ChaCha20 stream cipher +* **Poly1305** - Polynomial Evaluation Message Authentication Code modulo 2^130 - 5 +* **BLAKE2b** - Cryptographic Hash Function +* **SipHash-2-4** - Fast hash, but not collision-resistant; ideal for hash tables. + +### Features Excluded from this Polyfill + +* `sodium_memzero()` - Although we expose this API endpoint, we can't reliably + zero buffers from PHP. + + If you have the PHP extension installed, sodium_compat + will use the native implementation to zero out the string provided. Otherwise + it will throw a `SodiumException`. +* `sodium_crypto_pwhash()` - It's not feasible to polyfill scrypt or Argon2 + into PHP and get reasonable performance. Users would feel motivated to select + parameters that downgrade security to avoid denial of service (DoS) attacks. + + The only winning move is not to play. + + If ext/sodium or ext/libsodium is installed, these API methods will fallthrough + to the extension. Otherwise, our polyfill library will throw a `SodiumException`. + + To detect support for Argon2i at runtime, use + `ParagonIE_Sodium_Compat::crypto_pwhash_is_available()`, which returns a + boolean value (`TRUE` or `FALSE`). +* Libsodium's HKDF API (`crypto_kdf_hkdf_*()`) is not included because PHP has + its own [HMAC features](https://php.met/hash_hmac) amd it was not deemed necessary. + +### PHPCompatibility Ruleset + +For sodium_compat users and that utilize [`PHPCompatibility`](https://github.com/PHPCompatibility/PHPCompatibility) +in their CI process, there is now a custom ruleset available which can be used +to prevent false positives being thrown by `PHPCompatibility` for the native +PHP functionality being polyfilled by this repo. + +You can find the repo for the `PHPCompatibilityParagonieSodiumCompat` ruleset +here [on Github](https://github.com/PHPCompatibility/PHPCompatibilityParagonie) +and [on Packagist](https://packagist.org/packages/phpcompatibility/phpcompatibility-paragonie). diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/autoload.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/autoload.php new file mode 100644 index 000000000..b85ef8680 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/autoload.php @@ -0,0 +1,55 @@ + + * @throws SodiumException + */ + function sodium_crypto_secretstream_xchacha20poly1305_init_push( + #[\SensitiveParameter] + string $key + ): array { + return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_push($key); + } +} +if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_push')) { + /** + * @param string $state + * @param string $message + * @param string $additional_data + * @param int $tag + * @return string + * @throws SodiumException + */ + function sodium_crypto_secretstream_xchacha20poly1305_push( + string &$state, + #[\SensitiveParameter] + string $message, + string $additional_data = '', + int $tag = 0 + ): string { + return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_push( + $state, + $message, + $additional_data, + $tag + ); + } +} +if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_pull')) { + /** + * @param string $header + * @param string $key + * @return string + * @throws Exception + */ + function sodium_crypto_secretstream_xchacha20poly1305_init_pull( + string $header, + #[\SensitiveParameter] + string $key + ): string { + return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_pull($header, $key); + } +} +if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_pull')) { + /** + * @param string $state + * @param string $ciphertext + * @param string $additional_data + * @return bool|array{0: string, 1: int} + * @throws SodiumException + */ + function sodium_crypto_secretstream_xchacha20poly1305_pull( + #[\SensitiveParameter] + string &$state, + string $ciphertext, + string $additional_data = '' + ): bool|array { + return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_pull( + $state, + $ciphertext, + $additional_data + ); + } +} +if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_rekey')) { + /** + * @param string $state + * @return void + * @throws SodiumException + */ + function sodium_crypto_secretstream_xchacha20poly1305_rekey( + #[\SensitiveParameter] + string &$state + ): void { + ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_rekey($state); + } +} +if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_keygen')) { + /** + * @return string + * @throws Exception + */ + function sodium_crypto_secretstream_xchacha20poly1305_keygen(): string + { + return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_keygen(); + } +} +if (!is_callable('sodium_crypto_shorthash')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_shorthash() + * @param string $message + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_shorthash( + string $message, + #[\SensitiveParameter] + string $key + ): string { + return ParagonIE_Sodium_Compat::crypto_shorthash($message, $key); + } +} +if (!is_callable('sodium_crypto_shorthash_keygen')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_shorthash_keygen() + * @return string + * @throws Exception + */ + function sodium_crypto_shorthash_keygen(): string + { + return ParagonIE_Sodium_Compat::crypto_shorthash_keygen(); + } +} +if (!is_callable('sodium_crypto_sign')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign() + * @param string $message + * @param string $secret_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign( + string $message, + #[\SensitiveParameter] + string $secret_key + ): string { + return ParagonIE_Sodium_Compat::crypto_sign($message, $secret_key); + } +} +if (!is_callable('sodium_crypto_sign_detached')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_detached() + * @param string $message + * @param string $secret_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_detached( + string $message, + #[\SensitiveParameter] + string $secret_key + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_detached($message, $secret_key); + } +} +if (!is_callable('sodium_crypto_sign_keypair_from_secretkey_and_publickey')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey() + * @param string $secret_key + * @param string $public_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_keypair_from_secretkey_and_publickey( + #[\SensitiveParameter] + string $secret_key, + string $public_key + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey($secret_key, $public_key); + } +} +if (!is_callable('sodium_crypto_sign_keypair')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_keypair() + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_keypair(): string + { + return ParagonIE_Sodium_Compat::crypto_sign_keypair(); + } +} +if (!is_callable('sodium_crypto_sign_open')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_open() + * @param string $signedMessage + * @param string $public_key + * @return string|bool + */ + function sodium_crypto_sign_open(string $signedMessage, string $public_key): string|bool + { + try { + return ParagonIE_Sodium_Compat::crypto_sign_open($signedMessage, $public_key); + } catch (Exception|Error $ex) { + return false; + } + } +} +if (!is_callable('sodium_crypto_sign_publickey')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_publickey() + * @param string $key_pair + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_publickey( + #[\SensitiveParameter] + string $key_pair + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_publickey($key_pair); + } +} +if (!is_callable('sodium_crypto_sign_publickey_from_secretkey')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey() + * @param string $secret_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_publickey_from_secretkey( + #[\SensitiveParameter] + string $secret_key + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey($secret_key); + } +} +if (!is_callable('sodium_crypto_sign_secretkey')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_secretkey() + * @param string $key_pair + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_secretkey( + #[\SensitiveParameter] + string $key_pair + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_secretkey($key_pair); + } +} +if (!is_callable('sodium_crypto_sign_seed_keypair')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_seed_keypair() + * @param string $seed + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_seed_keypair( + #[\SensitiveParameter] + string $seed + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_seed_keypair($seed); + } +} +if (!is_callable('sodium_crypto_sign_verify_detached')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_verify_detached() + * @param string $signature + * @param string $message + * @param string $public_key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_verify_detached( + string $signature, + string $message, + string $public_key + ): bool { + return ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message, $public_key); + } +} +if (!is_callable('sodium_crypto_sign_ed25519_pk_to_curve25519')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519() + * @param string $public_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_ed25519_pk_to_curve25519(string $public_key): string + { + return ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519($public_key); + } +} +if (!is_callable('sodium_crypto_sign_ed25519_sk_to_curve25519')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519() + * @param string $secret_key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_sign_ed25519_sk_to_curve25519( + #[\SensitiveParameter] + string $secret_key + ): string { + return ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519($secret_key); + } +} +if (!is_callable('sodium_crypto_stream')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_stream() + * @param int $length + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_stream( + int $length, + string $nonce, + #[\SensitiveParameter] + string $key + ): string { + return ParagonIE_Sodium_Compat::crypto_stream($length, $nonce, $key); + } +} +if (!is_callable('sodium_crypto_stream_keygen')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_stream_keygen() + * @return string + * @throws Exception + */ + function sodium_crypto_stream_keygen(): string + { + return ParagonIE_Sodium_Compat::crypto_stream_keygen(); + } +} +if (!is_callable('sodium_crypto_stream_xor')) { + /** + * @see ParagonIE_Sodium_Compat::crypto_stream_xor() + * @param string $message + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_crypto_stream_xor( + #[\SensitiveParameter] + string $message, + string $nonce, + #[\SensitiveParameter] + string $key + ): string { + return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce, $key); + } +} +require_once dirname(__FILE__) . '/stream-xchacha20.php'; +if (!is_callable('sodium_hex2bin')) { + /** + * @see ParagonIE_Sodium_Compat::hex2bin() + * @param string $string + * @param string $ignore + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_hex2bin( + #[\SensitiveParameter] + string $string, + string $ignore = '' + ): string { + return ParagonIE_Sodium_Compat::hex2bin($string, $ignore); + } +} +if (!is_callable('sodium_increment')) { + /** + * @see ParagonIE_Sodium_Compat::increment() + * @param string $string + * @return void + * @throws SodiumException + * @throws TypeError + */ + function sodium_increment( + #[\SensitiveParameter] + string &$string + ): void { + ParagonIE_Sodium_Compat::increment($string); + } +} +if (!is_callable('sodium_library_version_major')) { + /** + * @see ParagonIE_Sodium_Compat::library_version_major() + * @return int + */ + function sodium_library_version_major(): int + { + return ParagonIE_Sodium_Compat::library_version_major(); + } +} +if (!is_callable('sodium_library_version_minor')) { + /** + * @see ParagonIE_Sodium_Compat::library_version_minor() + * @return int + */ + function sodium_library_version_minor(): int + { + return ParagonIE_Sodium_Compat::library_version_minor(); + } +} +if (!is_callable('sodium_version_string')) { + /** + * @see ParagonIE_Sodium_Compat::version_string() + * @return string + */ + function sodium_version_string(): string + { + return ParagonIE_Sodium_Compat::version_string(); + } +} +if (!is_callable('sodium_memcmp')) { + /** + * @see ParagonIE_Sodium_Compat::memcmp() + * @param string $string1 + * @param string $string2 + * @return int + * @throws SodiumException + * @throws TypeError + */ + function sodium_memcmp( + #[\SensitiveParameter] + string $string1, + #[\SensitiveParameter] + string $string2 + ): int { + return ParagonIE_Sodium_Compat::memcmp($string1, $string2); + } +} +if (!is_callable('sodium_memzero')) { + /** + * @see ParagonIE_Sodium_Compat::memzero() + * @param string $string + * @return void + * @throws SodiumException + * @throws TypeError + * + * @psalm-suppress ReferenceConstraintViolation + */ + function sodium_memzero + (#[\SensitiveParameter] + string &$string + ): void { + ParagonIE_Sodium_Compat::memzero($string); + } +} +if (!is_callable('sodium_pad')) { + /** + * @see ParagonIE_Sodium_Compat::pad() + * @param string $unpadded + * @param int $block_size + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_pad( + #[\SensitiveParameter] + string $unpadded, + int $block_size + ): string { + return ParagonIE_Sodium_Compat::pad($unpadded, $block_size, true); + } +} +if (!is_callable('sodium_unpad')) { + /** + * @see ParagonIE_Sodium_Compat::pad() + * @param string $padded + * @param int $block_size + * @return string + * @throws SodiumException + * @throws TypeError + */ + function sodium_unpad( + #[\SensitiveParameter] + string $padded, + int $block_size + ): string { + return ParagonIE_Sodium_Compat::unpad($padded, $block_size, true); + } +} +if (!is_callable('sodium_randombytes_buf')) { + /** + * @see ParagonIE_Sodium_Compat::randombytes_buf() + * @param int $amount + * @return string + * @throws Exception + */ + function sodium_randombytes_buf(int $amount): string + { + return ParagonIE_Sodium_Compat::randombytes_buf($amount); + } +} + +if (!is_callable('sodium_randombytes_uniform')) { + /** + * @see ParagonIE_Sodium_Compat::randombytes_uniform() + * @param int $upperLimit + * @return int + * @throws Exception + */ + function sodium_randombytes_uniform(int $upperLimit): int + { + return ParagonIE_Sodium_Compat::randombytes_uniform($upperLimit); + } +} + +if (!is_callable('sodium_randombytes_random16')) { + /** + * @see ParagonIE_Sodium_Compat::randombytes_random16() + * @return int + * @throws Exception + */ + function sodium_randombytes_random16(): int + { + return ParagonIE_Sodium_Compat::randombytes_random16(); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/lib/php72compat_const.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/lib/php72compat_const.php new file mode 100644 index 000000000..5a876a67f --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/lib/php72compat_const.php @@ -0,0 +1,92 @@ +>= 8; + } + $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); + } + + /** + * @param string $encoded + * @param int $variant + * @param string $ignore + * @return string + * @throws SodiumException + */ + public static function base642bin( + #[SensitiveParameter] + string $encoded, + int $variant, + string $ignore = '' + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) { + return ''; + } + + // Just strip before decoding + if (!empty($ignore)) { + $encoded = str_replace($ignore, '', $encoded); + } + + try { + return match ($variant) { + self::BASE64_VARIANT_ORIGINAL => ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true), + self::BASE64_VARIANT_ORIGINAL_NO_PADDING => ParagonIE_Sodium_Core_Base64_Original::decode($encoded), + self::BASE64_VARIANT_URLSAFE => ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true), + self::BASE64_VARIANT_URLSAFE_NO_PADDING => ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded), + default => throw new SodiumException('invalid base64 variant identifier'), + }; + } catch (Exception $ex) { + if ($ex instanceof SodiumException) { + throw $ex; + } + throw new SodiumException('invalid base64 string'); + } + } + + /** + * @param string $decoded + * @param int $variant + * @return string + * @throws SodiumException + */ + public static function bin2base64( + #[SensitiveParameter] + string $decoded, + int $variant + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) { + return ''; + } + + return match ($variant) { + self::BASE64_VARIANT_ORIGINAL => ParagonIE_Sodium_Core_Base64_Original::encode($decoded), + self::BASE64_VARIANT_ORIGINAL_NO_PADDING => ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded), + self::BASE64_VARIANT_URLSAFE => ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded), + self::BASE64_VARIANT_URLSAFE_NO_PADDING => ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded), + default => throw new SodiumException('invalid base64 variant identifier'), + }; + } + + /** + * Cache-timing-safe implementation of bin2hex(). + * + * @param string $string A string (probably raw binary) + * @return string A hexadecimal-encoded string + * @throws SodiumException + * @throws TypeError + */ + public static function bin2hex( + #[SensitiveParameter] + string $string + ): string { + if (self::useNewSodiumAPI()) { + return sodium_bin2hex($string); + } + if (self::use_fallback('bin2hex')) { + return (string) call_user_func('\\Sodium\\bin2hex', $string); + } + return ParagonIE_Sodium_Core_Util::bin2hex($string); + } + + /** + * Compare two strings, in constant-time. + * Compared to memcmp(), compare() is more useful for sorting. + * + * @param string $left The left operand; must be a string + * @param string $right The right operand; must be a string + * @return int If < 0 if the left operand is less than the right + * If = 0 if both strings are equal + * If > 0 if the right operand is less than the left + * @throws SodiumException + * @throws TypeError + */ + public static function compare( + #[SensitiveParameter] + string $left, + #[SensitiveParameter] + string $right + ): int { + if (self::useNewSodiumAPI()) { + return sodium_compare($left, $right); + } + if (self::use_fallback('compare')) { + return (int) call_user_func('\\Sodium\\compare', $left, $right); + } + return ParagonIE_Sodium_Core_Util::compare($left, $right); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * AEGIS-128L + * + * @param string $ciphertext Encrypted message (with MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 32 bytes + * @param string $key Encryption key + * + * @return string The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aegis128l_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS_128L_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); + } + $ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext); + if ($ct_length < self::CRYPTO_AEAD_AEGIS128L_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS128L_ABYTES long'); + } + + $ct = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + $ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES + ); + $tag = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + $ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES, + self::CRYPTO_AEAD_AEGIS128L_ABYTES + ); + return ParagonIE_Sodium_Core_AEGIS128L::decrypt($ct, $tag, $assocData, $key, $nonce); + } + + /** + * Authenticated Encryption with Associated Data: Encryption + * + * Algorithm: + * AEGIS-128L + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 32 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with 32-byte authentication tag appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aegis128l_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); + } + + list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS128L::encrypt($plaintext, $assocData, $key, $nonce); + return $ct . $tag; + } + + /** + * Return a secure random key for use with the AEGIS-128L + * symmetric AEAD interface. + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_aegis128l_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_AEGIS128L_KEYBYTES); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * AEGIS-256 + * + * @param string $ciphertext Encrypted message (with MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 32 bytes + * @param string $key Encryption key + * + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aegis256_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS256_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS256_KEYBYTES long'); + } + $ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext); + if ($ct_length < self::CRYPTO_AEAD_AEGIS256_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS256_ABYTES long'); + } + + $ct = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + $ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES + ); + $tag = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + $ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES, + self::CRYPTO_AEAD_AEGIS256_ABYTES + ); + return ParagonIE_Sodium_Core_AEGIS256::decrypt($ct, $tag, $assocData, $key, $nonce); + } + + /** + * Authenticated Encryption with Associated Data: Encryption + * + * Algorithm: + * AEGIS-256 + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 32 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with 32-byte authentication tag appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aegis256_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); + } + + list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS256::encrypt($plaintext, $assocData, $key, $nonce); + return $ct . $tag; + } + + /** + * Return a secure random key for use with the AEGIS-256 + * symmetric AEAD interface. + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_aegis256_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_AEGIS256_KEYBYTES); + } + + /** + * Is AES-256-GCM even available to use? + * + * @return bool + */ + public static function crypto_aead_aes256gcm_is_available(): bool + { + if (self::useNewSodiumAPI()) { + return sodium_crypto_aead_aes256gcm_is_available(); + } + if (self::use_fallback('crypto_aead_aes256gcm_is_available')) { + return call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available'); + } + if (!is_callable('openssl_encrypt') || !is_callable('openssl_decrypt')) { + // OpenSSL isn't installed + return false; + } + return in_array('aes-256-gcm', openssl_get_cipher_methods()); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * AES-256-GCM + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aes256gcm_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string|bool { + if (!self::crypto_aead_aes256gcm_is_available()) { + throw new SodiumException('AES-256-GCM is not available'); + } + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_AES256GCM_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_AES256GCM_ABYTES long'); + } + if (!is_callable('openssl_decrypt')) { + throw new SodiumException('The OpenSSL extension is not installed, or openssl_decrypt() is not available'); + } + + $ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0, -self::CRYPTO_AEAD_AES256GCM_ABYTES); + $authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext, -self::CRYPTO_AEAD_AES256GCM_ABYTES, 16); + return openssl_decrypt( + $ctext, + 'aes-256-gcm', + $key, + OPENSSL_RAW_DATA, + $nonce, + $authTag, + $assocData + ); + } + + /** + * Authenticated Encryption with Associated Data: Encryption + * + * Algorithm: + * AES-256-GCM + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte GCM message + * authentication code appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_aes256gcm_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + if (!self::crypto_aead_aes256gcm_is_available()) { + throw new SodiumException('AES-256-GCM is not available'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); + } + + if (!is_callable('openssl_encrypt')) { + throw new SodiumException('The OpenSSL extension is not installed, or openssl_encrypt() is not available'); + } + + $authTag = ''; + $ciphertext = openssl_encrypt( + $plaintext, + 'aes-256-gcm', + $key, + OPENSSL_RAW_DATA, + $nonce, + $authTag, + $assocData + ); + return $ciphertext . $authTag; + } + + /** + * Return a secure random key for use with the AES-256-GCM + * symmetric AEAD interface. + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_aes256gcm_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * ChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_aead_chacha20poly1305_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_decrypt', + $ciphertext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * ChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_aead_chacha20poly1305_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) { + return (string) call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_encrypt', + $plaintext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * ChaCha20-Poly1305 + * + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * Regular mode uses a 64-bit random nonce with a 64-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 12 bytes + * @param string $key Encryption key + * + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_ietf_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_aead_chacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt', + $ciphertext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Return a secure random key for use with the ChaCha20-Poly1305 + * symmetric AEAD interface. + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_chacha20poly1305_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * ChaCha20-Poly1305 + * + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * Regular mode uses a 64-bit random nonce with a 64-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_ietf_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_aead_chacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) { + return (string) call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt', + $plaintext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Return a secure random key for use with the ChaCha20-Poly1305 + * symmetric AEAD interface. (IETF version) + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_chacha20poly1305_ietf_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * XChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * @param bool $dontFallback Don't fallback to ext/sodium + * + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_xchacha20poly1305_ietf_decrypt( + string $ciphertext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '', + bool $dontFallback = false + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) { + throw new SodiumException('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long'); + } + if (self::useNewSodiumAPI() && !$dontFallback) { + if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) { + return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + } + + return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * XChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * @param bool $dontFallback Don't fallback to ext/sodium + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_aead_xchacha20poly1305_ietf_encrypt( + #[SensitiveParameter] + string $plaintext = '', + string $assocData = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '', + bool $dontFallback = false + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { + throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { + throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long'); + } + if (self::useNewSodiumAPI() && !$dontFallback) { + if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) { + return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + } + + return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Return a secure random key for use with the XChaCha20-Poly1305 + * symmetric AEAD interface. + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_aead_xchacha20poly1305_ietf_keygen(): string + { + return random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES); + } + + /** + * Authenticate a message. Uses symmetric-key cryptography. + * + * Algorithm: + * HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits. + * Not to be confused with HMAC-SHA-512/256 which would use the + * SHA-512/256 hash function (uses different initial parameters + * but still truncates to 256 bits to sidestep length-extension + * attacks). + * + * @param string $message Message to be authenticated + * @param string $key Symmetric authentication key + * @return string Message authentication code + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_auth( + string $message, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_auth($message, $key); + } + if (self::use_fallback('crypto_auth')) { + return (string) call_user_func('\\Sodium\\crypto_auth', $message, $key); + } + return ParagonIE_Sodium_Crypto::auth($message, $key); + } + + /** + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_auth_keygen(): string + { + return random_bytes(self::CRYPTO_AUTH_KEYBYTES); + } + + /** + * Verify the MAC of a message previously authenticated with crypto_auth. + * + * @param string $mac Message authentication code + * @param string $message Message whose authenticity you are attempting to + * verify (with a given MAC and key) + * @param string $key Symmetric authentication key + * @return bool TRUE if authenticated, FALSE otherwise + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_auth_verify( + string $mac, + string $message, + #[SensitiveParameter] + string $key + ): bool { + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_AUTH_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_auth_verify($mac, $message, $key); + } + if (self::use_fallback('crypto_auth_verify')) { + return (bool) call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key); + } + return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key); + } + + /** + * Authenticated asymmetric-key encryption. Both the sender and recipient + * may decrypt messages. + * + * Algorithm: X25519-XSalsa20-Poly1305. + * X25519: Elliptic-Curve Diffie Hellman over Curve25519. + * XSalsa20: Extended-nonce variant of salsa20. + * Poyl1305: Polynomial MAC for one-time message authentication. + * + * @param string $plaintext The message to be encrypted + * @param string $nonce A Number to only be used Once; must be 24 bytes + * @param string $keypair Your secret key and your recipient's public key + * @return string Ciphertext with 16-byte Poly1305 MAC + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box( + #[SensitiveParameter] + string $plaintext, + string $nonce, + #[SensitiveParameter] + string $keypair + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box($plaintext, $nonce, $keypair); + } + if (self::use_fallback('crypto_box')) { + return (string) call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair); + } + return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair); + } + + /** + * Anonymous public-key encryption. Only the recipient may decrypt messages. + * + * Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box. + * The sender's X25519 keypair is ephemeral. + * Nonce is generated from the BLAKE2b hash of both public keys. + * + * This provides ciphertext integrity. + * + * @param string $plaintext Message to be sealed + * @param string $publicKey Your recipient's public key + * @return string Sealed message that only your recipient can + * decrypt + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_seal( + #[SensitiveParameter] + string $plaintext, + string $publicKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_seal($plaintext, $publicKey); + } + if (self::use_fallback('crypto_box_seal')) { + return (string) call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey); + } + return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey); + } + + /** + * Opens a message encrypted with crypto_box_seal(). Requires + * the recipient's keypair (sk || pk) to decrypt successfully. + * + * This validates ciphertext integrity. + * + * @param string $ciphertext Sealed message to be opened + * @param string $keypair Your crypto_box keypair + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_seal_open( + string $ciphertext, + string $keypair + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_seal_open($ciphertext, $keypair); + } + if (self::use_fallback('crypto_box_seal_open')) { + return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair); + } + return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair); + } + + /** + * Generate a new random X25519 keypair. + * + * @return string A 64-byte string; the first 32 are your secret key, while + * the last 32 are your public key. crypto_box_secretkey() + * and crypto_box_publickey() exist to separate them so you + * don't accidentally get them mixed up! + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_keypair(): string + { + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_keypair(); + } + if (self::use_fallback('crypto_box_keypair')) { + return (string) call_user_func('\\Sodium\\crypto_box_keypair'); + } + return ParagonIE_Sodium_Crypto::box_keypair(); + } + + /** + * Combine two keys into a keypair for use in library methods that expect + * a keypair. This doesn't necessarily have to be the same person's keys. + * + * @param string $secretKey Secret key + * @param string $publicKey Public key + * @return string Keypair + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_keypair_from_secretkey_and_publickey( + #[SensitiveParameter] + string $secretKey, + string $publicKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); + } + if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) { + return (string) call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey); + } + return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); + } + + /** + * Decrypt a message previously encrypted with crypto_box(). + * + * @param string $ciphertext Encrypted message + * @param string $nonce Number to only be used Once; must be 24 bytes + * @param string $keypair Your secret key and the sender's public key + * @return string|bool The original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $keypair + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) { + throw new SodiumException('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_open($ciphertext, $nonce, $keypair); + } + if (self::use_fallback('crypto_box_open')) { + return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair); + } + return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair); + } + + /** + * Extract the public key from a crypto_box keypair. + * + * @param string $keypair Keypair containing secret and public key + * @return string Your crypto_box public key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_publickey( + #[SensitiveParameter] + string $keypair + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_publickey($keypair); + } + if (self::use_fallback('crypto_box_publickey')) { + return (string) call_user_func('\\Sodium\\crypto_box_publickey', $keypair); + } + return ParagonIE_Sodium_Crypto::box_publickey($keypair); + } + + /** + * Calculate the X25519 public key from a given X25519 secret key. + * + * @param string $secretKey Any X25519 secret key + * @return string The corresponding X25519 public key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_publickey_from_secretkey( + string $secretKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_publickey_from_secretkey($secretKey); + } + if (self::use_fallback('crypto_box_publickey_from_secretkey')) { + return (string) call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey); + } + return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey); + } + + /** + * Extract the secret key from a crypto_box keypair. + * + * @param string $keypair + * @return string Your crypto_box secret key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_secretkey( + #[SensitiveParameter] + string $keypair + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_secretkey($keypair); + } + if (self::use_fallback('crypto_box_secretkey')) { + return (string) call_user_func('\\Sodium\\crypto_box_secretkey', $keypair); + } + return ParagonIE_Sodium_Crypto::box_secretkey($keypair); + } + + /** + * Generate an X25519 keypair from a seed. + * + * @param string $seed + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_box_seed_keypair( + #[SensitiveParameter] + string $seed + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_box_seed_keypair($seed); + } + if (self::use_fallback('crypto_box_seed_keypair')) { + return (string) call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed); + } + return ParagonIE_Sodium_Crypto::box_seed_keypair($seed); + } + + /** + * Calculates a BLAKE2b hash, with an optional key. + * + * @param string $message The message to be hashed + * @param string|null $key If specified, must be a string between 16 + * and 64 bytes long + * @param int $length Output length in bytes; must be between 16 + * and 64 (default = 32) + * @return string Raw binary + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_generichash( + string $message, + #[SensitiveParameter] + ?string $key = '', + int $length = self::CRYPTO_GENERICHASH_BYTES + ): string { + if (is_null($key)) { + $key = ''; + } + /* Input validation: */ + if (!empty($key)) { + if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { + throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); + } + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_generichash($message, $key, $length); + } + if (self::use_fallback('crypto_generichash')) { + return (string) call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length); + } + return ParagonIE_Sodium_Crypto::generichash($message, $key, $length); + } + + /** + * Get the final BLAKE2b hash output for a given context. + * + * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). + * @param int $length Hash output size. + * @return string Final BLAKE2b hash. + * @throws SodiumException + * @throws TypeError + * @psalm-suppress ReferenceConstraintViolation + */ + public static function crypto_generichash_final( + string &$ctx, + int $length = self::CRYPTO_GENERICHASH_BYTES + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_generichash_final($ctx, $length); + } + if (self::use_fallback('crypto_generichash_final')) { + $func = '\\Sodium\\crypto_generichash_final'; + return (string) $func($ctx, $length); + } + if ($length < 1) { + try { + self::memzero($ctx); + } catch (SodiumException) { + unset($ctx); + } + return ''; + } + $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length); + try { + self::memzero($ctx); + } catch (SodiumException) { + unset($ctx); + } + return $result; + } + + /** + * Initialize a BLAKE2b hashing context, for use in a streaming interface. + * + * @param string|null $key If specified must be a string between 16 and 64 bytes + * @param int $length The size of the desired hash output + * @return string A BLAKE2 hashing context, encoded as a string + * (To be 100% compatible with ext/libsodium) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_generichash_init( + #[SensitiveParameter] + ?string $key = '', + int $length = self::CRYPTO_GENERICHASH_BYTES + ): string { + if (is_null($key)) { + $key = ''; + } + + /* Input validation: */ + if (!empty($key)) { + if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { + throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); + } + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_generichash_init($key, $length); + } + if (self::use_fallback('crypto_generichash_init')) { + return (string) call_user_func('\\Sodium\\crypto_generichash_init', $key, $length); + } + return ParagonIE_Sodium_Crypto::generichash_init($key, $length); + } + + /** + * Initialize a BLAKE2b hashing context, for use in a streaming interface. + * + * @param string|null $key If specified must be a string between 16 and 64 bytes + * @param int $length The size of the desired hash output + * @param string $salt Salt (up to 16 bytes) + * @param string $personal Personalization string (up to 16 bytes) + * @return string A BLAKE2 hashing context, encoded as a string + * (To be 100% compatible with ext/libsodium) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_generichash_init_salt_personal( + #[SensitiveParameter] + ?string $key = '', + int $length = self::CRYPTO_GENERICHASH_BYTES, + string $salt = '', + string $personal = '' + ): string { + if (is_null($key)) { + $key = ''; + } + $salt = str_pad($salt, 16, "\0"); + $personal = str_pad($personal, 16, "\0"); + + /* Input validation: */ + if (!empty($key)) { + if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); + } + } + return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal); + } + + /** + * Update a BLAKE2b hashing context with additional data. + * + * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). + * $ctx is passed by reference and gets updated in-place. + * @param-out string $ctx + * @param string $message The message to append to the existing hash state. + * @return void + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_generichash_update(string &$ctx, string $message): void + { + if (self::useNewSodiumAPI()) { + sodium_crypto_generichash_update($ctx, $message); + return; + } + if (self::use_fallback('crypto_generichash_update')) { + $func = '\\Sodium\\crypto_generichash_update'; + $func($ctx, $message); + return; + } + $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message); + } + + /** + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_generichash_keygen(): string + { + return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES); + } + + /** + * @param int $subkey_len + * @param int $subkey_id + * @param string $context + * @param string $key + * @return string + * @throws SodiumException + */ + public static function crypto_kdf_derive_from_key( + int $subkey_len, + int $subkey_id, + string $context, + #[SensitiveParameter] + string $key + ): string { + if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) { + throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN'); + } + if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) { + throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX'); + } + if ($subkey_id < 0) { + throw new SodiumException('subkey_id cannot be negative'); + } + if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) { + throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) { + throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes'); + } + + $salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id); + $state = self::crypto_generichash_init_salt_personal( + $key, + $subkey_len, + $salt, + $context + ); + return self::crypto_generichash_final($state, $subkey_len); + } + + /** + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_kdf_keygen(): string + { + return random_bytes(self::CRYPTO_KDF_KEYBYTES); + } + + /** + * Perform a key exchange, between a designated client and a server. + * + * Typically, you would designate one machine to be the client and the + * other to be the server. The first two keys are what you'd expect for + * scalarmult() below, but the latter two public keys don't swap places. + * + * | ALICE | BOB | + * | Client | Server | + * |--------------------------------|-------------------------------------| + * | shared = crypto_kx( | shared = crypto_kx( | + * | alice_sk, | bob_sk, | <- contextual + * | bob_pk, | alice_pk, | <- contextual + * | alice_pk, | alice_pk, | <----- static + * | bob_pk | bob_pk | <----- static + * | ) | ) | + * + * They are used along with the scalarmult product to generate a 256-bit + * BLAKE2b hash unique to the client and server keys. + * + * @param string $my_secret + * @param string $their_public + * @param string $client_public + * @param string $server_public + * @param bool $dontFallback + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_kx( + #[SensitiveParameter] + string $my_secret, + string $their_public, + string $client_public, + string $server_public, + bool $dontFallback = false + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI() && !$dontFallback) { + if (is_callable('sodium_crypto_kx')) { + return sodium_crypto_kx( + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + } + if (self::use_fallback('crypto_kx')) { + return call_user_func( + '\\Sodium\\crypto_kx', + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + return ParagonIE_Sodium_Crypto::keyExchange( + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + + /** + * @param string $seed + * @return string + * @throws SodiumException + */ + public static function crypto_kx_seed_keypair( + #[SensitiveParameter] + string $seed + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) { + throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes'); + } + + $sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES); + $pk = self::crypto_scalarmult_base($sk); + return $sk . $pk; + } + + /** + * @return string + * @throws Exception + */ + public static function crypto_kx_keypair(): string + { + $sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES); + $pk = self::crypto_scalarmult_base($sk); + return $sk . $pk; + } + + /** + * @param string $keypair + * @param string $serverPublicKey + * @return array{0: string, 1: string} + * @throws SodiumException + */ + public static function crypto_kx_client_session_keys( + #[SensitiveParameter] + string $keypair, + string $serverPublicKey + ): array { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { + throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); + } + if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { + throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); + } + + $sk = self::crypto_kx_secretkey($keypair); + $pk = self::crypto_kx_publickey($keypair); + $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); + self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey)); + self::crypto_generichash_update($h, $pk); + self::crypto_generichash_update($h, $serverPublicKey); + $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); + return array( + ParagonIE_Sodium_Core_Util::substr( + $sessionKeys, + 0, + self::CRYPTO_KX_SESSIONKEYBYTES + ), + ParagonIE_Sodium_Core_Util::substr( + $sessionKeys, + self::CRYPTO_KX_SESSIONKEYBYTES, + self::CRYPTO_KX_SESSIONKEYBYTES + ) + ); + } + + /** + * @param string $keypair + * @param string $clientPublicKey + * @return array{0: string, 1: string} + * @throws SodiumException + */ + public static function crypto_kx_server_session_keys( + #[SensitiveParameter] + string $keypair, + string $clientPublicKey + ): array { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { + throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); + } + if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { + throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); + } + + $sk = self::crypto_kx_secretkey($keypair); + $pk = self::crypto_kx_publickey($keypair); + $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); + self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey)); + self::crypto_generichash_update($h, $clientPublicKey); + self::crypto_generichash_update($h, $pk); + $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); + return array( + ParagonIE_Sodium_Core_Util::substr( + $sessionKeys, + self::CRYPTO_KX_SESSIONKEYBYTES, + self::CRYPTO_KX_SESSIONKEYBYTES + ), + ParagonIE_Sodium_Core_Util::substr( + $sessionKeys, + 0, + self::CRYPTO_KX_SESSIONKEYBYTES + ) + ); + } + + /** + * @param string $kp + * @return string + * @throws SodiumException + */ + public static function crypto_kx_secretkey( + #[SensitiveParameter] + string $kp + ): string { + return ParagonIE_Sodium_Core_Util::substr( + $kp, + 0, + self::CRYPTO_KX_SECRETKEYBYTES + ); + } + + /** + * @param string $kp + * @return string + * @throws SodiumException + */ + public static function crypto_kx_publickey( + string $kp + ): string { + return ParagonIE_Sodium_Core_Util::substr( + $kp, + self::CRYPTO_KX_SECRETKEYBYTES, + self::CRYPTO_KX_PUBLICKEYBYTES + ); + } + + /** + * @param int $outlen + * @param string $passwd + * @param string $salt + * @param int $opslimit + * @param int $memlimit + * @param int|null $alg + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash( + int $outlen, + #[SensitiveParameter] + string $passwd, + #[SensitiveParameter] + string $salt, + int $opslimit, + int $memlimit, + ?int $alg = null + ): string { + if (self::useNewSodiumAPI()) { + if (!is_null($alg)) { + return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg); + } + return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit); + } + if (self::use_fallback('crypto_pwhash')) { + return (string) call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' + ); + } + + /** + * !Exclusive to sodium_compat! + * + * This returns TRUE if the native crypto_pwhash API is available by libsodium. + * This returns FALSE if only sodium_compat is available. + * + * @return bool + */ + public static function crypto_pwhash_is_available(): bool + { + if (self::useNewSodiumAPI()) { + return true; + } + if (self::use_fallback('crypto_pwhash')) { + return true; + } + return false; + } + + /** + * @param string $passwd + * @param int $opslimit + * @param int $memlimit + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash_str( + #[SensitiveParameter] + string $passwd, + int $opslimit, + int $memlimit + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit); + } + if (self::use_fallback('crypto_pwhash_str')) { + return (string) call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' + ); + } + + /** + * Do we need to rehash this password? + * + * @param string $hash + * @param int $opslimit + * @param int $memlimit + * @return bool + * @throws SodiumException + */ + public static function crypto_pwhash_str_needs_rehash( + #[SensitiveParameter] + string $hash, + int $opslimit, + int $memlimit + ): bool { + // Just grab the first 4 pieces. + $pieces = explode('$', $hash); + $prefix = implode('$', array_slice($pieces, 0, 4)); + + // Rebuild the expected header. + $ops = $opslimit; + $mem = $memlimit >> 10; + $encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1'; + + // Do they match? If so, we don't need to rehash, so return false. + return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix); + } + + /** + * @param string $passwd + * @param string $hash + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash_str_verify( + #[SensitiveParameter] + string $passwd, + #[SensitiveParameter] + string $hash + ): bool { + if (self::useNewSodiumAPI()) { + return sodium_crypto_pwhash_str_verify($passwd, $hash); + } + if (self::use_fallback('crypto_pwhash_str_verify')) { + return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' + ); + } + + /** + * @param int $outlen + * @param string $passwd + * @param string $salt + * @param int $opslimit + * @param int $memlimit + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash_scryptsalsa208sha256( + int $outlen, + #[SensitiveParameter] + string $passwd, + #[SensitiveParameter] + string $salt, + int $opslimit, + int $memlimit + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_pwhash_scryptsalsa208sha256( + $outlen, + $passwd, + $salt, + $opslimit, + $memlimit + ); + } + if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { + return (string) call_user_func( + '\\Sodium\\crypto_pwhash_scryptsalsa208sha256', + $outlen, + $passwd, + $salt, + $opslimit, + $memlimit + ); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' + ); + } + + /** + * !Exclusive to sodium_compat! + * + * This returns TRUE if the native crypto_pwhash API is available by libsodium. + * This returns FALSE if only sodium_compat is available. + * + * @return bool + */ + public static function crypto_pwhash_scryptsalsa208sha256_is_available(): bool + { + if (self::useNewSodiumAPI()) { + return true; + } + if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { + return true; + } + return false; + } + + /** + * @param string $passwd + * @param int $opslimit + * @param int $memlimit + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash_scryptsalsa208sha256_str( + #[SensitiveParameter] + string $passwd, + int $opslimit, + int $memlimit + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_pwhash_scryptsalsa208sha256_str( + $passwd, + $opslimit, + $memlimit + ); + } + if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) { + return (string) call_user_func( + '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str', + $passwd, + $opslimit, + $memlimit + ); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' + ); + } + + /** + * @param string $passwd + * @param string $hash + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_pwhash_scryptsalsa208sha256_str_verify( + #[SensitiveParameter] + string $passwd, + #[SensitiveParameter] + string $hash + ): bool { + if (self::useNewSodiumAPI()) { + return sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash); + } + if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) { + return (bool) call_user_func( + '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify', + $passwd, + $hash + ); + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' + ); + } + + /** + * Calculate the shared secret between your secret key and your + * recipient's public key. + * + * Algorithm: X25519 (ECDH over Curve25519) + * + * @param string $secretKey + * @param string $publicKey + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_scalarmult( + #[SensitiveParameter] + string $secretKey, + string $publicKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_scalarmult($secretKey, $publicKey); + } + if (self::use_fallback('crypto_scalarmult')) { + return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey); + } + + /* Output validation: Forbid all-zero keys */ + if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { + throw new SodiumException('Zero secret key is not allowed'); + } + if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) { + throw new SodiumException('Zero public key is not allowed'); + } + return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey); + } + + /** + * Calculate an X25519 public key from an X25519 secret key. + * + * @param string $secretKey + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_scalarmult_base( + #[SensitiveParameter] + string $secretKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_scalarmult_base($secretKey); + } + if (self::use_fallback('crypto_scalarmult_base')) { + return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey); + } + if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { + throw new SodiumException('Zero secret key is not allowed'); + } + return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey); + } + + /** + * Authenticated symmetric-key encryption. + * + * Algorithm: XSalsa20-Poly1305 + * + * @param string $plaintext The message you're encrypting + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Ciphertext with Poly1305 MAC + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_secretbox( + #[SensitiveParameter] + string $plaintext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_secretbox($plaintext, $nonce, $key); + } + if (self::use_fallback('crypto_secretbox')) { + return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key); + } + return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key); + } + + /** + * Decrypts a message previously encrypted with crypto_secretbox(). + * + * @param string $ciphertext Ciphertext with Poly1305 MAC + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string|bool Original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_secretbox_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $key + ): string|bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_secretbox_open($ciphertext, $nonce, $key); + } + if (self::use_fallback('crypto_secretbox_open')) { + return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key); + } + return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key); + } + + /** + * Return a secure random key for use with crypto_secretbox + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_secretbox_keygen(): string + { + return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES); + } + + /** + * Authenticated symmetric-key encryption. + * + * Algorithm: XChaCha20-Poly1305 + * + * @param string $plaintext The message you're encrypting + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Ciphertext with Poly1305 MAC + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_secretbox_xchacha20poly1305( + #[SensitiveParameter] + string $plaintext, + string $nonce, + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key); + } + + /** + * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305(). + * + * @param string $ciphertext Ciphertext with Poly1305 MAC + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Original plaintext message + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_secretbox_xchacha20poly1305_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); + } + + /** + * @param string $key + * @return array Returns a state and a header. + * @throws Exception + * @throws SodiumException + */ + public static function crypto_secretstream_xchacha20poly1305_init_push( + #[SensitiveParameter] + string $key + ): array { + return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key); + } + + /** + * @param string $header + * @param string $key + * @return string Returns a state. + * @throws Exception + */ + public static function crypto_secretstream_xchacha20poly1305_init_pull( + string $header, + #[SensitiveParameter] + string $key + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) { + throw new SodiumException( + 'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes' + ); + } + return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header); + } + + /** + * @param string $state + * @param string $msg + * @param string $aad + * @param int $tag + * @return string + * @throws SodiumException + */ + public static function crypto_secretstream_xchacha20poly1305_push( + #[SensitiveParameter] + string &$state, + #[SensitiveParameter] + string $msg, + string $aad = '', + int $tag = 0 + ): string { + return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push( + $state, + $msg, + $aad, + $tag + ); + } + + /** + * @param string $state + * @param string $msg + * @param string $aad + * @return bool|array{0: string, 1: int} + * @throws SodiumException + */ + public static function crypto_secretstream_xchacha20poly1305_pull( + #[SensitiveParameter] + string &$state, + string $msg, + string $aad = '' + ): bool|array { + return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull( + $state, + $msg, + $aad + ); + } + + /** + * @return string + * @throws Exception + */ + public static function crypto_secretstream_xchacha20poly1305_keygen(): string + { + return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES); + } + + /** + * @param string $state + * @return void + * @throws SodiumException + */ + public static function crypto_secretstream_xchacha20poly1305_rekey( + #[SensitiveParameter] + string &$state + ): void { + ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state); + } + + /** + * Calculates a SipHash-2-4 hash of a message for a given key. + * + * @param string $message Input message + * @param string $key SipHash-2-4 key + * @return string Hash + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_shorthash( + string $message, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_shorthash($message, $key); + } + if (self::use_fallback('crypto_shorthash')) { + return (string) call_user_func('\\Sodium\\crypto_shorthash', $message, $key); + } + return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key); + } + + /** + * Return a secure random key for use with crypto_shorthash + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_shorthash_keygen(): string + { + return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES); + } + + /** + * Returns a signed message. You probably want crypto_sign_detached() + * instead, which only returns the signature. + * + * Algorithm: Ed25519 (EdDSA over Curve25519) + * + * @param string $message Message to be signed. + * @param string $secretKey Secret signing key. + * @return string Signed message (signature is prefixed). + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign( + string $message, + #[SensitiveParameter] + string $secretKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign($message, $secretKey); + } + if (self::use_fallback('crypto_sign')) { + return (string) call_user_func('\\Sodium\\crypto_sign', $message, $secretKey); + } + return ParagonIE_Sodium_Crypto::sign($message, $secretKey); + } + + /** + * Validates a signed message then returns the message. + * + * @param string $signedMessage A signed message + * @param string $publicKey A public key + * @return string|bool The original message (if the signature is + * valid for this public key) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_open(string $signedMessage, string $publicKey): string|bool + { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) { + throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_open($signedMessage, $publicKey); + } + if (self::use_fallback('crypto_sign_open')) { + return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey); + } + return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey); + } + + /** + * Generate a new random Ed25519 keypair. + * + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_keypair(): string + { + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_keypair(); + } + if (self::use_fallback('crypto_sign_keypair')) { + return (string) call_user_func('\\Sodium\\crypto_sign_keypair'); + } + return ParagonIE_Sodium_Core_Ed25519::keypair(); + } + + /** + * @param string $sk + * @param string $pk + * @return string + * @throws SodiumException + */ + public static function crypto_sign_keypair_from_secretkey_and_publickey( + #[SensitiveParameter] + string $sk, + string $pk + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes'); + } + if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk); + } + return $sk . $pk; + } + + /** + * Generate an Ed25519 keypair from a seed. + * + * @param string $seed Input seed + * @return string Keypair + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_seed_keypair( + #[SensitiveParameter] + string $seed + ): string { + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_seed_keypair($seed); + } + if (self::use_fallback('crypto_sign_keypair')) { + return (string) call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed); + } + $publicKey = ''; + $secretKey = ''; + ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed); + return $secretKey . $publicKey; + } + + /** + * Extract an Ed25519 public key from an Ed25519 keypair. + * + * @param string $keypair Keypair + * @return string Public key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_publickey( + #[SensitiveParameter] + string $keypair + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_publickey($keypair); + } + if (self::use_fallback('crypto_sign_publickey')) { + return (string) call_user_func('\\Sodium\\crypto_sign_publickey', $keypair); + } + return ParagonIE_Sodium_Core_Ed25519::publickey($keypair); + } + + /** + * Calculate an Ed25519 public key from an Ed25519 secret key. + * + * @param string $secretKey Your Ed25519 secret key + * @return string The corresponding Ed25519 public key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_publickey_from_secretkey( + #[SensitiveParameter] + string $secretKey + ): string { + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_publickey_from_secretkey($secretKey); + } + if (self::use_fallback('crypto_sign_publickey_from_secretkey')) { + return (string) call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey); + } + return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey); + } + + /** + * Extract an Ed25519 secret key from an Ed25519 keypair. + * + * @param string $keypair Keypair + * @return string Secret key + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_secretkey( + #[SensitiveParameter] + string $keypair + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_secretkey($keypair); + } + if (self::use_fallback('crypto_sign_secretkey')) { + return (string) call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair); + } + return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair); + } + + /** + * Calculate the Ed25519 signature of a message and return ONLY the signature. + * + * Algorithm: Ed25519 (EdDSA over Curve25519) + * + * @param string $message Message to be signed + * @param string $secretKey Secret signing key + * @return string Digital signature + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_detached( + string $message, + #[SensitiveParameter] + string $secretKey + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_detached($message, $secretKey); + } + if (self::use_fallback('crypto_sign_detached')) { + return (string) call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey); + } + return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey); + } + + /** + * Verify the Ed25519 signature of a message. + * + * @param string $signature Digital sginature + * @param string $message Message to be verified + * @param string $publicKey Public key + * @return bool TRUE if this signature is good for this public key; + * FALSE otherwise + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_verify_detached( + string $signature, + string $message, + string $publicKey + ): bool { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) { + throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_sign_verify_detached($signature, $message, $publicKey); + } + if (self::use_fallback('crypto_sign_verify_detached')) { + return (bool) call_user_func( + '\\Sodium\\crypto_sign_verify_detached', + $signature, + $message, + $publicKey + ); + } + return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey); + } + + /** + * Convert an Ed25519 public key to a Curve25519 public key + * + * @param string $pk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_ed25519_pk_to_curve25519(string $pk): string + { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($pk) < self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_PUBLICKEYBYTES long.'); + } + if (self::useNewSodiumAPI()) { + if (is_callable('crypto_sign_ed25519_pk_to_curve25519')) { + return sodium_crypto_sign_ed25519_pk_to_curve25519($pk); + } + } + if (self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) { + return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519', $pk); + } + return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk); + } + + /** + * Convert an Ed25519 secret key to a Curve25519 secret key + * + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_sign_ed25519_sk_to_curve25519( + #[SensitiveParameter] + string $sk + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) { + throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.'); + } + if (self::useNewSodiumAPI()) { + if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) { + return sodium_crypto_sign_ed25519_sk_to_curve25519($sk); + } + } + if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) { + return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk); + } + + $h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true); + $h[0] = ParagonIE_Sodium_Core_Util::intToChr( + ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248 + ); + $h[31] = ParagonIE_Sodium_Core_Util::intToChr( + (ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64 + ); + return ParagonIE_Sodium_Core_Util::substr($h, 0, 32); + } + + /** + * Expand a key and nonce into a keystream of pseudorandom bytes. + * + * @param int $len Number of bytes desired + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key XSalsa20 key + * @return string Pseudorandom stream that can be XORed with messages + * to provide encryption (but not authentication; see + * Poly1305 or crypto_auth() for that, which is not + * optional for security) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_stream( + int $len, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_stream($len, $nonce, $key); + } + if (self::use_fallback('crypto_stream')) { + return (string) call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key); + } + return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key); + } + + /** + * DANGER! UNAUTHENTICATED ENCRYPTION! + * + * Unless you are following expert advice, do not use this feature. + * + * Algorithm: XSalsa20 + * + * This DOES NOT provide ciphertext integrity. + * + * @param string $message Plaintext message + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key Encryption key + * @return string Encrypted text which is vulnerable to chosen- + * ciphertext attacks unless you implement some + * other mitigation to the ciphertext (i.e. + * Encrypt then MAC) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_stream_xor( + #[SensitiveParameter] + string $message, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI()) { + return sodium_crypto_stream_xor($message, $nonce, $key); + } + if (self::use_fallback('crypto_stream_xor')) { + return (string) call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key); + } + return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key); + } + + /** + * Return a secure random key for use with crypto_stream + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_stream_keygen(): string + { + return random_bytes(self::CRYPTO_STREAM_KEYBYTES); + } + + /** + * Expand a key and nonce into a keystream of pseudorandom bytes. + * + * @param int $len Number of bytes desired + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key XChaCha20 key + * @param bool $dontFallback + * @return string Pseudorandom stream that can be XORed with messages + * to provide encryption (but not authentication; see + * Poly1305 or crypto_auth() for that, which is not + * optional for security) + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_stream_xchacha20( + int $len, + string $nonce, + #[SensitiveParameter] + string $key, + bool $dontFallback = false + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_STREAM_XCHACHA20_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_stream_xchacha20($len, $nonce, $key); + } + return ParagonIE_Sodium_Core_XChaCha20::stream($len, $nonce, $key); + } + + /** + * DANGER! UNAUTHENTICATED ENCRYPTION! + * + * Unless you are following expert advice, do not use this feature. + * + * Algorithm: XChaCha20 + * + * This DOES NOT provide ciphertext integrity. + * + * @param string $message Plaintext message + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key Encryption key + * @return string Encrypted text which is vulnerable to chosen- + * ciphertext attacks unless you implement some + * other mitigation to the ciphertext (i.e. + * Encrypt then MAC) + * @param bool $dontFallback + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_stream_xchacha20_xor( + #[SensitiveParameter] + string $message, + string $nonce, + #[SensitiveParameter] + string $key, + bool $dontFallback = false + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.'); + } + + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_stream_xchacha20_xor($message, $nonce, $key); + } + return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key); + } + + /** + * DANGER! UNAUTHENTICATED ENCRYPTION! + * + * Unless you are following expert advice, do not use this feature. + * + * Algorithm: XChaCha20 + * + * This DOES NOT provide ciphertext integrity. + * + * @param string $message Plaintext message + * @param string $nonce Number to be used Once; must be 24 bytes + * @param int $counter + * @param string $key Encryption key + * @return string Encrypted text which is vulnerable to chosen- + * ciphertext attacks unless you implement some + * other mitigation to the ciphertext (i.e. + * Encrypt then MAC) + * @param bool $dontFallback + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_stream_xchacha20_xor_ic( + #[SensitiveParameter] + string $message, + string $nonce, + int $counter, + #[SensitiveParameter] + string $key, + bool $dontFallback = false + ): string { + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { + throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { + throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.'); + } + + if (is_callable('sodium_crypto_stream_xchacha20_xor_ic') && !$dontFallback) { + return sodium_crypto_stream_xchacha20_xor_ic($message, $nonce, $counter, $key); + } + + $ic = ParagonIE_Sodium_Core_Util::store64_le($counter); + return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key, $ic); + } + + /** + * Return a secure random key for use with crypto_stream_xchacha20 + * + * @return string + * @throws Exception + * @throws Error + */ + public static function crypto_stream_xchacha20_keygen(): string + { + return random_bytes(self::CRYPTO_STREAM_XCHACHA20_KEYBYTES); + } + + /** + * Cache-timing-safe implementation of hex2bin(). + * + * @param string $string Hexadecimal string + * @param string $ignore List of characters to ignore; useful for whitespace + * @return string Raw binary string + * @throws SodiumException + * @throws TypeError + */ + public static function hex2bin( + #[SensitiveParameter] + string $string, + string $ignore = '' + ): string { + if (self::useNewSodiumAPI()) { + if (is_callable('sodium_hex2bin')) { + return sodium_hex2bin($string, $ignore); + } + } + if (self::use_fallback('hex2bin')) { + return (string) call_user_func('\\Sodium\\hex2bin', $string, $ignore); + } + return ParagonIE_Sodium_Core_Util::hex2bin($string, $ignore); + } + + /** + * Increase a string (little endian) + * + * @param string $var + * + * @return void + * @throws SodiumException + * @throws TypeError + */ + public static function increment( + #[SensitiveParameter] + string &$var + ): void { + if (self::useNewSodiumAPI()) { + sodium_increment($var); + return; + } + if (self::use_fallback('increment')) { + $func = '\\Sodium\\increment'; + $func($var); + return; + } + + $len = ParagonIE_Sodium_Core_Util::strlen($var); + $c = 1; + $copy = ''; + for ($i = 0; $i < $len; ++$i) { + $c += ParagonIE_Sodium_Core_Util::chrToInt( + ParagonIE_Sodium_Core_Util::substr($var, $i, 1) + ); + $copy .= ParagonIE_Sodium_Core_Util::intToChr($c); + $c >>= 8; + } + $var = $copy; + } + + /** + * @param string $str + * @return bool + * + * @throws SodiumException + */ + public static function is_zero( + #[SensitiveParameter] + string $str + ): bool { + $d = 0; + for ($i = 0; $i < 32; ++$i) { + $d |= ParagonIE_Sodium_Core_Util::chrToInt($str[$i]); + } + return ((($d - 1) >> 31) & 1) === 1; + } + + /** + * The equivalent to the libsodium minor version we aim to be compatible + * with (sans pwhash and memzero). + * + * @return int + */ + public static function library_version_major(): int + { + if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MAJOR_VERSION')) { + return SODIUM_LIBRARY_MAJOR_VERSION; + } + if (self::use_fallback('library_version_major')) { + /** @psalm-suppress UndefinedFunction */ + return (int) call_user_func('\\Sodium\\library_version_major'); + } + return self::LIBRARY_VERSION_MAJOR; + } + + /** + * The equivalent to the libsodium minor version we aim to be compatible + * with (sans pwhash and memzero). + * + * @return int + */ + public static function library_version_minor(): int + { + if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MINOR_VERSION')) { + return SODIUM_LIBRARY_MINOR_VERSION; + } + if (self::use_fallback('library_version_minor')) { + /** @psalm-suppress UndefinedFunction */ + return (int) call_user_func('\\Sodium\\library_version_minor'); + } + return self::LIBRARY_VERSION_MINOR; + } + + /** + * Compare two strings. + * + * @param string $left + * @param string $right + * @return int + * @throws SodiumException + * @throws TypeError + */ + public static function memcmp( + #[SensitiveParameter] + string $left, + #[SensitiveParameter] + string $right + ): int { + if (self::useNewSodiumAPI()) { + return sodium_memcmp($left, $right); + } + if (self::use_fallback('memcmp')) { + return (int) call_user_func('\\Sodium\\memcmp', $left, $right); + } + return ParagonIE_Sodium_Core_Util::memcmp($left, $right); + } + + /** + * It's actually not possible to zero memory buffers in PHP. You need the + * native library for that. + * + * @param ?string $var + * @param-out string|null $var + * + * @return void + * @throws SodiumException (Unless libsodium is installed) + * @throws TypeError + * @psalm-suppress TooFewArguments + */ + public static function memzero( + #[SensitiveParameter] + ?string &$var + ): void { + if (is_null($var)) { + return; + } + if (self::useNewSodiumAPI()) { + /** @psalm-suppress MixedArgument */ + sodium_memzero($var); + return; + } + if (self::use_fallback('memzero')) { + $func = '\\Sodium\\memzero'; + $func($var); + return; + } + // This is the best we can do. + throw new SodiumException( + 'This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. ' . + 'To fix this error, make sure libsodium is installed and the PHP extension is enabled.' + ); + } + + /** + * @param string $unpadded + * @param int $blockSize + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function pad( + #[SensitiveParameter] + string $unpadded, + int $blockSize, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_pad($unpadded, $blockSize); + } + + if ($blockSize <= 0) { + throw new SodiumException( + 'block size cannot be less than 1' + ); + } + $unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded); + $xpadlen = ($blockSize - 1); + if (($blockSize & ($blockSize - 1)) === 0) { + $xpadlen -= $unpadded_len & ($blockSize - 1); + } else { + $xpadlen -= $unpadded_len % $blockSize; + } + + $xpadded_len = $unpadded_len + $xpadlen; + $padded = str_repeat("\0", $xpadded_len - 1); + if ($unpadded_len > 0) { + $st = 1; + $i = 0; + $k = $unpadded_len; + for ($j = 0; $j <= $xpadded_len; ++$j) { + $i = (int) $i; + /** @psalm-suppress RedundantCast */ + $k = (int) $k; + if ($j >= $unpadded_len) { + $padded[$j] = "\0"; + } else { + $padded[$j] = $unpadded[$j]; + } + $k -= $st; + $st = (~( + ( + ( + ($k >> 48) + | + ($k >> 32) + | + ($k >> 16) + | + $k + ) - 1 + ) >> 16 + ) + ) & 1; + $i += $st; + } + } + + $mask = 0; + $tail = $xpadded_len; + for ($i = 0; $i < $blockSize; ++$i) { + # barrier_mask = (unsigned char) + # (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT)); + $barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1); + # tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); + $padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr( + (ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask) + | + (0x80 & $barrier_mask) + ); + # mask |= barrier_mask; + $mask |= $barrier_mask; + } + return $padded; + } + + /** + * @param string $padded + * @param int $blockSize + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function unpad( + #[SensitiveParameter] + string $padded, + int $blockSize, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_unpad($padded, $blockSize); + } + if ($blockSize <= 0) { + throw new SodiumException('block size cannot be less than 1'); + } + $padded_len = ParagonIE_Sodium_Core_Util::strlen($padded); + if ($padded_len < $blockSize) { + throw new SodiumException('invalid padding'); + } + + # tail = &padded[padded_len - 1U]; + $tail = $padded_len - 1; + + $acc = 0; + $valid = 0; + $pad_len = 0; + + $found = 0; + for ($i = 0; $i < $blockSize; ++$i) { + # c = tail[-i]; + $c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]); + + # is_barrier = + # (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; + $is_barrier = ( + ( + ($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1) + ) >> 7 + ) & 1; + $is_barrier &= ~$found; + $found |= $is_barrier; + + # acc |= c; + $acc |= $c; + + # pad_len |= i & (1U + ~is_barrier); + $pad_len |= $i & (1 + ~$is_barrier); + + # valid |= (unsigned char) is_barrier; + $valid |= ($is_barrier & 0xff); + } + # unpadded_len = padded_len - 1U - pad_len; + $unpadded_len = $padded_len - 1 - $pad_len; + if ($valid !== 1) { + throw new SodiumException('invalid padding'); + } + return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len); + } + + /** + * Will sodium_compat run fast on the current hardware and PHP configuration? + * + * @return bool + */ + public static function polyfill_is_fast(): bool + { + if (extension_loaded('sodium')) { + return true; + } + if (extension_loaded('libsodium')) { + return true; + } + return PHP_INT_SIZE === 8; + } + + /** + * Generate a string of bytes from the kernel's CSPRNG. + * Proudly uses /dev/urandom (if getrandom(2) is not available). + * + * @param int $numBytes + * @return string + * @throws Exception + * @throws TypeError + */ + public static function randombytes_buf(int $numBytes): string + { + /** @var positive-int $numBytes */ + if (self::use_fallback('randombytes_buf')) { + return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes); + } + return random_bytes($numBytes); + } + + /** + * Generate an integer between 0 and $range (non-inclusive). + * + * @param int $range + * @return int + * @throws Exception + * @throws Error + * @throws TypeError + */ + public static function randombytes_uniform(int $range): int + { + if (self::use_fallback('randombytes_uniform')) { + return (int) call_user_func('\\Sodium\\randombytes_uniform', $range); + } + return random_int(0, $range - 1); + } + + /** + * Generate a random 16-bit integer. + * + * @return int + * @throws Exception + * @throws Error + * @throws TypeError + */ + public static function randombytes_random16(): int + { + if (self::use_fallback('randombytes_random16')) { + return (int) call_user_func('\\Sodium\\randombytes_random16'); + } + return random_int(0, 65535); + } + + /** + * @param string $p + * @param bool $dontFallback + * @return bool + * @throws SodiumException + */ + public static function ristretto255_is_valid_point( + string $p, + bool $dontFallback = false + ): bool { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_is_valid_point($p); + } + try { + $r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p); + return $r['res'] === 0 && + ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1; + } catch (SodiumException $ex) { + if ($ex->getMessage() === 'S is not canonical') { + return false; + } + throw $ex; + } + } + + /** + * @param string $p + * @param string $q + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_add( + #[SensitiveParameter] + string $p, + #[SensitiveParameter] + string $q, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_add($p, $q); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q); + } + + /** + * @param string $p + * @param string $q + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_sub( + #[SensitiveParameter] + string $p, + #[SensitiveParameter] + string $q, + bool $dontFallback = false + ): string{ + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_sub($p, $q); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q); + } + + /** + * @param string $r + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_from_hash( + #[SensitiveParameter] + string $r, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_from_hash($r); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r); + } + + /** + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_random(bool $dontFallback = false): string + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_random(); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random(); + } + + /** + * @param bool $dontFallback + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_scalar_random(bool $dontFallback = false): string + { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_random(); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random(); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_invert( + #[SensitiveParameter] + string $s, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_invert($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s); + } + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_negate( + #[SensitiveParameter] + string $s, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_negate($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_complement( + #[SensitiveParameter] + string $s, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_complement($s); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_add( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_add($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_sub( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_sub($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y); + } + + /** + * @param string $x + * @param string $y + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_mul( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_mul($x, $y); + } + return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y); + } + + /** + * @param string $n + * @param string $p + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255( + #[SensitiveParameter] + string $n, + #[SensitiveParameter] + string $p, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_scalarmult_ristretto255($n, $p); + } + return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p); + } + + /** + * @param string $n + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255_base( + #[SensitiveParameter] + string $n, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_scalarmult_ristretto255_base($n); + } + return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n); + } + + /** + * @param string $s + * @param bool $dontFallback + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_reduce( + #[SensitiveParameter] + string $s, + bool $dontFallback = false + ): string { + if (self::useNewSodiumAPI() && !$dontFallback) { + return sodium_crypto_core_ristretto255_scalar_reduce($s); + } + return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s); + } + + /** + * Add two numbers (little-endian unsigned), storing the value in the first + * parameter. + * + * This mutates $val. + * + * @param string $val + * @param string $addv + * @return void + * @throws SodiumException + */ + public static function sub( + #[SensitiveParameter] + string &$val, + #[SensitiveParameter] + string $addv + ): void { + $val_len = ParagonIE_Sodium_Core_Util::strlen($val); + $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); + if ($val_len !== $addv_len) { + throw new SodiumException('values must have the same length'); + } + $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); + $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); + + $c = 0; + for ($i = 0; $i < $val_len; $i++) { + $c = ($A[$i] - $B[$i] - $c); + $A[$i] = ($c & 0xff); + $c = ($c >> 8) & 1; + } + $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); + } + + /** + * This emulates libsodium's version_string() function, except ours is + * prefixed with 'polyfill-'. + * + * @return string + * @psalm-suppress MixedInferredReturnType + * @psalm-suppress UndefinedFunction + */ + public static function version_string(): string + { + if (self::useNewSodiumAPI()) { + return sodium_version_string(); + } + if (self::use_fallback('version_string')) { + return (string) call_user_func('\\Sodium\\version_string'); + } + return self::VERSION_STRING; + } + + /** + * Should we use the libsodium core function instead? + * This is always a good idea, if it's available. (Unless we're in the + * middle of running our unit test suite.) + * + * If ext/libsodium is available, use it. Return TRUE. + * Otherwise, we have to use the code provided herein. Return FALSE. + * + * @param string $sodium_func_name + * + * @return bool + */ + protected static function use_fallback(string $sodium_func_name = ''): bool + { + static $res = null; + if ($res === null) { + $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300; + } + if ($res === false) { + // No libsodium installed + return false; + } + if (self::$disableFallbackForUnitTests) { + // Don't fallback. Use the PHP implementation. + return false; + } + if (!empty($sodium_func_name)) { + return is_callable('\\Sodium\\' . $sodium_func_name); + } + return true; + } + + /** + * Libsodium as implemented in PHP 7.2 + * and/or ext/sodium (via PECL) + * + * @ref https://wiki.php.net/rfc/libsodium + * @return bool + */ + protected static function useNewSodiumAPI(): bool + { + static $res = null; + if ($res === null) { + $res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium'); + } + if (self::$disableFallbackForUnitTests) { + // Don't fallback. Use the PHP implementation. + return false; + } + return (bool) $res; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State128L.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State128L.php new file mode 100644 index 000000000..3e33cf74f --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State128L.php @@ -0,0 +1,295 @@ + $state */ + protected array $state; + + public function __construct() + { + $this->state = array_fill(0, 8, ''); + } + + /** + * @internal Only use this for unit tests! + * @return string[] + */ + public function getState(): array + { + return array_values($this->state); + } + + /** + * @param array $input + * @return self + * @throws SodiumException + * + * @internal Only for unit tests + */ + public static function initForUnitTests(array $input): self + { + if (count($input) < 8) { + throw new SodiumException('invalid input'); + } + $state = new self(); + for ($i = 0; $i < 8; ++$i) { + $state->state[$i] = $input[$i]; + } + return $state; + } + + /** + * @param string $key + * @param string $nonce + * @return self + */ + public static function init( + #[SensitiveParameter] + string $key, + string $nonce + ): self { + $state = new self(); + + // S0 = key ^ nonce + $state->state[0] = $key ^ $nonce; + // S1 = C1 + $state->state[1] = SODIUM_COMPAT_AEGIS_C1; + // S2 = C0 + $state->state[2] = SODIUM_COMPAT_AEGIS_C0; + // S3 = C1 + $state->state[3] = SODIUM_COMPAT_AEGIS_C1; + // S4 = key ^ nonce + $state->state[4] = $key ^ $nonce; + // S5 = key ^ C0 + $state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0; + // S6 = key ^ C1 + $state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1; + // S7 = key ^ C0 + $state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0; + + // Repeat(10, Update(nonce, key)) + for ($i = 0; $i < 10; ++$i) { + $state->update($nonce, $key); + } + return $state; + } + + /** + * @param string $ai + * @return static + * + * @throws SodiumException + */ + public function absorb(string $ai): static + { + if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) { + throw new SodiumException('Input must be two AES blocks in size'); + } + $t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16); + $t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16); + return $this->update($t0, $t1); + } + + + /** + * @param string $ci + * @return string + * @throws SodiumException + */ + public function dec(string $ci): string + { + if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) { + throw new SodiumException('Input must be two AES blocks in size'); + } + + // z0 = S6 ^ S1 ^ (S2 & S3) + $z0 = $this->state[6] + ^ $this->state[1] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + // z1 = S2 ^ S5 ^ (S6 & S7) + $z1 = $this->state[2] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); + + // t0, t1 = Split(xi, 128) + $t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16); + $t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16); + + // out0 = t0 ^ z0 + // out1 = t1 ^ z1 + $out0 = $t0 ^ $z0; + $out1 = $t1 ^ $z1; + + // Update(out0, out1) + // xi = out0 || out1 + $this->update($out0, $out1); + return $out0 . $out1; + } + + /** + * @param string $cn + * @return string + * + * @throws SodiumException + */ + public function decPartial(string $cn): string + { + $len = ParagonIE_Sodium_Core_Util::strlen($cn); + + // z0 = S6 ^ S1 ^ (S2 & S3) + $z0 = $this->state[6] + ^ $this->state[1] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + // z1 = S2 ^ S5 ^ (S6 & S7) + $z1 = $this->state[2] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); + + // t0, t1 = Split(ZeroPad(cn, 256), 128) + $cn = str_pad($cn, 32, "\0"); + $t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16); + $t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16); + // out0 = t0 ^ z0 + // out1 = t1 ^ z1 + $out0 = $t0 ^ $z0; + $out1 = $t1 ^ $z1; + + // xn = Truncate(out0 || out1, |cn|) + $xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len); + + // v0, v1 = Split(ZeroPad(xn, 256), 128) + $padded = str_pad($xn, 32, "\0"); + $v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16); + $v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16); + // Update(v0, v1) + $this->update($v0, $v1); + + // return xn + return $xn; + } + + /** + * @param string $xi + * @return string + * @throws SodiumException + */ + public function enc( + #[SensitiveParameter] + string $xi + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) { + throw new SodiumException('Input must be two AES blocks in size'); + } + + // z0 = S6 ^ S1 ^ (S2 & S3) + $z0 = $this->state[6] + ^ $this->state[1] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + // z1 = S2 ^ S5 ^ (S6 & S7) + $z1 = $this->state[2] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); + + // t0, t1 = Split(xi, 128) + $t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16); + $t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16); + + // out0 = t0 ^ z0 + // out1 = t1 ^ z1 + $out0 = $t0 ^ $z0; + $out1 = $t1 ^ $z1; + + // Update(t0, t1) + // ci = out0 || out1 + $this->update($t0, $t1); + + // return ci + return $out0 . $out1; + } + + /** + * @param int $ad_len_bits + * @param int $msg_len_bits + * @return string + */ + public function finalize(int $ad_len_bits, int $msg_len_bits): string + { + $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . + ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits); + $t = $this->state[2] ^ $encoded; + for ($i = 0; $i < 7; ++$i) { + $this->update($t, $t); + } + return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) . + ($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]); + } + + /** + * @param string $m0 + * @param string $m1 + * @return static + */ + public function update(string $m0, string $m1): static + { + /* + S'0 = AESRound(S7, S0 ^ M0) + S'1 = AESRound(S0, S1) + S'2 = AESRound(S1, S2) + S'3 = AESRound(S2, S3) + S'4 = AESRound(S3, S4 ^ M1) + S'5 = AESRound(S4, S5) + S'6 = AESRound(S5, S6) + S'7 = AESRound(S6, S7) + */ + list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[7], $this->state[0] ^ $m0, + $this->state[0], $this->state[1] + ); + + list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[1], $this->state[2], + $this->state[2], $this->state[3] + ); + + list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[3], $this->state[4] ^ $m1, + $this->state[4], $this->state[5] + ); + list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[5], $this->state[6], + $this->state[6], $this->state[7] + ); + + /* + S0 = S'0 + S1 = S'1 + S2 = S'2 + S3 = S'3 + S4 = S'4 + S5 = S'5 + S6 = S'6 + S7 = S'7 + */ + $this->state[0] = $s_0; + $this->state[1] = $s_1; + $this->state[2] = $s_2; + $this->state[3] = $s_3; + $this->state[4] = $s_4; + $this->state[5] = $s_5; + $this->state[6] = $s_6; + $this->state[7] = $s_7; + return $this; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State256.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State256.php new file mode 100644 index 000000000..30cb5ef85 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS/State256.php @@ -0,0 +1,251 @@ + $state */ + protected array $state; + + public function __construct() + { + $this->state = array_fill(0, 6, ''); + } + + /** + * @internal Only use this for unit tests! + * @return string[] + */ + public function getState(): array + { + return array_values($this->state); + } + + /** + * @param array $input + * @return self + * @throws SodiumException + * + * @internal Only for unit tests + */ + public static function initForUnitTests(array $input): self + { + if (count($input) < 6) { + throw new SodiumException('invalid input'); + } + $state = new self(); + for ($i = 0; $i < 6; ++$i) { + $state->state[$i] = $input[$i]; + } + return $state; + } + + /** + * @param string $key + * @param string $nonce + * @return self + */ + public static function init( + #[SensitiveParameter] + string $key, + string $nonce + ): self { + $state = new self(); + $k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16); + $k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16); + $n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16); + $n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16); + + // S0 = k0 ^ n0 + // S1 = k1 ^ n1 + // S2 = C1 + // S3 = C0 + // S4 = k0 ^ C0 + // S5 = k1 ^ C1 + $k0_n0 = $k0 ^ $n0; + $k1_n1 = $k1 ^ $n1; + $state->state[0] = $k0_n0; + $state->state[1] = $k1_n1; + $state->state[2] = SODIUM_COMPAT_AEGIS_C1; + $state->state[3] = SODIUM_COMPAT_AEGIS_C0; + $state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0; + $state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1; + + // Repeat(4, + // Update(k0) + // Update(k1) + // Update(k0 ^ n0) + // Update(k1 ^ n1) + // ) + for ($i = 0; $i < 4; ++$i) { + $state->update($k0); + $state->update($k1); + $state->update($k0 ^ $n0); + $state->update($k1 ^ $n1); + } + return $state; + } + + /** + * @param string $ai + * @return static + * @throws SodiumException + */ + public function absorb(string $ai): static + { + if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) { + throw new SodiumException('Input must be an AES block in size'); + } + return $this->update($ai); + } + + /** + * @param string $ci + * @return string + * @throws SodiumException + */ + public function dec(string $ci): string + { + if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) { + throw new SodiumException('Input must be an AES block in size'); + } + // z = S1 ^ S4 ^ S5 ^ (S2 & S3) + $z = $this->state[1] + ^ $this->state[4] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + $xi = $ci ^ $z; + $this->update($xi); + return $xi; + } + + /** + * @param string $cn + * @return string + * + * @throws SodiumException + */ + public function decPartial(string $cn): string + { + $len = ParagonIE_Sodium_Core_Util::strlen($cn); + // z = S1 ^ S4 ^ S5 ^ (S2 & S3) + $z = $this->state[1] + ^ $this->state[4] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + + // t = ZeroPad(cn, 128) + $t = str_pad($cn, 16, "\0"); + + // out = t ^ z + $out = $t ^ $z; + + // xn = Truncate(out, |cn|) + $xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len); + + // v = ZeroPad(xn, 128) + $v = str_pad($xn, 16, "\0"); + // Update(v) + $this->update($v); + + // return xn + return $xn; + } + + /** + * @param string $xi + * @return string + * @throws SodiumException + */ + public function enc( + #[SensitiveParameter] + string $xi + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) { + throw new SodiumException('Input must be an AES block in size'); + } + // z = S1 ^ S4 ^ S5 ^ (S2 & S3) + $z = $this->state[1] + ^ $this->state[4] + ^ $this->state[5] + ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); + $this->update($xi); + return $xi ^ $z; + } + + /** + * @param int $ad_len_bits + * @param int $msg_len_bits + * @return string + */ + public function finalize( + int $ad_len_bits, + int $msg_len_bits + ): string { + $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . + ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits); + $t = $this->state[3] ^ $encoded; + + for ($i = 0; $i < 7; ++$i) { + $this->update($t); + } + + return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) . + ($this->state[3] ^ $this->state[4] ^ $this->state[5]); + } + + /** + * @param string $m + * @return static + */ + public function update(string $m): static + { + /* + S'0 = AESRound(S5, S0 ^ M) + S'1 = AESRound(S0, S1) + S'2 = AESRound(S1, S2) + S'3 = AESRound(S2, S3) + S'4 = AESRound(S3, S4) + S'5 = AESRound(S4, S5) + */ + list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[5],$this->state[0] ^ $m, + $this->state[0], $this->state[1] + ); + + list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[1], $this->state[2], + $this->state[2], $this->state[3] + ); + list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound( + $this->state[3], $this->state[4], + $this->state[4], $this->state[5] + ); + + /* + S0 = S'0 + S1 = S'1 + S2 = S'2 + S3 = S'3 + S4 = S'4 + S5 = S'5 + */ + $this->state[0] = $s_0; + $this->state[1] = $s_1; + $this->state[2] = $s_2; + $this->state[3] = $s_3; + $this->state[4] = $s_4; + $this->state[5] = $s_5; + return $this; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS128L.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS128L.php new file mode 100644 index 000000000..bf38c0503 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS128L.php @@ -0,0 +1,132 @@ +> 5; + for ($i = 0; $i < $ad_blocks; ++$i) { + $ai = self::substr($ad, $i << 5, 32); + if (self::strlen($ai) < 32) { + $ai = str_pad($ai, 32, "\0"); + } + $state->absorb($ai); + } + + $msg = ''; + $cn = self::strlen($ct) & 31; + $ct_blocks = self::strlen($ct) >> 5; + for ($i = 0; $i < $ct_blocks; ++$i) { + $msg .= $state->dec(self::substr($ct, $i << 5, 32)); + } + if ($cn) { + $start = $ct_blocks << 5; + $msg .= $state->decPartial(self::substr($ct, $start, $cn)); + } + $expected_tag = $state->finalize( + self::strlen($ad) << 3, + self::strlen($msg) << 3 + ); + if (!self::hashEquals($expected_tag, $tag)) { + try { + // The RFC says to erase msg, so we shall try: + ParagonIE_Sodium_Compat::memzero($msg); + } catch (SodiumException) { + // Do nothing if we cannot memzero + } + throw new SodiumException('verification failed'); + } + return $msg; + } + + /** + * @param string $msg + * @param string $ad + * @param string $key + * @param string $nonce + * @return array + * + * @throws SodiumException + */ + public static function encrypt( + #[SensitiveParameter] + string $msg, + string $ad, + #[SensitiveParameter] + string $key, + string $nonce + ): array { + $state = self::init($key, $nonce); + // ad_blocks = Split(ZeroPad(ad, 256), 256) + // for ai in ad_blocks: + // Absorb(ai) + $ad_len = self::strlen($ad); + $msg_len = self::strlen($msg); + $ad_blocks = ($ad_len + 31) >> 5; + for ($i = 0; $i < $ad_blocks; ++$i) { + $ai = self::substr($ad, $i << 5, 32); + if (self::strlen($ai) < 32) { + $ai = str_pad($ai, 32, "\0"); + } + $state->absorb($ai); + } + + // msg_blocks = Split(ZeroPad(msg, 256), 256) + // for xi in msg_blocks: + // ct = ct || Enc(xi) + $ct = ''; + $msg_blocks = ($msg_len + 31) >> 5; + for ($i = 0; $i < $msg_blocks; ++$i) { + $xi = self::substr($msg, $i << 5, 32); + if (self::strlen($xi) < 32) { + $xi = str_pad($xi, 32, "\0"); + } + $ct .= $state->enc($xi); + } + // tag = Finalize(|ad|, |msg|) + // ct = Truncate(ct, |msg|) + $tag = $state->finalize( + $ad_len << 3, + $msg_len << 3 + ); + // return ct and tag + return array( + self::substr($ct, 0, $msg_len), + $tag + ); + } + + /** + * @param string $key + * @param string $nonce + * @return ParagonIE_Sodium_Core_AEGIS_State128L + */ + public static function init(string $key, string $nonce): ParagonIE_Sodium_Core_AEGIS_State128L + { + return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS256.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS256.php new file mode 100644 index 000000000..c2d9bb004 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AEGIS256.php @@ -0,0 +1,134 @@ +> 4; + // for ai in ad_blocks: + // Absorb(ai) + for ($i = 0; $i < $ad_blocks; ++$i) { + $ai = self::substr($ad, $i << 4, 16); + if (self::strlen($ai) < 16) { + $ai = str_pad($ai, 16, "\0"); + } + $state->absorb($ai); + } + + $msg = ''; + $cn = self::strlen($ct) & 15; + $ct_blocks = self::strlen($ct) >> 4; + // ct_blocks = Split(ZeroPad(ct, 128), 128) + // cn = Tail(ct, |ct| mod 128) + for ($i = 0; $i < $ct_blocks; ++$i) { + $msg .= $state->dec(self::substr($ct, $i << 4, 16)); + } + // if cn is not empty: + // msg = msg || DecPartial(cn) + if ($cn) { + $start = $ct_blocks << 4; + $msg .= $state->decPartial(self::substr($ct, $start, $cn)); + } + $expected_tag = $state->finalize( + self::strlen($ad) << 3, + self::strlen($msg) << 3 + ); + if (!self::hashEquals($expected_tag, $tag)) { + try { + // The RFC says to erase msg, so we shall try: + ParagonIE_Sodium_Compat::memzero($msg); + } catch (SodiumException) { + // Do nothing if we cannot memzero + } + throw new SodiumException('verification failed'); + } + return $msg; + } + + /** + * @param string $msg + * @param string $ad + * @param string $key + * @param string $nonce + * @return array + * @throws SodiumException + */ + public static function encrypt( + #[SensitiveParameter] + string $msg, + string $ad, + #[SensitiveParameter] + string $key, + string $nonce + ): array { + $state = self::init($key, $nonce); + $ad_len = self::strlen($ad); + $msg_len = self::strlen($msg); + $ad_blocks = ($ad_len + 15) >> 4; + for ($i = 0; $i < $ad_blocks; ++$i) { + $ai = self::substr($ad, $i << 4, 16); + if (self::strlen($ai) < 16) { + $ai = str_pad($ai, 16, "\0"); + } + $state->absorb($ai); + } + + $ct = ''; + $msg_blocks = ($msg_len + 15) >> 4; + for ($i = 0; $i < $msg_blocks; ++$i) { + $xi = self::substr($msg, $i << 4, 16); + if (self::strlen($xi) < 16) { + $xi = str_pad($xi, 16, "\0"); + } + $ct .= $state->enc($xi); + } + $tag = $state->finalize( + $ad_len << 3, + $msg_len << 3 + ); + return array( + self::substr($ct, 0, $msg_len), + $tag + ); + + } + + /** + * @param string $key + * @param string $nonce + * @return ParagonIE_Sodium_Core_AEGIS_State256 + */ + public static function init( + #[SensitiveParameter] + string $key, + string $nonce + ): ParagonIE_Sodium_Core_AEGIS_State256 { + return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES.php new file mode 100644 index 000000000..6fd334330 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES.php @@ -0,0 +1,532 @@ +orthogonalize(); + self::sbox($q); + $q->orthogonalize(); + return $q[0] & self::U32_MAX; + } + + /** + * Calculate the key schedule from a given random key + * + * @param string $key + * @return ParagonIE_Sodium_Core_AES_KeySchedule + * @throws SodiumException + */ + public static function keySchedule( + #[SensitiveParameter] + string $key + ): ParagonIE_Sodium_Core_AES_KeySchedule { + $key_len = self::strlen($key); + $num_rounds = match ($key_len) { + 16 => 10, + 24 => 12, + 32 => 14, + default => throw new SodiumException('Invalid key length: ' . $key_len), + }; + $skey = array(); + $comp_skey = array(); + $nk = $key_len >> 2; + $nkf = ($num_rounds + 1) << 2; + $tmp = 0; + + for ($i = 0; $i < $nk; ++$i) { + $tmp = self::load_4(self::substr($key, $i << 2, 4)); + $skey[($i << 1)] = $tmp; + $skey[($i << 1) + 1] = $tmp; + } + + for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) { + if ($j === 0) { + $tmp = (($tmp & 0xff) << 24) | ($tmp >> 8); + /** @psalm-suppress InvalidArrayOffset */ + $tmp = (self::subWord($tmp) ^ self::Rcon[$k]) & self::U32_MAX; + } elseif ($nk > 6 && $j === 4) { + $tmp = self::subWord($tmp); + } + $tmp ^= $skey[($i - $nk) << 1]; + $skey[($i << 1)] = $tmp & self::U32_MAX; + $skey[($i << 1) + 1] = $tmp & self::U32_MAX; + if (++$j === $nk) { + /** @psalm-suppress LoopInvalidation */ + $j = 0; + ++$k; + } + } + for ($i = 0; $i < $nkf; $i += 4) { + $q = ParagonIE_Sodium_Core_AES_Block::fromArray( + array_slice($skey, $i << 1, 8) + ); + $q->orthogonalize(); + // We have to overwrite $skey since we're not using C pointers like BearSSL did + for ($j = 0; $j < 8; ++$j) { + $skey[($i << 1) + $j] = $q[$j]; + } + } + for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) { + $comp_skey[$i] = ($skey[$j] & 0x55555555) + | ($skey[$j + 1] & 0xAAAAAAAA); + } + return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds); + } + + /** + * Mutates $q + * + * @param ParagonIE_Sodium_Core_AES_KeySchedule $skey + * @param ParagonIE_Sodium_Core_AES_Block $q + * @param int $offset + * @return void + */ + public static function addRoundKey( + ParagonIE_Sodium_Core_AES_Block $q, + ParagonIE_Sodium_Core_AES_KeySchedule $skey, + int $offset = 0 + ): void { + $block = $skey->getRoundKey($offset); + for ($j = 0; $j < 8; ++$j) { + $q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX; + } + } + + /** + * This mainly exists for testing, as we need the round key features for AEGIS. + * + * @param string $message + * @param string $key + * @return string + * @throws SodiumException + */ + public static function decryptBlockECB( + string $message, + #[SensitiveParameter] + string $key + ): string { + if (self::strlen($message) !== 16) { + throw new SodiumException('decryptBlockECB() expects a 16 byte message'); + } + $skey = self::keySchedule($key)->expand(); + $q = ParagonIE_Sodium_Core_AES_Block::init(); + $q[0] = self::load_4(self::substr($message, 0, 4)); + $q[2] = self::load_4(self::substr($message, 4, 4)); + $q[4] = self::load_4(self::substr($message, 8, 4)); + $q[6] = self::load_4(self::substr($message, 12, 4)); + + $q->orthogonalize(); + self::bitsliceDecryptBlock($skey, $q); + $q->orthogonalize(); + + return self::store32_le($q[0]) . + self::store32_le($q[2]) . + self::store32_le($q[4]) . + self::store32_le($q[6]); + } + + /** + * This mainly exists for testing, as we need the round key features for AEGIS. + * + * @param string $message + * @param string $key + * @return string + * @throws SodiumException + */ + public static function encryptBlockECB( + #[SensitiveParameter] + string $message, + #[SensitiveParameter] + string $key + ): string { + if (self::strlen($message) !== 16) { + throw new SodiumException('encryptBlockECB() expects a 16 byte message'); + } + $comp_skey = self::keySchedule($key); + $skey = $comp_skey->expand(); + $q = ParagonIE_Sodium_Core_AES_Block::init(); + $q[0] = self::load_4(self::substr($message, 0, 4)); + $q[2] = self::load_4(self::substr($message, 4, 4)); + $q[4] = self::load_4(self::substr($message, 8, 4)); + $q[6] = self::load_4(self::substr($message, 12, 4)); + + $q->orthogonalize(); + self::bitsliceEncryptBlock($skey, $q); + $q->orthogonalize(); + + return self::store32_le($q[0]) . + self::store32_le($q[2]) . + self::store32_le($q[4]) . + self::store32_le($q[6]); + } + + /** + * Mutates $q + * + * @param ParagonIE_Sodium_Core_AES_Expanded $skey + * @param ParagonIE_Sodium_Core_AES_Block $q + * @return void + */ + public static function bitsliceEncryptBlock( + ParagonIE_Sodium_Core_AES_Expanded $skey, + ParagonIE_Sodium_Core_AES_Block $q + ): void { + self::addRoundKey($q, $skey); + for ($u = 1; $u < $skey->getNumRounds(); ++$u) { + self::sbox($q); + $q->shiftRows(); + $q->mixColumns(); + self::addRoundKey($q, $skey, ($u << 3)); + } + self::sbox($q); + $q->shiftRows(); + self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3)); + } + + /** + * @param string $x + * @param string $y + * @return string + */ + public static function aesRound( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y + ): string { + $q = ParagonIE_Sodium_Core_AES_Block::init(); + $q[0] = self::load_4(self::substr($x, 0, 4)); + $q[2] = self::load_4(self::substr($x, 4, 4)); + $q[4] = self::load_4(self::substr($x, 8, 4)); + $q[6] = self::load_4(self::substr($x, 12, 4)); + + $rk = ParagonIE_Sodium_Core_AES_Block::init(); + $rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4)); + $rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4)); + $rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4)); + $rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4)); + + $q->orthogonalize(); + self::sbox($q); + $q->shiftRows(); + $q->mixColumns(); + $q->orthogonalize(); + // add round key without key schedule: + for ($i = 0; $i < 8; ++$i) { + $q[$i] ^= $rk[$i]; + } + return self::store32_le($q[0]) . + self::store32_le($q[2]) . + self::store32_le($q[4]) . + self::store32_le($q[6]); + } + + /** + * Process two AES blocks in one shot. + * + * @param string $b0 First AES block + * @param string $rk0 First round key + * @param string $b1 Second AES block + * @param string $rk1 Second round key + * @return string[] + */ + public static function doubleRound( + #[SensitiveParameter] + string $b0, + #[SensitiveParameter] + string $rk0, + #[SensitiveParameter] + string $b1, + #[SensitiveParameter] + string $rk1 + ): array { + $q = ParagonIE_Sodium_Core_AES_Block::init(); + // First block + $q[0] = self::load_4(self::substr($b0, 0, 4)); + $q[2] = self::load_4(self::substr($b0, 4, 4)); + $q[4] = self::load_4(self::substr($b0, 8, 4)); + $q[6] = self::load_4(self::substr($b0, 12, 4)); + // Second block + $q[1] = self::load_4(self::substr($b1, 0, 4)); + $q[3] = self::load_4(self::substr($b1, 4, 4)); + $q[5] = self::load_4(self::substr($b1, 8, 4)); + $q[7] = self::load_4(self::substr($b1, 12, 4)); + + $rk = ParagonIE_Sodium_Core_AES_Block::init(); + // First round key + $rk[0] = self::load_4(self::substr($rk0, 0, 4)); + $rk[2] = self::load_4(self::substr($rk0, 4, 4)); + $rk[4] = self::load_4(self::substr($rk0, 8, 4)); + $rk[6] = self::load_4(self::substr($rk0, 12, 4)); + // Second round key + $rk[1] = self::load_4(self::substr($rk1, 0, 4)); + $rk[3] = self::load_4(self::substr($rk1, 4, 4)); + $rk[5] = self::load_4(self::substr($rk1, 8, 4)); + $rk[7] = self::load_4(self::substr($rk1, 12, 4)); + + $q->orthogonalize(); + self::sbox($q); + $q->shiftRows(); + $q->mixColumns(); + $q->orthogonalize(); + // add round key without key schedule: + for ($i = 0; $i < 8; ++$i) { + $q[$i] ^= $rk[$i]; + } + return array( + self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]), + self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]), + ); + } + + /** + * @param ParagonIE_Sodium_Core_AES_Expanded $skey + * @param ParagonIE_Sodium_Core_AES_Block $q + * @return void + */ + public static function bitsliceDecryptBlock( + ParagonIE_Sodium_Core_AES_Expanded $skey, + ParagonIE_Sodium_Core_AES_Block $q + ): void { + self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3)); + for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) { + $q->inverseShiftRows(); + self::invSbox($q); + self::addRoundKey($q, $skey, ($u << 3)); + $q->inverseMixColumns(); + } + $q->inverseShiftRows(); + self::invSbox($q); + self::addRoundKey($q, $skey, ($u << 3)); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Block.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Block.php new file mode 100644 index 000000000..c93c1a487 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Block.php @@ -0,0 +1,354 @@ + + */ + protected array $values = array(); + + /** + * @var int + */ + protected int $size; + + /** + * @param int $size + */ + public function __construct(int $size = 8) + { + parent::__construct($size); + $this->size = $size; + $this->values = array_fill(0, $size, 0); + } + + /** + * @return self + */ + public static function init(): self + { + return new self(8); + } + + /** + * @internal You should not use this directly from another application + * + * @param array $array + * @param bool $save_indexes + * @return self + * + * @psalm-suppress MethodSignatureMismatch + */ + #[ReturnTypeWillChange] + public static function fromArray($array, ?bool $save_indexes = null) + { + $count = count($array); + if ($save_indexes) { + $keys = array_keys($array); + } else { + $keys = range(0, $count - 1); + } + $array = array_values($array); + /** @var array $keys */ + + $obj = new ParagonIE_Sodium_Core_AES_Block(); + if ($save_indexes) { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($keys[$i], $array[$i]); + } + } else { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($i, $array[$i]); + } + } + return $obj; + } + + + /** + * @internal You should not use this directly from another application + * + * @param int|null $offset + * @param int $value + * @return void + * + * @psalm-suppress MethodSignatureMismatch + * @psalm-suppress MixedArrayOffset + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value): void + { + if (is_null($offset)) { + $this->values[] = $value; + } else { + $this->values[$offset] = $value; + } + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return bool + * + * @psalm-suppress MethodSignatureMismatch + * @psalm-suppress MixedArrayOffset + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->values[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return void + * + * @psalm-suppress MethodSignatureMismatch + * @psalm-suppress MixedArrayOffset + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset): void + { + unset($this->values[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return int + * + * @psalm-suppress MethodSignatureMismatch + * @psalm-suppress MixedArrayOffset + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + if (!isset($this->values[$offset])) { + $this->values[$offset] = 0; + } + return $this->values[$offset]; + } + + /** + * @internal You should not use this directly from another application + * + * @return array + */ + public function __debugInfo() + { + $out = array(); + foreach ($this->values as $v) { + $out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT); + } + return array(implode(', ', $out)); + /* + return array(implode(', ', $this->values)); + */ + } + + /** + * @param int $cl low bit mask + * @param int $ch high bit mask + * @param int $s shift + * @param int $x index 1 + * @param int $y index 2 + * @return static + */ + public function swapN( + int $cl, + int $ch, + int $s, + int $x, + int $y + ): static { + static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX; + $a = $this->values[$x] & $u32mask; + $b = $this->values[$y] & $u32mask; + // (x) = (a & cl) | ((b & cl) << (s)); + $this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask); + // (y) = ((a & ch) >> (s)) | (b & ch); + $this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch); + return $this; + } + + /** + * @param int $x index 1 + * @param int $y index 2 + * @return static + */ + public function swap2( + int $x, + int $y + ): static { + return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y); + } + + /** + * @param int $x index 1 + * @param int $y index 2 + * @return static + */ + public function swap4( + int $x, + int $y + ): static { + return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y); + } + + /** + * @param int $x index 1 + * @param int $y index 2 + * @return static + */ + public function swap8( + int $x, + int $y + ): static { + return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y); + } + + /** + * @return static + */ + public function orthogonalize(): static + { + return $this + ->swap2(0, 1) + ->swap2(2, 3) + ->swap2(4, 5) + ->swap2(6, 7) + + ->swap4(0, 2) + ->swap4(1, 3) + ->swap4(4, 6) + ->swap4(5, 7) + + ->swap8(0, 4) + ->swap8(1, 5) + ->swap8(2, 6) + ->swap8(3, 7); + } + + /** + * @return static + */ + public function shiftRows(): static + { + for ($i = 0; $i < 8; ++$i) { + $x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX; + $this->values[$i] = ( + ($x & 0x000000FF) + | (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6) + | (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4) + | (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2) + ) & ParagonIE_Sodium_Core_Util::U32_MAX; + } + return $this; + } + + /** + * @param int $x + * @return int + */ + public static function rotr16(int $x): int + { + return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16); + } + + /** + * @return static + */ + public function mixColumns(): static + { + $q0 = $this->values[0]; + $q1 = $this->values[1]; + $q2 = $this->values[2]; + $q3 = $this->values[3]; + $q4 = $this->values[4]; + $q5 = $this->values[5]; + $q6 = $this->values[6]; + $q7 = $this->values[7]; + $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + + $this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0); + $this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1); + $this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2); + $this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3); + $this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4); + $this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5); + $this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6); + $this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7); + return $this; + } + + /** + * @return static + */ + public function inverseMixColumns(): static + { + $q0 = $this->values[0]; + $q1 = $this->values[1]; + $q2 = $this->values[2]; + $q3 = $this->values[3]; + $q4 = $this->values[4]; + $q5 = $this->values[5]; + $q6 = $this->values[6]; + $q7 = $this->values[7]; + $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; + + $this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5); + $this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6); + $this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7); + $this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7); + $this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6); + $this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7); + $this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7); + $this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7); + return $this; + } + + /** + * @return static + */ + public function inverseShiftRows(): static + { + for ($i = 0; $i < 8; ++$i) { + $x = $this->values[$i]; + $this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & ( + ($x & 0x000000FF) + | (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6) + | (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4) + | (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2) + ); + } + return $this; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Expanded.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Expanded.php new file mode 100644 index 000000000..053b5601d --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/AES/Expanded.php @@ -0,0 +1,12 @@ + $skey -- has size 120 */ + protected array $skey; + + /** @var bool $expanded */ + protected bool $expanded = false; + + /** @var int $numRounds */ + private int $numRounds; + + /** + * @param array $skey + * @param int $numRounds + */ + public function __construct(array $skey, int $numRounds = 10) + { + $this->skey = $skey; + $this->numRounds = $numRounds; + } + + /** + * Get a value at an arbitrary index. Mostly used for unit testing. + * + * @param int $i + * @return int + */ + public function get(int $i): int + { + return $this->skey[$i]; + } + + /** + * @return int + */ + public function getNumRounds(): int + { + return $this->numRounds; + } + + /** + * @param int $offset + * @return ParagonIE_Sodium_Core_AES_Block + */ + public function getRoundKey(int $offset): ParagonIE_Sodium_Core_AES_Block + { + return ParagonIE_Sodium_Core_AES_Block::fromArray( + array_slice($this->skey, $offset, 8) + ); + } + + /** + * Return an expanded key schedule + * + * @return ParagonIE_Sodium_Core_AES_Expanded + */ + public function expand(): ParagonIE_Sodium_Core_AES_Expanded + { + $exp = new ParagonIE_Sodium_Core_AES_Expanded( + array_fill(0, 120, 0), + $this->numRounds + ); + $n = ($exp->numRounds + 1) << 2; + for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) { + $x = $y = $this->skey[$u]; + $x &= 0x55555555; + $exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX; + $y &= 0xAAAAAAAA; + $exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX; + } + return $exp; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/BLAKE2b.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/BLAKE2b.php new file mode 100644 index 000000000..fbe348b30 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/BLAKE2b.php @@ -0,0 +1,758 @@ +> + */ + protected const SIGMA = [ + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0], + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3] + ]; + + const KEYBYTES = 64; + + /** + * Turn two 32-bit integers into a fixed array representing a 64-bit integer. + * + * @internal You should not use this directly from another application + * + * @param int $high + * @param int $low + * @return SplFixedArray + */ + public static function new64(int $high, int $low): SplFixedArray + { + $i64 = new SplFixedArray(2); + $i64[0] = $high & 0xffffffff; + $i64[1] = $low & 0xffffffff; + return $i64; + } + + /** + * Convert an arbitrary number into an SplFixedArray of two 32-bit integers + * that represents a 64-bit integer. + * + * @internal You should not use this directly from another application + * + * @param int $num + * @return SplFixedArray + * @throws SodiumException + */ + protected static function to64(int $num): SplFixedArray + { + list($hi, $lo) = self::numericTo64BitInteger($num); + return self::new64($hi, $lo); + } + + /** + * Adds two 64-bit integers together, returning their sum as a SplFixedArray + * containing two 32-bit integers (representing a 64-bit integer). + * + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param SplFixedArray $y + * @return SplFixedArray + * + * @throws SodiumException + */ + protected static function add64(SplFixedArray $x, SplFixedArray $y): SplFixedArray + { + $l = ($x[1] + $y[1]) & 0xffffffff; + return self::new64( + (int) ($x[0] + $y[0] + ( + ($l < $x[1]) ? 1 : 0 + )), + $l + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param SplFixedArray $y + * @param SplFixedArray $z + * @return SplFixedArray + * @throws SodiumException + */ + protected static function add364( + SplFixedArray $x, + SplFixedArray $y, + SplFixedArray $z + ): SplFixedArray { + return self::add64($x, self::add64($y, $z)); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param SplFixedArray $y + * @return SplFixedArray + * @throws SodiumException + * @throws TypeError + */ + protected static function xor64(SplFixedArray $x, SplFixedArray $y): SplFixedArray + { + if (!is_numeric($x[0])) { + throw new SodiumException('x[0] is not an integer'); + } + if (!is_numeric($x[1])) { + throw new SodiumException('x[1] is not an integer'); + } + if (!is_numeric($y[0])) { + throw new SodiumException('y[0] is not an integer'); + } + if (!is_numeric($y[1])) { + throw new SodiumException('y[1] is not an integer'); + } + return self::new64( + (int) (($x[0] ^ $y[0]) & 0xffffffff), + (int) (($x[1] ^ $y[1]) & 0xffffffff) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param int $c + * @return SplFixedArray + * + * @throws SodiumException + */ + public static function rotr64(SplFixedArray $x, int $c): SplFixedArray + { + if ($c >= 64) { + $c %= 64; + } + if ($c >= 32) { + /** @var int $tmp */ + $tmp = $x[0]; + $x[0] = $x[1]; + $x[1] = $tmp; + $c -= 32; + } + if ($c === 0) { + return $x; + } + + $l0 = 0; + /** @var int $c */ + $c = 64 - $c; + + if ($c < 32) { + $h0 = ((int) ($x[0]) << $c) | ( + ( + (int) ($x[1]) & ((1 << $c) - 1) + << + (32 - $c) + ) >> (32 - $c) + ); + $l0 = (int) ($x[1]) << $c; + } else { + $h0 = (int) ($x[1]) << ($c - 32); + } + + $h1 = 0; + $c1 = 64 - $c; + + if ($c1 < 32) { + $h1 = (int) ($x[0]) >> $c1; + $l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1 << $c1) - 1)) << (32 - $c1); + } else { + $l1 = (int) ($x[0]) >> ($c1 - 32); + } + + return self::new64($h0 | $h1, $l0 | $l1); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @return int + */ + protected static function flatten64(SplFixedArray $x): int + { + return (int) ($x[0] * 4294967296 + $x[1]); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param int $i + * @return SplFixedArray + */ + protected static function load64(SplFixedArray $x, int $i): SplFixedArray + { + $l = (int) ($x[$i]) + | ((int) ($x[$i+1]) << 8) + | ((int) ($x[$i+2]) << 16) + | ((int) ($x[$i+3]) << 24); + $h = (int) ($x[$i+4]) + | ((int) ($x[$i+5]) << 8) + | ((int) ($x[$i+6]) << 16) + | ((int) ($x[$i+7]) << 24); + return self::new64($h, $l); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param int $i + * @param SplFixedArray $u + * @return void + */ + protected static function store64(SplFixedArray $x, int $i, SplFixedArray $u): void + { + $maxLength = $x->getSize() - 1; + for ($j = 0; $j < 8; ++$j) { + /* + [0, 1, 2, 3, 4, 5, 6, 7] + ... becomes ... + [0, 0, 0, 0, 1, 1, 1, 1] + */ + $uIdx = ((7 - $j) & 4) >> 2; + $x[$i] = ((int) ($u[$uIdx]) & 0xff); + if (++$i > $maxLength) { + return; + } + $u[$uIdx] >>= 8; + } + } + + /** + * This just sets the $iv static variable. + * + * @internal You should not use this directly from another application + * + * @return void + * + * @throws SodiumException + */ + public static function pseudoConstructor(): void + { + static $called = false; + if ($called) { + return; + } + self::$iv = new SplFixedArray(8); + self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908); + self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b); + self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b); + self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1); + self::$iv[4] = self::new64(0x510e527f, 0xade682d1); + self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f); + self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b); + self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179); + + $called = true; + } + + /** + * Returns a fresh BLAKE2 context. + * + * @internal You should not use this directly from another application + * + * @return SplFixedArray + * + * @throws SodiumException + */ + protected static function context(): SplFixedArray + { + $ctx = new SplFixedArray(6); + $ctx[0] = new SplFixedArray(8); // h + $ctx[1] = new SplFixedArray(2); // t + $ctx[2] = new SplFixedArray(2); // f + $ctx[3] = new SplFixedArray(256); // buf + $ctx[4] = 0; // buflen + $ctx[5] = 0; // last_node (uint8_t) + + for ($i = 8; $i--;) { + $ctx[0][$i] = self::$iv[$i]; + } + for ($i = 256; $i--;) { + $ctx[3][$i] = 0; + } + + $zero = self::new64(0, 0); + $ctx[1][0] = $zero; + $ctx[1][1] = $zero; + $ctx[2][0] = $zero; + $ctx[2][1] = $zero; + + return $ctx; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $buf + * @return void + * @throws SodiumException + * @throws TypeError + */ + protected static function compress(SplFixedArray $ctx, SplFixedArray $buf): void + { + $m = new SplFixedArray(16); + $v = new SplFixedArray(16); + + for ($i = 16; $i--;) { + $m[$i] = self::load64($buf, $i << 3); + } + + for ($i = 8; $i--;) { + $v[$i] = $ctx[0][$i]; + } + + $v[ 8] = self::$iv[0]; + $v[ 9] = self::$iv[1]; + $v[10] = self::$iv[2]; + $v[11] = self::$iv[3]; + + $v[12] = self::xor64($ctx[1][0], self::$iv[4]); + $v[13] = self::xor64($ctx[1][1], self::$iv[5]); + $v[14] = self::xor64($ctx[2][0], self::$iv[6]); + $v[15] = self::xor64($ctx[2][1], self::$iv[7]); + + for ($r = 0; $r < 12; ++$r) { + $v = self::G($r, 0, 0, 4, 8, 12, $v, $m); + $v = self::G($r, 1, 1, 5, 9, 13, $v, $m); + $v = self::G($r, 2, 2, 6, 10, 14, $v, $m); + $v = self::G($r, 3, 3, 7, 11, 15, $v, $m); + $v = self::G($r, 4, 0, 5, 10, 15, $v, $m); + $v = self::G($r, 5, 1, 6, 11, 12, $v, $m); + $v = self::G($r, 6, 2, 7, 8, 13, $v, $m); + $v = self::G($r, 7, 3, 4, 9, 14, $v, $m); + } + + for ($i = 8; $i--;) { + $ctx[0][$i] = self::xor64( + $ctx[0][$i], self::xor64($v[$i], $v[$i+8]) + ); + } + } + + /** + * @internal You should not use this directly from another application + * + * @param int $r + * @param int $i + * @param int $a + * @param int $b + * @param int $c + * @param int $d + * @param SplFixedArray $v + * @param SplFixedArray $m + * @return SplFixedArray + * @throws SodiumException + * @throws TypeError + */ + public static function G( + int $r, + int $i, + int $a, + int $b, + int $c, + int $d, + SplFixedArray $v, + SplFixedArray $m + ): SplFixedArray { + $v[$a] = self::add364($v[$a], $v[$b], $m[self::SIGMA[$r][$i << 1]]); + $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32); + $v[$c] = self::add64($v[$c], $v[$d]); + $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24); + $v[$a] = self::add364($v[$a], $v[$b], $m[self::SIGMA[$r][($i << 1) + 1]]); + $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16); + $v[$c] = self::add64($v[$c], $v[$d]); + $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63); + return $v; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param int $inc + * @return void + * + * @throws SodiumException + */ + public static function increment_counter(SplFixedArray $ctx, int $inc): void + { + if ($inc < 0) { + throw new SodiumException('Increasing by a negative number makes no sense.'); + } + $t = self::to64($inc); + # S->t is $ctx[1] in our implementation + + # S->t[0] = ( uint64_t )( t >> 0 ); + $ctx[1][0] = self::add64($ctx[1][0], $t); + + # S->t[1] += ( S->t[0] < inc ); + if (self::flatten64($ctx[1][0]) < $inc) { + $ctx[1][1] = self::add64($ctx[1][1], self::to64(1)); + } + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $p + * @param int $plen + * @return void + * + * @throws SodiumException + * @throws TypeError + */ + public static function update(SplFixedArray $ctx, SplFixedArray $p, int $plen): void + { + self::pseudoConstructor(); + + $offset = 0; + while ($plen > 0) { + $left = $ctx[4]; + $fill = 256 - $left; + + if ($plen > $fill) { + # memcpy( S->buf + left, in, fill ); /* Fill buffer */ + for ($i = $fill; $i--;) { + $ctx[3][$i + $left] = $p[(int) ($i + $offset)]; + } + + # S->buflen += fill; + $ctx[4] += $fill; + + # blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + self::increment_counter($ctx, 128); + + # blake2b_compress( S, S->buf ); /* Compress */ + self::compress($ctx, $ctx[3]); + + # memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */ + for ($i = 128; $i--;) { + $ctx[3][$i] = $ctx[3][$i + 128]; + } + + # S->buflen -= BLAKE2B_BLOCKBYTES; + $ctx[4] -= 128; + + # in += fill; + $offset += $fill; + + # inlen -= fill; + $plen -= $fill; + } else { + for ($i = $plen; $i--;) { + $ctx[3][$i + $left] = $p[(int) ($i + $offset)]; + } + $ctx[4] += $plen; + $offset += $plen; + $plen -= $plen; + } + } + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $out + * @return SplFixedArray + * + * @throws SodiumException + * @throws TypeError + */ + public static function finish(SplFixedArray $ctx, SplFixedArray $out): SplFixedArray + { + self::pseudoConstructor(); + if ($ctx[4] > 128) { + self::increment_counter($ctx, 128); + self::compress($ctx, $ctx[3]); + $ctx[4] -= 128; + if ($ctx[4] > 128) { + throw new SodiumException('Failed to assert that buflen <= 128 bytes'); + } + for ($i = $ctx[4]; $i--;) { + $ctx[3][$i] = $ctx[3][$i + 128]; + } + } + + self::increment_counter($ctx, $ctx[4]); + $ctx[2][0] = self::new64(0xffffffff, 0xffffffff); + + for ($i = 256 - $ctx[4]; $i--;) { + $ctx[3][$i+$ctx[4]] = 0; + } + + self::compress($ctx, $ctx[3]); + + $i = (int) (($out->getSize() - 1) / 8); + for (; $i >= 0; --$i) { + self::store64($out, $i << 3, $ctx[0][$i]); + } + return $out; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray|null $key + * @param int $outlen + * @param SplFixedArray|null $salt + * @param SplFixedArray|null $personal + * @return SplFixedArray + * + * @throws SodiumException + * @throws TypeError + */ + public static function init( + ?SplFixedArray $key = null, + int $outlen = 64, + ?SplFixedArray $salt = null, + ?SplFixedArray $personal = null + ): SplFixedArray { + self::pseudoConstructor(); + $klen = 0; + + if ($key !== null) { + if (count($key) > 64) { + throw new SodiumException('Invalid key size'); + } + $klen = count($key); + } + + if ($outlen > 64) { + throw new SodiumException('Invalid output size'); + } + + $ctx = self::context(); + + $p = new SplFixedArray(64); + // Zero our param buffer... + for ($i = 64; --$i;) { + $p[$i] = 0; + } + + $p[0] = $outlen; // digest_length + $p[1] = $klen; // key_length + $p[2] = 1; // fanout + $p[3] = 1; // depth + + if ($salt instanceof SplFixedArray) { + // salt: [32] through [47] + for ($i = 0; $i < 16; ++$i) { + $p[32 + $i] = (int) $salt[$i]; + } + } + if ($personal instanceof SplFixedArray) { + // personal: [48] through [63] + for ($i = 0; $i < 16; ++$i) { + $p[48 + $i] = (int) $personal[$i]; + } + } + + $ctx[0][0] = self::xor64( + $ctx[0][0], + self::load64($p, 0) + ); + if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) { + // We need to do what blake2b_init_param() does: + for ($i = 1; $i < 8; ++$i) { + $ctx[0][$i] = self::xor64( + $ctx[0][$i], + self::load64($p, $i << 3) + ); + } + } + + if ($klen > 0 && $key instanceof SplFixedArray) { + $block = new SplFixedArray(128); + for ($i = 128; $i--;) { + $block[$i] = 0; + } + for ($i = $klen; $i--;) { + $block[$i] = $key[$i]; + } + self::update($ctx, $block, 128); + $ctx[4] = 128; + } + + return $ctx; + } + + /** + * Convert a string into an SplFixedArray of integers + * + * @internal You should not use this directly from another application + * + * @param string $str + * @return SplFixedArray + */ + public static function stringToSplFixedArray(string $str = ''): SplFixedArray + { + $values = unpack('C*', $str); + return SplFixedArray::fromArray(array_values($values)); + } + + /** + * Convert an SplFixedArray of integers into a string + * + * @internal You should not use this directly from another application + * + * @param SplFixedArray $a + * @return string + * @throws TypeError + */ + public static function SplFixedArrayToString(SplFixedArray $a): string + { + /** + * @var array $arr + */ + $arr = $a->toArray(); + $c = $a->count(); + array_unshift($arr, str_repeat('C', $c)); + return (string) (call_user_func_array('pack', $arr)); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @return string + * @throws TypeError + */ + public static function contextToString(SplFixedArray $ctx): string + { + $str = ''; + /** @var array> $ctxA */ + $ctxA = $ctx[0]->toArray(); + + # uint64_t h[8]; + for ($i = 0; $i < 8; ++$i) { + $str .= self::store32_le($ctxA[$i][1]); + $str .= self::store32_le($ctxA[$i][0]); + } + + # uint64_t t[2]; + # uint64_t f[2]; + for ($i = 1; $i < 3; ++$i) { + $ctxA = $ctx[$i]->toArray(); + $str .= self::store32_le($ctxA[0][1]); + $str .= self::store32_le($ctxA[0][0]); + $str .= self::store32_le($ctxA[1][1]); + $str .= self::store32_le($ctxA[1][0]); + } + + # uint8_t buf[2 * 128]; + $str .= self::SplFixedArrayToString($ctx[3]); + + /** @var int $ctx4 */ + $ctx4 = (int) $ctx[4]; + + # size_t buflen; + $str .= implode('', array( + self::intToChr($ctx4 & 0xff), + self::intToChr(($ctx4 >> 8) & 0xff), + self::intToChr(($ctx4 >> 16) & 0xff), + self::intToChr(($ctx4 >> 24) & 0xff), + self::intToChr(($ctx4 >> 32) & 0xff), + self::intToChr(($ctx4 >> 40) & 0xff), + self::intToChr(($ctx4 >> 48) & 0xff), + self::intToChr(($ctx4 >> 56) & 0xff) + )); + # uint8_t last_node; + return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23); + } + + /** + * Creates an SplFixedArray containing other SplFixedArray elements, from + * a string (compatible with \Sodium\crypto_generichash_{init, update, final}) + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return SplFixedArray + * @throws SodiumException + * @throws TypeError + */ + public static function stringToContext(string $string): SplFixedArray + { + $ctx = self::context(); + + # uint64_t h[8]; + for ($i = 0; $i < 8; ++$i) { + $ctx[0][$i] = SplFixedArray::fromArray( + array( + self::load_4( + self::substr($string, (($i << 3) + 4), 4) + ), + self::load_4( + self::substr($string, (($i << 3)), 4) + ) + ) + ); + } + + # uint64_t t[2]; + # uint64_t f[2]; + for ($i = 1; $i < 3; ++$i) { + $ctx[$i][1] = SplFixedArray::fromArray( + array( + self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)), + self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4)) + ) + ); + $ctx[$i][0] = SplFixedArray::fromArray( + array( + self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)), + self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4)) + ) + ); + } + + # uint8_t buf[2 * 128]; + $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256)); + + # uint8_t buf[2 * 128]; + $int = 0; + for ($i = 0; $i < 8; ++$i) { + $int |= self::chrToInt($string[352 + $i]) << ($i << 3); + } + $ctx[4] = $int; + + return $ctx; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/Original.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/Original.php new file mode 100644 index 000000000..683e8f5ff --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/Original.php @@ -0,0 +1,259 @@ + $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); + $b0 = $chunk[1]; + $b1 = $chunk[2]; + $b2 = $chunk[3]; + + $dest .= + self::encode6Bits( $b0 >> 2 ) . + self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . + self::encode6Bits( $b2 & 63); + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); + $b0 = $chunk[1]; + if ($i + 1 < $srcLen) { + $b1 = $chunk[2]; + $dest .= + self::encode6Bits($b0 >> 2) . + self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + self::encode6Bits(($b1 << 2) & 63); + if ($pad) { + $dest .= '='; + } + } else { + $dest .= + self::encode6Bits( $b0 >> 2) . + self::encode6Bits(($b0 << 4) & 63); + if ($pad) { + $dest .= '=='; + } + } + } + return $dest; + } + + /** + * decode from base64 into binary + * + * Base64 character set "./[A-Z][a-z][0-9]" + * + * @param string $src + * @param bool $strictPadding + * @return string + * @throws RangeException + * @throws TypeError + */ + public static function decode( + #[SensitiveParameter] + string $src, + bool $strictPadding = false + ): string { + // Remove padding + $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); + if ($srcLen === 0) { + return ''; + } + + if ($strictPadding) { + if (($srcLen & 3) === 0) { + if ($src[$srcLen - 1] === '=') { + $srcLen--; + if ($src[$srcLen - 1] === '=') { + $srcLen--; + } + } + } + if (($srcLen & 3) === 1) { + throw new RangeException( + 'Incorrect padding' + ); + } + if ($src[$srcLen - 1] === '=') { + throw new RangeException( + 'Incorrect padding' + ); + } + } else { + $src = rtrim($src, '='); + $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); + } + + $err = 0; + $dest = ''; + // Main loop (no padding): + for ($i = 0; $i + 4 <= $srcLen; $i += 4) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); + $c0 = self::decode6Bits($chunk[1]); + $c1 = self::decode6Bits($chunk[2]); + $c2 = self::decode6Bits($chunk[3]); + $c3 = self::decode6Bits($chunk[4]); + + $dest .= pack( + 'CCC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff), + ((($c2 << 6) | $c3) & 0xff) + ); + $err |= ($c0 | $c1 | $c2 | $c3) >> 8; + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); + $c0 = self::decode6Bits($chunk[1]); + + if ($i + 2 < $srcLen) { + $c1 = self::decode6Bits($chunk[2]); + $c2 = self::decode6Bits($chunk[3]); + $dest .= pack( + 'CC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff) + ); + $err |= ($c0 | $c1 | $c2) >> 8; + } elseif ($i + 1 < $srcLen) { + $c1 = self::decode6Bits($chunk[2]); + $dest .= pack( + 'C', + ((($c0 << 2) | ($c1 >> 4)) & 0xff) + ); + $err |= ($c0 | $c1) >> 8; + } + } + $check = ($err === 0); + if (!$check) { + throw new RangeException( + 'Base64::decode() only expects characters in the correct base64 alphabet' + ); + } + return $dest; + } + // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE + + /** + * Uses bitwise operators instead of table-lookups to turn 6-bit integers + * into 8-bit integers. + * + * Base64 character set: + * [A-Z] [a-z] [0-9] + / + * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f + * + * @param int $src + * @return int + */ + protected static function decode6Bits( + #[SensitiveParameter] + int $src + ): int { + $ret = -1; + + // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + + // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); + + // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); + + // if ($src == 0x2b) $ret += 62 + 1; + $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63; + + // if ($src == 0x2f) ret += 63 + 1; + $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64; + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits( + #[SensitiveParameter] + int $src + ): string { + $diff = 0x41; + + // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 + $diff += ((25 - $src) >> 8) & 6; + + // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 + $diff -= ((51 - $src) >> 8) & 75; + + // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15 + $diff -= ((61 - $src) >> 8) & 15; + + // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3 + $diff += ((62 - $src) >> 8) & 3; + + return pack('C', $src + $diff); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/UrlSafe.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/UrlSafe.php new file mode 100644 index 000000000..04733aa29 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Base64/UrlSafe.php @@ -0,0 +1,257 @@ + $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); + $b0 = $chunk[1]; + $b1 = $chunk[2]; + $b2 = $chunk[3]; + + $dest .= + self::encode6Bits( $b0 >> 2 ) . + self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . + self::encode6Bits( $b2 & 63); + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); + $b0 = $chunk[1]; + if ($i + 1 < $srcLen) { + $b1 = $chunk[2]; + $dest .= + self::encode6Bits($b0 >> 2) . + self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + self::encode6Bits(($b1 << 2) & 63); + if ($pad) { + $dest .= '='; + } + } else { + $dest .= + self::encode6Bits( $b0 >> 2) . + self::encode6Bits(($b0 << 4) & 63); + if ($pad) { + $dest .= '=='; + } + } + } + return $dest; + } + + /** + * decode from base64 into binary + * + * Base64 character set "./[A-Z][a-z][0-9]" + * + * @param string $src + * @param bool $strictPadding + * @return string + * @throws RangeException + * @throws TypeError + */ + public static function decode( + #[SensitiveParameter] + string $src, + bool $strictPadding = false + ): string { + // Remove padding + $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); + if ($srcLen === 0) { + return ''; + } + + if ($strictPadding) { + if (($srcLen & 3) === 0) { + if ($src[$srcLen - 1] === '=') { + $srcLen--; + if ($src[$srcLen - 1] === '=') { + $srcLen--; + } + } + } + if (($srcLen & 3) === 1) { + throw new RangeException( + 'Incorrect padding' + ); + } + if ($src[$srcLen - 1] === '=') { + throw new RangeException( + 'Incorrect padding' + ); + } + } else { + $src = rtrim($src, '='); + $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); + } + + $err = 0; + $dest = ''; + // Main loop (no padding): + for ($i = 0; $i + 4 <= $srcLen; $i += 4) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); + $c0 = self::decode6Bits($chunk[1]); + $c1 = self::decode6Bits($chunk[2]); + $c2 = self::decode6Bits($chunk[3]); + $c3 = self::decode6Bits($chunk[4]); + + $dest .= pack( + 'CCC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff), + ((($c2 << 6) | $c3) & 0xff) + ); + $err |= ($c0 | $c1 | $c2 | $c3) >> 8; + } + // The last chunk, which may have padding: + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); + $c0 = self::decode6Bits($chunk[1]); + + if ($i + 2 < $srcLen) { + $c1 = self::decode6Bits($chunk[2]); + $c2 = self::decode6Bits($chunk[3]); + $dest .= pack( + 'CC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff) + ); + $err |= ($c0 | $c1 | $c2) >> 8; + } elseif ($i + 1 < $srcLen) { + $c1 = self::decode6Bits($chunk[2]); + $dest .= pack( + 'C', + ((($c0 << 2) | ($c1 >> 4)) & 0xff) + ); + $err |= ($c0 | $c1) >> 8; + } + } + $check = ($err === 0); + if (!$check) { + throw new RangeException( + 'Base64::decode() only expects characters in the correct base64 alphabet' + ); + } + return $dest; + } + // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE + /** + * Uses bitwise operators instead of table-lookups to turn 6-bit integers + * into 8-bit integers. + * + * Base64 character set: + * [A-Z] [a-z] [0-9] + / + * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f + * + * @param int $src + * @return int + */ + protected static function decode6Bits( + #[SensitiveParameter] + int $src + ): int { + $ret = -1; + + // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + + // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); + + // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); + + // if ($src == 0x2c) $ret += 62 + 1; + $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; + + // if ($src == 0x5f) ret += 63 + 1; + $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64; + + return $ret; + } + + /** + * Uses bitwise operators instead of table-lookups to turn 8-bit integers + * into 6-bit integers. + * + * @param int $src + * @return string + */ + protected static function encode6Bits( + int $src + ): string { + $diff = 0x41; + + // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 + $diff += ((25 - $src) >> 8) & 6; + + // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 + $diff -= ((51 - $src) >> 8) & 75; + + // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13 + $diff -= ((61 - $src) >> 8) & 13; + + // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3 + $diff += ((62 - $src) >> 8) & 49; + + return pack('C', $src + $diff); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20.php new file mode 100644 index 000000000..a3adfba98 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20.php @@ -0,0 +1,309 @@ +> (32 - $n)) + ) + ); + } + + /** + * The ChaCha20 quarter round function. Works on four 32-bit integers. + * + * @internal You should not use this directly from another application + * + * @param int $a + * @param int $b + * @param int $c + * @param int $d + * @return array + */ + protected static function quarterRound(int $a, int $b, int $c, int $d): array + { + # a = PLUS(a,b); d = ROTATE(XOR(d,a),16); + /** @var int $a */ + $a = ($a + $b) & 0xffffffff; + $d = self::rotate($d ^ $a, 16); + + # c = PLUS(c,d); b = ROTATE(XOR(b,c),12); + /** @var int $c */ + $c = ($c + $d) & 0xffffffff; + $b = self::rotate($b ^ $c, 12); + + # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); + /** @var int $a */ + $a = ($a + $b) & 0xffffffff; + $d = self::rotate($d ^ $a, 8); + + # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + /** @var int $c */ + $c = ($c + $d) & 0xffffffff; + $b = self::rotate($b ^ $c, 7); + return array($a, $b, $c, $d); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx + * @param string $message + * + * @return string + * @throws TypeError + * @throws SodiumException + */ + public static function encryptBytes( + ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx, + #[SensitiveParameter] + string $message = '' + ): string { + $bytes = self::strlen($message); + + $j0 = (int) $ctx[0]; + $j1 = (int) $ctx[1]; + $j2 = (int) $ctx[2]; + $j3 = (int) $ctx[3]; + $j4 = (int) $ctx[4]; + $j5 = (int) $ctx[5]; + $j6 = (int) $ctx[6]; + $j7 = (int) $ctx[7]; + $j8 = (int) $ctx[8]; + $j9 = (int) $ctx[9]; + $j10 = (int) $ctx[10]; + $j11 = (int) $ctx[11]; + $j12 = (int) $ctx[12]; + $j13 = (int) $ctx[13]; + $j14 = (int) $ctx[14]; + $j15 = (int) $ctx[15]; + + $c = ''; + for (;;) { + if ($bytes < 64) { + $message .= str_repeat("\x00", 64 - $bytes); + } + + $x0 = $j0; + $x1 = $j1; + $x2 = $j2; + $x3 = $j3; + $x4 = $j4; + $x5 = $j5; + $x6 = $j6; + $x7 = $j7; + $x8 = $j8; + $x9 = $j9; + $x10 = $j10; + $x11 = $j11; + $x12 = $j12; + $x13 = $j13; + $x14 = $j14; + $x15 = $j15; + + # for (i = 20; i > 0; i -= 2) { + for ($i = 20; $i > 0; $i -= 2) { + [$x0, $x4, $x8, $x12] = self::quarterRound($x0, $x4, $x8, $x12); + [$x1, $x5, $x9, $x13] = self::quarterRound($x1, $x5, $x9, $x13); + [$x2, $x6, $x10, $x14] = self::quarterRound($x2, $x6, $x10, $x14); + [$x3, $x7, $x11, $x15] = self::quarterRound($x3, $x7, $x11, $x15); + + [$x0, $x5, $x10, $x15] = self::quarterRound($x0, $x5, $x10, $x15); + [$x1, $x6, $x11, $x12] = self::quarterRound($x1, $x6, $x11, $x12); + [$x2, $x7, $x8, $x13] = self::quarterRound($x2, $x7, $x8, $x13); + [$x3, $x4, $x9, $x14] = self::quarterRound($x3, $x4, $x9, $x14); + } + $x0 = ($x0 & 0xffffffff) + $j0; + $x1 = ($x1 & 0xffffffff) + $j1; + $x2 = ($x2 & 0xffffffff) + $j2; + $x3 = ($x3 & 0xffffffff) + $j3; + $x4 = ($x4 & 0xffffffff) + $j4; + $x5 = ($x5 & 0xffffffff) + $j5; + $x6 = ($x6 & 0xffffffff) + $j6; + $x7 = ($x7 & 0xffffffff) + $j7; + $x8 = ($x8 & 0xffffffff) + $j8; + $x9 = ($x9 & 0xffffffff) + $j9; + $x10 = ($x10 & 0xffffffff) + $j10; + $x11 = ($x11 & 0xffffffff) + $j11; + $x12 = ($x12 & 0xffffffff) + $j12; + $x13 = ($x13 & 0xffffffff) + $j13; + $x14 = ($x14 & 0xffffffff) + $j14; + $x15 = ($x15 & 0xffffffff) + $j15; + + $x0 ^= self::load_4(self::substr($message, 0, 4)); + $x1 ^= self::load_4(self::substr($message, 4, 4)); + $x2 ^= self::load_4(self::substr($message, 8, 4)); + $x3 ^= self::load_4(self::substr($message, 12, 4)); + $x4 ^= self::load_4(self::substr($message, 16, 4)); + $x5 ^= self::load_4(self::substr($message, 20, 4)); + $x6 ^= self::load_4(self::substr($message, 24, 4)); + $x7 ^= self::load_4(self::substr($message, 28, 4)); + $x8 ^= self::load_4(self::substr($message, 32, 4)); + $x9 ^= self::load_4(self::substr($message, 36, 4)); + $x10 ^= self::load_4(self::substr($message, 40, 4)); + $x11 ^= self::load_4(self::substr($message, 44, 4)); + $x12 ^= self::load_4(self::substr($message, 48, 4)); + $x13 ^= self::load_4(self::substr($message, 52, 4)); + $x14 ^= self::load_4(self::substr($message, 56, 4)); + $x15 ^= self::load_4(self::substr($message, 60, 4)); + + ++$j12; + if ($j12 & 0xf0000000) { + throw new SodiumException('Overflow'); + } + + $block = self::store32_le(($x0 & 0xffffffff)) . + self::store32_le(($x1 & 0xffffffff)) . + self::store32_le(($x2 & 0xffffffff)) . + self::store32_le(($x3 & 0xffffffff)) . + self::store32_le(($x4 & 0xffffffff)) . + self::store32_le(($x5 & 0xffffffff)) . + self::store32_le(($x6 & 0xffffffff)) . + self::store32_le(($x7 & 0xffffffff)) . + self::store32_le(($x8 & 0xffffffff)) . + self::store32_le(($x9 & 0xffffffff)) . + self::store32_le(($x10 & 0xffffffff)) . + self::store32_le(($x11 & 0xffffffff)) . + self::store32_le(($x12 & 0xffffffff)) . + self::store32_le(($x13 & 0xffffffff)) . + self::store32_le(($x14 & 0xffffffff)) . + self::store32_le(($x15 & 0xffffffff)); + + /* Partial block */ + if ($bytes < 64) { + $c .= self::substr($block, 0, $bytes); + break; + } + + /* Full block */ + $c .= $block; + $bytes -= 64; + if ($bytes <= 0) { + break; + } + $message = self::substr($message, 64); + } + /* end for(;;) loop */ + + $ctx[12] = $j12; + $ctx[13] = $j13; + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function stream( + int $len = 64, + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce), + str_repeat("\x00", $len) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function ietfStream( + int $len, + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce), + str_repeat("\x00", $len) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @param string $ic + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function ietfStreamXorIc( + #[SensitiveParameter] + string $message, + string $nonce = '', + #[SensitiveParameter] + string $key = '', + string $ic = '' + ): string { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic), + $message + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @param string $ic + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function streamXorIc( + #[SensitiveParameter] + string $message, + string $nonce = '', + #[SensitiveParameter] + string $key = '', + string $ic = '' + ): string { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic), + $message + ); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php new file mode 100644 index 000000000..4a4317c6e --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php @@ -0,0 +1,122 @@ + + * @psalm-suppress MissingTemplateParam + */ +class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util implements ArrayAccess +{ + /** + * @var SplFixedArray internally, + */ + protected SplFixedArray $container; + + /** + * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor. + * + * @internal You should not use this directly from another application + * + * @param string $key ChaCha20 key. + * @param string $iv Initialization Vector (a.k.a. nonce). + * @param string $counter The initial counter value. + * Defaults to 8 0x00 bytes. + * @throws InvalidArgumentException + * @throws TypeError + */ + public function __construct( + #[SensitiveParameter] + string $key = '', + string $iv = '', + string $counter = '' + ) { + if (self::strlen($key) !== 32) { + throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.'); + } + if (self::strlen($iv) !== 8) { + throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.'); + } + $this->container = new SplFixedArray(16); + + /* "expand 32-byte k" as per ChaCha20 spec */ + $this->container[0] = 0x61707865; + $this->container[1] = 0x3320646e; + $this->container[2] = 0x79622d32; + $this->container[3] = 0x6b206574; + $this->container[4] = self::load_4(self::substr($key, 0, 4)); + $this->container[5] = self::load_4(self::substr($key, 4, 4)); + $this->container[6] = self::load_4(self::substr($key, 8, 4)); + $this->container[7] = self::load_4(self::substr($key, 12, 4)); + $this->container[8] = self::load_4(self::substr($key, 16, 4)); + $this->container[9] = self::load_4(self::substr($key, 20, 4)); + $this->container[10] = self::load_4(self::substr($key, 24, 4)); + $this->container[11] = self::load_4(self::substr($key, 28, 4)); + + if (empty($counter)) { + $this->container[12] = 0; + $this->container[13] = 0; + } else { + $this->container[12] = self::load_4(self::substr($counter, 0, 4)); + $this->container[13] = self::load_4(self::substr($counter, 4, 4)); + } + $this->container[14] = self::load_4(self::substr($iv, 0, 4)); + $this->container[15] = self::load_4(self::substr($iv, 4, 4)); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @param int $value + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value): void + { + $this->container[$offset] = $value; + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset): void + { + unset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return mixed|null + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + return isset($this->container[$offset]) + ? $this->container[$offset] + : null; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php new file mode 100644 index 000000000..f75070a63 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php @@ -0,0 +1,43 @@ +container[12] = self::load_4(self::substr($counter, 0, 4)); + } + $this->container[13] = self::load_4(self::substr($iv, 0, 4)); + $this->container[14] = self::load_4(self::substr($iv, 4, 4)); + $this->container[15] = self::load_4(self::substr($iv, 8, 4)); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519.php new file mode 100644 index 000000000..79576a78b --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519.php @@ -0,0 +1,3165 @@ + $arr */ + $arr = array(); + for ($i = 0; $i < 10; ++$i) { + $arr[$i] = ($f[$i] + $g[$i]); + } + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr); + } + + /** + * Constant-time conditional move. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @param ParagonIE_Sodium_Core_Curve25519_Fe $g + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_cmov( + ParagonIE_Sodium_Core_Curve25519_Fe $f, + ParagonIE_Sodium_Core_Curve25519_Fe $g, + int $b = 0 + ): ParagonIE_Sodium_Core_Curve25519_Fe { + /** @var array $h */ + $h = array(); + $b *= -1; + for ($i = 0; $i < 10; ++$i) { + $x = (($f[$i] ^ $g[$i]) & $b); + $h[$i] = ($f[$i]) ^ $x; + } + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); + } + + /** + * Give: 32-byte string. + * Receive: A field element object to use for internal calculations. + * + * @internal You should not use this directly from another application + * + * @param string $s + * @return ParagonIE_Sodium_Core_Curve25519_Fe + * @throws RangeException + * @throws TypeError + */ + public static function fe_frombytes( + #[SensitiveParameter] + string $s + ): ParagonIE_Sodium_Core_Curve25519_Fe { + if (self::strlen($s) !== 32) { + throw new RangeException('Expected a 32-byte string.'); + } + $h0 = self::load_4($s); + $h1 = self::load_3(self::substr($s, 4, 3)) << 6; + $h2 = self::load_3(self::substr($s, 7, 3)) << 5; + $h3 = self::load_3(self::substr($s, 10, 3)) << 3; + $h4 = self::load_3(self::substr($s, 13, 3)) << 2; + $h5 = self::load_4(self::substr($s, 16, 4)); + $h6 = self::load_3(self::substr($s, 20, 3)) << 7; + $h7 = self::load_3(self::substr($s, 23, 3)) << 5; + $h8 = self::load_3(self::substr($s, 26, 3)) << 4; + $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19, 5); + $h9 -= $carry9 << 25; + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + [$h0, $h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9] + ); + } + + /** + * Convert a field element to a byte string. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $h + * @return string + */ + public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h): string + { + $h0 = $h[0]; + $h1 = $h[1]; + $h2 = $h[2]; + $h3 = $h[3]; + $h4 = $h[4]; + $h5 = $h[5]; + $h6 = $h[6]; + $h7 = $h[7]; + $h8 = $h[8]; + $h9 = $h[9]; + + $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25; + $q = ($h0 + $q) >> 26; + $q = ($h1 + $q) >> 25; + $q = ($h2 + $q) >> 26; + $q = ($h3 + $q) >> 25; + $q = ($h4 + $q) >> 26; + $q = ($h5 + $q) >> 25; + $q = ($h6 + $q) >> 26; + $q = ($h7 + $q) >> 25; + $q = ($h8 + $q) >> 26; + $q = ($h9 + $q) >> 25; + + $h0 += self::mul($q, 19, 5); + + $carry0 = $h0 >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry1 = $h1 >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry2 = $h2 >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry3 = $h3 >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry4 = $h4 >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry5 = $h5 >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + $carry6 = $h6 >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + $carry7 = $h7 >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + $carry8 = $h8 >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + $carry9 = $h9 >> 25; + $h9 -= $carry9 << 25; + + return self::intArrayToString([ + (($h0 >> 0) & 0xff), + (($h0 >> 8) & 0xff), + (($h0 >> 16) & 0xff), + ((($h0 >> 24) | ($h1 << 2)) & 0xff), + (($h1 >> 6) & 0xff), + (($h1 >> 14) & 0xff), + ((($h1 >> 22) | ($h2 << 3)) & 0xff), + (($h2 >> 5) & 0xff), + (($h2 >> 13) & 0xff), + ((($h2 >> 21) | ($h3 << 5)) & 0xff), + (($h3 >> 3) & 0xff), + (($h3 >> 11) & 0xff), + ((($h3 >> 19) | ($h4 << 6)) & 0xff), + (($h4 >> 2) & 0xff), + (($h4 >> 10) & 0xff), + (($h4 >> 18) & 0xff), + (($h5 >> 0) & 0xff), + (($h5 >> 8) & 0xff), + (($h5 >> 16) & 0xff), + ((($h5 >> 24) | ($h6 << 1)) & 0xff), + (($h6 >> 7) & 0xff), + (($h6 >> 15) & 0xff), + ((($h6 >> 23) | ($h7 << 3)) & 0xff), + (($h7 >> 5) & 0xff), + (($h7 >> 13) & 0xff), + ((($h7 >> 21) | ($h8 << 4)) & 0xff), + (($h8 >> 4) & 0xff), + (($h8 >> 12) & 0xff), + ((($h8 >> 20) | ($h9 << 6)) & 0xff), + (($h9 >> 2) & 0xff), + (($h9 >> 10) & 0xff), + (($h9 >> 18) & 0xff) + ]); + } + + /** + * Is a field element negative? (1 = yes, 0 = no. Used in calculations.) + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return int + * @throws SodiumException + * @throws TypeError + */ + public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f): int + { + $str = self::fe_tobytes($f); + return (self::chrToInt($str[0]) & 1); + } + + /** + * Returns 0 if this field element results in all NUL bytes. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f): bool + { + static $zero; + if ($zero === null) { + $zero = str_repeat("\x00", 32); + } + $str = self::fe_tobytes($f); + return !self::verify_32($str, $zero); + } + + /** + * Multiply two field elements + * + * h = f * g + * + * @internal You should not use this directly from another application + * + * @security Is multiplication a source of timing leaks? If so, can we do + * anything to prevent that from happening? + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @param ParagonIE_Sodium_Core_Curve25519_Fe $g + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_mul( + ParagonIE_Sodium_Core_Curve25519_Fe $f, + ParagonIE_Sodium_Core_Curve25519_Fe $g + ): ParagonIE_Sodium_Core_Curve25519_Fe { + // Ensure limbs aren't oversized. + $f = self::fe_normalize($f); + $g = self::fe_normalize($g); + $g1_19 = self::mul($g[1], 19, 5); + $g2_19 = self::mul($g[2], 19, 5); + $g3_19 = self::mul($g[3], 19, 5); + $g4_19 = self::mul($g[4], 19, 5); + $g5_19 = self::mul($g[5], 19, 5); + $g6_19 = self::mul($g[6], 19, 5); + $g7_19 = self::mul($g[7], 19, 5); + $g8_19 = self::mul($g[8], 19, 5); + $g9_19 = self::mul($g[9], 19, 5); + $f1_2 = $f[1] << 1; + $f3_2 = $f[3] << 1; + $f5_2 = $f[5] << 1; + $f7_2 = $f[7] << 1; + $f9_2 = $f[9] << 1; + $f0g0 = self::mul($f[0], $g[0], 26); + $f0g1 = self::mul($f[0], $g[1], 25); + $f0g2 = self::mul($f[0], $g[2], 26); + $f0g3 = self::mul($f[0], $g[3], 25); + $f0g4 = self::mul($f[0], $g[4], 26); + $f0g5 = self::mul($f[0], $g[5], 25); + $f0g6 = self::mul($f[0], $g[6], 26); + $f0g7 = self::mul($f[0], $g[7], 25); + $f0g8 = self::mul($f[0], $g[8], 26); + $f0g9 = self::mul($f[0], $g[9], 26); + $f1g0 = self::mul($f[1], $g[0], 26); + $f1g1_2 = self::mul($f1_2, $g[1], 25); + $f1g2 = self::mul($f[1], $g[2], 26); + $f1g3_2 = self::mul($f1_2, $g[3], 25); + $f1g4 = self::mul($f[1], $g[4], 26); + $f1g5_2 = self::mul($f1_2, $g[5], 25); + $f1g6 = self::mul($f[1], $g[6], 26); + $f1g7_2 = self::mul($f1_2, $g[7], 25); + $f1g8 = self::mul($f[1], $g[8], 26); + $f1g9_38 = self::mul($g9_19, $f1_2, 26); + $f2g0 = self::mul($f[2], $g[0], 26); + $f2g1 = self::mul($f[2], $g[1], 25); + $f2g2 = self::mul($f[2], $g[2], 26); + $f2g3 = self::mul($f[2], $g[3], 25); + $f2g4 = self::mul($f[2], $g[4], 26); + $f2g5 = self::mul($f[2], $g[5], 25); + $f2g6 = self::mul($f[2], $g[6], 26); + $f2g7 = self::mul($f[2], $g[7], 25); + $f2g8_19 = self::mul($g8_19, $f[2], 26); + $f2g9_19 = self::mul($g9_19, $f[2], 26); + $f3g0 = self::mul($f[3], $g[0], 26); + $f3g1_2 = self::mul($f3_2, $g[1], 25); + $f3g2 = self::mul($f[3], $g[2], 26); + $f3g3_2 = self::mul($f3_2, $g[3], 25); + $f3g4 = self::mul($f[3], $g[4], 26); + $f3g5_2 = self::mul($f3_2, $g[5], 25); + $f3g6 = self::mul($f[3], $g[6], 26); + $f3g7_38 = self::mul($g7_19, $f3_2, 26); + $f3g8_19 = self::mul($g8_19, $f[3], 25); + $f3g9_38 = self::mul($g9_19, $f3_2, 26); + $f4g0 = self::mul($f[4], $g[0], 26); + $f4g1 = self::mul($f[4], $g[1], 25); + $f4g2 = self::mul($f[4], $g[2], 26); + $f4g3 = self::mul($f[4], $g[3], 25); + $f4g4 = self::mul($f[4], $g[4], 26); + $f4g5 = self::mul($f[4], $g[5], 25); + $f4g6_19 = self::mul($g6_19, $f[4], 26); + $f4g7_19 = self::mul($g7_19, $f[4], 26); + $f4g8_19 = self::mul($g8_19, $f[4], 26); + $f4g9_19 = self::mul($g9_19, $f[4], 26); + $f5g0 = self::mul($f[5], $g[0], 26); + $f5g1_2 = self::mul($f5_2, $g[1], 25); + $f5g2 = self::mul($f[5], $g[2], 26); + $f5g3_2 = self::mul($f5_2, $g[3], 25); + $f5g4 = self::mul($f[5], $g[4], 26); + $f5g5_38 = self::mul($g5_19, $f5_2, 26); + $f5g6_19 = self::mul($g6_19, $f[5], 25); + $f5g7_38 = self::mul($g7_19, $f5_2, 26); + $f5g8_19 = self::mul($g8_19, $f[5], 25); + $f5g9_38 = self::mul($g9_19, $f5_2, 26); + $f6g0 = self::mul($f[6], $g[0], 26); + $f6g1 = self::mul($f[6], $g[1], 25); + $f6g2 = self::mul($f[6], $g[2], 26); + $f6g3 = self::mul($f[6], $g[3], 25); + $f6g4_19 = self::mul($g4_19, $f[6], 26); + $f6g5_19 = self::mul($g5_19, $f[6], 26); + $f6g6_19 = self::mul($g6_19, $f[6], 26); + $f6g7_19 = self::mul($g7_19, $f[6], 26); + $f6g8_19 = self::mul($g8_19, $f[6], 26); + $f6g9_19 = self::mul($g9_19, $f[6], 26); + $f7g0 = self::mul($f[7], $g[0], 26); + $f7g1_2 = self::mul($f7_2, $g[1], 25); + $f7g2 = self::mul($f[7], $g[2], 26); + $f7g3_38 = self::mul($g3_19, $f7_2, 26); + $f7g4_19 = self::mul($g4_19, $f[7], 26); + $f7g5_38 = self::mul($g5_19, $f7_2, 26); + $f7g6_19 = self::mul($g6_19, $f[7], 25); + $f7g7_38 = self::mul($g7_19, $f7_2, 26); + $f7g8_19 = self::mul($g8_19, $f[7], 25); + $f7g9_38 = self::mul($g9_19,$f7_2, 26); + $f8g0 = self::mul($f[8], $g[0], 26); + $f8g1 = self::mul($f[8], $g[1], 25); + $f8g2_19 = self::mul($g2_19, $f[8], 26); + $f8g3_19 = self::mul($g3_19, $f[8], 26); + $f8g4_19 = self::mul($g4_19, $f[8], 26); + $f8g5_19 = self::mul($g5_19, $f[8], 26); + $f8g6_19 = self::mul($g6_19, $f[8], 26); + $f8g7_19 = self::mul($g7_19, $f[8], 26); + $f8g8_19 = self::mul($g8_19, $f[8], 26); + $f8g9_19 = self::mul($g9_19, $f[8], 26); + $f9g0 = self::mul($f[9], $g[0], 26); + $f9g1_38 = self::mul($g1_19, $f9_2, 26); + $f9g2_19 = self::mul($g2_19, $f[9], 25); + $f9g3_38 = self::mul($g3_19, $f9_2, 26); + $f9g4_19 = self::mul($g4_19, $f[9], 25); + $f9g5_38 = self::mul($g5_19, $f9_2, 26); + $f9g6_19 = self::mul($g6_19, $f[9], 25); + $f9g7_38 = self::mul($g7_19, $f9_2, 26); + $f9g8_19 = self::mul($g8_19, $f[9], 25); + $f9g9_38 = self::mul($g9_19, $f9_2, 26); + + $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38; + $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19; + $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38; + $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19; + $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38; + $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19; + $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38; + $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19; + $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38; + $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19, 5); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return self::fe_normalize( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + [$h0, $h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9] + ) + ); + } + + /** + * Get the negative values for each piece of the field element. + * + * h = -f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f): ParagonIE_Sodium_Core_Curve25519_Fe + { + $h = new ParagonIE_Sodium_Core_Curve25519_Fe(); + for ($i = 0; $i < 10; ++$i) { + $h[$i] = -$f[$i]; + } + return self::fe_normalize($h); + } + + /** + * Square a field element + * + * h = f * f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sq( + ParagonIE_Sodium_Core_Curve25519_Fe $f + ): ParagonIE_Sodium_Core_Curve25519_Fe { + $f = self::fe_normalize($f); + $f0_2 = $f[0] << 1; + $f1_2 = $f[1] << 1; + $f2_2 = $f[2] << 1; + $f3_2 = $f[3] << 1; + $f4_2 = $f[4] << 1; + $f5_2 = $f[5] << 1; + $f6_2 = $f[6] << 1; + $f7_2 = $f[7] << 1; + $f5_38 = self::mul($f[5], 38, 6); + $f6_19 = self::mul($f[6], 19, 5); + $f7_38 = self::mul($f[7], 38, 6); + $f8_19 = self::mul($f[8], 19, 5); + $f9_38 = self::mul($f[9], 38, 6); + $f0f0 = self::mul($f[0], $f[0], 26); + $f0f1_2 = self::mul($f0_2, $f[1], 26); + $f0f2_2 = self::mul($f0_2, $f[2], 26); + $f0f3_2 = self::mul($f0_2, $f[3], 26); + $f0f4_2 = self::mul($f0_2, $f[4], 26); + $f0f5_2 = self::mul($f0_2, $f[5], 26); + $f0f6_2 = self::mul($f0_2, $f[6], 26); + $f0f7_2 = self::mul($f0_2, $f[7], 26); + $f0f8_2 = self::mul($f0_2, $f[8], 26); + $f0f9_2 = self::mul($f0_2, $f[9], 26); + $f1f1_2 = self::mul($f1_2, $f[1], 26); + $f1f2_2 = self::mul($f1_2, $f[2], 26); + $f1f3_4 = self::mul($f1_2, $f3_2, 26); + $f1f4_2 = self::mul($f1_2, $f[4], 26); + $f1f5_4 = self::mul($f1_2, $f5_2, 26); + $f1f6_2 = self::mul($f1_2, $f[6], 26); + $f1f7_4 = self::mul($f1_2, $f7_2, 26); + $f1f8_2 = self::mul($f1_2, $f[8], 26); + $f1f9_76 = self::mul($f9_38, $f1_2, 27); + $f2f2 = self::mul($f[2], $f[2], 27); + $f2f3_2 = self::mul($f2_2, $f[3], 27); + $f2f4_2 = self::mul($f2_2, $f[4], 27); + $f2f5_2 = self::mul($f2_2, $f[5], 27); + $f2f6_2 = self::mul($f2_2, $f[6], 27); + $f2f7_2 = self::mul($f2_2, $f[7], 27); + $f2f8_38 = self::mul($f8_19, $f2_2, 27); + $f2f9_38 = self::mul($f9_38, $f[2], 26); + $f3f3_2 = self::mul($f3_2, $f[3], 26); + $f3f4_2 = self::mul($f3_2, $f[4], 26); + $f3f5_4 = self::mul($f3_2, $f5_2, 26); + $f3f6_2 = self::mul($f3_2, $f[6], 26); + $f3f7_76 = self::mul($f7_38, $f3_2, 26); + $f3f8_38 = self::mul($f8_19, $f3_2, 26); + $f3f9_76 = self::mul($f9_38, $f3_2, 26); + $f4f4 = self::mul($f[4], $f[4], 26); + $f4f5_2 = self::mul($f4_2, $f[5], 26); + $f4f6_38 = self::mul($f6_19, $f4_2, 27); + $f4f7_38 = self::mul($f7_38, $f[4], 26); + $f4f8_38 = self::mul($f8_19, $f4_2, 27); + $f4f9_38 = self::mul($f9_38, $f[4], 26); + $f5f5_38 = self::mul($f5_38, $f[5], 26); + $f5f6_38 = self::mul($f6_19, $f5_2, 26); + $f5f7_76 = self::mul($f7_38, $f5_2, 26); + $f5f8_38 = self::mul($f8_19, $f5_2, 26); + $f5f9_76 = self::mul($f9_38, $f5_2, 26); + $f6f6_19 = self::mul($f6_19, $f[6], 26); + $f6f7_38 = self::mul($f7_38, $f[6], 26); + $f6f8_38 = self::mul($f8_19, $f6_2, 27); + $f6f9_38 = self::mul($f9_38, $f[6], 26); + $f7f7_38 = self::mul($f7_38, $f[7], 26); + $f7f8_38 = self::mul($f8_19, $f7_2, 26); + $f7f9_76 = self::mul($f9_38, $f7_2, 26); + $f8f8_19 = self::mul($f8_19, $f[8], 26); + $f8f9_38 = self::mul($f9_38, $f[8], 26); + $f9f9_38 = self::mul($f9_38, $f[9], 26); + $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38; + $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38; + $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19; + $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38; + $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38; + $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38; + $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19; + $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38; + $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38; + $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19, 5); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return self::fe_normalize( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + [$h0, $h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9] + ) + ); + } + + + /** + * Square and double a field element + * + * h = 2 * f * f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f): ParagonIE_Sodium_Core_Curve25519_Fe + { + $f = self::fe_normalize($f); + $f0_2 = $f[0] << 1; + $f1_2 = $f[1] << 1; + $f2_2 = $f[2] << 1; + $f3_2 = $f[3] << 1; + $f4_2 = $f[4] << 1; + $f5_2 = $f[5] << 1; + $f6_2 = $f[6] << 1; + $f7_2 = $f[7] << 1; + $f5_38 = self::mul($f[5], 38, 6); /* 1.959375*2^30 */ + $f6_19 = self::mul($f[6], 19, 5); /* 1.959375*2^30 */ + $f7_38 = self::mul($f[7], 38, 6); /* 1.959375*2^30 */ + $f8_19 = self::mul($f[8], 19, 5); /* 1.959375*2^30 */ + $f9_38 = self::mul($f[9], 38, 6); /* 1.959375*2^30 */ + $f0f0 = self::mul($f[0], $f[0], 24); + $f0f1_2 = self::mul($f0_2, $f[1], 24); + $f0f2_2 = self::mul($f0_2, $f[2], 24); + $f0f3_2 = self::mul($f0_2, $f[3], 24); + $f0f4_2 = self::mul($f0_2, $f[4], 24); + $f0f5_2 = self::mul($f0_2, $f[5], 24); + $f0f6_2 = self::mul($f0_2, $f[6], 24); + $f0f7_2 = self::mul($f0_2, $f[7], 24); + $f0f8_2 = self::mul($f0_2, $f[8], 24); + $f0f9_2 = self::mul($f0_2, $f[9], 24); + $f1f1_2 = self::mul($f1_2, $f[1], 24); + $f1f2_2 = self::mul($f1_2, $f[2], 24); + $f1f3_4 = self::mul($f1_2, $f3_2, 24); + $f1f4_2 = self::mul($f1_2, $f[4], 24); + $f1f5_4 = self::mul($f1_2, $f5_2, 24); + $f1f6_2 = self::mul($f1_2, $f[6], 24); + $f1f7_4 = self::mul($f1_2, $f7_2, 24); + $f1f8_2 = self::mul($f1_2, $f[8], 24); + $f1f9_76 = self::mul($f9_38, $f1_2, 24); + $f2f2 = self::mul($f[2], $f[2], 24); + $f2f3_2 = self::mul($f2_2, $f[3], 24); + $f2f4_2 = self::mul($f2_2, $f[4], 24); + $f2f5_2 = self::mul($f2_2, $f[5], 24); + $f2f6_2 = self::mul($f2_2, $f[6], 24); + $f2f7_2 = self::mul($f2_2, $f[7], 24); + $f2f8_38 = self::mul($f8_19, $f2_2, 25); + $f2f9_38 = self::mul($f9_38, $f[2], 24); + $f3f3_2 = self::mul($f3_2, $f[3], 24); + $f3f4_2 = self::mul($f3_2, $f[4], 24); + $f3f5_4 = self::mul($f3_2, $f5_2, 24); + $f3f6_2 = self::mul($f3_2, $f[6], 24); + $f3f7_76 = self::mul($f7_38, $f3_2, 24); + $f3f8_38 = self::mul($f8_19, $f3_2, 24); + $f3f9_76 = self::mul($f9_38, $f3_2, 24); + $f4f4 = self::mul($f[4], $f[4], 24); + $f4f5_2 = self::mul($f4_2, $f[5], 24); + $f4f6_38 = self::mul($f6_19, $f4_2, 25); + $f4f7_38 = self::mul($f7_38, $f[4], 24); + $f4f8_38 = self::mul($f8_19, $f4_2, 25); + $f4f9_38 = self::mul($f9_38, $f[4], 24); + $f5f5_38 = self::mul($f5_38, $f[5], 24); + $f5f6_38 = self::mul($f6_19, $f5_2, 24); + $f5f7_76 = self::mul($f7_38, $f5_2, 24); + $f5f8_38 = self::mul($f8_19, $f5_2, 24); + $f5f9_76 = self::mul($f9_38, $f5_2, 24); + $f6f6_19 = self::mul($f6_19, $f[6], 24); + $f6f7_38 = self::mul($f7_38, $f[6], 24); + $f6f8_38 = self::mul($f8_19, $f6_2, 25); + $f6f9_38 = self::mul($f9_38, $f[6], 24); + $f7f7_38 = self::mul($f7_38, $f[7], 24); + $f7f8_38 = self::mul($f8_19, $f7_2, 24); + $f7f9_76 = self::mul($f9_38, $f7_2, 24); + $f8f8_19 = self::mul($f8_19, $f[8], 24); + $f8f9_38 = self::mul($f9_38, $f[8], 24); + $f9f9_38 = self::mul($f9_38, $f[9], 24); + + $h0 = ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1; + $h1 = ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1; + $h2 = ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1; + $h3 = ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1; + $h4 = ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1; + $h5 = ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1; + $h6 = ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1; + $h7 = ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1; + $h8 = ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1; + $h9 = ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19, 5); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return self::fe_normalize( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + [$h0, $h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9] + ) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_invert( + ParagonIE_Sodium_Core_Curve25519_Fe $Z + ): ParagonIE_Sodium_Core_Curve25519_Fe { + $t0 = self::fe_sq($Z); + $t1 = self::fe_sq($t0); + $t1 = self::fe_sq($t1); + $t1 = self::fe_mul($Z, $t1); + $t0 = self::fe_mul($t0, $t1); + $t2 = self::fe_sq($t0); + $t1 = self::fe_mul($t1, $t2); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 5; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 10; ++$i) { + $t2 = self::fe_sq($t2); + } + $t2 = self::fe_mul($t2, $t1); + $t3 = self::fe_sq($t2); + for ($i = 1; $i < 20; ++$i) { + $t3 = self::fe_sq($t3); + } + $t2 = self::fe_mul($t3, $t2); + $t2 = self::fe_sq($t2); + for ($i = 1; $i < 10; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 50; ++$i) { + $t2 = self::fe_sq($t2); + } + $t2 = self::fe_mul($t2, $t1); + $t3 = self::fe_sq($t2); + for ($i = 1; $i < 100; ++$i) { + $t3 = self::fe_sq($t3); + } + $t2 = self::fe_mul($t3, $t2); + $t2 = self::fe_sq($t2); + for ($i = 1; $i < 50; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + for ($i = 1; $i < 5; ++$i) { + $t1 = self::fe_sq($t1); + } + return self::fe_mul($t1, $t0); + } + + /** + * @internal You should not use this directly from another application + * + * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106 + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $z + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z): ParagonIE_Sodium_Core_Curve25519_Fe + { + $z = self::fe_normalize($z); + $t0 = self::fe_sq($z); + $t1 = self::fe_sq($t0); + $t1 = self::fe_sq($t1); + $t1 = self::fe_mul($z, $t1); + $t0 = self::fe_mul($t0, $t1); + $t0 = self::fe_sq($t0); + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + for ($i = 1; $i < 5; ++$i) { + $t1 = self::fe_sq($t1); + } + + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + for ($i = 1; $i < 10; ++$i) { + $t1 = self::fe_sq($t1); + } + + $t1 = self::fe_mul($t1, $t0); + $t2 = self::fe_sq($t1); + + for ($i = 1; $i < 20; ++$i) { + $t2 = self::fe_sq($t2); + } + + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + + for ($i = 1; $i < 10; ++$i) { + $t1 = self::fe_sq($t1); + } + + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + for ($i = 1; $i < 50; ++$i) { + $t1 = self::fe_sq($t1); + } + + $t1 = self::fe_mul($t1, $t0); + $t2 = self::fe_sq($t1); + + for ($i = 1; $i < 100; ++$i) { + $t2 = self::fe_sq($t2); + } + + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + + for ($i = 1; $i < 50; ++$i) { + $t1 = self::fe_sq($t1); + } + + $t0 = self::fe_mul($t1, $t0); + $t0 = self::fe_sq($t0); + $t0 = self::fe_sq($t0); + return self::fe_mul($t0, $z); + } + + /** + * Subtract two field elements. + * + * h = f - g + * + * Preconditions: + * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + * Postconditions: + * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @param ParagonIE_Sodium_Core_Curve25519_Fe $g + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sub( + ParagonIE_Sodium_Core_Curve25519_Fe $f, + ParagonIE_Sodium_Core_Curve25519_Fe $g + ): ParagonIE_Sodium_Core_Curve25519_Fe { + return self::fe_normalize( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + ($f[0] - $g[0]), + ($f[1] - $g[1]), + ($f[2] - $g[2]), + ($f[3] - $g[3]), + ($f[4] - $g[4]), + ($f[5] - $g[5]), + ($f[6] - $g[6]), + ($f[7] - $g[7]), + ($f[8] - $g[8]), + ($f[9] - $g[9]) + ) + ) + ); + } + + /** + * Add two group elements. + * + * r = p + q + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_add( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->YplusX); + $r->Y = self::fe_mul($r->Y, $q->YminusX); + $r->T = self::fe_mul($q->T2d, $p->T); + $r->X = self::fe_mul($p->Z, $q->Z); + $t0 = self::fe_add($r->X, $r->X); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_add($t0, $r->T); + $r->T = self::fe_sub($t0, $r->T); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215 + * @param string $a + * @return array + * @throws SodiumException + * @throws TypeError + */ + public static function slide(string $a): array + { + if (self::strlen($a) < 256) { + if (self::strlen($a) < 16) { + $a = str_pad($a, 256, '0'); + } + } + /** @var array $r */ + $r = array(); + + for ($i = 0; $i < 256; ++$i) { + $r[$i] = ( + 1 & ( + self::chrToInt($a[($i >> 3)]) + >> + ($i & 7) + ) + ); + } + + for ($i = 0;$i < 256;++$i) { + if ($r[$i]) { + for ($b = 1;$b <= 6 && $i + $b < 256;++$b) { + if ($r[$i + $b]) { + if ($r[$i] + ($r[$i + $b] << $b) <= 15) { + $r[$i] += $r[$i + $b] << $b; + $r[$i + $b] = 0; + } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) { + $r[$i] -= $r[$i + $b] << $b; + for ($k = $i + $b; $k < 256; ++$k) { + if (!$r[$k]) { + $r[$k] = 1; + break; + } + $r[$k] = 0; + } + } else { + break; + } + } + } + } + } + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $s + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + * @throws SodiumException + * @throws TypeError + */ + public static function ge_frombytes_negate_vartime( + string $s + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + static $d = null; + if (!$d) { + $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D); + } + $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_0(), + self::fe_frombytes($s), + self::fe_1() + ); + + $u = self::fe_sq($h->Y); + $v = self::fe_mul($u, $d); + $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */ + $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */ + + $v3 = self::fe_sq($v); + $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */ + $h->X = self::fe_sq($v3); + $h->X = self::fe_mul($h->X, $v); + $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */ + + $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */ + $h->X = self::fe_mul($h->X, $v3); + $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */ + + $vxx = self::fe_sq($h->X); + $vxx = self::fe_mul($vxx, $v); + $check = self::fe_sub($vxx, $u); /* vx^2 - u */ + + if (self::fe_isnonzero($check)) { + $check = self::fe_add($vxx, $u); /* vx^2 + u */ + if (self::fe_isnonzero($check)) { + throw new RangeException('Internal check failed.'); + } + $h->X = self::fe_mul( + $h->X, + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1) + ); + } + $i = self::chrToInt($s[31]); + if (self::fe_isnegative($h->X) === ($i >> 7)) { + $h->X = self::fe_neg($h->X); + } + + # fe_mul(h->T,h->X,h->Y); + $h->T = self::fe_mul($h->X, $h->Y); + return $h; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_madd( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + $r = clone $R; + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->yplusx); + $r->Y = self::fe_mul($r->Y, $q->yminusx); + $r->T = self::fe_mul($q->xy2d, $p->T); + $t0 = self::fe_add(clone $p->Z, clone $p->Z); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_add($t0, $r->T); + $r->T = self::fe_sub($t0, $r->T); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_msub( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + $r = clone $R; + + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->yminusx); + $r->Y = self::fe_mul($r->Y, $q->yplusx); + $r->T = self::fe_mul($q->xy2d, $p->T); + $t0 = self::fe_add($p->Z, $p->Z); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_sub($t0, $r->T); + $r->T = self::fe_add($t0, $r->T); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p1p1_to_p2( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P2{ + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2(); + $r->X = self::fe_mul($p->X, $p->T); + $r->Y = self::fe_mul($p->Y, $p->Z); + $r->Z = self::fe_mul($p->Z, $p->T); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_p1p1_to_p3( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); + $r->X = self::fe_mul($p->X, $p->T); + $r->Y = self::fe_mul($p->Y, $p->Z); + $r->Z = self::fe_mul($p->Z, $p->T); + $r->T = self::fe_mul($p->X, $p->Y); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p2_0(): ParagonIE_Sodium_Core_Curve25519_Ge_P2 + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( + self::fe_0(), + self::fe_1(), + self::fe_1() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_p2_dbl( + ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + $r->X = self::fe_sq($p->X); + $r->Z = self::fe_sq($p->Y); + $r->T = self::fe_sq2($p->Z); + $r->Y = self::fe_add($p->X, $p->Y); + $t0 = self::fe_sq($r->Y); + $r->Y = self::fe_add($r->Z, $r->X); + $r->Z = self::fe_sub($r->Z, $r->X); + $r->X = self::fe_sub($t0, $r->Y); + $r->T = self::fe_sub($r->T, $r->Z); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_p3_0(): ParagonIE_Sodium_Core_Curve25519_Ge_P3 + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_0(), + self::fe_1(), + self::fe_1(), + self::fe_0() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached + */ + public static function ge_p3_to_cached( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_Cached { + static $d2 = null; + if ($d2 === null) { + $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D2); + } + /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */ + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); + $r->YplusX = self::fe_add($p->Y, $p->X); + $r->YminusX = self::fe_sub($p->Y, $p->X); + $r->Z = clone $p->Z; + $r->T2d = self::fe_mul($p->T, $d2); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p3_to_p2( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P2 { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( + $p->X, + $p->Y, + $p->Z + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function ge_p3_tobytes( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + ): string { + $recip = self::fe_invert($h->Z); + $x = self::fe_mul($h->X, $recip); + $y = self::fe_mul($h->Y, $recip); + $s = self::fe_tobytes($y); + $s[31] = self::intToChr( + self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) + ); + return $s; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_p3_dbl( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + return self::ge_p2_dbl(self::ge_p3_to_p2($p)); + } + + /** + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + */ + public static function ge_precomp_0(): ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + self::fe_1(), + self::fe_1(), + self::fe_0() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $b + * @param int $c + * @return int + */ + public static function equal(int $b, int $c): int + { + return ((($b ^ $c) - 1) >> 31) & 1; + } + + /** + * @internal You should not use this directly from another application + * + * @param int|string $char + * @return int (1 = yes, 0 = no) + * @throws SodiumException + * + * @throws TypeError + */ + public static function negative(int|string $char): int + { + if (is_int($char)) { + return ($char >> 63) & 1; + } + $x = self::chrToInt(self::substr($char, 0, 1)); + return ($x >> 63); + } + + /** + * Conditional move + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + */ + public static function cmov( + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u, + #[SensitiveParameter] + int $b + ): ParagonIE_Sodium_Core_Curve25519_Ge_Precomp { + return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + self::fe_cmov($t->yplusx, $u->yplusx, $b), + self::fe_cmov($t->yminusx, $u->yminusx, $b), + self::fe_cmov($t->xy2d, $u->xy2d, $b) + ); + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached + */ + public static function ge_cmov_cached( + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t, + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u, + #[SensitiveParameter] + int $b + ): ParagonIE_Sodium_Core_Curve25519_Ge_Cached { + $b &= 1; + $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); + $ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b); + $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b); + $ret->Z = self::fe_cmov($t->Z, $u->Z, $b); + $ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b); + return $ret; + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached + * @throws SodiumException + */ + public static function ge_cmov8_cached( + array $cached, + #[SensitiveParameter] + int $b + ): ParagonIE_Sodium_Core_Curve25519_Ge_Cached { + $bNegative = self::negative($b); + $babs = $b - (((-$bNegative) & $b) << 1); + + $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( + self::fe_1(), + self::fe_1(), + self::fe_1(), + self::fe_0() + ); + + for ($x = 0; $x < 8; ++$x) { + $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1)); + } + + $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( + $t->YminusX, + $t->YplusX, + $t->Z, + self::fe_neg($t->T2d) + ); + return self::ge_cmov_cached($t, $minust, $bNegative); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $pos + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + * @throws SodiumException + * @throws TypeError + */ + public static function ge_select(int $pos = 0, int $b = 0): ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + { + static $base = null; + if ($base === null) { + $base = array(); + /** @var int $i */ + foreach (self::BASE as $i => $bas) { + for ($j = 0; $j < 8; ++$j) { + $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2]) + ); + } + } + } + /** @var array> $base */ + if ($pos < 0 || $pos > 31) { + throw new RangeException('Position is out of range [0, 31]'); + } + + $bnegative = self::negative($b); + $babs = $b - (((-$bnegative) & $b) << 1); + + $t = self::ge_precomp_0(); + for ($i = 0; $i < 8; ++$i) { + $t = self::cmov( + $t, + $base[$pos][$i], + self::equal($babs, $i + 1) + ); + } + $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + $t->yminusx, + $t->yplusx, + self::fe_neg($t->xy2d) + ); + return self::cmov($t, $minusT, $bnegative); + } + + /** + * Subtract two group elements. + * + * r = p - q + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_sub( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + ): ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->YminusX); + $r->Y = self::fe_mul($r->Y, $q->YplusX); + $r->T = self::fe_mul($q->T2d, $p->T); + $r->X = self::fe_mul($p->Z, $q->Z); + $t0 = self::fe_add($r->X, $r->X); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_sub($t0, $r->T); + $r->T = self::fe_add($t0, $r->T); + + return $r; + } + + /** + * Convert a group element to a byte string. + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h): string + { + $recip = self::fe_invert($h->Z); + $x = self::fe_mul($h->X, $recip); + $y = self::fe_mul($h->Y, $recip); + $s = self::fe_tobytes($y); + $s[31] = self::intToChr( + self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) + ); + return $s; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $a + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A + * @param string $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + * @throws SodiumException + * @throws TypeError + */ + public static function ge_double_scalarmult_vartime( + string $a, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A, + string $b + ): ParagonIE_Sodium_Core_Curve25519_Ge_P2 { + /** @var array $Ai */ + $Ai = array(); + + /** @var array $Bi */ + static $Bi = array(); + if (!$Bi) { + for ($i = 0; $i < 8; ++$i) { + $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::BASE2[$i][0]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::BASE2[$i][1]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::BASE2[$i][2]) + ); + } + } + for ($i = 0; $i < 8; ++$i) { + $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( + self::fe_0(), + self::fe_0(), + self::fe_0(), + self::fe_0() + ); + } + + /** @var array $aslide */ + $aslide = self::slide($a); + /** @var array $bslide */ + $bslide = self::slide($b); + + $Ai[0] = self::ge_p3_to_cached($A); + $t = self::ge_p3_dbl($A); + $A2 = self::ge_p1p1_to_p3($t); + + for ($i = 0; $i < 7; ++$i) { + $t = self::ge_add($A2, $Ai[$i]); + $u = self::ge_p1p1_to_p3($t); + $Ai[$i + 1] = self::ge_p3_to_cached($u); + } + $r = self::ge_p2_0(); + $i = 255; + for (; $i >= 0; --$i) { + if ($aslide[$i] || $bslide[$i]) { + break; + } + } + + for (; $i >= 0; --$i) { + $t = self::ge_p2_dbl($r); + + if ($aslide[$i] > 0) { + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_add( + $u, + $Ai[(int) floor($aslide[$i] / 2)] + ); + } elseif ($aslide[$i] < 0) { + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_sub( + $u, + $Ai[(int) floor(-$aslide[$i] / 2)] + ); + } + + if ($bslide[$i] > 0) { + $index = (int) floor($bslide[$i] / 2); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_madd($t, $u, $Bi[$index]); + # } else if (bslide[i] < 0) { + } elseif ($bslide[$i] < 0) { + $index = (int) floor(-$bslide[$i] / 2); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_msub($t, $u, $Bi[$index]); + } + $r = self::ge_p1p1_to_p2($t); + } + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $a + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + * @throws SodiumException + * @throws TypeError + */ + public static function ge_scalarmult( + #[SensitiveParameter] + string $a, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + $e = array_fill(0, 64, 0); + + /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */ + $pi = array(); + + $pi[0] = self::ge_p3_to_cached($p); + + $t2 = self::ge_p3_dbl($p); + $p2 = self::ge_p1p1_to_p3($t2); + $pi[1] = self::ge_p3_to_cached($p2); + + $t3 = self::ge_add($p, $pi[1]); + $p3 = self::ge_p1p1_to_p3($t3); + $pi[2] = self::ge_p3_to_cached($p3); + + $t4 = self::ge_p3_dbl($p2); + $p4 = self::ge_p1p1_to_p3($t4); + $pi[3] = self::ge_p3_to_cached($p4); + + $t5 = self::ge_add($p, $pi[3]); + $p5 = self::ge_p1p1_to_p3($t5); + $pi[4] = self::ge_p3_to_cached($p5); + + $t6 = self::ge_p3_dbl($p3); + $p6 = self::ge_p1p1_to_p3($t6); + $pi[5] = self::ge_p3_to_cached($p6); + + $t7 = self::ge_add($p, $pi[5]); + $p7 = self::ge_p1p1_to_p3($t7); + $pi[6] = self::ge_p3_to_cached($p7); + + $t8 = self::ge_p3_dbl($p4); + $p8 = self::ge_p1p1_to_p3($t8); + $pi[7] = self::ge_p3_to_cached($p8); + + for ($i = 0; $i < 32; ++$i) { + $e[($i << 1) ] = self::chrToInt($a[$i]) & 15; + $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15; + } + // /* each e[i] is between 0 and 15 */ + // /* e[63] is between 0 and 7 */ + $carry = 0; + for ($i = 0; $i < 63; ++$i) { + $e[$i] += $carry; + $carry = $e[$i] + 8; + $carry >>= 4; + $e[$i] -= $carry << 4; + } + $e[63] += $carry; + + $h = self::ge_p3_0(); + + for ($i = 63; $i != 0; --$i) { + $t = self::ge_cmov8_cached($pi, $e[$i]); + $r = self::ge_add($h, $t); + + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + + $h = self::ge_p1p1_to_p3($r); /* *16 */ + } + + $t = self::ge_cmov8_cached($pi, $e[0]); + $r = self::ge_add($h, $t); + return self::ge_p1p1_to_p3($r); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $a + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + * @throws SodiumException + * @throws TypeError + */ + public static function ge_scalarmult_base( + #[SensitiveParameter] + string $a + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + /** @var array $e */ + $e = array(); + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + for ($i = 0; $i < 32; ++$i) { + $dbl = $i << 1; + $e[$dbl] = self::chrToInt($a[$i]) & 15; + $e[$dbl + 1] = (self::chrToInt($a[$i]) >> 4) & 15; + } + + $carry = 0; + for ($i = 0; $i < 63; ++$i) { + $e[$i] += $carry; + $carry = $e[$i] + 8; + $carry >>= 4; + $e[$i] -= $carry << 4; + } + $e[63] += $carry; + + $h = self::ge_p3_0(); + + for ($i = 1; $i < 64; $i += 2) { + $t = self::ge_select((int) floor($i / 2), (int) $e[$i]); + $r = self::ge_madd($r, $h, $t); + $h = self::ge_p1p1_to_p3($r); + } + + $r = self::ge_p3_dbl($h); + + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + + $h = self::ge_p1p1_to_p3($r); + + for ($i = 0; $i < 64; $i += 2) { + $t = self::ge_select($i >> 1, (int) $e[$i]); + $r = self::ge_madd($r, $h, $t); + $h = self::ge_p1p1_to_p3($r); + } + return $h; + } + + /** + * Calculates (ab + c) mod l + * where l = 2^252 + 27742317777372353535851937790883648493 + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @param string $c + * @return string + * @throws TypeError + */ + public static function sc_muladd( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b, + #[SensitiveParameter] + string $c + ): string { + $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); + $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); + $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); + $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); + $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); + $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); + $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); + $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); + $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); + $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); + $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); + $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); + + $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); + $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); + $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); + $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); + $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); + $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); + $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); + $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); + $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); + $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); + $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); + $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); + + $c0 = 2097151 & self::load_3(self::substr($c, 0, 3)); + $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5); + $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2); + $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7); + $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4); + $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1); + $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6); + $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3); + $c8 = 2097151 & self::load_3(self::substr($c, 21, 3)); + $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5); + $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2); + $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7); + + /* Can't really avoid the pyramid here: */ + $s0 = $c0 + self::mul($a0, $b0, 24); + $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24); + $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24); + $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24); + $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) + + self::mul($a4, $b0, 24); + $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) + + self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24); + $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) + + self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24); + $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) + + self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24); + $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) + + self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) + + self::mul($a8, $b0, 24); + $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) + + self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) + + self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24); + $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) + + self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) + + self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24); + $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) + + self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) + + self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24); + $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) + + self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) + + self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24); + $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) + + self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) + + self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24); + $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) + + self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) + + self::mul($a11, $b3, 24); + $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) + + self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24); + $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) + + self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24); + $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) + + self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24); + $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) + + self::mul($a11, $b7, 24); + $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24); + $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24); + $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24); + $s22 = self::mul($a11, $b11, 24); + $s23 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= $carry12 << 21; + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= $carry14 << 21; + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= $carry16 << 21; + $carry18 = ($s18 + (1 << 20)) >> 21; + $s19 += $carry18; + $s18 -= $carry18 << 21; + $carry20 = ($s20 + (1 << 20)) >> 21; + $s21 += $carry20; + $s20 -= $carry20 << 21; + $carry22 = ($s22 + (1 << 20)) >> 21; + $s23 += $carry22; + $s22 -= $carry22 << 21; + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= $carry13 << 21; + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= $carry15 << 21; + $carry17 = ($s17 + (1 << 20)) >> 21; + $s18 += $carry17; + $s17 -= $carry17 << 21; + $carry19 = ($s19 + (1 << 20)) >> 21; + $s20 += $carry19; + $s19 -= $carry19 << 21; + $carry21 = ($s21 + (1 << 20)) >> 21; + $s22 += $carry21; + $s21 -= $carry21 << 21; + + $s11 += self::mul($s23, 666643, 20); + $s12 += self::mul($s23, 470296, 19); + $s13 += self::mul($s23, 654183, 20); + $s14 -= self::mul($s23, 997805, 20); + $s15 += self::mul($s23, 136657, 18); + $s16 -= self::mul($s23, 683901, 20); + + $s10 += self::mul($s22, 666643, 20); + $s11 += self::mul($s22, 470296, 19); + $s12 += self::mul($s22, 654183, 20); + $s13 -= self::mul($s22, 997805, 20); + $s14 += self::mul($s22, 136657, 18); + $s15 -= self::mul($s22, 683901, 20); + + $s9 += self::mul($s21, 666643, 20); + $s10 += self::mul($s21, 470296, 19); + $s11 += self::mul($s21, 654183, 20); + $s12 -= self::mul($s21, 997805, 20); + $s13 += self::mul($s21, 136657, 18); + $s14 -= self::mul($s21, 683901, 20); + + $s8 += self::mul($s20, 666643, 20); + $s9 += self::mul($s20, 470296, 19); + $s10 += self::mul($s20, 654183, 20); + $s11 -= self::mul($s20, 997805, 20); + $s12 += self::mul($s20, 136657, 18); + $s13 -= self::mul($s20, 683901, 20); + + $s7 += self::mul($s19, 666643, 20); + $s8 += self::mul($s19, 470296, 19); + $s9 += self::mul($s19, 654183, 20); + $s10 -= self::mul($s19, 997805, 20); + $s11 += self::mul($s19, 136657, 18); + $s12 -= self::mul($s19, 683901, 20); + + $s6 += self::mul($s18, 666643, 20); + $s7 += self::mul($s18, 470296, 19); + $s8 += self::mul($s18, 654183, 20); + $s9 -= self::mul($s18, 997805, 20); + $s10 += self::mul($s18, 136657, 18); + $s11 -= self::mul($s18, 683901, 20); + + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= $carry12 << 21; + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= $carry14 << 21; + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= $carry16 << 21; + + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= $carry13 << 21; + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= $carry15 << 21; + + $s5 += self::mul($s17, 666643, 20); + $s6 += self::mul($s17, 470296, 19); + $s7 += self::mul($s17, 654183, 20); + $s8 -= self::mul($s17, 997805, 20); + $s9 += self::mul($s17, 136657, 18); + $s10 -= self::mul($s17, 683901, 20); + + $s4 += self::mul($s16, 666643, 20); + $s5 += self::mul($s16, 470296, 19); + $s6 += self::mul($s16, 654183, 20); + $s7 -= self::mul($s16, 997805, 20); + $s8 += self::mul($s16, 136657, 18); + $s9 -= self::mul($s16, 683901, 20); + + $s3 += self::mul($s15, 666643, 20); + $s4 += self::mul($s15, 470296, 19); + $s5 += self::mul($s15, 654183, 20); + $s6 -= self::mul($s15, 997805, 20); + $s7 += self::mul($s15, 136657, 18); + $s8 -= self::mul($s15, 683901, 20); + + $s2 += self::mul($s14, 666643, 20); + $s3 += self::mul($s14, 470296, 19); + $s4 += self::mul($s14, 654183, 20); + $s5 -= self::mul($s14, 997805, 20); + $s6 += self::mul($s14, 136657, 18); + $s7 -= self::mul($s14, 683901, 20); + + $s1 += self::mul($s13, 666643, 20); + $s2 += self::mul($s13, 470296, 19); + $s3 += self::mul($s13, 654183, 20); + $s4 -= self::mul($s13, 997805, 20); + $s5 += self::mul($s13, 136657, 18); + $s6 -= self::mul($s13, 683901, 20); + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry11 = $s11 >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + return self::intArrayToString([ + (0xff & ($s0 >> 0)), + (0xff & ($s0 >> 8)), + (0xff & (($s0 >> 16) | $s1 << 5)), + (0xff & ($s1 >> 3)), + (0xff & ($s1 >> 11)), + (0xff & (($s1 >> 19) | $s2 << 2)), + (0xff & ($s2 >> 6)), + (0xff & (($s2 >> 14) | $s3 << 7)), + (0xff & ($s3 >> 1)), + (0xff & ($s3 >> 9)), + (0xff & (($s3 >> 17) | $s4 << 4)), + (0xff & ($s4 >> 4)), + (0xff & ($s4 >> 12)), + (0xff & (($s4 >> 20) | $s5 << 1)), + (0xff & ($s5 >> 7)), + (0xff & (($s5 >> 15) | $s6 << 6)), + (0xff & ($s6 >> 2)), + (0xff & ($s6 >> 10)), + (0xff & (($s6 >> 18) | $s7 << 3)), + (0xff & ($s7 >> 5)), + (0xff & ($s7 >> 13)), + (0xff & ($s8 >> 0)), + (0xff & ($s8 >> 8)), + (0xff & (($s8 >> 16) | $s9 << 5)), + (0xff & ($s9 >> 3)), + (0xff & ($s9 >> 11)), + (0xff & (($s9 >> 19) | $s10 << 2)), + (0xff & ($s10 >> 6)), + (0xff & (($s10 >> 14) | $s11 << 7)), + (0xff & ($s11 >> 1)), + (0xff & ($s11 >> 9)), + 0xff & ($s11 >> 17) + ]); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $s + * @return string + * @throws TypeError + */ + public static function sc_reduce( + #[SensitiveParameter] + string $s + ): string { + $s0 = 2097151 & self::load_3(self::substr($s, 0, 3)); + $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5); + $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2); + $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7); + $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4); + $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1); + $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6); + $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3); + $s8 = 2097151 & self::load_3(self::substr($s, 21, 3)); + $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5); + $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2); + $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7); + $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4); + $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1); + $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6); + $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3); + $s16 = 2097151 & self::load_3(self::substr($s, 42, 3)); + $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5); + $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2); + $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7); + $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4); + $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1); + $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6); + $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3); + + $s11 += self::mul($s23, 666643, 20); + $s12 += self::mul($s23, 470296, 19); + $s13 += self::mul($s23, 654183, 20); + $s14 -= self::mul($s23, 997805, 20); + $s15 += self::mul($s23, 136657, 18); + $s16 -= self::mul($s23, 683901, 20); + + $s10 += self::mul($s22, 666643, 20); + $s11 += self::mul($s22, 470296, 19); + $s12 += self::mul($s22, 654183, 20); + $s13 -= self::mul($s22, 997805, 20); + $s14 += self::mul($s22, 136657, 18); + $s15 -= self::mul($s22, 683901, 20); + + $s9 += self::mul($s21, 666643, 20); + $s10 += self::mul($s21, 470296, 19); + $s11 += self::mul($s21, 654183, 20); + $s12 -= self::mul($s21, 997805, 20); + $s13 += self::mul($s21, 136657, 18); + $s14 -= self::mul($s21, 683901, 20); + + $s8 += self::mul($s20, 666643, 20); + $s9 += self::mul($s20, 470296, 19); + $s10 += self::mul($s20, 654183, 20); + $s11 -= self::mul($s20, 997805, 20); + $s12 += self::mul($s20, 136657, 18); + $s13 -= self::mul($s20, 683901, 20); + + $s7 += self::mul($s19, 666643, 20); + $s8 += self::mul($s19, 470296, 19); + $s9 += self::mul($s19, 654183, 20); + $s10 -= self::mul($s19, 997805, 20); + $s11 += self::mul($s19, 136657, 18); + $s12 -= self::mul($s19, 683901, 20); + + $s6 += self::mul($s18, 666643, 20); + $s7 += self::mul($s18, 470296, 19); + $s8 += self::mul($s18, 654183, 20); + $s9 -= self::mul($s18, 997805, 20); + $s10 += self::mul($s18, 136657, 18); + $s11 -= self::mul($s18, 683901, 20); + + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= $carry12 << 21; + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= $carry14 << 21; + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= $carry16 << 21; + + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= $carry13 << 21; + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= $carry15 << 21; + + $s5 += self::mul($s17, 666643, 20); + $s6 += self::mul($s17, 470296, 19); + $s7 += self::mul($s17, 654183, 20); + $s8 -= self::mul($s17, 997805, 20); + $s9 += self::mul($s17, 136657, 18); + $s10 -= self::mul($s17, 683901, 20); + + $s4 += self::mul($s16, 666643, 20); + $s5 += self::mul($s16, 470296, 19); + $s6 += self::mul($s16, 654183, 20); + $s7 -= self::mul($s16, 997805, 20); + $s8 += self::mul($s16, 136657, 18); + $s9 -= self::mul($s16, 683901, 20); + + $s3 += self::mul($s15, 666643, 20); + $s4 += self::mul($s15, 470296, 19); + $s5 += self::mul($s15, 654183, 20); + $s6 -= self::mul($s15, 997805, 20); + $s7 += self::mul($s15, 136657, 18); + $s8 -= self::mul($s15, 683901, 20); + + $s2 += self::mul($s14, 666643, 20); + $s3 += self::mul($s14, 470296, 19); + $s4 += self::mul($s14, 654183, 20); + $s5 -= self::mul($s14, 997805, 20); + $s6 += self::mul($s14, 136657, 18); + $s7 -= self::mul($s14, 683901, 20); + + $s1 += self::mul($s13, 666643, 20); + $s2 += self::mul($s13, 470296, 19); + $s3 += self::mul($s13, 654183, 20); + $s4 -= self::mul($s13, 997805, 20); + $s5 += self::mul($s13, 136657, 18); + $s6 -= self::mul($s13, 683901, 20); + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry11 = $s11 >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + return self::intArrayToString([ + ($s0 >> 0), + ($s0 >> 8), + (($s0 >> 16) | $s1 << 5), + ($s1 >> 3), + ($s1 >> 11), + (($s1 >> 19) | $s2 << 2), + ($s2 >> 6), + (($s2 >> 14) | $s3 << 7), + ($s3 >> 1), + ($s3 >> 9), + (($s3 >> 17) | $s4 << 4), + ($s4 >> 4), + ($s4 >> 12), + (($s4 >> 20) | $s5 << 1), + ($s5 >> 7), + (($s5 >> 15) | $s6 << 6), + ($s6 >> 2), + ($s6 >> 10), + (($s6 >> 18) | $s7 << 3), + ($s7 >> 5), + ($s7 >> 13), + ($s8 >> 0), + ($s8 >> 8), + (($s8 >> 16) | $s9 << 5), + ($s9 >> 3), + ($s9 >> 11), + (($s9 >> 19) | $s10 << 2), + ($s10 >> 6), + (($s10 >> 14) | $s11 << 7), + ($s11 >> 1), + ($s11 >> 9), + $s11 >> 17 + ]); + } + + /** + * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_mul_l( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + $aslide = array( + 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, + 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, + 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, + 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + ); + + /** @var array $Ai size 8 */ + $Ai = array(); + + $Ai[0] = self::ge_p3_to_cached($A); + $t = self::ge_p3_dbl($A); + $A2 = self::ge_p1p1_to_p3($t); + + for ($i = 1; $i < 8; ++$i) { + $t = self::ge_add($A2, $Ai[$i - 1]); + $u = self::ge_p1p1_to_p3($t); + $Ai[$i] = self::ge_p3_to_cached($u); + } + + $r = self::ge_p3_0(); + for ($i = 252; $i >= 0; --$i) { + $t = self::ge_p3_dbl($r); + if ($aslide[$i] > 0) { + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]); + } elseif ($aslide[$i] < 0) { + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]); + } + } + + return self::ge_p1p1_to_p3($t); + } + + /** + * @param string $a + * @param string $b + * @return string + */ + public static function sc25519_mul( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): string { + $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); + $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); + $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); + $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); + $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); + $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); + $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); + $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); + $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); + $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); + $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); + $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); + + $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); + $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); + $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); + $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); + $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); + $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); + $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); + $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); + $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); + $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); + $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); + $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); + + $s0 = self::mul($a0, $b0, 22); + $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22); + $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22); + $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22); + $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) + + self::mul($a4, $b0, 22); + $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) + + self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22); + $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) + + self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22); + $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) + + self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22); + $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) + + self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) + + self::mul($a8, $b0, 22); + $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) + + self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) + + self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22); + $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) + + self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) + + self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22); + $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) + + self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) + + self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22); + $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) + + self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) + + self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22); + $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) + + self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) + + self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22); + $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) + + self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) + + self::mul($a11, $b3, 22); + $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) + + self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22); + $s16 = + self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) + + self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22); + $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) + + self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22); + $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22) + + self::mul($a11, $b7, 22); + $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) + + self::mul($a11, $b8, 22); + $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22); + $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22); + $s22 = self::mul($a11, $b11, 22); + $s23 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= $carry12 << 21; + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= $carry14 << 21; + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= $carry16 << 21; + $carry18 = ($s18 + (1 << 20)) >> 21; + $s19 += $carry18; + $s18 -= $carry18 << 21; + $carry20 = ($s20 + (1 << 20)) >> 21; + $s21 += $carry20; + $s20 -= $carry20 << 21; + $carry22 = ($s22 + (1 << 20)) >> 21; + $s23 += $carry22; + $s22 -= $carry22 << 21; + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= $carry13 << 21; + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= $carry15 << 21; + $carry17 = ($s17 + (1 << 20)) >> 21; + $s18 += $carry17; + $s17 -= $carry17 << 21; + $carry19 = ($s19 + (1 << 20)) >> 21; + $s20 += $carry19; + $s19 -= $carry19 << 21; + $carry21 = ($s21 + (1 << 20)) >> 21; + $s22 += $carry21; + $s21 -= $carry21 << 21; + + $s11 += self::mul($s23, 666643, 20); + $s12 += self::mul($s23, 470296, 19); + $s13 += self::mul($s23, 654183, 20); + $s14 -= self::mul($s23, 997805, 20); + $s15 += self::mul($s23, 136657, 18); + $s16 -= self::mul($s23, 683901, 20); + + $s10 += self::mul($s22, 666643, 20); + $s11 += self::mul($s22, 470296, 19); + $s12 += self::mul($s22, 654183, 20); + $s13 -= self::mul($s22, 997805, 20); + $s14 += self::mul($s22, 136657, 18); + $s15 -= self::mul($s22, 683901, 20); + + $s9 += self::mul($s21, 666643, 20); + $s10 += self::mul($s21, 470296, 19); + $s11 += self::mul($s21, 654183, 20); + $s12 -= self::mul($s21, 997805, 20); + $s13 += self::mul($s21, 136657, 18); + $s14 -= self::mul($s21, 683901, 20); + + $s8 += self::mul($s20, 666643, 20); + $s9 += self::mul($s20, 470296, 19); + $s10 += self::mul($s20, 654183, 20); + $s11 -= self::mul($s20, 997805, 20); + $s12 += self::mul($s20, 136657, 18); + $s13 -= self::mul($s20, 683901, 20); + + $s7 += self::mul($s19, 666643, 20); + $s8 += self::mul($s19, 470296, 19); + $s9 += self::mul($s19, 654183, 20); + $s10 -= self::mul($s19, 997805, 20); + $s11 += self::mul($s19, 136657, 18); + $s12 -= self::mul($s19, 683901, 20); + + $s6 += self::mul($s18, 666643, 20); + $s7 += self::mul($s18, 470296, 19); + $s8 += self::mul($s18, 654183, 20); + $s9 -= self::mul($s18, 997805, 20); + $s10 += self::mul($s18, 136657, 18); + $s11 -= self::mul($s18, 683901, 20); + + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= $carry12 << 21; + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= $carry14 << 21; + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= $carry16 << 21; + + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= $carry13 << 21; + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= $carry15 << 21; + + $s5 += self::mul($s17, 666643, 20); + $s6 += self::mul($s17, 470296, 19); + $s7 += self::mul($s17, 654183, 20); + $s8 -= self::mul($s17, 997805, 20); + $s9 += self::mul($s17, 136657, 18); + $s10 -= self::mul($s17, 683901, 20); + + $s4 += self::mul($s16, 666643, 20); + $s5 += self::mul($s16, 470296, 19); + $s6 += self::mul($s16, 654183, 20); + $s7 -= self::mul($s16, 997805, 20); + $s8 += self::mul($s16, 136657, 18); + $s9 -= self::mul($s16, 683901, 20); + + $s3 += self::mul($s15, 666643, 20); + $s4 += self::mul($s15, 470296, 19); + $s5 += self::mul($s15, 654183, 20); + $s6 -= self::mul($s15, 997805, 20); + $s7 += self::mul($s15, 136657, 18); + $s8 -= self::mul($s15, 683901, 20); + + $s2 += self::mul($s14, 666643, 20); + $s3 += self::mul($s14, 470296, 19); + $s4 += self::mul($s14, 654183, 20); + $s5 -= self::mul($s14, 997805, 20); + $s6 += self::mul($s14, 136657, 18); + $s7 -= self::mul($s14, 683901, 20); + + $s1 += self::mul($s13, 666643, 20); + $s2 += self::mul($s13, 470296, 19); + $s3 += self::mul($s13, 654183, 20); + $s4 -= self::mul($s13, 997805, 20); + $s5 += self::mul($s13, 136657, 18); + $s6 -= self::mul($s13, 683901, 20); + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + $s12 = 0; + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + $carry11 = $s11 >> 21; + $s12 += $carry11; + $s11 -= $carry11 << 21; + + $s0 += self::mul($s12, 666643, 20); + $s1 += self::mul($s12, 470296, 19); + $s2 += self::mul($s12, 654183, 20); + $s3 -= self::mul($s12, 997805, 20); + $s4 += self::mul($s12, 136657, 18); + $s5 -= self::mul($s12, 683901, 20); + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= $carry0 << 21; + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= $carry1 << 21; + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= $carry2 << 21; + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= $carry3 << 21; + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= $carry4 << 21; + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= $carry5 << 21; + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= $carry6 << 21; + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= $carry7 << 21; + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= $carry8 << 21; + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= $carry9 << 21; + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= $carry10 << 21; + + $s = array_fill(0, 32, 0); + $s[0] = $s0 >> 0; + $s[1] = $s0 >> 8; + $s[2] = ($s0 >> 16) | ($s1 << 5); + $s[3] = $s1 >> 3; + $s[4] = $s1 >> 11; + $s[5] = ($s1 >> 19) | ($s2 << 2); + $s[6] = $s2 >> 6; + $s[7] = ($s2 >> 14) | ($s3 << 7); + $s[8] = $s3 >> 1; + $s[9] = $s3 >> 9; + $s[10] = ($s3 >> 17) | ($s4 << 4); + $s[11] = $s4 >> 4; + $s[12] = $s4 >> 12; + $s[13] = ($s4 >> 20) | ($s5 << 1); + $s[14] = $s5 >> 7; + $s[15] = ($s5 >> 15) | ($s6 << 6); + $s[16] = $s6 >> 2; + $s[17] = $s6 >> 10; + $s[18] = ($s6 >> 18) | ($s7 << 3); + $s[19] = $s7 >> 5; + $s[20] = $s7 >> 13; + $s[21] = $s8 >> 0; + $s[22] = $s8 >> 8; + $s[23] = ($s8 >> 16) | ($s9 << 5); + $s[24] = $s9 >> 3; + $s[25] = $s9 >> 11; + $s[26] = ($s9 >> 19) | ($s10 << 2); + $s[27] = $s10 >> 6; + $s[28] = ($s10 >> 14) | ($s11 << 7); + $s[29] = $s11 >> 1; + $s[30] = $s11 >> 9; + $s[31] = $s11 >> 17; + return self::intArrayToString($s); + } + + /** + * @param string $s + * @return string + */ + public static function sc25519_sq( + #[SensitiveParameter] + string $s + ): string { + return self::sc25519_mul($s, $s); + } + + /** + * @param string $s + * @param int $n + * @param string $a + * @return string + */ + public static function sc25519_sqmul( + #[SensitiveParameter] + string $s, + int $n, + #[SensitiveParameter] + string $a + ): string { + for ($i = 0; $i < $n; ++$i) { + $s = self::sc25519_sq($s); + } + return self::sc25519_mul($s, $a); + } + + /** + * @param string $s + * @return string + */ + public static function sc25519_invert( + #[SensitiveParameter] + string $s + ): string { + $_10 = self::sc25519_sq($s); + $_11 = self::sc25519_mul($s, $_10); + $_100 = self::sc25519_mul($s, $_11); + $_1000 = self::sc25519_sq($_100); + $_1010 = self::sc25519_mul($_10, $_1000); + $_1011 = self::sc25519_mul($s, $_1010); + $_10000 = self::sc25519_sq($_1000); + $_10110 = self::sc25519_sq($_1011); + $_100000 = self::sc25519_mul($_1010, $_10110); + $_100110 = self::sc25519_mul($_10000, $_10110); + $_1000000 = self::sc25519_sq($_100000); + $_1010000 = self::sc25519_mul($_10000, $_1000000); + $_1010011 = self::sc25519_mul($_11, $_1010000); + $_1100011 = self::sc25519_mul($_10000, $_1010011); + $_1100111 = self::sc25519_mul($_100, $_1100011); + $_1101011 = self::sc25519_mul($_100, $_1100111); + $_10010011 = self::sc25519_mul($_1000000, $_1010011); + $_10010111 = self::sc25519_mul($_100, $_10010011); + $_10111101 = self::sc25519_mul($_100110, $_10010111); + $_11010011 = self::sc25519_mul($_10110, $_10111101); + $_11100111 = self::sc25519_mul($_1010000, $_10010111); + $_11101011 = self::sc25519_mul($_100, $_11100111); + $_11110101 = self::sc25519_mul($_1010, $_11101011); + + $recip = self::sc25519_mul($_1011, $_11110101); + $recip = self::sc25519_sqmul($recip, 126, $_1010011); + $recip = self::sc25519_sqmul($recip, 9, $_10); + $recip = self::sc25519_mul($recip, $_11110101); + $recip = self::sc25519_sqmul($recip, 7, $_1100111); + $recip = self::sc25519_sqmul($recip, 9, $_11110101); + $recip = self::sc25519_sqmul($recip, 11, $_10111101); + $recip = self::sc25519_sqmul($recip, 8, $_11100111); + $recip = self::sc25519_sqmul($recip, 9, $_1101011); + $recip = self::sc25519_sqmul($recip, 6, $_1011); + $recip = self::sc25519_sqmul($recip, 14, $_10010011); + $recip = self::sc25519_sqmul($recip, 10, $_1100011); + $recip = self::sc25519_sqmul($recip, 9, $_10010111); + $recip = self::sc25519_sqmul($recip, 10, $_11110101); + $recip = self::sc25519_sqmul($recip, 8, $_11010011); + return self::sc25519_sqmul($recip, 8, $_11101011); + } + + /** + * Ensure limbs are less than 28 bits long to prevent float promotion. + * + * This uses a constant-time conditional swap under the hood. + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_normalize( + ParagonIE_Sodium_Core_Curve25519_Fe $f + ): ParagonIE_Sodium_Core_Curve25519_Fe { + $x = (PHP_INT_SIZE << 3) - 1; // 31 or 63 + + $g = $f; + for ($i = 0; $i < 10; ++$i) { + $mask = -(($g[$i] >> $x) & 1); + + /* + * Get two candidate normalized values for $g[$i], depending on the sign of $g[$i]: + */ + $a = $g[$i] & 0x7ffffff; + $b = -((-$g[$i]) & 0x7ffffff); + + /* + * Return the appropriate candidate value, based on the sign of the original input: + * + * The following is equivalent to this ternary: + * + * $g[$i] = (($g[$i] >> $x) & 1) ? $a : $b; + * + * Except what's written doesn't contain timing leaks. + */ + $g[$i] = ($a ^ (($a ^ $b) & $mask)); + } + return $g; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Fe.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Fe.php new file mode 100644 index 000000000..4569ce234 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Fe.php @@ -0,0 +1,124 @@ + + */ + protected array $container = []; + + /** + * @var int + */ + protected int $size = 10; + + /** + * @internal You should not use this directly from another application + * + * @param array $array + * @param bool $save_indexes + * @return self + */ + public static function fromArray(array $array, bool $save_indexes = false): self + { + $count = count($array); + if ($save_indexes) { + $keys = array_keys($array); + } else { + $keys = range(0, $count - 1); + } + $array = array_values($array); + /** @var array $keys */ + + $obj = new ParagonIE_Sodium_Core_Curve25519_Fe(); + if ($save_indexes) { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($keys[$i], $array[$i]); + } + } else { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($i, $array[$i]); + } + } + return $obj; + } + + /** + * @internal You should not use this directly from another application + * + * @param int|null $offset + * @param int $value + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value): void + { + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset): bool + { + return isset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset): void + { + unset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @return int + * @psalm-suppress ImplementedReturnTypeMismatch + */ + #[ReturnTypeWillChange] + public function offsetGet($offset): int + { + if (!isset($this->container[$offset])) { + $this->container[$offset] = 0; + } + return $this->container[$offset]; + } + + /** + * @internal You should not use this directly from another application + * + * @return array + */ + public function __debugInfo() + { + return array(implode(', ', $this->container)); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php new file mode 100644 index 000000000..a18884885 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php @@ -0,0 +1,50 @@ +YplusX = $YplusX; + if ($YminusX === null) { + $YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->YminusX = $YminusX; + if ($Z === null) { + $Z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $Z; + if ($T2d === null) { + $T2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T2d = $T2d; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php new file mode 100644 index 000000000..02c255383 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php @@ -0,0 +1,50 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + if ($t === null) { + $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T = $t; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php new file mode 100644 index 000000000..aa2a1c4f8 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php @@ -0,0 +1,44 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php new file mode 100644 index 000000000..2474bf31a --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php @@ -0,0 +1,51 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + if ($t === null) { + $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T = $t; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php new file mode 100644 index 000000000..1e9a5eb3d --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php @@ -0,0 +1,44 @@ +yplusx = $yplusx; + if ($yminusx === null) { + $yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->yminusx = $yminusx; + if ($xy2d === null) { + $xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->xy2d = $xy2d; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/H.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/H.php new file mode 100644 index 000000000..19def1dd8 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/H.php @@ -0,0 +1,1544 @@ +>>> Basically, int[32][8][3][10] + */ + protected const BASE = array( + array( + array( + array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), + array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), + array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), + ), + array( + array(-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303), + array(-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081), + array(26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697), + ), + array( + array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), + array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), + array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), + ), + array( + array(-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540), + array(23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397), + array(7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325), + ), + array( + array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), + array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), + array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), + ), + array( + array(-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777), + array(-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737), + array(-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652), + ), + array( + array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), + array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), + array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), + ), + array( + array(14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726), + array(-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955), + array(27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425), + ), + ), + array( + array( + array(-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171), + array(27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510), + array(17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660), + ), + array( + array(-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639), + array(29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963), + array(5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950), + ), + array( + array(-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568), + array(12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335), + array(25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628), + ), + array( + array(-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007), + array(-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772), + array(-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653), + ), + array( + array(2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567), + array(13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686), + array(21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372), + ), + array( + array(-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887), + array(-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954), + array(-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953), + ), + array( + array(24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833), + array(-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532), + array(-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876), + ), + array( + array(2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268), + array(33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214), + array(1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038), + ), + ), + array( + array( + array(6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800), + array(4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645), + array(-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664), + ), + array( + array(1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933), + array(-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182), + array(-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222), + ), + array( + array(-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991), + array(20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880), + array(9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092), + ), + array( + array(-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295), + array(19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788), + array(8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553), + ), + array( + array(-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026), + array(11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347), + array(-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033), + ), + array( + array(-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395), + array(-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278), + array(1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890), + ), + array( + array(32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995), + array(-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596), + array(-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891), + ), + array( + array(31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060), + array(11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608), + array(-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606), + ), + ), + array( + array( + array(7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389), + array(-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016), + array(-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341), + ), + array( + array(-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505), + array(14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553), + array(-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655), + ), + array( + array(15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220), + array(12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631), + array(-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099), + ), + array( + array(26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556), + array(14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749), + array(236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930), + ), + array( + array(1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391), + array(5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253), + array(20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066), + ), + array( + array(24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958), + array(-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082), + array(-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383), + ), + array( + array(-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521), + array(-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807), + array(23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948), + ), + array( + array(9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134), + array(-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455), + array(27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629), + ), + ), + array( + array( + array(-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069), + array(-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746), + array(24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919), + ), + array( + array(11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837), + array(8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906), + array(-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771), + ), + array( + array(-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817), + array(10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098), + array(10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409), + ), + array( + array(-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504), + array(-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727), + array(28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420), + ), + array( + array(-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003), + array(-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605), + array(-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384), + ), + array( + array(-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701), + array(-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683), + array(29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708), + ), + array( + array(-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563), + array(-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260), + array(-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387), + ), + array( + array(-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672), + array(23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686), + array(-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665), + ), + ), + array( + array( + array(11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182), + array(-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277), + array(14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628), + ), + array( + array(-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474), + array(-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539), + array(-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822), + ), + array( + array(-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970), + array(19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756), + array(-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508), + ), + array( + array(-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683), + array(-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655), + array(-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158), + ), + array( + array(-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125), + array(-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839), + array(-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664), + ), + array( + array(27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294), + array(-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899), + array(-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070), + ), + array( + array(3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294), + array(-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949), + array(-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083), + ), + array( + array(31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420), + array(-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940), + array(29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396), + ), + ), + array( + array( + array(-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567), + array(20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127), + array(-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294), + ), + array( + array(-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887), + array(22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964), + array(16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195), + ), + array( + array(9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244), + array(24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999), + array(-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762), + ), + array( + array(-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274), + array(-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236), + array(-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605), + ), + array( + array(-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761), + array(-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884), + array(-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482), + ), + array( + array(-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638), + array(-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490), + array(-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170), + ), + array( + array(5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736), + array(10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124), + array(-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392), + ), + array( + array(8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029), + array(6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048), + array(28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958), + ), + ), + array( + array( + array(24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593), + array(26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071), + array(-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692), + ), + array( + array(11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687), + array(-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441), + array(-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001), + ), + array( + array(-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460), + array(-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007), + array(-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762), + ), + array( + array(15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005), + array(-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674), + array(4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035), + ), + array( + array(7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590), + array(-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957), + array(-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812), + ), + array( + array(33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740), + array(-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122), + array(-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158), + ), + array( + array(8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885), + array(26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140), + array(19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857), + ), + array( + array(801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155), + array(19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260), + array(19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483), + ), + ), + array( + array( + array(-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677), + array(32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815), + array(22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751), + ), + array( + array(-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203), + array(-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208), + array(1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230), + ), + array( + array(16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850), + array(-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389), + array(-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968), + ), + array( + array(-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689), + array(14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880), + array(5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304), + ), + array( + array(30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632), + array(-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412), + array(20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566), + ), + array( + array(-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038), + array(-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232), + array(-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943), + ), + array( + array(17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856), + array(23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738), + array(15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971), + ), + array( + array(-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718), + array(-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697), + array(-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883), + ), + ), + array( + array( + array(5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912), + array(-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358), + array(3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849), + ), + array( + array(29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307), + array(-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977), + array(-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335), + ), + array( + array(-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644), + array(-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616), + array(-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735), + ), + array( + array(-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099), + array(29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341), + array(-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336), + ), + array( + array(-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646), + array(31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425), + array(-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388), + ), + array( + array(-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743), + array(-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822), + array(-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462), + ), + array( + array(18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985), + array(9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702), + array(-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797), + ), + array( + array(21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293), + array(27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100), + array(19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688), + ), + ), + array( + array( + array(12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186), + array(2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610), + array(-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707), + ), + array( + array(7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220), + array(915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025), + array(32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044), + ), + array( + array(32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992), + array(-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027), + array(21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197), + ), + array( + array(8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901), + array(31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952), + array(19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878), + ), + array( + array(-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390), + array(32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730), + array(2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730), + ), + array( + array(-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180), + array(-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272), + array(-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715), + ), + array( + array(-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970), + array(-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772), + array(-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865), + ), + array( + array(15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750), + array(20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373), + array(32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348), + ), + ), + array( + array( + array(9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144), + array(-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195), + array(5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086), + ), + array( + array(-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684), + array(-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518), + array(-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233), + ), + array( + array(-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793), + array(-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794), + array(580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435), + ), + array( + array(23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921), + array(13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518), + array(2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563), + ), + array( + array(14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278), + array(-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024), + array(4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030), + ), + array( + array(10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783), + array(27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717), + array(6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844), + ), + array( + array(14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333), + array(16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048), + array(22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760), + ), + array( + array(-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760), + array(-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757), + array(-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112), + ), + ), + array( + array( + array(-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468), + array(3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184), + array(10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289), + ), + array( + array(15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066), + array(24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882), + array(13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226), + ), + array( + array(16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101), + array(29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279), + array(-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811), + ), + array( + array(27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709), + array(20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714), + array(-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121), + ), + array( + array(9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464), + array(12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847), + array(13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400), + ), + array( + array(4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414), + array(-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158), + array(17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045), + ), + array( + array(-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415), + array(-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459), + array(-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079), + ), + array( + array(21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412), + array(-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743), + array(-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836), + ), + ), + array( + array( + array(12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022), + array(18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429), + array(-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065), + ), + array( + array(30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861), + array(10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000), + array(-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101), + ), + array( + array(32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815), + array(29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642), + array(10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966), + ), + array( + array(25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574), + array(-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742), + array(-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689), + ), + array( + array(12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020), + array(-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772), + array(3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982), + ), + array( + array(-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953), + array(-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218), + array(-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265), + ), + array( + array(29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073), + array(-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325), + array(-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798), + ), + array( + array(-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870), + array(-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863), + array(-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927), + ), + ), + array( + array( + array(-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267), + array(-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663), + array(22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862), + ), + array( + array(-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673), + array(15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943), + array(15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020), + ), + array( + array(-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238), + array(11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064), + array(14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795), + ), + array( + array(15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052), + array(-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904), + array(29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531), + ), + array( + array(-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979), + array(-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841), + array(10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431), + ), + array( + array(10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324), + array(-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940), + array(10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320), + ), + array( + array(-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184), + array(14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114), + array(30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878), + ), + array( + array(12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784), + array(-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091), + array(-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585), + ), + ), + array( + array( + array(-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208), + array(10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864), + array(17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661), + ), + array( + array(7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233), + array(26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212), + array(-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525), + ), + array( + array(-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068), + array(9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397), + array(-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988), + ), + array( + array(5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889), + array(32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038), + array(14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697), + ), + array( + array(20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875), + array(-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905), + array(-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656), + ), + array( + array(11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818), + array(27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714), + array(10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203), + ), + array( + array(20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931), + array(-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024), + array(-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084), + ), + array( + array(-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204), + array(20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817), + array(27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667), + ), + ), + array( + array( + array(11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504), + array(-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768), + array(-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255), + ), + array( + array(6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790), + array(1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438), + array(-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333), + ), + array( + array(17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971), + array(31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905), + array(29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409), + ), + array( + array(12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409), + array(6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499), + array(-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363), + ), + array( + array(28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664), + array(-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324), + array(-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940), + ), + array( + array(13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990), + array(-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914), + array(-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290), + ), + array( + array(24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257), + array(-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433), + array(-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236), + ), + array( + array(-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045), + array(11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093), + array(-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347), + ), + ), + array( + array( + array(-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191), + array(-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507), + array(-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906), + ), + array( + array(3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018), + array(-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109), + array(-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926), + ), + array( + array(-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528), + array(8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625), + array(-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286), + ), + array( + array(2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033), + array(27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866), + array(21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896), + ), + array( + array(30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075), + array(26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347), + array(-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437), + ), + array( + array(-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165), + array(-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588), + array(-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193), + ), + array( + array(-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017), + array(-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883), + array(21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961), + ), + array( + array(8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043), + array(29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663), + array(-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362), + ), + ), + array( + array( + array(-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860), + array(2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466), + array(-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063), + ), + array( + array(-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997), + array(-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295), + array(-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369), + ), + array( + array(9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385), + array(18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109), + array(2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906), + ), + array( + array(4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424), + array(-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185), + array(7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962), + ), + array( + array(-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325), + array(10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593), + array(696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404), + ), + array( + array(-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644), + array(17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801), + array(26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804), + ), + array( + array(-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884), + array(-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577), + array(-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849), + ), + array( + array(32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473), + array(-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644), + array(-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319), + ), + ), + array( + array( + array(-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599), + array(-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768), + array(-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084), + ), + array( + array(-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328), + array(-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369), + array(20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920), + ), + array( + array(12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815), + array(-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025), + array(-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397), + ), + array( + array(-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448), + array(6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981), + array(30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165), + ), + array( + array(32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501), + array(17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073), + array(-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861), + ), + array( + array(14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845), + array(-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211), + array(18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870), + ), + array( + array(10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096), + array(33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803), + array(-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168), + ), + array( + array(30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965), + array(-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505), + array(18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598), + ), + ), + array( + array( + array(5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782), + array(5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900), + array(-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479), + ), + array( + array(-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208), + array(8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232), + array(17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719), + ), + array( + array(16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271), + array(-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326), + array(-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132), + ), + array( + array(14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300), + array(8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570), + array(15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670), + ), + array( + array(-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994), + array(-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913), + array(31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317), + ), + array( + array(-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730), + array(842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096), + array(-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078), + ), + array( + array(-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411), + array(-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905), + array(-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654), + ), + array( + array(-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870), + array(-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498), + array(12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579), + ), + ), + array( + array( + array(14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677), + array(10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647), + array(-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743), + ), + array( + array(-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468), + array(21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375), + array(-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155), + ), + array( + array(6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725), + array(-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612), + array(-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943), + ), + array( + array(-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944), + array(30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928), + array(9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406), + ), + array( + array(22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139), + array(-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963), + array(-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693), + ), + array( + array(1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734), + array(-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680), + array(-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410), + ), + array( + array(-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931), + array(-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654), + array(22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710), + ), + array( + array(29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180), + array(-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684), + array(-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895), + ), + ), + array( + array( + array(22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501), + array(-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413), + array(6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880), + ), + array( + array(-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874), + array(22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962), + array(-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899), + ), + array( + array(21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152), + array(9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063), + array(7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080), + ), + array( + array(-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146), + array(-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183), + array(-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133), + ), + array( + array(-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421), + array(-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622), + array(-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197), + ), + array( + array(2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663), + array(31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753), + array(4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755), + ), + array( + array(-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862), + array(-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118), + array(26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171), + ), + array( + array(15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380), + array(16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824), + array(28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270), + ), + ), + array( + array( + array(-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438), + array(-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584), + array(-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562), + ), + array( + array(30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471), + array(18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610), + array(19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269), + ), + array( + array(-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650), + array(14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369), + array(19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461), + ), + array( + array(30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462), + array(-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793), + array(-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218), + ), + array( + array(-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226), + array(18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019), + array(-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037), + ), + array( + array(31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171), + array(-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132), + array(-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841), + ), + array( + array(21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181), + array(-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210), + array(-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040), + ), + array( + array(3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935), + array(24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105), + array(-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814), + ), + ), + array( + array( + array(793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852), + array(5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581), + array(-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646), + ), + array( + array(10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844), + array(10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025), + array(27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453), + ), + array( + array(-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068), + array(4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192), + array(-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921), + ), + array( + array(-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259), + array(-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426), + array(-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072), + ), + array( + array(-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305), + array(13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832), + array(28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943), + ), + array( + array(-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011), + array(24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447), + array(17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494), + ), + array( + array(-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245), + array(-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859), + array(28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915), + ), + array( + array(16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707), + array(10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848), + array(-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224), + ), + ), + array( + array( + array(-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391), + array(15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215), + array(-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101), + ), + array( + array(23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713), + array(21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849), + array(-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930), + ), + array( + array(-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940), + array(-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031), + array(-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404), + ), + array( + array(-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243), + array(-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116), + array(-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525), + ), + array( + array(-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509), + array(-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883), + array(15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865), + ), + array( + array(-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660), + array(4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273), + array(-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138), + ), + array( + array(-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560), + array(-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135), + array(2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941), + ), + array( + array(-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739), + array(18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756), + array(-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819), + ), + ), + array( + array( + array(-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347), + array(-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028), + array(21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075), + ), + array( + array(16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799), + array(-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609), + array(-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817), + ), + array( + array(-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989), + array(-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523), + array(4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278), + ), + array( + array(31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045), + array(19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377), + array(24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480), + ), + array( + array(17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016), + array(510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426), + array(18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525), + ), + array( + array(13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396), + array(9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080), + array(12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892), + ), + array( + array(15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275), + array(11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074), + array(20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140), + ), + array( + array(-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717), + array(-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101), + array(24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127), + ), + ), + array( + array( + array(-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632), + array(-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415), + array(-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160), + ), + array( + array(31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876), + array(22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625), + array(-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478), + ), + array( + array(27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164), + array(26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595), + array(-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248), + ), + array( + array(-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858), + array(15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193), + array(8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184), + ), + array( + array(-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942), + array(-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635), + array(21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948), + ), + array( + array(11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935), + array(-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415), + array(-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416), + ), + array( + array(-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018), + array(4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778), + array(366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659), + ), + array( + array(-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385), + array(18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503), + array(476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329), + ), + ), + array( + array( + array(20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056), + array(-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838), + array(24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948), + ), + array( + array(-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691), + array(-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118), + array(-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517), + ), + array( + array(-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269), + array(-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904), + array(-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589), + ), + array( + array(-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193), + array(-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910), + array(-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930), + ), + array( + array(-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667), + array(25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481), + array(-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876), + ), + array( + array(22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640), + array(-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278), + array(-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112), + ), + array( + array(26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272), + array(17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012), + array(-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221), + ), + array( + array(30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046), + array(13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345), + array(-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310), + ), + ), + array( + array( + array(19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937), + array(31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636), + array(-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008), + ), + array( + array(-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429), + array(-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576), + array(31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066), + ), + array( + array(-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490), + array(-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104), + array(33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053), + ), + array( + array(31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275), + array(-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511), + array(22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095), + ), + array( + array(-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439), + array(23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939), + array(-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424), + ), + array( + array(2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310), + array(3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608), + array(-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079), + ), + array( + array(-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101), + array(21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418), + array(18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576), + ), + array( + array(30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356), + array(9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996), + array(-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099), + ), + ), + array( + array( + array(-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728), + array(-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658), + array(-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242), + ), + array( + array(-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001), + array(-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766), + array(18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373), + ), + array( + array(26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458), + array(-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628), + array(-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657), + ), + array( + array(-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062), + array(25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616), + array(31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014), + ), + array( + array(24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383), + array(-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814), + array(-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718), + ), + array( + array(30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417), + array(2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222), + array(33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444), + ), + array( + array(-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597), + array(23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970), + array(1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799), + ), + array( + array(-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647), + array(13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511), + array(-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032), + ), + ), + array( + array( + array(9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834), + array(-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461), + array(29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062), + ), + array( + array(-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516), + array(-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547), + array(-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240), + ), + array( + array(-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038), + array(-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741), + array(16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103), + ), + array( + array(-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747), + array(-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323), + array(31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016), + ), + array( + array(-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373), + array(15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228), + array(-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141), + ), + array( + array(16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399), + array(11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831), + array(-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376), + ), + array( + array(-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313), + array(-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958), + array(-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577), + ), + array( + array(-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743), + array(29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684), + array(-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476), + ), + ) + ); + + /** + * See: libsodium's crypto_core/curve25519/ref10/base2.h + * + * @var array basically int[8][3] + */ + protected const BASE2 = array( + array( + array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), + array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), + array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), + ), + array( + array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), + array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), + array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), + ), + array( + array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), + array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), + array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), + ), + array( + array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), + array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), + array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), + ), + array( + array(-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877), + array(-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951), + array(4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784), + ), + array( + array(-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436), + array(25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918), + array(23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877), + ), + array( + array(-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800), + array(-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305), + array(-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300), + ), + array( + array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876), + array(-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619), + array(-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683), + ) + ); + + /** + * 37095705934669439343138083508754565189542113879843219016388785533085940283555 + */ + protected const D = array( + -10913610, + 13857413, + -15372611, + 6949391, + 114729, + -8787816, + -6275908, + -3247719, + -18696448, + -12055116 + ); + + /** + * 2 * d = 16295367250680780974490674513165176452449235426866156013048779062215315747161 + */ + protected const D2 = array( + -21827239, + -5839606, + -30745221, + 13898782, + 229458, + 15978800, + -12551817, + -6495438, + 29715968, + 9444199 + ); + + /** + * sqrt(-1) + */ + protected const SQRTM1 = array( + -32595792, + -7943725, + 9377950, + 3500415, + 12389472, + -272473, + -25146209, + -2005654, + 326686, + 11406482 + ); + + /** + * 1 / sqrt(a - d) + * + * @var array + */ + protected const INVSQRTAMD = array( + 6111485, + 4156064, + -27798727, + 12243468, + -25904040, + 120897, + 20826367, + -7060776, + 6093568, + -1986012 + ); + + /** + * sqrt(ad - 1) with a = -1 (mod p) + * + * @var array + */ + protected const SQRTADM1 = array( + 24849947, + -153582, + -23613485, + 6347715, + -21072328, + -667138, + -25271143, + -15367704, + -870347, + 14525639 + ); + + /** + * 1 - d ^ 2 + * + * @var array + */ + protected const ONEMSQD = array( + 6275446, + -16617371, + -22938544, + -3773710, + 11667077, + 7397348, + -27922721, + 1766195, + -24433858, + 672203 + ); + + /** + * (d - 1) ^ 2 + * @var array + */ + protected const SQDMONE = array( + 15551795, + -11097455, + -13425098, + -10125071, + -11896535, + 10178284, + -26634327, + 4729244, + -5282110, + -10116402 + ); + + + /* + * 2^252+27742317777372353535851937790883648493 + static const unsigned char L[] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + }; + */ + const L = "\xed\xd3\xf5\x5c\x1a\x63\x12\x58\xd6\x9c\xf7\xa2\xde\xf9\xde\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"; +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/README.md b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/README.md new file mode 100644 index 000000000..e8097fa34 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Curve25519/README.md @@ -0,0 +1,3 @@ +# Curve25519 Data Structures + +These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h). diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ed25519.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ed25519.php new file mode 100644 index 000000000..ffae0c335 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ed25519.php @@ -0,0 +1,547 @@ +X)) { + throw new SodiumException('Unexpected zero result'); + } + $one_minux_y = self::fe_invert( + self::fe_sub( + self::fe_1(), + $A->Y + ) + ); + $x = self::fe_mul( + self::fe_add(self::fe_1(), $A->Y), + $one_minux_y + ); + return self::fe_tobytes($x); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sk_to_pk( + #[SensitiveParameter] + string $sk + ): string { + return self::ge_p3_tobytes( + self::ge_scalarmult_base( + self::substr($sk, 0, 32) + ) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sign( + string $message, + #[SensitiveParameter] + string $sk + ): string { + $signature = self::sign_detached($message, $sk); + return $signature . $message; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message A signed message + * @param string $pk Public key + * @return string Message (without signature) + * @throws SodiumException + * @throws TypeError + */ + public static function sign_open( + string $message, + string $pk + ): string { + $signature = self::substr($message, 0, 64); + + /** @var string $message */ + $message = self::substr($message, 64); + + if (self::verify_detached($signature, $message, $pk)) { + return $message; + } + throw new SodiumException('Invalid signature'); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sign_detached( + string $message, + #[SensitiveParameter] + string $sk + ): string { + $az = hash('sha512', self::substr($sk, 0, 32), true); + + $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); + $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); + + $hs = hash_init('sha512'); + hash_update($hs, self::substr($az, 32, 32)); + hash_update($hs, $message); + $nonceHash = hash_final($hs, true); + + $pk = self::substr($sk, 32, 32); + + $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); + $sig = self::ge_p3_tobytes( + self::ge_scalarmult_base($nonce) + ); + + $hs = hash_init('sha512'); + hash_update($hs, self::substr($sig, 0, 32)); + hash_update($hs, self::substr($pk, 0, 32)); + hash_update($hs, $message); + $hramHash = hash_final($hs, true); + + $hram = self::sc_reduce($hramHash); + $sigAfter = self::sc_muladd($hram, $az, $nonce); + $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); + + try { + ParagonIE_Sodium_Compat::memzero($az); + } catch (SodiumException) { + $az = null; + } + return $sig; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $sig + * @param string $message + * @param string $pk + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function verify_detached( + string $sig, + string $message, + string $pk + ): bool { + if (self::strlen($sig) < 64) { + throw new SodiumException('Signature is too short'); + } + if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { + throw new SodiumException('S < L - Invalid signature'); + } + if (self::small_order($sig)) { + throw new SodiumException('Signature is on too small of an order'); + } + if ((self::chrToInt($sig[63]) & 224) !== 0) { + throw new SodiumException('Invalid signature'); + } + $d = 0; + for ($i = 0; $i < 32; ++$i) { + $d |= self::chrToInt($pk[$i]); + } + if ($d === 0) { + throw new SodiumException('All zero public key'); + } + + /* The original value of ParagonIE_Sodium_Compat::$fastMult */ + $orig = ParagonIE_Sodium_Compat::$fastMult; + + // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. + ParagonIE_Sodium_Compat::$fastMult = true; + + $A = self::ge_frombytes_negate_vartime($pk); + + $hDigest = hash( + 'sha512', + self::substr($sig, 0, 32) . + self::substr($pk, 0, 32) . + $message, + true + ); + $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); + $R = self::ge_double_scalarmult_vartime( + $h, + $A, + self::substr($sig, 32) + ); + $rcheck = self::ge_tobytes($R); + + // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. + ParagonIE_Sodium_Compat::$fastMult = $orig; + + return self::verify_32($rcheck, self::substr($sig, 0, 32)); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $S + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function check_S_lt_L(string $S): bool + { + if (self::strlen($S) < 32) { + throw new SodiumException('Signature must be 32 bytes'); + } + $L = array( + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + ); + $c = 0; + $n = 1; + $i = 32; + + /** @var array $L */ + do { + --$i; + $x = self::chrToInt($S[$i]); + $c |= ( + (($x - $L[$i]) >> 8) & $n + ); + $n &= ( + (($x ^ $L[$i]) - 1) >> 8 + ); + } while ($i !== 0); + return $c === 0; + } + + /** + * @param string $R + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function small_order(string $R): bool + { + /** @var array> $blocklist */ + $blocklist = array( + /* 0 (order 4) */ + array( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ), + /* 1 (order 1) */ + array( + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ), + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ + array( + 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, + 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, + 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, + 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 + ), + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ + array( + 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, + 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, + 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, + 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a + ), + /* p-1 (order 2) */ + array( + 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, + 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, + 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, + 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 + ), + /* p (order 4) */ + array( + 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, + 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, + 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, + 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa + ), + /* p+1 (order 1) */ + array( + 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ + array( + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ + array( + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* 2p-1 (order 2) */ + array( + 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ), + /* 2p (order 4) */ + array( + 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ), + /* 2p+1 (order 1) */ + array( + 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ) + ); + $countBlocklist = count($blocklist); + for ($i = 0; $i < $countBlocklist; ++$i) { + $c = 0; + for ($j = 0; $j < 32; ++$j) { + $c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j]; + } + if ($c === 0) { + return true; + } + } + return false; + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function scalar_complement( + #[SensitiveParameter] + string $s + ): string { + $t_ = self::L . str_repeat("\x00", 32); + sodium_increment($t_); + $s_ = $s . str_repeat("\x00", 32); + ParagonIE_Sodium_Compat::sub($t_, $s_); + return self::sc_reduce($t_); + } + + /** + * @return string + * @throws SodiumException + */ + public static function scalar_random(): string + { + do { + $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); + $r[self::SCALAR_BYTES - 1] = self::intToChr( + self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f + ); + } while ( + !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) + ); + return $r; + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function scalar_negate( + #[SensitiveParameter] + string $s + ): string { + $t_ = self::L . str_repeat("\x00", 32) ; + $s_ = $s . str_repeat("\x00", 32) ; + ParagonIE_Sodium_Compat::sub($t_, $s_); + return self::sc_reduce($t_); + } + + /** + * @param string $a + * @param string $b + * @return string + * @throws SodiumException + */ + public static function scalar_add( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): string { + $a_ = $a . str_repeat("\x00", 32); + $b_ = $b . str_repeat("\x00", 32); + ParagonIE_Sodium_Compat::add($a_, $b_); + return self::sc_reduce($a_); + } + + /** + * @param string $x + * @param string $y + * @return string + * @throws SodiumException + */ + public static function scalar_sub( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y + ): string { + return self::scalar_add($x, self::scalar_negate($y)); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/HChaCha20.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/HChaCha20.php new file mode 100644 index 000000000..54eb6b2ca --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/HChaCha20.php @@ -0,0 +1,99 @@ + 0; $i -= 2) { + $x4 ^= self::rotate($x0 + $x12, 7); + $x8 ^= self::rotate($x4 + $x0, 9); + $x12 ^= self::rotate($x8 + $x4, 13); + $x0 ^= self::rotate($x12 + $x8, 18); + $x9 ^= self::rotate($x5 + $x1, 7); + $x13 ^= self::rotate($x9 + $x5, 9); + $x1 ^= self::rotate($x13 + $x9, 13); + $x5 ^= self::rotate($x1 + $x13, 18); + $x14 ^= self::rotate($x10 + $x6, 7); + $x2 ^= self::rotate($x14 + $x10, 9); + $x6 ^= self::rotate($x2 + $x14, 13); + $x10 ^= self::rotate($x6 + $x2, 18); + $x3 ^= self::rotate($x15 + $x11, 7); + $x7 ^= self::rotate($x3 + $x15, 9); + $x11 ^= self::rotate($x7 + $x3, 13); + $x15 ^= self::rotate($x11 + $x7, 18); + $x1 ^= self::rotate($x0 + $x3, 7); + $x2 ^= self::rotate($x1 + $x0, 9); + $x3 ^= self::rotate($x2 + $x1, 13); + $x0 ^= self::rotate($x3 + $x2, 18); + $x6 ^= self::rotate($x5 + $x4, 7); + $x7 ^= self::rotate($x6 + $x5, 9); + $x4 ^= self::rotate($x7 + $x6, 13); + $x5 ^= self::rotate($x4 + $x7, 18); + $x11 ^= self::rotate($x10 + $x9, 7); + $x8 ^= self::rotate($x11 + $x10, 9); + $x9 ^= self::rotate($x8 + $x11, 13); + $x10 ^= self::rotate($x9 + $x8, 18); + $x12 ^= self::rotate($x15 + $x14, 7); + $x13 ^= self::rotate($x12 + $x15, 9); + $x14 ^= self::rotate($x13 + $x12, 13); + $x15 ^= self::rotate($x14 + $x13, 18); + } + + return self::store32_le($x0) . + self::store32_le($x5) . + self::store32_le($x10) . + self::store32_le($x15) . + self::store32_le($x6) . + self::store32_le($x7) . + self::store32_le($x8) . + self::store32_le($x9); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305.php new file mode 100644 index 000000000..5f0767ef6 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305.php @@ -0,0 +1,71 @@ +update($m) + ->finish(); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $mac + * @param string $m + * @param string $key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function onetimeauth_verify( + string $mac, + string $m, + #[SensitiveParameter] + string $key + ): bool { + if (self::strlen($key) < 32) { + throw new InvalidArgumentException( + 'Key must be 32 bytes long.' + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + self::substr($key, 0, 32) + ); + $calc = $state + ->update($m) + ->finish(); + return self::verify_16($calc, $mac); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305/State.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305/State.php new file mode 100644 index 000000000..f6f153a2a --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Poly1305/State.php @@ -0,0 +1,424 @@ + + */ + protected array $buffer = array(); + protected bool $final = false; + /** + * @var array + */ + public array $h; + protected int $leftover = 0; + + /** + * @var int[] + */ + public array $r; + + /** + * @var int[] + */ + public array $pad; + + /** + * ParagonIE_Sodium_Core_Poly1305_State constructor. + * + * @internal You should not use this directly from another application + * + * @param string $key + * @throws InvalidArgumentException + * @throws TypeError + */ + public function __construct(string $key = '') + { + if (self::strlen($key) < 32) { + throw new InvalidArgumentException( + 'Poly1305 requires a 32-byte key' + ); + } + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + $this->r = array( + ((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff), + ((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03), + ((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff), + ((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff), + ((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff) + ); + + /* h = 0 */ + $this->h = array(0, 0, 0, 0, 0); + + /* save pad for later */ + $this->pad = array( + self::load_4(self::substr($key, 16, 4)), + self::load_4(self::substr($key, 20, 4)), + self::load_4(self::substr($key, 24, 4)), + self::load_4(self::substr($key, 28, 4)), + ); + + $this->leftover = 0; + $this->final = false; + } + + /** + * Zero internal buffer upon destruction + */ + public function __destruct() + { + $this->r[0] ^= $this->r[0]; + $this->r[1] ^= $this->r[1]; + $this->r[2] ^= $this->r[2]; + $this->r[3] ^= $this->r[3]; + $this->r[4] ^= $this->r[4]; + $this->h[0] ^= $this->h[0]; + $this->h[1] ^= $this->h[1]; + $this->h[2] ^= $this->h[2]; + $this->h[3] ^= $this->h[3]; + $this->h[4] ^= $this->h[4]; + $this->pad[0] ^= $this->pad[0]; + $this->pad[1] ^= $this->pad[1]; + $this->pad[2] ^= $this->pad[2]; + $this->pad[3] ^= $this->pad[3]; + $this->leftover = 0; + $this->final = true; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @return self + * @throws SodiumException + * @throws TypeError + */ + public function update(string $message = ''): self + { + $bytes = self::strlen($message); + if ($bytes < 1) { + return $this; + } + + /* handle leftover */ + if ($this->leftover) { + $want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover; + if ($want > $bytes) { + $want = $bytes; + } + for ($i = 0; $i < $want; ++$i) { + $mi = self::chrToInt($message[$i]); + $this->buffer[$this->leftover + $i] = $mi; + } + // We snip off the leftmost bytes. + $message = self::substr($message, $want); + $bytes = self::strlen($message); + $this->leftover += $want; + if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + // We still don't have enough to run $this->blocks() + return $this; + } + + $this->blocks( + self::intArrayToString($this->buffer), + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + $this->leftover = 0; + } + + /* process full blocks */ + if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + /** @var int $want */ + $want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1); + if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + $block = self::substr($message, 0, $want); + if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + $this->blocks($block, $want); + $message = self::substr($message, $want); + $bytes = self::strlen($message); + } + } + } + + /* store leftover */ + if ($bytes) { + for ($i = 0; $i < $bytes; ++$i) { + $mi = self::chrToInt($message[$i]); + $this->buffer[$this->leftover + $i] = $mi; + } + $this->leftover = $this->leftover + $bytes; + } + return $this; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param int $bytes + * @return static + * @throws TypeError + */ + public function blocks(string $message, int $bytes): static + { + if (self::strlen($message) < 16) { + $message = str_pad($message, 16, "\x00"); + } + $hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */ + $r0 = $this->r[0]; + $r1 = $this->r[1]; + $r2 = $this->r[2]; + $r3 = $this->r[3]; + $r4 = $this->r[4]; + + $s1 = self::mul($r1, 5, 3); + $s2 = self::mul($r2, 5, 3); + $s3 = self::mul($r3, 5, 3); + $s4 = self::mul($r4, 5, 3); + + $h0 = $this->h[0]; + $h1 = $this->h[1]; + $h2 = $this->h[2]; + $h3 = $this->h[3]; + $h4 = $this->h[4]; + + while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + /* h += m[i] */ + $h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff; + $h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff; + $h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff; + $h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff; + $h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit; + + /* h *= r */ + $d0 = ( + self::mul($h0, $r0, 27) + + self::mul($s4, $h1, 27) + + self::mul($s3, $h2, 27) + + self::mul($s2, $h3, 27) + + self::mul($s1, $h4, 27) + ); + + $d1 = ( + self::mul($h0, $r1, 27) + + self::mul($h1, $r0, 27) + + self::mul($s4, $h2, 27) + + self::mul($s3, $h3, 27) + + self::mul($s2, $h4, 27) + ); + + $d2 = ( + self::mul($h0, $r2, 27) + + self::mul($h1, $r1, 27) + + self::mul($h2, $r0, 27) + + self::mul($s4, $h3, 27) + + self::mul($s3, $h4, 27) + ); + + $d3 = ( + self::mul($h0, $r3, 27) + + self::mul($h1, $r2, 27) + + self::mul($h2, $r1, 27) + + self::mul($h3, $r0, 27) + + self::mul($s4, $h4, 27) + ); + + $d4 = ( + self::mul($h0, $r4, 27) + + self::mul($h1, $r3, 27) + + self::mul($h2, $r2, 27) + + self::mul($h3, $r1, 27) + + self::mul($h4, $r0, 27) + ); + + /* (partial) h %= p */ + $c = $d0 >> 26; + $h0 = $d0 & 0x3ffffff; + $d1 += $c; + + $c = $d1 >> 26; + $h1 = $d1 & 0x3ffffff; + $d2 += $c; + + $c = $d2 >> 26; + $h2 = $d2 & 0x3ffffff; + $d3 += $c; + + $c = $d3 >> 26; + $h3 = $d3 & 0x3ffffff; + $d4 += $c; + + $c = $d4 >> 26; + $h4 = $d4 & 0x3ffffff; + $h0 += self::mul($c, 5, 3); + + $c = $h0 >> 26; + $h0 &= 0x3ffffff; + $h1 += $c; + + // Chop off the left 32 bytes. + $message = self::substr( + $message, + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + $bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; + } + + $this->h = array( + ($h0 & 0xffffffff), + ($h1 & 0xffffffff), + ($h2 & 0xffffffff), + ($h3 & 0xffffffff), + ($h4 & 0xffffffff) + ); + return $this; + } + + /** + * @internal You should not use this directly from another application + * + * @return string + * @throws TypeError + */ + public function finish(): string + { + /* process the remaining block */ + if ($this->leftover) { + $i = $this->leftover; + $this->buffer[$i++] = 1; + for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) { + $this->buffer[$i] = 0; + } + $this->final = true; + $this->blocks( + self::substr( + self::intArrayToString($this->buffer), + 0, + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ), + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + } + + $h0 = $this->h[0]; + $h1 = $this->h[1]; + $h2 = $this->h[2]; + $h3 = $this->h[3]; + $h4 = $this->h[4]; + + /** @var int $c */ + $c = $h1 >> 26; + /** @var int $h1 */ + $h1 &= 0x3ffffff; + /** @var int $h2 */ + $h2 += $c; + /** @var int $c */ + $c = $h2 >> 26; + /** @var int $h2 */ + $h2 &= 0x3ffffff; + $h3 += $c; + /** @var int $c */ + $c = $h3 >> 26; + $h3 &= 0x3ffffff; + $h4 += $c; + /** @var int $c */ + $c = $h4 >> 26; + $h4 &= 0x3ffffff; + /** @var int $h0 */ + $h0 += self::mul($c, 5, 3); + /** @var int $c */ + $c = $h0 >> 26; + /** @var int $h0 */ + $h0 &= 0x3ffffff; + /** @var int $h1 */ + $h1 += $c; + + /* compute h + -p */ + /** @var int $g0 */ + $g0 = $h0 + 5; + /** @var int $c */ + $c = $g0 >> 26; + /** @var int $g0 */ + $g0 &= 0x3ffffff; + + /** @var int $g1 */ + $g1 = $h1 + $c; + /** @var int $c */ + $c = $g1 >> 26; + $g1 &= 0x3ffffff; + + /** @var int $g2 */ + $g2 = $h2 + $c; + /** @var int $c */ + $c = $g2 >> 26; + /** @var int $g2 */ + $g2 &= 0x3ffffff; + + /** @var int $g3 */ + $g3 = $h3 + $c; + /** @var int $c */ + $c = $g3 >> 26; + /** @var int $g3 */ + $g3 &= 0x3ffffff; + + /** @var int $g4 */ + $g4 = ($h4 + $c - (1 << 26)) & 0xffffffff; + + /* select h if h < p, or h + -p if h >= p */ + /** @var int $mask */ + $mask = ($g4 >> 31) - 1; + + $g0 &= $mask; + $g1 &= $mask; + $g2 &= $mask; + $g3 &= $mask; + $g4 &= $mask; + + /** @var int $mask */ + $mask = ~$mask & 0xffffffff; + /** @var int $h0 */ + $h0 = ($h0 & $mask) | $g0; + /** @var int $h1 */ + $h1 = ($h1 & $mask) | $g1; + /** @var int $h2 */ + $h2 = ($h2 & $mask) | $g2; + /** @var int $h3 */ + $h3 = ($h3 & $mask) | $g3; + /** @var int $h4 */ + $h4 = ($h4 & $mask) | $g4; + + /* h = h % (2^128) */ + /** @var int $h0 */ + $h0 = (($h0) | ($h1 << 26)) & 0xffffffff; + /** @var int $h1 */ + $h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff; + /** @var int $h2 */ + $h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff; + /** @var int $h3 */ + $h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + $f = ($h0 + $this->pad[0]); + $h0 = $f; + $f = ($h1 + $this->pad[1] + ($f >> 32)); + $h1 = $f; + $f = ($h2 + $this->pad[2] + ($f >> 32)); + $h2 = $f; + $f = ($h3 + $this->pad[3] + ($f >> 32)); + $h3 = $f; + + return self::store32_le($h0 & 0xffffffff) . + self::store32_le($h1 & 0xffffffff) . + self::store32_le($h2 & 0xffffffff) . + self::store32_le($h3 & 0xffffffff); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ristretto255.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ristretto255.php new file mode 100644 index 000000000..364cfea45 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Ristretto255.php @@ -0,0 +1,764 @@ +> 31) & 1; + } + + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Fe $u + * @param ParagonIE_Sodium_Core_Curve25519_Fe $v + * @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int} + * + * @throws SodiumException + */ + public static function ristretto255_sqrt_ratio_m1( + ParagonIE_Sodium_Core_Curve25519_Fe $u, + ParagonIE_Sodium_Core_Curve25519_Fe $v + ): array { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1); + + $v3 = self::fe_mul( + self::fe_sq($v), + $v + ); /* v3 = v^3 */ + $x = self::fe_mul( + self::fe_mul( + self::fe_sq($v3), + $u + ), + $v + ); /* x = uv^7 */ + + $x = self::fe_mul( + self::fe_mul( + self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */ + $v3 + ), + $u + ); /* x = uv^3(uv^7)^((q-5)/8) */ + + $vxx = self::fe_mul( + self::fe_sq($x), + $v + ); /* vx^2 */ + + $m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */ + $p_root_check = self::fe_add($vxx, $u); /* vx^2+u */ + $f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */ + $f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */ + + $has_m_root = self::fe_iszero($m_root_check); + $has_p_root = self::fe_iszero($p_root_check); + $has_f_root = self::fe_iszero($f_root_check); + + $x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */ + + $x = self::fe_abs( + self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root) + ); + return array( + 'x' => $x, + 'nonsquare' => $has_m_root | $has_p_root + ); + } + + /** + * @param string $s + * @return int + * @throws SodiumException + */ + public static function ristretto255_point_is_canonical( + #[SensitiveParameter] + string $s + ): int { + $c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f; + for ($i = 30; $i > 0; --$i) { + $c |= self::chrToInt($s[$i]) ^ 0xff; + } + $c = ($c - 1) >> 8; + $d = (0xed - 1 - self::chrToInt($s[0])) >> 8; + $e = self::chrToInt($s[31]) >> 7; + + return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1); + } + + /** + * @param string $s + * @param bool $skipCanonicalCheck + * @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int} + * @throws SodiumException + */ + public static function ristretto255_frombytes( + #[SensitiveParameter] + string $s, + bool $skipCanonicalCheck = false + ): array { + if (!$skipCanonicalCheck) { + if (!self::ristretto255_point_is_canonical($s)) { + throw new SodiumException('S is not canonical'); + } + } + + $s_ = self::fe_frombytes($s); + $ss = self::fe_sq($s_); /* ss = s^2 */ + + $u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */ + $u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */ + + $u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */ + $u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */ + + $v = self::fe_mul( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D), + $u1u1 + ); /* v = d*u1^2 */ + $v = self::fe_neg($v); /* v = -d*u1^2 */ + $v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */ + $v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */ + + $one = self::fe_1(); + $result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2); + $inv_sqrt = $result['x']; + $notsquare = $result['nonsquare']; + + $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); + + $h->X = self::fe_mul($inv_sqrt, $u2); + $h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v); + + $h->X = self::fe_mul($h->X, $s_); + $h->X = self::fe_abs( + self::fe_add($h->X, $h->X) + ); + $h->Y = self::fe_mul($u1, $h->Y); + $h->Z = self::fe_1(); + $h->T = self::fe_mul($h->X, $h->Y); + + $res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y)); + return array('h' => $h, 'res' => $res); + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + * @return string + * @throws SodiumException + */ + public static function ristretto255_p3_tobytes( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + ): string { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1); + $invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::INVSQRTAMD); + + $u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */ + $zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */ + $u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */ + $u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */ + + $u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */ + $one = self::fe_1(); + + $result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2); + $inv_sqrt = $result['x']; + + $den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */ + $den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */ + $z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */ + + $ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */ + $iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */ + $eden = self::fe_mul($den1, $invsqrtamd); + + $t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */ + $rotate = self::fe_isnegative($t_z_inv); + + $x_ = clone $h->X; + $y_ = clone $h->Y; + $den_inv = clone $den2; + + $x_ = self::fe_cmov($x_, $iy, $rotate); + $y_ = self::fe_cmov($y_, $ix, $rotate); + $den_inv = self::fe_cmov($den_inv, $eden, $rotate); + + $x_z_inv = self::fe_mul($x_, $z_inv); + $y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv)); + + + return self::fe_tobytes( + self::fe_abs( + self::fe_mul( + $den_inv, + self::fe_sub($h->Z, $y_) + ) + ) + ); + } + + /** + * @param ParagonIE_Sodium_Core_Curve25519_Fe $t + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + * + * @throws SodiumException + */ + public static function ristretto255_elligator( + ParagonIE_Sodium_Core_Curve25519_Fe $t + ): ParagonIE_Sodium_Core_Curve25519_Ge_P3 { + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1); + $onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::ONEMSQD); + $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D); + $sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQDMONE); + $sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTADM1); + + $one = self::fe_1(); + $r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */ + $u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */ + $c = self::fe_neg(self::fe_1()); /* c = -1 */ + $rpd = self::fe_add($r, $d); /* rpd = r+d */ + + $v = self::fe_mul( + self::fe_sub( + $c, + self::fe_mul($r, $d) + ), + $rpd + ); /* v = (c-r*d)*(r+d) */ + + $result = self::ristretto255_sqrt_ratio_m1($u, $v); + $s = $result['x']; + $wasnt_square = 1 - $result['nonsquare']; + + $s_prime = self::fe_neg( + self::fe_abs( + self::fe_mul($s, $t) + ) + ); /* s_prime = -|s*t| */ + $s = self::fe_cmov($s, $s_prime, $wasnt_square); + $c = self::fe_cmov($c, $r, $wasnt_square); + + $n = self::fe_sub( + self::fe_mul( + self::fe_mul( + self::fe_sub($r, $one), + $c + ), + $sqdmone + ), + $v + ); /* n = c*(r-1)*(d-1)^2-v */ + + $w0 = self::fe_mul( + self::fe_add($s, $s), + $v + ); /* w0 = 2s*v */ + + $w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */ + $ss = self::fe_sq($s); /* ss = s^2 */ + $w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */ + $w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */ + + return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_mul($w0, $w3), + self::fe_mul($w2, $w1), + self::fe_mul($w1, $w3), + self::fe_mul($w0, $w2) + ); + } + + /** + * @param string $h + * @return string + * @throws SodiumException + */ + public static function ristretto255_from_hash( + #[SensitiveParameter] + string $h + ): string { + if (self::strlen($h) !== 64) { + throw new SodiumException('Hash must be 64 bytes'); + } + $r0 = self::fe_frombytes(self::substr($h, 0, 32)); + $r1 = self::fe_frombytes(self::substr($h, 32, 32)); + + $p0 = self::ristretto255_elligator($r0); + $p1 = self::ristretto255_elligator($r1); + + $p_p1p1 = self::ge_add( + $p0, + self::ge_p3_to_cached($p1) + ); + return self::ristretto255_p3_tobytes( + self::ge_p1p1_to_p3($p_p1p1) + ); + } + + /** + * @param string $p + * @return int + * @throws SodiumException + */ + public static function is_valid_point( + #[SensitiveParameter] + string $p + ): int { + $result = self::ristretto255_frombytes($p); + if ($result['res'] !== 0) { + return 0; + } + return 1; + } + + /** + * @param string $p + * @param string $q + * @return string + * @throws SodiumException + */ + public static function ristretto255_add( + string $p, + string $q + ): string { + $p_res = self::ristretto255_frombytes($p); + $q_res = self::ristretto255_frombytes($q); + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { + throw new SodiumException('Could not add points'); + } + $p_p3 = $p_res['h']; + $q_p3 = $q_res['h']; + $q_cached = self::ge_p3_to_cached($q_p3); + $r_p1p1 = self::ge_add($p_p3, $q_cached); + $r_p3 = self::ge_p1p1_to_p3($r_p1p1); + return self::ristretto255_p3_tobytes($r_p3); + } + + /** + * @param string $p + * @param string $q + * @return string + * @throws SodiumException + */ + public static function ristretto255_sub( + #[SensitiveParameter] + string $p, + #[SensitiveParameter] + string $q + ): string { + $p_res = self::ristretto255_frombytes($p); + $q_res = self::ristretto255_frombytes($q); + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { + throw new SodiumException('Could not add points'); + } + $p_p3 = $p_res['h']; + $q_p3 = $q_res['h']; + $q_cached = self::ge_p3_to_cached($q_p3); + $r_p1p1 = self::ge_sub($p_p3, $q_cached); + $r_p3 = self::ge_p1p1_to_p3($r_p1p1); + return self::ristretto255_p3_tobytes($r_p3); + } + + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @return string + * @throws SodiumException + */ + protected static function h2c_string_to_hash_sha256( + int $hLen, + #[SensitiveParameter] + ?string $ctx, + #[SensitiveParameter] + string $msg + ): string { + $h = array_fill(0, $hLen, 0); + if (is_null($ctx)) { + $ctx = ''; + } + $ctx_len = self::strlen($ctx); + if ($hLen > 0xff) { + throw new SodiumException('Hash must be less than 256 bytes'); + } + + if ($ctx_len > 0xff) { + $st = hash_init('sha256'); + hash_update($st, "H2C-OVERSIZE-DST-"); + hash_update($st, $ctx); + $ctx = hash_final($st, true); + $ctx_len = 32; + } + $t = array(0, $hLen, 0); + $ux = str_repeat("\0", 64); + $st = hash_init('sha256'); + hash_update($st, $ux); + hash_update($st, $msg); + hash_update($st, self::intArrayToString($t)); + hash_update($st, $ctx); + hash_update($st, self::intToChr($ctx_len)); + $u0 = hash_final($st, true); + + for ($i = 0; $i < $hLen; $i += 64) { + $ux = self::xorStrings($ux, $u0); + ++$t[2]; + $st = hash_init('sha256'); + hash_update($st, $ux); + hash_update($st, self::intToChr($t[2])); + hash_update($st, $ctx); + hash_update($st, self::intToChr($ctx_len)); + $ux = hash_final($st, true); + $amount = min($hLen - $i, 64); + for ($j = 0; $j < $amount; ++$j) { + $h[$i + $j] = self::chrToInt($ux[$i]); + } + } + return self::intArrayToString(array_slice($h, 0, $hLen)); + } + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @return string + * @throws SodiumException + */ + protected static function h2c_string_to_hash_sha512( + int $hLen, + #[SensitiveParameter] + ?string $ctx, + #[SensitiveParameter] + string $msg + ): string { + $h = array_fill(0, $hLen, 0); + if (is_null($ctx)) { + $ctx = ''; + } + $ctx_len = self::strlen($ctx); + if ($hLen > 0xff) { + throw new SodiumException('Hash must be less than 256 bytes'); + } + + if ($ctx_len > 0xff) { + $st = hash_init('sha256'); + hash_update($st, "H2C-OVERSIZE-DST-"); + hash_update($st, $ctx); + $ctx = hash_final($st, true); + $ctx_len = 32; + } + $t = array(0, $hLen, 0); + $ux = str_repeat("\0", 128); + $st = hash_init('sha512'); + hash_update($st, $ux); + hash_update($st, $msg); + hash_update($st, self::intArrayToString($t)); + hash_update($st, $ctx); + hash_update($st, self::intToChr($ctx_len)); + $u0 = hash_final($st, true); + + for ($i = 0; $i < $hLen; $i += 128) { + $ux = self::xorStrings($ux, $u0); + ++$t[2]; + $st = hash_init('sha512'); + hash_update($st, $ux); + hash_update($st, self::intToChr($t[2])); + hash_update($st, $ctx); + hash_update($st, self::intToChr($ctx_len)); + $ux = hash_final($st, true); + $amount = min($hLen - $i, 128); + for ($j = 0; $j < $amount; ++$j) { + $h[$i + $j] = self::chrToInt($ux[$i]); + } + } + return self::intArrayToString(array_slice($h, 0, $hLen)); + } + + /** + * @param int $hLen + * @param ?string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + public static function h2c_string_to_hash( + int $hLen, + #[SensitiveParameter] + ?string $ctx, + #[SensitiveParameter] + string $msg, + int $hash_alg + ): string { + return match ($hash_alg) { + self::CORE_H2C_SHA256 => self::h2c_string_to_hash_sha256($hLen, $ctx, $msg), + self::CORE_H2C_SHA512 => self::h2c_string_to_hash_sha512($hLen, $ctx, $msg), + default => throw new SodiumException('Invalid H2C hash algorithm'), + }; + } + + /** + * @param ?string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + protected static function _string_to_element( + #[SensitiveParameter] + ?string $ctx, + #[SensitiveParameter] + string $msg, + int $hash_alg + ): string { + return self::ristretto255_from_hash( + self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg) + ); + } + + /** + * @return string + * @throws SodiumException + * @throws Exception + */ + public static function ristretto255_random(): string + { + return self::ristretto255_from_hash( + ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES) + ); + } + + /** + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_random(): string + { + return self::scalar_random(); + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_complement( + #[SensitiveParameter] + string $s + ): string { + return self::scalar_complement($s); + } + + + /** + * @param string $s + * @return string + */ + public static function ristretto255_scalar_invert( + #[SensitiveParameter] + string $s + ): string { + return self::sc25519_invert($s); + } + + /** + * @param string $s + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_negate( + #[SensitiveParameter] + string $s + ): string { + return self::scalar_negate($s); + } + + /** + * @param string $x + * @param string $y + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_scalar_add( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y + ): string { + return self::scalar_add($x, $y); + } + + /** + * @param string $x + * @param string $y + * @return string + * + * @throws SodiumException + */ + public static function ristretto255_scalar_sub( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y + ): string { + return self::scalar_sub($x, $y); + } + + /** + * @param string $x + * @param string $y + * @return string + */ + public static function ristretto255_scalar_mul( + #[SensitiveParameter] + string $x, + #[SensitiveParameter] + string $y + ): string { + return self::sc25519_mul($x, $y); + } + + /** + * @param string $ctx + * @param string $msg + * @param int $hash_alg + * @return string + * @throws SodiumException + */ + public static function ristretto255_scalar_from_string( + #[SensitiveParameter] + string $ctx, + #[SensitiveParameter] + string $msg, + int $hash_alg + ): string { + $h = array_fill(0, 64, 0); + $h_be = self::stringToIntArray( + self::h2c_string_to_hash( + self::HASH_SC_L, $ctx, $msg, $hash_alg + ) + ); + + for ($i = 0; $i < self::HASH_SC_L; ++$i) { + $h[$i] = $h_be[self::HASH_SC_L - 1 - $i]; + } + return self::ristretto255_scalar_reduce(self::intArrayToString($h)); + } + + /** + * @param string $s + * @return string + */ + public static function ristretto255_scalar_reduce( + #[SensitiveParameter] + string $s + ): string { + return self::sc_reduce($s); + } + + /** + * @param string $n + * @param string $p + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255( + #[SensitiveParameter] + string $n, + #[SensitiveParameter] + string $p + ): string { + if (self::strlen($n) !== 32) { + throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.'); + } + if (self::strlen($p) !== 32) { + throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.'); + } + $result = self::ristretto255_frombytes($p); + if ($result['res'] !== 0) { + throw new SodiumException('Could not multiply points'); + } + $P = $result['h']; + + $t = self::stringToIntArray($n); + $t[31] &= 0x7f; + $Q = self::ge_scalarmult(self::intArrayToString($t), $P); + $q = self::ristretto255_p3_tobytes($Q); + if (ParagonIE_Sodium_Compat::is_zero($q)) { + throw new SodiumException('An unknown error has occurred'); + } + return $q; + } + + /** + * @param string $n + * @return string + * @throws SodiumException + */ + public static function scalarmult_ristretto255_base( + #[SensitiveParameter] + string $n + ): string { + $t = self::stringToIntArray($n); + $t[31] &= 0x7f; + $Q = self::ge_scalarmult_base(self::intArrayToString($t)); + $q = self::ristretto255_p3_tobytes($Q); + if (ParagonIE_Sodium_Compat::is_zero($q)) { + throw new SodiumException('An unknown error has occurred'); + } + return $q; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Salsa20.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Salsa20.php new file mode 100644 index 000000000..1bd47eca5 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Salsa20.php @@ -0,0 +1,293 @@ + 0; $i -= 2) { + $x4 ^= self::rotate($x0 + $x12, 7); + $x8 ^= self::rotate($x4 + $x0, 9); + $x12 ^= self::rotate($x8 + $x4, 13); + $x0 ^= self::rotate($x12 + $x8, 18); + + $x9 ^= self::rotate($x5 + $x1, 7); + $x13 ^= self::rotate($x9 + $x5, 9); + $x1 ^= self::rotate($x13 + $x9, 13); + $x5 ^= self::rotate($x1 + $x13, 18); + + $x14 ^= self::rotate($x10 + $x6, 7); + $x2 ^= self::rotate($x14 + $x10, 9); + $x6 ^= self::rotate($x2 + $x14, 13); + $x10 ^= self::rotate($x6 + $x2, 18); + + $x3 ^= self::rotate($x15 + $x11, 7); + $x7 ^= self::rotate($x3 + $x15, 9); + $x11 ^= self::rotate($x7 + $x3, 13); + $x15 ^= self::rotate($x11 + $x7, 18); + + $x1 ^= self::rotate($x0 + $x3, 7); + $x2 ^= self::rotate($x1 + $x0, 9); + $x3 ^= self::rotate($x2 + $x1, 13); + $x0 ^= self::rotate($x3 + $x2, 18); + + $x6 ^= self::rotate($x5 + $x4, 7); + $x7 ^= self::rotate($x6 + $x5, 9); + $x4 ^= self::rotate($x7 + $x6, 13); + $x5 ^= self::rotate($x4 + $x7, 18); + + $x11 ^= self::rotate($x10 + $x9, 7); + $x8 ^= self::rotate($x11 + $x10, 9); + $x9 ^= self::rotate($x8 + $x11, 13); + $x10 ^= self::rotate($x9 + $x8, 18); + + $x12 ^= self::rotate($x15 + $x14, 7); + $x13 ^= self::rotate($x12 + $x15, 9); + $x14 ^= self::rotate($x13 + $x12, 13); + $x15 ^= self::rotate($x14 + $x13, 18); + } + + $x0 += $j0; + $x1 += $j1; + $x2 += $j2; + $x3 += $j3; + $x4 += $j4; + $x5 += $j5; + $x6 += $j6; + $x7 += $j7; + $x8 += $j8; + $x9 += $j9; + $x10 += $j10; + $x11 += $j11; + $x12 += $j12; + $x13 += $j13; + $x14 += $j14; + $x15 += $j15; + + return self::store32_le($x0) . + self::store32_le($x1) . + self::store32_le($x2) . + self::store32_le($x3) . + self::store32_le($x4) . + self::store32_le($x5) . + self::store32_le($x6) . + self::store32_le($x7) . + self::store32_le($x8) . + self::store32_le($x9) . + self::store32_le($x10) . + self::store32_le($x11) . + self::store32_le($x12) . + self::store32_le($x13) . + self::store32_le($x14) . + self::store32_le($x15); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function salsa20( + int $len, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + if (self::strlen($key) !== 32) { + throw new RangeException('Key must be 32 bytes long'); + } + $kcopy = $key; + $in = self::substr($nonce, 0, 8) . str_repeat("\0", 8); + $c = ''; + while ($len >= 64) { + $c .= self::core_salsa20($in, $kcopy); + $u = 1; + // Internal counter. + for ($i = 8; $i < 16; ++$i) { + $u += self::chrToInt($in[$i]); + $in[$i] = self::intToChr($u & 0xff); + $u >>= 8; + } + $len -= 64; + } + if ($len > 0) { + $c .= self::substr( + self::core_salsa20($in, $kcopy), + 0, + $len + ); + } + try { + ParagonIE_Sodium_Compat::memzero($kcopy); + } catch (SodiumException) { + $kcopy = null; + } + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $m + * @param string $n + * @param int $ic + * @param string $k + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function salsa20_xor_ic( + #[SensitiveParameter] + string $m, + string $n, + int $ic, + #[SensitiveParameter] + string $k + ): string { + $mlen = self::strlen($m); + if ($mlen < 1) { + return ''; + } + $kcopy = self::substr($k, 0, 32); + $in = self::substr($n, 0, 8); + // Initialize the counter + $in .= ParagonIE_Sodium_Core_Util::store64_le($ic); + + $c = ''; + while ($mlen >= 64) { + $block = self::core_salsa20($in, $kcopy); + $c .= self::xorStrings( + self::substr($m, 0, 64), + self::substr($block, 0, 64) + ); + $u = 1; + for ($i = 8; $i < 16; ++$i) { + $u += self::chrToInt($in[$i]); + $in[$i] = self::intToChr($u & 0xff); + $u >>= 8; + } + + $mlen -= 64; + $m = self::substr($m, 64); + } + + if ($mlen) { + $block = self::core_salsa20($in, $kcopy); + $c .= self::xorStrings( + self::substr($m, 0, $mlen), + self::substr($block, 0, $mlen) + ); + } + try { + ParagonIE_Sodium_Compat::memzero($block); + ParagonIE_Sodium_Compat::memzero($kcopy); + } catch (SodiumException) { + $block = null; + $kcopy = null; + } + + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function salsa20_xor( + #[SensitiveParameter] + string $message, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + return self::xorStrings( + $message, + self::salsa20( + self::strlen($message), + $nonce, + $key + ) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $u + * @param int $c + * @return int + */ + public static function rotate(int $u, int $c): int + { + $u &= 0xffffffff; + $c %= 32; + return (0xffffffff & ( + ($u << $c) + | + ($u >> (32 - $c)) + ) + ); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SecretStream/State.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SecretStream/State.php new file mode 100644 index 000000000..5aa84e314 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SecretStream/State.php @@ -0,0 +1,161 @@ +key = $key; + $this->counter = 1; + if (is_null($nonce)) { + $nonce = str_repeat("\0", 12); + } + $this->nonce = str_pad($nonce, 12, "\0"); + $this->_pad = str_repeat("\0", 4); + } + + /** + * @return self + */ + public function counterReset(): self + { + $this->counter = 1; + $this->_pad = str_repeat("\0", 4); + return $this; + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return string + */ + public function getCounter(): string + { + return ParagonIE_Sodium_Core_Util::store32_le($this->counter); + } + + /** + * @return string + */ + public function getNonce(): string + { + if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) { + $this->nonce = str_pad($this->nonce, 12, "\0"); + } + return $this->nonce; + } + + /** + * @return string + */ + public function getCombinedNonce(): string + { + return $this->getCounter() . + ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8); + } + + /** + * @return self + */ + public function incrementCounter(): self + { + ++$this->counter; + return $this; + } + + /** + * @return bool + */ + public function needsRekey(): bool + { + return ($this->counter & 0xffff) === 0; + } + + /** + * @param string $newKeyAndNonce + * @return self + */ + public function rekey( + #[SensitiveParameter] + string $newKeyAndNonce + ): self { + $this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32); + $this->nonce = str_pad( + ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32), + 12, + "\0" + ); + return $this; + } + + /** + * @param string $str + * @return self + */ + public function xorNonce( + #[SensitiveParameter] + string $str + ): self { + $this->nonce = ParagonIE_Sodium_Core_Util::xorStrings( + $this->getNonce(), + str_pad( + ParagonIE_Sodium_Core_Util::substr($str, 0, 8), + 12, + "\0" + ) + ); + return $this; + } + + /** + * @param string $string + * @return self + */ + public static function fromString( + #[SensitiveParameter] + string $string + ): self { + $state = new ParagonIE_Sodium_Core_SecretStream_State( + ParagonIE_Sodium_Core_Util::substr($string, 0, 32) + ); + $state->counter = ParagonIE_Sodium_Core_Util::load_4( + ParagonIE_Sodium_Core_Util::substr($string, 32, 4) + ); + $state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36, 12); + $state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48, 8); + return $state; + } + + /** + * @return string + */ + public function toString(): string + { + return $this->key . + $this->getCounter() . + $this->nonce . + $this->_pad; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SipHash.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SipHash.php new file mode 100644 index 000000000..f52ee5e29 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/SipHash.php @@ -0,0 +1,310 @@ + + */ + public static function add(array $a, array $b): array + { + /** @var int $x1 */ + $x1 = $a[1] + $b[1]; + /** @var int $c */ + $c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff + /** @var int $x0 */ + $x0 = $a[0] + $b[0] + $c; + return array( + $x0 & 0xffffffff, + $x1 & 0xffffffff + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $int0 + * @param int $int1 + * @param int $c + * @return array + */ + public static function rotl_64(int $int0, int $int1, int $c): array + { + $int0 &= 0xffffffff; + $int1 &= 0xffffffff; + $c &= 63; + if ($c === 32) { + return array($int1, $int0); + } + if ($c > 31) { + $tmp = $int1; + $int1 = $int0; + $int0 = $tmp; + $c &= 31; + } + if ($c === 0) { + return array($int0, $int1); + } + return array( + 0xffffffff & ( + ($int0 << $c) + | + ($int1 >> (32 - $c)) + ), + 0xffffffff & ( + ($int1 << $c) + | + ($int0 >> (32 - $c)) + ), + ); + } + + /** + * Implements Siphash-2-4 using only 32-bit numbers. + * + * When we split an int into two, the higher bits go to the lower index. + * e.g. 0xDEADBEEFAB10C92D becomes [ + * 0 => 0xDEADBEEF, + * 1 => 0xAB10C92D + * ]. + * + * @internal You should not use this directly from another application + * + * @param string $in + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + * + * @psalm-suppress PossiblyUndefinedArrayOffset + */ + public static function sipHash24( + #[SensitiveParameter] + string $in, + #[SensitiveParameter] + string $key + ): string { + $inlen = self::strlen($in); + + # /* "somepseudorandomlygeneratedbytes" */ + # u64 v0 = 0x736f6d6570736575ULL; + # u64 v1 = 0x646f72616e646f6dULL; + # u64 v2 = 0x6c7967656e657261ULL; + # u64 v3 = 0x7465646279746573ULL; + $v = array( + 0x736f6d65, // 0 + 0x70736575, // 1 + 0x646f7261, // 2 + 0x6e646f6d, // 3 + 0x6c796765, // 4 + 0x6e657261, // 5 + 0x74656462, // 6 + 0x79746573 // 7 + ); + // v0 => $v[0], $v[1] + // v1 => $v[2], $v[3] + // v2 => $v[4], $v[5] + // v3 => $v[6], $v[7] + + # u64 k0 = LOAD64_LE( k ); + # u64 k1 = LOAD64_LE( k + 8 ); + $k = array( + self::load_4(self::substr($key, 4, 4)), + self::load_4(self::substr($key, 0, 4)), + self::load_4(self::substr($key, 12, 4)), + self::load_4(self::substr($key, 8, 4)) + ); + // k0 => $k[0], $k[1] + // k1 => $k[2], $k[3] + + # b = ( ( u64 )inlen ) << 56; + $b = array( + $inlen << 24, + 0 + ); + // See docblock for why the 0th index gets the higher bits. + + # v3 ^= k1; + $v[6] ^= $k[2]; + $v[7] ^= $k[3]; + # v2 ^= k0; + $v[4] ^= $k[0]; + $v[5] ^= $k[1]; + # v1 ^= k1; + $v[2] ^= $k[2]; + $v[3] ^= $k[3]; + # v0 ^= k0; + $v[0] ^= $k[0]; + $v[1] ^= $k[1]; + + $left = $inlen; + # for ( ; in != end; in += 8 ) + while ($left >= 8) { + # m = LOAD64_LE( in ); + $m = array( + self::load_4(self::substr($in, 4, 4)), + self::load_4(self::substr($in, 0, 4)) + ); + + # v3 ^= m; + $v[6] ^= $m[0]; + $v[7] ^= $m[1]; + + # SIPROUND; + # SIPROUND; + $v = self::sipRound($v); + $v = self::sipRound($v); + + # v0 ^= m; + $v[0] ^= $m[0]; + $v[1] ^= $m[1]; + + $in = self::substr($in, 8); + $left -= 8; + } + + # switch( left ) + # { + # case 7: b |= ( ( u64 )in[ 6] ) << 48; + # case 6: b |= ( ( u64 )in[ 5] ) << 40; + # case 5: b |= ( ( u64 )in[ 4] ) << 32; + # case 4: b |= ( ( u64 )in[ 3] ) << 24; + # case 3: b |= ( ( u64 )in[ 2] ) << 16; + # case 2: b |= ( ( u64 )in[ 1] ) << 8; + # case 1: b |= ( ( u64 )in[ 0] ); break; + # case 0: break; + # } + switch ($left) { + case 7: + $b[0] |= self::chrToInt($in[6]) << 16; + case 6: + $b[0] |= self::chrToInt($in[5]) << 8; + case 5: + $b[0] |= self::chrToInt($in[4]); + case 4: + $b[1] |= self::chrToInt($in[3]) << 24; + case 3: + $b[1] |= self::chrToInt($in[2]) << 16; + case 2: + $b[1] |= self::chrToInt($in[1]) << 8; + case 1: + $b[1] |= self::chrToInt($in[0]); + case 0: + break; + } + // See docblock for why the 0th index gets the higher bits. + + # v3 ^= b; + $v[6] ^= $b[0]; + $v[7] ^= $b[1]; + + # SIPROUND; + # SIPROUND; + $v = self::sipRound($v); + $v = self::sipRound($v); + + # v0 ^= b; + $v[0] ^= $b[0]; + $v[1] ^= $b[1]; + + // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation + # v2 ^= 0xff; + $v[5] ^= 0xff; + + # SIPROUND; + # SIPROUND; + # SIPROUND; + # SIPROUND; + $v = self::sipRound(self::sipRound(self::sipRound(self::sipRound($v)))); + + # b = v0 ^ v1 ^ v2 ^ v3; + # STORE64_LE( out, b ); + return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) . + self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Util.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Util.php new file mode 100644 index 000000000..268117134 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/Util.php @@ -0,0 +1,676 @@ +> $size) & 1); + return ( + ($integer ^ $negative) + + + (($negative >> $realSize) & 1) + ); + } + + /** + * @param string $a + * @param string $b + * @return string + * @throws SodiumException + */ + public static function andStrings( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): string { + $len = self::strlen($a); + if (self::strlen($b) !== $len) { + throw new SodiumException('Both strings must be of equal length to combine with bitwise AND'); + } + return $a & $b; + } + + /** + * Convert a binary string into a hexadecimal string without cache-timing + * leaks + * + * @internal You should not use this directly from another application + * + * @param string $binaryString (raw binary) + * @return string + * @throws TypeError + */ + public static function bin2hex( + #[SensitiveParameter] + string $binaryString + ): string { + $hex = ''; + $len = self::strlen($binaryString); + for ($i = 0; $i < $len; ++$i) { + /** @var array $chunk */ + $chunk = unpack('C', $binaryString[$i]); + /** @var int $c */ + $c = $chunk[1] & 0xf; + /** @var int $b */ + $b = $chunk[1] >> 4; + $hex .= pack( + 'CC', + (87 + $b + ((($b - 10) >> 8) & ~38)), + (87 + $c + ((($c - 10) >> 8) & ~38)) + ); + } + return $hex; + } + + /** + * Cache-timing-safe variant of ord() + * + * @internal You should not use this directly from another application + * + * @param string $chr + * @return int + * @throws SodiumException + * @throws TypeError + */ + public static function chrToInt( + #[SensitiveParameter] + string $chr + ): int { + if (self::strlen($chr) !== 1) { + throw new SodiumException('chrToInt() expects a string that is exactly 1 character long'); + } + /** @var array $chunk */ + $chunk = unpack('C', $chr); + return $chunk[1]; + } + + /** + * Compares two strings. + * + * @internal You should not use this directly from another application + * + * @param string $left + * @param string $right + * @param ?int $len + * @return int + * @throws SodiumException + * @throws TypeError + */ + public static function compare( + #[SensitiveParameter] + string $left, + #[SensitiveParameter] + string $right, + ?int $len = null + ): int { + $leftLen = self::strlen($left); + $rightLen = self::strlen($right); + if ($len === null) { + $len = max($leftLen, $rightLen); + $left = str_pad($left, $len, "\x00"); + $right = str_pad($right, $len, "\x00"); + } + + $gt = 0; + $eq = 1; + $i = $len; + while ($i !== 0) { + --$i; + $gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq; + $eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8; + } + return ($gt + $gt + $eq) - 1; + } + + /** + * Evaluate whether or not two strings are equal (in constant-time) + * + * @param string $left + * @param string $right + * @return bool + * + * @throws TypeError + */ + public static function hashEquals( + #[SensitiveParameter] + string $left, + #[SensitiveParameter] + string $right + ): bool { + return hash_equals($left, $right); + } + + /** + * Convert a hexadecimal string into a binary string without cache-timing + * leaks + * + * @internal You should not use this directly from another application + * + * @param string $hexString + * @param string $ignore + * @param bool $strictPadding + * @return string (raw binary) + * @throws RangeException + * @throws TypeError + */ + public static function hex2bin( + #[SensitiveParameter] + string $hexString, + string $ignore = '', + bool $strictPadding = false + ): string { + $hex_pos = 0; + $bin = ''; + $c_acc = 0; + $hex_len = self::strlen($hexString); + $state = 0; + if (($hex_len & 1) !== 0) { + if ($strictPadding) { + throw new RangeException( + 'Expected an even number of hexadecimal characters' + ); + } else { + $hexString = '0' . $hexString; + ++$hex_len; + } + } + + $chunk = unpack('C*', $hexString); + while ($hex_pos < $hex_len) { + ++$hex_pos; + /** @var int $c */ + $c = $chunk[$hex_pos]; + $c_num = $c ^ 48; + $c_num0 = ($c_num - 10) >> 8; + $c_alpha = ($c & ~32) - 55; + $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; + if (($c_num0 | $c_alpha0) === 0) { + if ($ignore && $state === 0 && str_contains($ignore, self::intToChr($c))) { + continue; + } + throw new RangeException( + 'hex2bin() only expects hexadecimal characters' + ); + } + $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); + if ($state === 0) { + $c_acc = $c_val * 16; + } else { + $bin .= pack('C', $c_acc | $c_val); + } + $state ^= 1; + } + return $bin; + } + + /** + * Turn an array of integers into a string + * + * @internal You should not use this directly from another application + * + * @param array $ints + * @return string + */ + public static function intArrayToString(array $ints): string + { + $args = $ints; + foreach ($args as $i => $v) { + $args[$i] = ($v & 0xff); + } + array_unshift($args, str_repeat('C', count($ints))); + return (string) (call_user_func_array('pack', $args)); + } + + /** + * Cache-timing-safe variant of ord() + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function intToChr( + #[SensitiveParameter] + int $int + ): string { + return pack('C', $int); + } + + /** + * Load a 3 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * @throws RangeException + * @throws TypeError + */ + public static function load_3( + #[SensitiveParameter] + string $string + ): int { + /* Input validation: */ + if (self::strlen($string) < 3) { + throw new RangeException( + 'String must be 3 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + /** @var array $unpacked */ + $unpacked = unpack('V', $string . "\0"); + return ($unpacked[1] & 0xffffff); + } + + /** + * Load a 4 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * @throws RangeException + * @throws TypeError + */ + public static function load_4( + #[SensitiveParameter] + string $string + ): int { + /* Input validation: */ + if (self::strlen($string) < 4) { + throw new RangeException( + 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + /** @var array $unpacked */ + $unpacked = unpack('V', $string); + return $unpacked[1]; + } + + /** + * Load a 8 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * + * @throws RangeException + * @throws SodiumException + * @throws TypeError + */ + public static function load64_le( + #[SensitiveParameter] + string $string + ): int { + /* Input validation: */ + if (self::strlen($string) < 4) { + throw new RangeException( + 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + $unpacked = unpack('P', $string); + return (int) $unpacked[1]; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $left + * @param string $right + * @return int + * @throws TypeError + */ + public static function memcmp( + #[SensitiveParameter] + string $left, + #[SensitiveParameter] + string $right + ): int { + if (self::hashEquals($left, $right)) { + return 0; + } + return -1; + } + + /** + * Multiply two integers in constant-time + * + * Micro-architecture timing side-channels caused by how your CPU + * implements multiplication are best prevented by never using the + * multiplication operators and ensuring that our code always takes + * the same number of operations to complete, regardless of the values + * of $a and $b. + * + * @internal You should not use this directly from another application + * + * @param int $a + * @param int $b + * @param int $size Limits the number of operations (useful for small, + * constant operands) + * @return int + */ + public static function mul( + #[SensitiveParameter] + int $a, + #[SensitiveParameter] + int $b, + int $size = 0 + ): int { + if (ParagonIE_Sodium_Compat::$fastMult) { + return (int) ($a * $b); + } + + static $defaultSize = null; + if (!$defaultSize) { + $defaultSize = (PHP_INT_SIZE << 3) - 1; + } + if ($size < 1) { + $size = $defaultSize; + } + /** @var int $size */ + + $c = 0; + + /** + * Mask is either -1 or 0. + * + * -1 in binary looks like 0x1111 ... 1111 + * 0 in binary looks like 0x0000 ... 0000 + */ + $mask = -(($b >> ($defaultSize)) & 1); + + /** + * Ensure $b is a positive integer, without creating + * a branching side-channel + * + * @var int $b + */ + $b = ($b & ~$mask) | ($mask & -$b); + + /** + * Unless $size is provided: + * + * This loop always runs 32 times when PHP_INT_SIZE is 4. + * This loop always runs 64 times when PHP_INT_SIZE is 8. + */ + for ($i = $size; $i >= 0; --$i) { + $c += ($a & -($b & 1)); + $a <<= 1; + $b >>= 1; + } + $c = (int) @($c & -1); + + /** + * If $b was negative, we then apply the same value to $c here. + * It doesn't matter much if $a was negative; the $c += above would + * have produced a negative integer to begin with. But a negative $b + * makes $b >>= 1 never return 0, so we would end up with incorrect + * results. + * + * The end result is what we'd expect from integer multiplication. + */ + return (($c & ~$mask) | ($mask & -$c)); + } + + /** + * Convert any arbitrary numbers into two 32-bit integers that represent + * a 64-bit integer. + * + * @internal You should not use this directly from another application + * + * @param int|float $num + * @return array + * @psalm-suppress RedundantCastGivenDocblockType + */ + public static function numericTo64BitInteger(int|float $num): array + { + $high = 0; + /** @var int $low */ + if (PHP_INT_SIZE === 4) { + $low = (int) $num; + } else { + $low = $num & 0xffffffff; + } + + if ((+(abs($num))) >= 1) { + if ($num > 0) { + /** @var int $high */ + $high = min((+(floor($num/4294967296))), 4294967295); + } else { + $high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296)))); + } + } + /** + * @var int $high + * @var int $low + */ + return array((int) $high, (int) $low); + } + + /** + * Store a 32-bit integer into a string, treating it as little-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store32_le(int $int): string + { + return pack('V', $int); + } + + /** + * Stores a 64-bit integer as an string, treating it as little-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store64_le(int $int): string + { + return pack('P', $int); + } + + /** + * Safe string length + * + * @internal You should not use this directly from another application + * + * @ref mbstring.func_overload + * + * @param string $str + * @return int + * @throws TypeError + */ + public static function strlen( + #[SensitiveParameter] + string $str + ): int { + return ( + self::isMbStringOverride() + ? mb_strlen($str, '8bit') + : strlen($str) + ); + } + + /** + * Turn a string into an array of integers + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return array + * @throws TypeError + */ + public static function stringToIntArray(string $string): array + { + return array_values( + unpack('C*', $string) + ); + } + + /** + * Safe substring + * + * @internal You should not use this directly from another application + * + * @ref mbstring.func_overload + * + * @param string $str + * @param int $start + * @param ?int $length + * @return string + * @throws TypeError + */ + public static function substr( + #[SensitiveParameter] + string $str, + int $start = 0, + ?int $length = null + ): string { + if ($length === 0) { + return ''; + } + + if (self::isMbStringOverride()) { + if (PHP_VERSION_ID < 50400 && $length === null) { + $length = self::strlen($str); + } + $sub = mb_substr($str, $start, $length, '8bit'); + } elseif ($length === null) { + $sub = substr($str, $start); + } else { + $sub = substr($str, $start, $length); + } + if ($sub !== '') { + return $sub; + } + return ''; + } + + /** + * Compare a 16-character byte string in constant time. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return bool + * @throws TypeError + */ + public static function verify_16( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): bool { + return self::hashEquals( + self::substr($a, 0, 16), + self::substr($b, 0, 16) + ); + } + + /** + * Compare a 32-character byte string in constant time. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return bool + * + * @throws SodiumException + * @throws TypeError + */ + public static function verify_32( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): bool { + return self::hashEquals( + self::substr($a, 0, 32), + self::substr($b, 0, 32) + ); + } + + /** + * Calculate $a ^ $b for two strings. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return string + * @throws TypeError + */ + public static function xorStrings( + #[SensitiveParameter] + string $a, + #[SensitiveParameter] + string $b + ): string { + return $a ^ $b; + } + + /** + * Returns whether or not mbstring.func_overload is in effect. + * + * @internal You should not use this directly from another application + * + * Note: MB_OVERLOAD_STRING === 2, but we don't reference the constant + * (for nuisance-free PHP 8 support) + * + * @return bool + */ + protected static function isMbStringOverride(): bool + { + static $mbstring = null; + + if ($mbstring === null) { + if (!defined('MB_OVERLOAD_STRING')) { + $mbstring = false; + return $mbstring; + } + $mbstring = extension_loaded('mbstring') + && defined('MB_OVERLOAD_STRING') + && + ((int) (ini_get('mbstring.func_overload')) & 2); + // MB_OVERLOAD_STRING === 2 + } + /** @var bool $mbstring */ + + return $mbstring; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/X25519.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/X25519.php new file mode 100644 index 000000000..d691c9d8b --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/X25519.php @@ -0,0 +1,238 @@ +> 25; + $h[0] += self::mul($carry9, 19, 5); + $h[9] -= $carry9 << 25; + + $carry1 = ($h[1] + (1 << 24)) >> 25; + $h[2] += $carry1; + $h[1] -= $carry1 << 25; + + $carry3 = ($h[3] + (1 << 24)) >> 25; + $h[4] += $carry3; + $h[3] -= $carry3 << 25; + + $carry5 = ($h[5] + (1 << 24)) >> 25; + $h[6] += $carry5; + $h[5] -= $carry5 << 25; + + $carry7 = ($h[7] + (1 << 24)) >> 25; + $h[8] += $carry7; + $h[7] -= $carry7 << 25; + + + $carry0 = ($h[0] + (1 << 25)) >> 26; + $h[1] += $carry0; + $h[0] -= $carry0 << 26; + + $carry2 = ($h[2] + (1 << 25)) >> 26; + $h[3] += $carry2; + $h[2] -= $carry2 << 26; + + $carry4 = ($h[4] + (1 << 25)) >> 26; + $h[5] += $carry4; + $h[4] -= $carry4 << 26; + + $carry6 = ($h[6] + (1 << 25)) >> 26; + $h[7] += $carry6; + $h[6] -= $carry6 << 26; + + $carry8 = ($h[8] + (1 << 25)) >> 26; + $h[9] += $carry8; + $h[8] -= $carry8 << 26; + + foreach ($h as $i => $value) { + $h[$i] = (int) $value; + } + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); + } + + /** + * @internal You should not use this directly from another application + * + * Inline comments preceded by # are from libsodium's ref10 code. + * + * @param string $n + * @param string $p + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_scalarmult_curve25519_ref10( + #[SensitiveParameter] + string $n, + #[SensitiveParameter] + string $p + ): string { + $e = $n; + $e[0] = self::intToChr( + self::chrToInt($e[0]) & 248 + ); + $e[31] = self::intToChr( + (self::chrToInt($e[31]) & 127) | 64 + ); + $x1 = self::fe_frombytes($p); + $x2 = self::fe_1(); + $z2 = self::fe_0(); + $x3 = clone $x1; + $z3 = self::fe_1(); + + $swap = 0; + for ($pos = 254; $pos >= 0; --$pos) { + # b = e[pos / 8] >> (pos & 7); + $b = self::chrToInt( + $e[$pos >> 3] + ) >> ($pos & 7); + $b &= 1; + $swap ^= $b; + self::fe_cswap($x2, $x3, $swap); + self::fe_cswap($z2, $z3, $swap); + $swap = $b; + $tmp0 = self::fe_sub($x3, $z3); + $tmp1 = self::fe_sub($x2, $z2); + $x2 = self::fe_add($x2, $z2); + $z2 = self::fe_add($x3, $z3); + $z3 = self::fe_mul($tmp0, $x2); + $z2 = self::fe_mul($z2, $tmp1); + $tmp0 = self::fe_sq($tmp1); + $tmp1 = self::fe_sq($x2); + $x3 = self::fe_add($z3, $z2); + $z2 = self::fe_sub($z3, $z2); + $x2 = self::fe_mul($tmp1, $tmp0); + $tmp1 = self::fe_sub($tmp1, $tmp0); + $z2 = self::fe_sq($z2); + $z3 = self::fe_mul121666($tmp1); + $x3 = self::fe_sq($x3); + $tmp0 = self::fe_add($tmp0, $z3); + $z3 = self::fe_mul($x1, $z2); + $z2 = self::fe_mul($tmp1, $tmp0); + } + self::fe_cswap($x2, $x3, $swap); + self::fe_cswap($z2, $z3, $swap); + + $z2 = self::fe_invert($z2); + $x2 = self::fe_mul($x2, $z2); + return self::fe_tobytes($x2); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY + * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function edwards_to_montgomery( + ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY, + ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ + ): ParagonIE_Sodium_Core_Curve25519_Fe { + $tempX = self::fe_add($edwardsZ, $edwardsY); + $tempZ = self::fe_sub($edwardsZ, $edwardsY); + $tempZ = self::fe_invert($tempZ); + return self::fe_mul($tempX, $tempZ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $n + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function crypto_scalarmult_curve25519_ref10_base( + #[SensitiveParameter] + string $n + ): string { + $e = $n; + $e[0] = self::intToChr( + self::chrToInt($e[0]) & 248 + ); + $e[31] = self::intToChr( + (self::chrToInt($e[31]) & 127) | 64 + ); + + $A = self::ge_scalarmult_base($e); + $pk = self::edwards_to_montgomery($A->Y, $A->Z); + return self::fe_tobytes($pk); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/XChaCha20.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/XChaCha20.php new file mode 100644 index 000000000..4e91dd79f --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/Core/XChaCha20.php @@ -0,0 +1,137 @@ +update($ad); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update($ciphertext); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); + $computed_mac = $state->finish(); + + /* Compare the given MAC with the recalculated MAC: */ + if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { + throw new SodiumException('Invalid MAC'); + } + + // Here, we know that the MAC is valid, so we decrypt and return the plaintext + return ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $ciphertext, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305 + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function aead_chacha20poly1305_encrypt( + #[SensitiveParameter] + string $message = '', + string $ad = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Length of the plaintext message */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /* Length of the associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /* The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( + 32, + $nonce, + $key + ); + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (SodiumException) { + $block0 = null; + } + + /** @var string $ciphertext - Raw encrypted data */ + $ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $message, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + + $state->update($ad); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update($ciphertext); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); + return $ciphertext . $state->finish(); + } + + /** + * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function aead_chacha20poly1305_ietf_decrypt( + string $message = '', + string $ad = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Length of associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /* Length of message (ciphertext + MAC) */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /* Length of ciphertext */ + $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; + + /* The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( + 32, + $nonce, + $key + ); + + /** @var string $mac - Message authentication code */ + $mac = ParagonIE_Sodium_Core_Util::substr( + $message, + $len - self::aead_chacha20poly1305_IETF_ABYTES, + self::aead_chacha20poly1305_IETF_ABYTES + ); + + /** @var string $ciphertext - The encrypted message (sans MAC) */ + $ciphertext = ParagonIE_Sodium_Core_Util::substr( + $message, + 0, + $len - self::aead_chacha20poly1305_IETF_ABYTES + ); + + /* Recalculate the Poly1305 authentication tag (MAC): */ + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (SodiumException) { + $block0 = null; + } + $state->update($ad); + $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); + $state->update($ciphertext); + $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); + $computed_mac = $state->finish(); + + /* Compare the given MAC with the recalculated MAC: */ + if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { + throw new SodiumException('Invalid MAC'); + } + + // Here, we know that the MAC is valid, so we decrypt and return the plaintext + return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $ciphertext, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function aead_chacha20poly1305_ietf_encrypt( + #[SensitiveParameter] + string $message = '', + string $ad = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + /* Length of the plaintext message */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /* Length of the associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /* The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( + 32, + $nonce, + $key + ); + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (SodiumException) { + $block0 = null; + } + + /** @var string $ciphertext - Raw encrypted data */ + $ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $message, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + + $state->update($ad); + $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); + $state->update($ciphertext); + $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); + return $ciphertext . $state->finish(); + } + + /** + * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function aead_xchacha20poly1305_ietf_decrypt( + string $message = '', + string $ad = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = "\x00\x00\x00\x00" . + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function aead_xchacha20poly1305_ietf_encrypt( + #[SensitiveParameter] + string $message = '', + string $ad = '', + string $nonce = '', + #[SensitiveParameter] + string $key = '' + ): string { + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = "\x00\x00\x00\x00" . + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); + } + + /** + * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $key + * @return string + * @throws TypeError + */ + public static function auth( + string $message, + #[SensitiveParameter] + string $key + ): string { + return ParagonIE_Sodium_Core_Util::substr( + hash_hmac('sha512', $message, $key, true), + 0, + 32 + ); + } + + /** + * HMAC-SHA-512-256 validation. Constant-time via hash_equals(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $mac + * @param string $message + * @param string $key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function auth_verify( + string $mac, + string $message, + #[SensitiveParameter] + string $key + ): bool { + return ParagonIE_Sodium_Core_Util::hashEquals( + $mac, + self::auth($message, $key) + ); + } + + /** + * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $keypair + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box( + #[SensitiveParameter] + string $plaintext, + string $nonce, + #[SensitiveParameter] + string $keypair + ): string { + return self::secretbox( + $plaintext, + $nonce, + self::box_beforenm( + self::box_secretkey($keypair), + self::box_publickey($keypair) + ) + ); + } + + /** + * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $publicKey + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box_seal( + #[SensitiveParameter] + string $message, + string $publicKey + ): string { + /** @var string $ephemeralKeypair */ + $ephemeralKeypair = self::box_keypair(); + + /** @var string $ephemeralSK */ + $ephemeralSK = self::box_secretkey($ephemeralKeypair); + + /** @var string $ephemeralPK */ + $ephemeralPK = self::box_publickey($ephemeralKeypair); + + /** @var string $nonce */ + $nonce = self::generichash( + $ephemeralPK . $publicKey, + '', + 24 + ); + + /** @var string $keypair - The combined keypair used in crypto_box() */ + $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); + + /** @var string $ciphertext Ciphertext + MAC from crypto_box */ + $ciphertext = self::box($message, $nonce, $keypair); + try { + ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); + ParagonIE_Sodium_Compat::memzero($ephemeralSK); + ParagonIE_Sodium_Compat::memzero($nonce); + } catch (SodiumException) { + $ephemeralKeypair = null; + $ephemeralSK = null; + $nonce = null; + } + return $ephemeralPK . $ciphertext; + } + + /** + * Opens a message encrypted via box_seal(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $keypair + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box_seal_open( + string $message, + #[SensitiveParameter] + string $keypair + ): string { + /** @var string $ephemeralPK */ + $ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32); + + /** @var string $ciphertext (ciphertext + MAC) */ + $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32); + + /** @var string $secretKey */ + $secretKey = self::box_secretkey($keypair); + + /** @var string $publicKey */ + $publicKey = self::box_publickey($keypair); + + /** @var string $nonce */ + $nonce = self::generichash( + $ephemeralPK . $publicKey, + '', + 24 + ); + + /** @var string $keypair */ + $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); + + /** @var string $m */ + $m = self::box_open($ciphertext, $nonce, $keypair); + try { + ParagonIE_Sodium_Compat::memzero($secretKey); + ParagonIE_Sodium_Compat::memzero($ephemeralPK); + ParagonIE_Sodium_Compat::memzero($nonce); + } catch (SodiumException) { + $secretKey = null; + $ephemeralPK = null; + $nonce = null; + } + return $m; + } + + /** + * Used by crypto_box() to get the crypto_secretbox() key. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sk + * @param string $pk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box_beforenm( + #[SensitiveParameter] + string $sk, + string $pk + ): string + { + return ParagonIE_Sodium_Core_HSalsa20::hsalsa20( + str_repeat("\x00", 16), + self::scalarmult($sk, $pk) + ); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @return string + * @throws Exception + * @throws SodiumException + * @throws TypeError + */ + public static function box_keypair(): string + { + $sKey = random_bytes(32); + $pKey = self::scalarmult_base($sKey); + return $sKey . $pKey; + } + + /** + * @param string $seed + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box_seed_keypair( + #[SensitiveParameter] + string $seed + ): string + { + $sKey = ParagonIE_Sodium_Core_Util::substr( + hash('sha512', $seed, true), + 0, + 32 + ); + $pKey = self::scalarmult_base($sKey); + return $sKey . $pKey; + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @param string $pKey + * @return string + * @throws TypeError + */ + public static function box_keypair_from_secretkey_and_publickey( + #[SensitiveParameter] + string $sKey, + string $pKey + ): string { + return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) . + ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $keypair + * @return string + * @throws RangeException + * @throws TypeError + */ + public static function box_secretkey( + #[SensitiveParameter] + string $keypair + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) { + throw new RangeException( + 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' + ); + } + return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $keypair + * @return string + * @throws RangeException + * @throws TypeError + */ + public static function box_publickey( + #[SensitiveParameter] + string $keypair + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { + throw new RangeException( + 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' + ); + } + return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @return string + * @throws RangeException + * @throws SodiumException + * @throws TypeError + */ + public static function box_publickey_from_secretkey( + #[SensitiveParameter] + string $sKey + ): string { + if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { + throw new RangeException( + 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.' + ); + } + return self::scalarmult_base($sKey); + } + + /** + * Decrypt a message encrypted with box(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $keypair + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function box_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $keypair + ): string { + return self::secretbox_open( + $ciphertext, + $nonce, + self::box_beforenm( + self::box_secretkey($keypair), + self::box_publickey($keypair) + ) + ); + } + + /** + * Calculate a BLAKE2b hash. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string|null $key + * @param int $outlen + * @return string + * @throws RangeException + * @throws SodiumException + * @throws TypeError + */ + public static function generichash( + string $message, + #[SensitiveParameter] + ?string $key = '', + int $outlen = 32 + ): string { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + /** @psalm-suppress RiskyTruthyFalsyComparison */ + if (!empty($key)) { + /** @var SplFixedArray $k */ + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + + /** @var SplFixedArray $in */ + $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); + + /** @var SplFixedArray $ctx */ + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen); + ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count()); + + /** @var SplFixedArray $out */ + $out = new SplFixedArray($outlen); + $out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out); + + /** @var array */ + $outArray = $out->toArray(); + return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); + } + + /** + * Finalize a BLAKE2b hashing context, returning the hash. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ctx + * @param int $outlen + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function generichash_final(string $ctx, int $outlen = 32): string + { + $out = new SplFixedArray($outlen); + $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); + $out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out); + $outArray = $out->toArray(); + return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); + } + + /** + * Initialize a hashing context for BLAKE2b. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $key + * @param int $outputLength + * @return string + * @throws RangeException + * @throws SodiumException + * @throws TypeError + */ + public static function generichash_init( + #[SensitiveParameter] + string $key = '', + int $outputLength = 32 + ): string { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + if (!empty($key)) { + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + + /** @var SplFixedArray $ctx */ + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength); + + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); + } + + /** + * Initialize a hashing context for BLAKE2b. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $key + * @param int $outputLength + * @param string $salt + * @param string $personal + * @return string + * @throws RangeException + * @throws SodiumException + * @throws TypeError + */ + public static function generichash_init_salt_personal( + #[SensitiveParameter] + string $key = '', + int $outputLength = 32, + string $salt = '', + string $personal = '' + ): string { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + if (!empty($key)) { + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + if (!empty($salt)) { + $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt); + } else { + $s = null; + } + if (!empty($salt)) { + $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal); + } else { + $p = null; + } + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p); + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); + } + + /** + * Update a hashing context for BLAKE2b with $message + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ctx + * @param string $message + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function generichash_update(string $ctx, string $message): string + { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); + $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); + ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count()); + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context); + } + + /** + * Libsodium's crypto_kx(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $my_sk + * @param string $their_pk + * @param string $client_pk + * @param string $server_pk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function keyExchange( + #[SensitiveParameter] + string $my_sk, + string $their_pk, + string $client_pk, + string $server_pk + ): string { + return ParagonIE_Sodium_Compat::crypto_generichash( + ParagonIE_Sodium_Compat::crypto_scalarmult($my_sk, $their_pk) . + $client_pk . + $server_pk + ); + } + + /** + * ECDH over Curve25519 + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @param string $pKey + * @return string + * + * @throws SodiumException + * @throws TypeError + */ + public static function scalarmult( + #[SensitiveParameter] + string $sKey, + string $pKey + ): string { + $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); + self::scalarmult_throw_if_zero($q); + return $q; + } + + /** + * ECDH over Curve25519, using the basepoint. + * Used to get a secret key from a public key. + * + * @param string $secret + * @return string + * + * @throws SodiumException + * @throws TypeError + */ + public static function scalarmult_base( + #[SensitiveParameter] + string $secret + ): string { + $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret); + self::scalarmult_throw_if_zero($q); + return $q; + } + + /** + * This throws an Error if a zero public key was passed to the function. + * + * @param string $q + * @return void + * @throws SodiumException + * @throws TypeError + */ + protected static function scalarmult_throw_if_zero( + #[SensitiveParameter] + string $q + ): void { + $d = 0; + for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { + $d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]); + } + + /* branch-free variant of === 0 */ + if (-(1 & (($d - 1) >> 8))) { + throw new SodiumException('Zero public key is not allowed'); + } + } + + /** + * XSalsa20-Poly1305 authenticated symmetric-key encryption. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox( + #[SensitiveParameter] + string $plaintext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + $block0 = str_repeat("\x00", 32); + + /* Length of the plaintext message */ + $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); + $mlen0 = min($mlen, 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES); + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( + $block0, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $block0, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ); + if ($mlen > $mlen0) { + $c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + ParagonIE_Sodium_Core_Util::substr( + $plaintext, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + 1, + $subkey + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + self::onetimeauth_poly1305_KEYBYTES + ) + ); + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (SodiumException) { + $block0 = null; + $subkey = null; + } + + $state->update($c); + + /** @var string $c - MAC || ciphertext */ + $c = $state->finish() . $c; + unset($state); + + return $c; + } + + /** + * Decrypt a ciphertext generated via secretbox(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + $mac = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + self::secretbox_xsalsa20poly1305_MACBYTES + ); + + $c = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + self::secretbox_xsalsa20poly1305_MACBYTES + ); + + $clen = ParagonIE_Sodium_Core_Util::strlen($c); + + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( + $mac, + $c, + ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) + ); + if (!$verified) { + try { + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (SodiumException) { + $subkey = null; + } + throw new SodiumException('Invalid MAC'); + } + + /* Decrypted message */ + $m = ParagonIE_Sodium_Core_Util::xorStrings( + ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), + ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) + ); + if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { + // We had more than 1 block, so let's continue to decrypt the rest. + $m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + ParagonIE_Sodium_Core_Util::substr( + $c, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + 1, + $subkey + ); + } + return $m; + } + + /** + * XChaCha20-Poly1305 authenticated symmetric-key encryption. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox_xchacha20poly1305( + #[SensitiveParameter] + string $plaintext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + $block0 = str_repeat("\x00", 32); + + /*Length of the plaintext message */ + $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); + $mlen0 = $mlen; + if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { + $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; + } + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $block0, + $nonceLast, + $subkey + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $block0, + self::secretbox_xchacha20poly1305_ZEROBYTES + ); + if ($mlen > $mlen0) { + $c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + ParagonIE_Sodium_Core_Util::substr( + $plaintext, + self::secretbox_xchacha20poly1305_ZEROBYTES + ), + $nonceLast, + $subkey, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + self::onetimeauth_poly1305_KEYBYTES + ) + ); + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (SodiumException) { + $block0 = null; + $subkey = null; + } + + $state->update($c); + + /** @var string $c - MAC || ciphertext */ + $c = $state->finish() . $c; + unset($state); + + return $c; + } + + /** + * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $key + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox_xchacha20poly1305_open( + string $ciphertext, + string $nonce, + #[SensitiveParameter] + string $key + ): string { + /** @var string $mac */ + $mac = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + self::secretbox_xchacha20poly1305_MACBYTES + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + self::secretbox_xchacha20poly1305_MACBYTES + ); + + /** @var int $clen */ + $clen = ParagonIE_Sodium_Core_Util::strlen($c); + + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( + $mac, + $c, + ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) + ); + + if (!$verified) { + try { + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (SodiumException) { + $subkey = null; + } + throw new SodiumException('Invalid MAC'); + } + + /* Decrypted message */ + $m = ParagonIE_Sodium_Core_Util::xorStrings( + ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), + ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) + ); + + if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { + // We had more than 1 block, so let's continue to decrypt the rest. + $m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + ParagonIE_Sodium_Core_Util::substr( + $c, + self::secretbox_xchacha20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + return $m; + } + + /** + * @param string $key + * @return array Returns a state and a header. + * @throws Exception + * @throws SodiumException + */ + public static function secretstream_xchacha20poly1305_init_push( + #[SensitiveParameter] + string $key + ): array { + # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); + $out = random_bytes(24); + + # crypto_core_hchacha20(state->k, out, k, NULL); + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key); + $state = new ParagonIE_Sodium_Core_SecretStream_State( + $subkey, + ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4) + ); + + # _crypto_secretstream_xchacha20poly1305_counter_reset(state); + $state->counterReset(); + + # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, + # crypto_secretstream_xchacha20poly1305_INONCEBYTES); + # memset(state->_pad, 0, sizeof state->_pad); + return array( + $state->toString(), + $out + ); + } + + /** + * @param string $key + * @param string $header + * @return string Returns a state. + * @throws Exception + */ + public static function secretstream_xchacha20poly1305_init_pull( + #[SensitiveParameter] + string $key, + string $header + ): string { + # crypto_core_hchacha20(state->k, in, k, NULL); + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($header, 0, 16), + $key + ); + $state = new ParagonIE_Sodium_Core_SecretStream_State( + $subkey, + ParagonIE_Sodium_Core_Util::substr($header, 16) + ); + $state->counterReset(); + # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, + # crypto_secretstream_xchacha20poly1305_INONCEBYTES); + # memset(state->_pad, 0, sizeof state->_pad); + # return 0; + return $state->toString(); + } + + /** + * @param string $state + * @param string $msg + * @param string $aad + * @param int $tag + * @return string + * @throws SodiumException + */ + public static function secretstream_xchacha20poly1305_push( + #[SensitiveParameter] + string &$state, + #[SensitiveParameter] + string $msg, + string $aad = '', + int $tag = 0 + ): string { + $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); + # crypto_onetimeauth_poly1305_state poly1305_state; + # unsigned char block[64U]; + # unsigned char slen[8U]; + # unsigned char *c; + # unsigned char *mac; + + $msglen = ParagonIE_Sodium_Core_Util::strlen($msg); + $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad); + + if ((($msglen + 63) >> 6) > 0xfffffffe) { + throw new SodiumException( + 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' + ); + } + + # if (outlen_p != NULL) { + # *outlen_p = 0U; + # } + # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { + # sodium_misuse(); + # } + + # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + # crypto_onetimeauth_poly1305_init(&poly1305_state, block); + # sodium_memzero(block, sizeof block); + $auth = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) + ); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + $auth->update($aad); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + # (0x10 - adlen) & 0xf); + $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); + + # memset(block, 0, sizeof block); + # block[0] = tag; + # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + # state->nonce, 1U, state->k); + $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + $auth->update($block); + + # out[0] = block[0]; + $out = $block[0]; + # c = out + (sizeof tag); + # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); + $cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $msg, + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(2) + ); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + $auth->update($cipher); + + $out .= $cipher; + unset($cipher); + + # crypto_onetimeauth_poly1305_update + # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); + + # STORE64_LE(slen, (uint64_t) adlen); + $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + $auth->update($slen); + + # STORE64_LE(slen, (sizeof block) + mlen); + $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + $auth->update($slen); + + # mac = c + mlen; + # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + $mac = $auth->finish(); + $out .= $mac; + + # sodium_memzero(&poly1305_state, sizeof poly1305_state); + unset($auth); + + + # XOR_BUF(STATE_INONCE(state), mac, + # crypto_secretstream_xchacha20poly1305_INONCEBYTES); + $st->xorNonce($mac); + + # sodium_increment(STATE_COUNTER(state), + # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + $st->incrementCounter(); + // Overwrite by reference: + $state = $st->toString(); + + /** @var bool $rekey */ + $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; + # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + # sodium_is_zero(STATE_COUNTER(state), + # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + # crypto_secretstream_xchacha20poly1305_rekey(state); + # } + if ($rekey || $st->needsRekey()) { + // DO REKEY + self::secretstream_xchacha20poly1305_rekey($state); + } + # if (outlen_p != NULL) { + # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; + # } + return $out; + } + + /** + * @param string $state + * @param string $cipher + * @param string $aad + * @return bool|array{0: string, 1: int} + * @throws SodiumException + */ + public static function secretstream_xchacha20poly1305_pull( + #[SensitiveParameter] + string &$state, + string $cipher, + string $aad = '' + ): bool|array { + $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); + + $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher); + # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; + $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; + $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad); + + # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { + # sodium_misuse(); + # } + if ((($msglen + 63) >> 6) > 0xfffffffe) { + throw new SodiumException( + 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' + ); + } + + # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + # crypto_onetimeauth_poly1305_init(&poly1305_state, block); + # sodium_memzero(block, sizeof block); + $auth = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) + ); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + $auth->update($aad); + + # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + # (0x10 - adlen) & 0xf); + $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); + + + # memset(block, 0, sizeof block); + # block[0] = in[0]; + # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + # state->nonce, 1U, state->k); + $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $cipher[0] . str_repeat("\0", 63), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + # tag = block[0]; + # block[0] = in[0]; + # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + $tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]); + $block[0] = $cipher[0]; + $auth->update($block); + + + # c = in + (sizeof tag); + # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + $auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen)); + + # crypto_onetimeauth_poly1305_update + # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); + + # STORE64_LE(slen, (uint64_t) adlen); + # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen); + $auth->update($slen); + + # STORE64_LE(slen, (sizeof block) + mlen); + # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen); + $auth->update($slen); + + # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + # sodium_memzero(&poly1305_state, sizeof poly1305_state); + $mac = $auth->finish(); + + # stored_mac = c + mlen; + # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { + # sodium_memzero(mac, sizeof mac); + # return -1; + # } + + $stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16); + if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) { + return false; + } + + # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); + $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen), + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(2) + ); + + # XOR_BUF(STATE_INONCE(state), mac, + # crypto_secretstream_xchacha20poly1305_INONCEBYTES); + $st->xorNonce($mac); + + # sodium_increment(STATE_COUNTER(state), + # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + $st->incrementCounter(); + + # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + # sodium_is_zero(STATE_COUNTER(state), + # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + # crypto_secretstream_xchacha20poly1305_rekey(state); + # } + + // Overwrite by reference: + $state = $st->toString(); + + /** @var bool $rekey */ + $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; + if ($rekey || $st->needsRekey()) { + // DO REKEY + self::secretstream_xchacha20poly1305_rekey($state); + } + return array($out, $tag); + } + + /** + * @param string $state + * @return void + * @throws SodiumException + */ + public static function secretstream_xchacha20poly1305_rekey( + #[SensitiveParameter] + string &$state + ): void { + $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); + # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + + # crypto_secretstream_xchacha20poly1305_INONCEBYTES]; + # size_t i; + # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { + # new_key_and_inonce[i] = state->k[i]; + # } + $new_key_and_inonce = $st->getKey(); + + # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = + # STATE_INONCE(state)[i]; + # } + $new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8); + + # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, + # sizeof new_key_and_inonce, + # state->nonce, state->k); + + $st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $new_key_and_inonce, + $st->getCombinedNonce(), + $st->getKey(), + ParagonIE_Sodium_Core_Util::store64_le(0) + )); + + # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { + # state->k[i] = new_key_and_inonce[i]; + # } + # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + # STATE_INONCE(state)[i] = + # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; + # } + # _crypto_secretstream_xchacha20poly1305_counter_reset(state); + $st->counterReset(); + + $state = $st->toString(); + } + + /** + * Detached Ed25519 signature. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sign_detached( + string $message, + #[SensitiveParameter] + string $sk + ): string { + return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk); + } + + /** + * Attached Ed25519 signature. (Returns a signed message.) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $sk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sign( + string $message, + #[SensitiveParameter] + string $sk + ): string { + return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk); + } + + /** + * Opens a signed message. If valid, returns the message. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $signedMessage + * @param string $pk + * @return string + * @throws SodiumException + * @throws TypeError + */ + public static function sign_open( + string $signedMessage, + #[SensitiveParameter] + string $pk + ): string { + return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk); + } + + /** + * Verify a detached signature of a given message and public key. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $signature + * @param string $message + * @param string $pk + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function sign_verify_detached( + string $signature, + string $message, + string $pk + ): bool { + return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/File.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/File.php new file mode 100644 index 000000000..01943452e --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/File.php @@ -0,0 +1,972 @@ + ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes'); + } + } + if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) { + throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN'); + } + if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) { + throw new SodiumException('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX'); + } + + $size = filesize($filePath); + if (!is_int($size)) { + throw new SodiumException('Could not obtain the file size'); + } + + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new SodiumException('Could not open input file for reading'); + } + $ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength); + while ($size > 0) { + $blockSize = min($size, 64); + $read = fread($fp, $blockSize); + if (!is_string($read)) { + throw new SodiumException('Could not read input file'); + } + ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $read); + $size -= $blockSize; + } + + fclose($fp); + return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength); + } + + /** + * Encrypt a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_secretbox(), but produces + * the same result. + * + * @param string $inputFile Absolute path to a file on the filesystem + * @param string $outputFile Absolute path to a file on the filesystem + * @param string $nonce Number to be used only once + * @param string $key Encryption key + * + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox( + string $inputFile, + string $outputFile, + string $nonce, + #[SensitiveParameter] + string $key + ): bool { + /* Input validation: */ + if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new TypeError('Argument 3 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); + } + if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_KEYBYTES bytes'); + } + + $size = filesize($inputFile); + if (!is_int($size)) { + throw new SodiumException('Could not obtain the file size'); + } + + $ifp = fopen($inputFile, 'rb'); + if (!is_resource($ifp)) { + throw new SodiumException('Could not open input file for reading'); + } + + $ofp = fopen($outputFile, 'wb'); + if (!is_resource($ofp)) { + fclose($ifp); + throw new SodiumException('Could not open output file for writing'); + } + + $res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key); + fclose($ifp); + fclose($ofp); + return $res; + } + + /** + * Seal a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_secretbox_open(), but produces + * the same result. + * + * Warning: Does not protect against TOCTOU attacks. You should + * just load the file into memory and use crypto_secretbox_open() if + * you are worried about those. + * + * @param string $inputFile + * @param string $outputFile + * @param string $nonce + * @param string $key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + public static function secretbox_open( + string $inputFile, + string $outputFile, + string $nonce, + #[SensitiveParameter] + string $key + ): bool { + /* Input validation: */ + if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); + } + if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOXBOX_KEYBYTES bytes'); + } + + $size = filesize($inputFile); + if (!is_int($size)) { + throw new SodiumException('Could not obtain the file size'); + } + + $ifp = fopen($inputFile, 'rb'); + if (!is_resource($ifp)) { + throw new SodiumException('Could not open input file for reading'); + } + + $ofp = fopen($outputFile, 'wb'); + if (!is_resource($ofp)) { + fclose($ifp); + throw new SodiumException('Could not open output file for writing'); + } + + $res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key); + fclose($ifp); + fclose($ofp); + try { + ParagonIE_Sodium_Compat::memzero($key); + } catch (SodiumException) { + /** @psalm-suppress PossiblyUndefinedVariable */ + unset($key); + } + return $res; + } + + /** + * Sign a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces + * the same result. + * + * @param string $filePath Absolute path to a file on the filesystem + * @param string $secretKey Secret signing key + * + * @return string Ed25519 signature + * @throws SodiumException + * @throws TypeError + */ + public static function sign( + string $filePath, + #[SensitiveParameter] + string $secretKey + ): string { + /* Input validation: */ + if (self::strlen($secretKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new TypeError('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES bytes'); + } + + $size = filesize($filePath); + if (!is_int($size)) { + throw new SodiumException('Could not obtain the file size'); + } + + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new SodiumException('Could not open input file for reading'); + } + + /** @var string $az */ + $az = hash('sha512', self::substr($secretKey, 0, 32), true); + + $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); + $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); + + $hs = hash_init('sha512'); + hash_update($hs, self::substr($az, 32, 32)); + $hs = self::updateHashWithFile($hs, $fp, $size); + + /** @var string $nonceHash */ + $nonceHash = hash_final($hs, true); + + /** @var string $pk */ + $pk = self::substr($secretKey, 32, 32); + + /** @var string $nonce */ + $nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); + + /** @var string $sig */ + $sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes( + ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce) + ); + + $hs = hash_init('sha512'); + hash_update($hs, self::substr($sig, 0, 32)); + hash_update($hs, self::substr($pk, 0, 32)); + $hs = self::updateHashWithFile($hs, $fp, $size); + + /** @var string $hramHash */ + $hramHash = hash_final($hs, true); + + /** @var string $hram */ + $hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash); + + /** @var string $sigAfter */ + $sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az, $nonce); + + /** @var string $sig */ + $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); + + try { + ParagonIE_Sodium_Compat::memzero($az); + } catch (SodiumException) { + $az = null; + } + fclose($fp); + return $sig; + } + + /** + * Verify a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but + * produces the same result. + * + * @param string $sig Ed25519 signature + * @param string $filePath Absolute path to a file on the filesystem + * @param string $publicKey Signing public key + * + * @return bool + * @throws SodiumException + * @throws TypeError + * @throws Exception + */ + public static function verify(string $sig, string $filePath, string $publicKey): bool + { + /* Input validation: */ + if (self::strlen($sig) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) { + throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES bytes'); + } + if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new TypeError('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes'); + } + if (self::strlen($sig) < 64) { + throw new SodiumException('Signature is too short'); + } + + + /* Security checks */ + if ( + (ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240) + && + ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32)) + ) { + throw new SodiumException('S < L - Invalid signature'); + } + if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) { + throw new SodiumException('Signature is on too small of an order'); + } + if ((self::chrToInt($sig[63]) & 224) !== 0) { + throw new SodiumException('Invalid signature'); + } + $d = 0; + for ($i = 0; $i < 32; ++$i) { + $d |= self::chrToInt($publicKey[$i]); + } + if ($d === 0) { + throw new SodiumException('All zero public key'); + } + + $size = filesize($filePath); + if (!is_int($size)) { + throw new SodiumException('Could not obtain the file size'); + } + + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new SodiumException('Could not open input file for reading'); + } + + /* The original value of ParagonIE_Sodium_Compat::$fastMult */ + $orig = ParagonIE_Sodium_Compat::$fastMult; + + // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. + ParagonIE_Sodium_Compat::$fastMult = true; + + $A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey); + + $hs = hash_init('sha512'); + hash_update($hs, self::substr($sig, 0, 32)); + hash_update($hs, self::substr($publicKey, 0, 32)); + + $hs = self::updateHashWithFile($hs, $fp, $size); + $hDigest = hash_final($hs, true); + $h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); + $R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime( + $h, + $A, + self::substr($sig, 32) + ); + + /** @var string $rcheck */ + $rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R); + + // Close the file handle + fclose($fp); + + // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. + ParagonIE_Sodium_Compat::$fastMult = $orig; + return self::verify_32($rcheck, self::substr($sig, 0, 32)); + } + + /** + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $boxKeypair + * @return bool + * @throws SodiumException + * @throws TypeError + */ + protected static function box_encrypt( + $ifp, + $ofp, + int $mlen, + string $nonce, + #[SensitiveParameter] + string $boxKeypair + ): bool { + return self::secretbox_encrypt( + $ifp, + $ofp, + $mlen, + $nonce, + ParagonIE_Sodium_Crypto::box_beforenm( + ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), + ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) + ) + ); + } + + + /** + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $boxKeypair + * @return bool + * @throws SodiumException + * @throws TypeError + */ + protected static function box_decrypt( + $ifp, + $ofp, + int $mlen, + string $nonce, + #[SensitiveParameter] + string $boxKeypair + ): bool { + return self::secretbox_decrypt( + $ifp, + $ofp, + $mlen, + $nonce, + ParagonIE_Sodium_Crypto::box_beforenm( + ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), + ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) + ) + ); + } + + /** + * Encrypt a file + * + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + protected static function secretbox_encrypt( + $ifp, + $ofp, + int $mlen, + string $nonce, + #[SensitiveParameter] + string $key + ): bool { + $plaintext = fread($ifp, 32); + if (!is_string($plaintext)) { + throw new SodiumException('Could not read input file'); + } + $first32 = self::ftell($ifp); + + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + $block0 = str_repeat("\x00", 32); + + /* Length of the plaintext message */ + $mlen0 = $mlen; + if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { + $mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; + } + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( + $block0, + $realNonce, + $subkey + ); + + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES + ) + ); + + // Pre-write 16 blank bytes for the Poly1305 tag + $start = self::ftell($ofp); + fwrite($ofp, str_repeat("\x00", 16)); + + /** @var string $c */ + $cBlock = ParagonIE_Sodium_Core_Util::substr( + $block0, + ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES + ); + $state->update($cBlock); + fwrite($ofp, $cBlock); + $mlen -= 32; + + $iter = 1; + $incr = self::BUFFER_SIZE >> 6; + /* + * Set the cursor to the end of the first half-block. All future bytes will + * generated from salsa20_xor_ic, starting from 1 (second block). + */ + fseek($ifp, $first32); + + while ($mlen > 0) { + $blockSize = min($mlen, self::BUFFER_SIZE); + $plaintext = fread($ifp, $blockSize); + if (!is_string($plaintext)) { + throw new SodiumException('Could not read input file'); + } + $cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + $plaintext, + $realNonce, + $iter, + $subkey + ); + fwrite($ofp, $cBlock, $blockSize); + $state->update($cBlock); + + $mlen -= $blockSize; + $iter += $incr; + } + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (SodiumException) { + $block0 = null; + $subkey = null; + } + $end = self::ftell($ofp); + + /* + * Write the Poly1305 authentication tag that provides integrity + * over the ciphertext (encrypt-then-MAC) + */ + fseek($ofp, $start); + fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); + fseek($ofp, $end); + unset($state); + + return true; + } + + /** + * Decrypt a file + * + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $key + * @return bool + * @throws SodiumException + * @throws TypeError + */ + protected static function secretbox_decrypt( + $ifp, + $ofp, + int $mlen, + string $nonce, + #[SensitiveParameter] + string $key + ): bool { + $tag = fread($ifp, 16); + if (!is_string($tag)) { + throw new SodiumException('Could not read input file'); + } + + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + + /* Verify the Poly1305 MAC -before- attempting to decrypt! */ + $state = new ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32)); + if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) { + throw new SodiumException('Invalid MAC'); + } + + /* + * Set the cursor to the end of the first half-block. All future bytes will + * generated from salsa20_xor_ic, starting from 1 (second block). + */ + $first32 = fread($ifp, 32); + if (!is_string($first32)) { + throw new SodiumException('Could not read input file'); + } + $first32len = self::strlen($first32); + fwrite( + $ofp, + self::xorStrings( + self::substr($block0, 32, $first32len), + self::substr($first32, 0, $first32len) + ) + ); + $mlen -= 32; + $iter = 1; + $incr = self::BUFFER_SIZE >> 6; + + /* Decrypts ciphertext, writes to output file. */ + while ($mlen > 0) { + $blockSize = min($mlen, self::BUFFER_SIZE); + $ciphertext = fread($ifp, $blockSize); + if (!is_string($ciphertext)) { + throw new SodiumException('Could not read input file'); + } + $pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + $ciphertext, + $realNonce, + $iter, + $subkey + ); + fwrite($ofp, $pBlock, $blockSize); + $mlen -= $blockSize; + $iter += $incr; + } + return true; + } + + /** + * @param ParagonIE_Sodium_Core_Poly1305_State $state + * @param resource $ifp + * @param string $tag + * @param int $mlen + * @return bool + * @throws SodiumException + * @throws TypeError + */ + protected static function onetimeauth_verify( + ParagonIE_Sodium_Core_Poly1305_State $state, + $ifp, + string $tag = '', + int $mlen = 0 + ): bool { + $pos = self::ftell($ifp); + while ($mlen > 0) { + $blockSize = min($mlen, self::BUFFER_SIZE); + $ciphertext = fread($ifp, $blockSize); + if (!is_string($ciphertext)) { + throw new SodiumException('Could not read input file'); + } + $state->update($ciphertext); + $mlen -= $blockSize; + } + $res = ParagonIE_Sodium_Core_Util::verify_16($tag, $state->finish()); + + fseek($ifp, $pos); + return $res; + } + + /** + * Update a hash context with the contents of a file, without + * loading the entire file into memory. + * + * @param HashContext $hash + * @param resource $fp + * @param int $size + * @return HashContext Resource on PHP < 7.2, HashContext object on PHP >= 7.2 + * @throws SodiumException + * @throws TypeError + */ + public static function updateHashWithFile(HashContext $hash, $fp, int $size = 0): HashContext + { + /** + * @psalm-suppress DocblockTypeContradiction + * We can't statically type resources. + */ + if (!is_resource($fp)) { + throw new TypeError('Argument 2 must be a resource, ' . gettype($fp) . ' given.'); + } + $originalPosition = self::ftell($fp); + + // Move file pointer to beginning of file + fseek($fp, 0); + for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) { + /** @var string|bool $message */ + $message = fread( + $fp, + ($size - $i) > self::BUFFER_SIZE + ? $size - $i + : self::BUFFER_SIZE + ); + if (!is_string($message)) { + throw new SodiumException('Unexpected error reading from file.'); + } + hash_update($hash, $message); + } + // Reset file pointer's position + fseek($fp, $originalPosition); + return $hash; + } + + /** + * @param resource $resource + * @return int + * @throws SodiumException + */ + private static function ftell($resource): int + { + $return = ftell($resource); + if (!is_int($return)) { + throw new SodiumException('ftell() returned false'); + } + return $return; + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/SodiumException.php b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/SodiumException.php new file mode 100644 index 000000000..b80c1590a --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/sodium_compat/src/SodiumException.php @@ -0,0 +1,13 @@ + + * @author João Vieira */ -$PHPMAILER_LANG['authenticate'] = 'Erro do SMTP: Não foi possível realizar a autenticação.'; -$PHPMAILER_LANG['connect_host'] = 'Erro do SMTP: Não foi possível realizar ligação com o servidor SMTP.'; -$PHPMAILER_LANG['data_not_accepted'] = 'Erro do SMTP: Os dados foram rejeitados.'; -$PHPMAILER_LANG['empty_message'] = 'A mensagem no e-mail está vazia.'; +$PHPMAILER_LANG['authenticate'] = 'Erro SMTP: Falha na autenticação.'; +$PHPMAILER_LANG['buggy_php'] = 'A sua versão do PHP tem um bug que pode causar mensagens corrompidas. Para resolver, utilize o envio por SMTP, desative a opção mail.add_x_header no ficheiro php.ini, mude para MacOS ou Linux, ou atualize o PHP para a versão 7.0.17+ ou 7.1.3+.'; +$PHPMAILER_LANG['connect_host'] = 'Erro SMTP: Não foi possível ligar ao servidor SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Erro SMTP: Dados não aceites.'; +$PHPMAILER_LANG['empty_message'] = 'A mensagem de e-mail está vazia.'; $PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: '; $PHPMAILER_LANG['execute'] = 'Não foi possível executar: '; -$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder o ficheiro: '; -$PHPMAILER_LANG['file_open'] = 'Abertura do ficheiro: Não foi possível abrir o ficheiro: '; -$PHPMAILER_LANG['from_failed'] = 'Ocorreram falhas nos endereços dos seguintes remententes: '; -$PHPMAILER_LANG['instantiate'] = 'Não foi possível iniciar uma instância da função mail.'; -$PHPMAILER_LANG['invalid_address'] = 'Não foi enviado nenhum e-mail para o endereço de e-mail inválido: '; -$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.'; -$PHPMAILER_LANG['provide_address'] = 'Tem de fornecer pelo menos um endereço como destinatário do e-mail.'; -$PHPMAILER_LANG['recipients_failed'] = 'Erro do SMTP: O endereço do seguinte destinatário falhou: '; -$PHPMAILER_LANG['signing'] = 'Erro ao assinar: '; -$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.'; -$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: '; -$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; $PHPMAILER_LANG['extension_missing'] = 'Extensão em falta: '; +$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder ao ficheiro: '; +$PHPMAILER_LANG['file_open'] = 'Erro ao abrir o ficheiro: '; +$PHPMAILER_LANG['from_failed'] = 'O envio falhou para o seguinte endereço do remetente: '; +$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.'; +$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: '; +$PHPMAILER_LANG['invalid_header'] = 'Nome ou valor do cabeçalho inválido.'; +$PHPMAILER_LANG['invalid_hostentry'] = 'Entrada de host inválida: '; +$PHPMAILER_LANG['invalid_host'] = 'Host inválido: '; +$PHPMAILER_LANG['mailer_not_supported'] = 'O cliente de e-mail não é suportado.'; +$PHPMAILER_LANG['provide_address'] = 'Deve fornecer pelo menos um endereço de destinatário.'; +$PHPMAILER_LANG['recipients_failed'] = 'Erro SMTP: Falha no envio para os seguintes destinatários: '; +$PHPMAILER_LANG['signing'] = 'Erro ao assinar: '; +$PHPMAILER_LANG['smtp_code'] = 'Código SMTP: '; +$PHPMAILER_LANG['smtp_code_ex'] = 'Informações adicionais SMTP: '; +$PHPMAILER_LANG['smtp_connect_failed'] = 'Falha na função SMTP connect().'; +$PHPMAILER_LANG['smtp_detail'] = 'Detalhes: '; +$PHPMAILER_LANG['smtp_error'] = 'Erro do servidor SMTP: '; +$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: '; diff --git a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/PHPMailer.php b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/PHPMailer.php index 4a6077c01..2444bcf35 100644 --- a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/PHPMailer.php +++ b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/PHPMailer.php @@ -580,6 +580,10 @@ class PHPMailer * May be a callable to inject your own validator, but there are several built-in validators. * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option. * + * If CharSet is UTF8, the validator is left at the default value, + * and you send to addresses that use non-ASCII local parts, then + * PHPMailer automatically changes to the 'eai' validator. + * * @see PHPMailer::validateAddress() * * @var string|callable @@ -659,6 +663,14 @@ class PHPMailer */ protected $ReplyToQueue = []; + /** + * Whether the need for SMTPUTF8 has been detected. Set by + * preSend() if necessary. + * + * @var bool + */ + public $UseSMTPUTF8 = false; + /** * The array of attachments. * @@ -756,7 +768,7 @@ class PHPMailer * * @var string */ - const VERSION = '6.9.3'; + const VERSION = '6.10.0'; /** * Error severity: message only, continue processing. @@ -1110,19 +1122,22 @@ class PHPMailer $params = [$kind, $address, $name]; //Enqueue addresses with IDN until we know the PHPMailer::$CharSet. //Domain is assumed to be whatever is after the last @ symbol in the address - if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) { - if ('Reply-To' !== $kind) { - if (!array_key_exists($address, $this->RecipientsQueue)) { - $this->RecipientsQueue[$address] = $params; + if ($this->has8bitChars(substr($address, ++$pos))) { + if (static::idnSupported()) { + if ('Reply-To' !== $kind) { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + + return true; + } + } elseif (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; return true; } - } elseif (!array_key_exists($address, $this->ReplyToQueue)) { - $this->ReplyToQueue[$address] = $params; - - return true; } - + //We have an 8-bit domain, but we are missing the necessary extensions to support it + //Or we are already sending to this address return false; } @@ -1160,6 +1175,15 @@ class PHPMailer */ protected function addAnAddress($kind, $address, $name = '') { + if ( + self::$validator === 'php' && + ((bool) preg_match('/[\x80-\xFF]/', $address)) + ) { + //The caller has not altered the validator and is sending to an address + //with UTF-8, so assume that they want UTF-8 support instead of failing + $this->CharSet = self::CHARSET_UTF8; + self::$validator = 'eai'; + } if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) { $error_message = sprintf( '%s: %s', @@ -1362,6 +1386,7 @@ class PHPMailer * * `pcre` Use old PCRE implementation; * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `eai` Use a pattern similar to the HTML5 spec for 'email' and to firefox, extended to support EAI (RFC6530). * * `noregex` Don't use a regex: super fast, really dumb. * Alternatively you may pass in a callable to inject your own validator, for example: * @@ -1432,6 +1457,24 @@ class PHPMailer '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', $address ); + case 'eai': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type + * form input elements (as above), modified to accept Unicode email addresses. + * This is also more lenient than Firefox' html5 spec, in order to make the regex faster. + * 'eai' is an acronym for Email Address Internationalization. + * This validator is selected automatically if you attempt to use recipient addresses + * that contain Unicode characters in the local part. + * + * @see https://html.spec.whatwg.org/#e-mail-state-(type=email) + * @see https://en.wikipedia.org/wiki/International_email + */ + return (bool) preg_match( + '/^[-\p{L}\p{N}\p{M}.!#$%&\'*+\/=?^_`{|}~]+@[\p{L}\p{N}\p{M}](?:[\p{L}\p{N}\p{M}-]{0,61}' . + '[\p{L}\p{N}\p{M}])?(?:\.[\p{L}\p{N}\p{M}]' . + '(?:[-\p{L}\p{N}\p{M}]{0,61}[\p{L}\p{N}\p{M}])?)*$/usD', + $address + ); case 'php': default: return filter_var($address, FILTER_VALIDATE_EMAIL) !== false; @@ -1565,9 +1608,26 @@ class PHPMailer $this->error_count = 0; //Reset errors $this->mailHeader = ''; + //The code below tries to support full use of Unicode, + //while remaining compatible with legacy SMTP servers to + //the greatest degree possible: If the message uses + //Unicode in the local parts of any addresses, it is sent + //using SMTPUTF8. If not, it it sent using + //punycode-encoded domains and plain SMTP. + if ( + static::CHARSET_UTF8 === strtolower($this->CharSet) && + ($this->anyAddressHasUnicodeLocalPart($this->RecipientsQueue) || + $this->anyAddressHasUnicodeLocalPart(array_keys($this->all_recipients)) || + $this->anyAddressHasUnicodeLocalPart($this->ReplyToQueue) || + $this->addressHasUnicodeLocalPart($this->From)) + ) { + $this->UseSMTPUTF8 = true; + } //Dequeue recipient and Reply-To addresses with IDN foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { - $params[1] = $this->punyencodeAddress($params[1]); + if (!$this->UseSMTPUTF8) { + $params[1] = $this->punyencodeAddress($params[1]); + } call_user_func_array([$this, 'addAnAddress'], $params); } if (count($this->to) + count($this->cc) + count($this->bcc) < 1) { @@ -2058,6 +2118,11 @@ class PHPMailer if (!$this->smtpConnect($this->SMTPOptions)) { throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); } + //If we have recipient addresses that need Unicode support, + //but the server doesn't support it, stop here + if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) { + throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL); + } //Sender already validated in preSend() if ('' === $this->Sender) { $smtp_from = $this->From; @@ -2159,6 +2224,7 @@ class PHPMailer $this->smtp->setDebugLevel($this->SMTPDebug); $this->smtp->setDebugOutput($this->Debugoutput); $this->smtp->setVerp($this->do_verp); + $this->smtp->setSMTPUTF8($this->UseSMTPUTF8); if ($this->Host === null) { $this->Host = 'localhost'; } @@ -2356,6 +2422,7 @@ class PHPMailer 'smtp_detail' => 'Detail: ', 'smtp_error' => 'SMTP server error: ', 'variable_set' => 'Cannot set or reset variable: ', + 'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses', ]; if (empty($lang_path)) { //Calculate an absolute path so it can work if CWD is not here @@ -2870,7 +2937,9 @@ class PHPMailer $bodyEncoding = $this->Encoding; $bodyCharSet = $this->CharSet; //Can we do a 7-bit downgrade? - if (static::ENCODING_8BIT === $bodyEncoding && !$this->has8bitChars($this->Body)) { + if ($this->UseSMTPUTF8) { + $bodyEncoding = static::ENCODING_8BIT; + } elseif (static::ENCODING_8BIT === $bodyEncoding && !$this->has8bitChars($this->Body)) { $bodyEncoding = static::ENCODING_7BIT; //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit $bodyCharSet = static::CHARSET_ASCII; @@ -3507,7 +3576,8 @@ class PHPMailer /** * Encode a header value (not including its label) optimally. * Picks shortest of Q, B, or none. Result includes folding if needed. - * See RFC822 definitions for phrase, comment and text positions. + * See RFC822 definitions for phrase, comment and text positions, + * and RFC2047 for inline encodings. * * @param string $str The header value to encode * @param string $position What context the string will be used in @@ -3516,6 +3586,11 @@ class PHPMailer */ public function encodeHeader($str, $position = 'text') { + $position = strtolower($position); + if ($this->UseSMTPUTF8 && !("comment" === $position)) { + return trim(static::normalizeBreaks($str)); + } + $matchcount = 0; switch (strtolower($position)) { case 'phrase': @@ -4180,7 +4255,7 @@ class PHPMailer if ('smtp' === $this->Mailer && null !== $this->smtp) { $lasterror = $this->smtp->getError(); if (!empty($lasterror['error'])) { - $msg .= $this->lang('smtp_error') . $lasterror['error']; + $msg .= ' ' . $this->lang('smtp_error') . $lasterror['error']; if (!empty($lasterror['detail'])) { $msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail']; } @@ -4267,6 +4342,45 @@ class PHPMailer return filter_var('https://' . $host, FILTER_VALIDATE_URL) !== false; } + /** + * Check whether the supplied address uses Unicode in the local part. + * + * @return bool + */ + protected function addressHasUnicodeLocalPart($address) + { + return (bool) preg_match('/[\x80-\xFF].*@/', $address); + } + + /** + * Check whether any of the supplied addresses use Unicode in the local part. + * + * @return bool + */ + protected function anyAddressHasUnicodeLocalPart($addresses) + { + foreach ($addresses as $address) { + if (is_array($address)) { + $address = $address[0]; + } + if ($this->addressHasUnicodeLocalPart($address)) { + return true; + } + } + return false; + } + + /** + * Check whether the message requires SMTPUTF8 based on what's known so far. + * + * @return bool + */ + public function needsSMTPUTF8() + { + return $this->UseSMTPUTF8; + } + + /** * Get an error message in the current language. * diff --git a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/POP3.php b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/POP3.php index 376fae2a8..1190a1e20 100644 --- a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/POP3.php +++ b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/POP3.php @@ -46,7 +46,7 @@ class POP3 * * @var string */ - const VERSION = '6.9.3'; + const VERSION = '6.10.0'; /** * Default POP3 port number. diff --git a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/SMTP.php b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/SMTP.php index b4eff4042..7226ee93b 100644 --- a/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/SMTP.php +++ b/lam/lib/3rdParty/composer/phpmailer/phpmailer/src/SMTP.php @@ -35,7 +35,7 @@ class SMTP * * @var string */ - const VERSION = '6.9.3'; + const VERSION = '6.10.0'; /** * SMTP line break constant. @@ -159,6 +159,15 @@ class SMTP */ public $do_verp = false; + /** + * Whether to use SMTPUTF8. + * + * @see https://www.rfc-editor.org/rfc/rfc6531 + * + * @var bool + */ + public $do_smtputf8 = false; + /** * The timeout value for connection, in seconds. * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. @@ -913,7 +922,15 @@ class SMTP * $from. Returns true if successful or false otherwise. If True * the mail transaction is started and then one or more recipient * commands may be called followed by a data command. - * Implements RFC 821: MAIL FROM: . + * Implements RFC 821: MAIL FROM: and + * two extensions, namely XVERP and SMTPUTF8. + * + * The server's EHLO response is not checked. If use of either + * extensions is enabled even though the server does not support + * that, mail submission will fail. + * + * XVERP is documented at https://www.postfix.org/VERP_README.html + * and SMTPUTF8 is specified in RFC 6531. * * @param string $from Source address of this message * @@ -922,10 +939,11 @@ class SMTP public function mail($from) { $useVerp = ($this->do_verp ? ' XVERP' : ''); + $useSmtputf8 = ($this->do_smtputf8 ? ' SMTPUTF8' : ''); return $this->sendCommand( 'MAIL FROM', - 'MAIL FROM:<' . $from . '>' . $useVerp, + 'MAIL FROM:<' . $from . '>' . $useSmtputf8 . $useVerp, 250 ); } @@ -1364,6 +1382,26 @@ class SMTP return $this->do_verp; } + /** + * Enable or disable use of SMTPUTF8. + * + * @param bool $enabled + */ + public function setSMTPUTF8($enabled = false) + { + $this->do_smtputf8 = $enabled; + } + + /** + * Get SMTPUTF8 use. + * + * @return bool + */ + public function getSMTPUTF8() + { + return $this->do_smtputf8; + } + /** * Set error messages and codes. * diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/BACKERS.md b/lam/lib/3rdParty/composer/phpseclib/phpseclib/BACKERS.md index 946b8f5f0..cafcf60a2 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/BACKERS.md +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/BACKERS.md @@ -15,4 +15,5 @@ phpseclib ongoing development is made possible by [Tidelift](https://tidelift.co - [cjhaas](https://github.com/cjhaas) - [istiak-tridip](https://github.com/istiak-tridip) - [Anna Filina](https://github.com/afilina) -- [blakemckeeby](https://github.com/blakemckeeby) \ No newline at end of file +- [blakemckeeby](https://github.com/blakemckeeby) +- [ssddanbrown](https://github.com/ssddanbrown) \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php index fa750ba28..ad8f63b65 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php @@ -126,7 +126,9 @@ abstract class Strings // 64-bit floats can be used to get larger numbers then 32-bit signed ints would allow // for. sure, you're not gonna get the full precision of 64-bit numbers but just because // you need > 32-bit precision doesn't mean you need the full 64-bit precision - extract(unpack('Nupper/Nlower', self::shift($data, 8))); + $unpacked = unpack('Nupper/Nlower', self::shift($data, 8)); + $upper = $unpacked['upper']; + $lower = $unpacked['lower']; $temp = $upper ? 4294967296 * $upper : 0; $temp += $lower < 0 ? ($lower & 0x7FFFFFFFF) + 0x80000000 : $lower; // $temp = hexdec(bin2hex(self::shift($data, 8))); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php index 3cb2b3055..998cf8bb3 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php @@ -129,7 +129,7 @@ class Blowfish extends BlockCipher /** * Block Length of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size + * @see Common\SymmetricKey::block_size * @var int */ protected $block_size = 8; @@ -137,7 +137,7 @@ class Blowfish extends BlockCipher /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'blowfish'; @@ -145,7 +145,7 @@ class Blowfish extends BlockCipher /** * Optimizing value while CFB-encrypting * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len + * @see Common\SymmetricKey::cfb_init_len * @var int */ protected $cfb_init_len = 500; @@ -325,7 +325,7 @@ class Blowfish extends BlockCipher * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once.} * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength() + * @see Common\SymmetricKey::setKeyLength() * @var int */ protected $key_length = 16; @@ -368,7 +368,7 @@ class Blowfish extends BlockCipher * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() + * @see Common\SymmetricKey::isValidEngine() * @param int $engine * @return bool */ @@ -394,7 +394,7 @@ class Blowfish extends BlockCipher /** * Setup the key (expansion) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey() + * @see Common\SymmetricKey::_setupKey() */ protected function setupKey() { @@ -755,7 +755,7 @@ class Blowfish extends BlockCipher /** * Setup the performance-optimized function for de/encrypt() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt() + * @see Common\SymmetricKey::_setupInlineCrypt() */ protected function setupInlineCrypt() { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php index 4c761b839..98b8dacc9 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php @@ -50,6 +50,14 @@ abstract class JWK return $key; } + if (!is_object($key)) { + throw new \RuntimeException('invalid JWK: not an object'); + } + + if (!isset($key->keys)) { + throw new \RuntimeException('invalid JWK: object has no property "keys"'); + } + if (count($key->keys) != 1) { throw new \RuntimeException('Although the JWK key format supports multiple keys phpseclib does not'); } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php index 732ac5df7..2211a8747 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php @@ -83,6 +83,13 @@ abstract class PKCS8 extends PKCS */ private static $oidsLoaded = false; + /** + * Binary key flag + * + * @var bool + */ + private static $binary = false; + /** * Sets the default encryption algorithm * @@ -354,7 +361,9 @@ abstract class PKCS8 extends PKCS if (!$temp) { throw new \RuntimeException('Unable to decode BER'); } - extract(ASN1::asn1map($temp[0], Maps\PBEParameter::MAP)); + $map = ASN1::asn1map($temp[0], Maps\PBEParameter::MAP); + $salt = $map['salt']; + $iterationCount = $map['iterationCount']; $iterationCount = (int) $iterationCount->toString(); $cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount); $key = $cipher->decrypt($decrypted['encryptedData']); @@ -372,7 +381,8 @@ abstract class PKCS8 extends PKCS throw new \RuntimeException('Unable to decode BER'); } $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP); - extract($temp); + $keyDerivationFunc = $temp['keyDerivationFunc']; + $encryptionScheme = $temp['encryptionScheme']; $cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']); $meta['meta']['cipher'] = $encryptionScheme['algorithm']; @@ -382,7 +392,8 @@ abstract class PKCS8 extends PKCS throw new \RuntimeException('Unable to decode BER'); } $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP); - extract($temp); + $keyDerivationFunc = $temp['keyDerivationFunc']; + $encryptionScheme = $temp['encryptionScheme']; if (!$cipher instanceof RC2) { $cipher->setIV($encryptionScheme['parameters']['octetString']); @@ -391,7 +402,9 @@ abstract class PKCS8 extends PKCS if (!$temp) { throw new \RuntimeException('Unable to decode BER'); } - extract(ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP)); + $map = ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP); + $rc2ParametersVersion = $map['rc2ParametersVersion']; + $iv = $map['iv']; $effectiveKeyLength = (int) $rc2ParametersVersion->toString(); switch ($effectiveKeyLength) { case 160: @@ -416,9 +429,13 @@ abstract class PKCS8 extends PKCS if (!$temp) { throw new \RuntimeException('Unable to decode BER'); } - $prf = ['algorithm' => 'id-hmacWithSHA1']; $params = ASN1::asn1map($temp[0], Maps\PBKDF2params::MAP); - extract($params); + if (empty($params['prf'])) { + $params['prf'] = ['algorithm' => 'id-hmacWithSHA1']; + } + $salt = $params['salt']; + $iterationCount = $params['iterationCount']; + $prf = $params['prf']; $meta['meta']['prf'] = $prf['algorithm']; $hash = str_replace('-', '/', substr($prf['algorithm'], 11)); $params = [ @@ -513,6 +530,18 @@ abstract class PKCS8 extends PKCS throw new \RuntimeException('Unable to parse using either OneAsymmetricKey or PublicKeyInfo ASN1 maps'); } + /** + * Toggle between binary (DER) and printable (PEM) keys + * + * Printable keys are what are generated by default. + * + * @param bool $enabled + */ + public static function setBinaryOutput($enabled) + { + self::$binary = $enabled; + } + /** * Wrap a private key appropriately * @@ -616,11 +645,19 @@ abstract class PKCS8 extends PKCS $key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP); + if (isset($options['binary']) ? $options['binary'] : self::$binary) { + return $key; + } + return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . chunk_split(Strings::base64_encode($key), 64) . "-----END ENCRYPTED PRIVATE KEY-----"; } + if (isset($options['binary']) ? $options['binary'] : self::$binary) { + return $key; + } + return "-----BEGIN PRIVATE KEY-----\r\n" . chunk_split(Strings::base64_encode($key), 64) . "-----END PRIVATE KEY-----"; @@ -634,7 +671,7 @@ abstract class PKCS8 extends PKCS * @param string $oid * @return string */ - protected static function wrapPublicKey($key, $params, $oid = null) + protected static function wrapPublicKey($key, $params, $oid = null, array $options = []) { self::initialize_static_variables(); @@ -651,6 +688,10 @@ abstract class PKCS8 extends PKCS $key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP); + if (isset($options['binary']) ? $options['binary'] : self::$binary) { + return $key; + } + return "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(Strings::base64_encode($key), 64) . "-----END PUBLIC KEY-----"; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php index 85da83a73..ff4a95a82 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php @@ -199,7 +199,7 @@ abstract class PuTTY $source = Strings::packSSH2('ssss', $type, $encryption, $components['comment'], $public); - extract(unpack('Nlength', Strings::shift($public, 4))); + $length = unpack('Nlength', Strings::shift($public, 4))['length']; $newtype = Strings::shift($public, $length); if ($newtype != $type) { throw new \RuntimeException('The binary type does not match the human readable type field'); @@ -227,7 +227,10 @@ abstract class PuTTY $parallelism = trim(preg_replace('#Argon2-Parallelism: (\d+)#', '$1', $key[$offset++])); $salt = Strings::hex2bin(trim(preg_replace('#Argon2-Salt: ([0-9a-f]+)#', '$1', $key[$offset++]))); - extract(self::generateV3Key($password, $flavour, $memory, $passes, $salt)); + $v3key = self::generateV3Key($password, $flavour, $memory, $passes, $salt); + $symkey = $v3key['symkey']; + $symiv = $v3key['symiv']; + $hashkey = $v3key['hashkey']; break; case 2: @@ -323,7 +326,10 @@ abstract class PuTTY $key .= "Argon2-Passes: 13\r\n"; $key .= "Argon2-Parallelism: 1\r\n"; $key .= "Argon2-Salt: " . Strings::bin2hex($salt) . "\r\n"; - extract(self::generateV3Key($password, 'Argon2id', 8192, 13, $salt)); + $v3key = self::generateV3Key($password, 'Argon2id', 8192, 13, $salt); + $symkey = $v3key['symkey']; + $symiv = $v3key['symiv']; + $hashkey = $v3key['hashkey']; $hash = new Hash('sha256'); $hash->setKey($hashkey); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php index 0d9690822..c7c080f4e 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php @@ -26,7 +26,7 @@ abstract class StreamCipher extends SymmetricKey * * Stream ciphers do not have a block size * - * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size + * @see SymmetricKey::block_size * @var int */ protected $block_size = 0; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DES.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DES.php index 3b0383000..93d7ad2ed 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DES.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DES.php @@ -68,7 +68,7 @@ class DES extends BlockCipher /** * Block Length of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size + * @see Common\SymmetricKey::block_size * @var int */ protected $block_size = 8; @@ -76,7 +76,7 @@ class DES extends BlockCipher /** * Key Length (in bytes) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength() + * @see Common\SymmetricKey::setKeyLength() * @var int */ protected $key_length = 8; @@ -84,7 +84,7 @@ class DES extends BlockCipher /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'des'; @@ -92,7 +92,7 @@ class DES extends BlockCipher /** * The OpenSSL names of the cipher / modes * - * @see \phpseclib3\Crypt\Common\SymmetricKey::openssl_mode_names + * @see Common\SymmetricKey::openssl_mode_names * @var array */ protected $openssl_mode_names = [ @@ -106,7 +106,7 @@ class DES extends BlockCipher /** * Optimizing value while CFB-encrypting * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len + * @see Common\SymmetricKey::cfb_init_len * @var int */ protected $cfb_init_len = 500; @@ -586,7 +586,7 @@ class DES extends BlockCipher * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() + * @see Common\SymmetricKey::isValidEngine() * @param int $engine * @return bool */ @@ -615,7 +615,7 @@ class DES extends BlockCipher * * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey() + * @see Common\SymmetricKey::setKey() * @param string $key */ public function setKey($key) @@ -631,8 +631,8 @@ class DES extends BlockCipher /** * Encrypts a block * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encryptBlock() - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see Common\SymmetricKey::encryptBlock() + * @see Common\SymmetricKey::encrypt() * @see self::encrypt() * @param string $in * @return string @@ -645,8 +645,8 @@ class DES extends BlockCipher /** * Decrypts a block * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decryptBlock() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see Common\SymmetricKey::decryptBlock() + * @see Common\SymmetricKey::decrypt() * @see self::decrypt() * @param string $in * @return string @@ -747,7 +747,7 @@ class DES extends BlockCipher /** * Creates the key schedule * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey() + * @see Common\SymmetricKey::setupKey() */ protected function setupKey() { @@ -1281,7 +1281,7 @@ class DES extends BlockCipher /** * Setup the performance-optimized function for de/encrypt() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt() + * @see Common\SymmetricKey::setupInlineCrypt() */ protected function setupInlineCrypt() { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php index 7d02e5f33..3b83a4290 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php @@ -127,6 +127,6 @@ abstract class PKCS8 extends Progenitor $params = ASN1::encodeDER($params, Maps\DHParameter::MAP); $params = new ASN1\Element($params); $key = ASN1::encodeDER($publicKey, ['type' => ASN1::TYPE_INTEGER]); - return self::wrapPublicKey($key, $params); + return self::wrapPublicKey($key, $params, null, $options); } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php index 238f42c25..359ed09ea 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php @@ -141,6 +141,6 @@ abstract class PKCS8 extends Progenitor $params = ASN1::encodeDER($params, Maps\DSAParams::MAP); $params = new ASN1\Element($params); $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP); - return self::wrapPublicKey($key, $params); + return self::wrapPublicKey($key, $params, null, $options); } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PuTTY.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PuTTY.php index f6177f462..8549a2ec7 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PuTTY.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PuTTY.php @@ -56,7 +56,10 @@ abstract class PuTTY extends Progenitor if (!isset($components['private'])) { return $components; } - extract($components); + $type = $components['type']; + $comment = $components['comment']; + $public = $components['public']; + $private = $components['private']; unset($components['public'], $components['private']); list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $public); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php index 87cd77a7a..90252139d 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php @@ -88,7 +88,9 @@ final class PrivateKey extends DSA implements Common\PrivateKey return $signature; } - extract(ASN1Signature::load($signature)); + $loaded = ASN1Signature::load($signature); + $r = $loaded['r']; + $s = $loaded['s']; return $format::save($r, $s); } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php index c14ffbdf5..3e16762b8 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php @@ -40,7 +40,8 @@ final class PublicKey extends DSA implements Common\PublicKey if ($params === false || count($params) != 2) { return false; } - extract($params); + $r = $params['r']; + $s = $params['s']; if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php index bf02569dc..431f9575c 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php @@ -219,7 +219,7 @@ class Montgomery extends Base public function multiplyPoint(array $p, BigInteger $d) { $p1 = [$this->one, $this->zero]; - $alreadyInternal = isset($x[1]); + $alreadyInternal = isset($p[1]); $p2 = $this->convertToInternal($p); $x = $p[0]; @@ -246,7 +246,7 @@ class Montgomery extends Base * * x=X/Z * - * @return \phpseclib3\Math\PrimeField\Integer[] + * @return PrimeInteger[] */ public function convertToInternal(array $p) { @@ -266,7 +266,7 @@ class Montgomery extends Base /** * Returns the affine point * - * @return \phpseclib3\Math\PrimeField\Integer[] + * @return PrimeInteger[] */ public function convertToAffine(array $p) { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Prime.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Prime.php index 620040170..b1970557f 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Prime.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Prime.php @@ -751,7 +751,7 @@ class Prime extends Base * To convert a Jacobian Coordinate to an Affine Point * you do (x / z^2, y / z^3) * - * @return \phpseclib3\Math\PrimeField\Integer[] + * @return PrimeInteger[] */ public function convertToAffine(array $p) { @@ -770,7 +770,7 @@ class Prime extends Base /** * Converts an affine point to a jacobian coordinate * - * @return \phpseclib3\Math\PrimeField\Integer[] + * @return PrimeInteger[] */ public function convertToInternal(array $p) { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php index 004406acf..99aa38b20 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php @@ -171,7 +171,7 @@ class TwistedEdwards extends Base /** * Returns the affine point * - * @return PrimeField\Integer[] + * @return PrimeInteger[] */ public function convertToAffine(array $p) { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php index 66ec0308c..9fc84054e 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php @@ -178,7 +178,8 @@ abstract class PKCS8 extends Progenitor return self::wrapPublicKey( $curve->encodePoint($publicKey), null, - $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448' + $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448', + $options ); } @@ -186,7 +187,7 @@ abstract class PKCS8 extends Progenitor $key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); - return self::wrapPublicKey($key, $params, 'id-ecPublicKey'); + return self::wrapPublicKey($key, $params, 'id-ecPublicKey', $options); } /** diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.php index b0cb12650..7f6cf6345 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.php @@ -71,6 +71,10 @@ abstract class XML $use_errors = libxml_use_internal_errors(true); + if (substr($key, 0, 5) != '' . $key . ''; + } + $temp = self::isolateNamespace($key, 'http://www.w3.org/2009/xmldsig11#'); if ($temp) { $key = $temp; @@ -82,9 +86,6 @@ abstract class XML } $dom = new \DOMDocument(); - if (substr($key, 0, 5) != '' . $key . ''; - } if (!$dom->loadXML($key)) { libxml_use_internal_errors($use_errors); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php index 91253b8fd..9947bb7d5 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php @@ -157,7 +157,10 @@ final class PrivateKey extends EC implements Common\PrivateKey return $signature; } - extract(ASN1Signature::load($signature)); + $loaded = ASN1Signature::load($signature); + $r = $loaded['r']; + $s = $loaded['s']; + return $this->formatSignature($r, $s); } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php index 4558ce34d..d34c6c4dd 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php @@ -115,7 +115,8 @@ final class PublicKey extends EC implements Common\PublicKey if ($params === false || count($params) != 2) { return false; } - extract($params); + $r = $params['r']; + $s = $params['s']; if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Hash.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Hash.php index 09e48f960..cc5b42c08 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Hash.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Hash.php @@ -194,6 +194,15 @@ class Hash private static $maxwordrange128; /**#@-*/ + /**#@+ + * AES_CMAC variables + * + * @var string + */ + private $k1; + private $k2; + /**#@-*/ + /** * Default Constructor. * @@ -299,6 +308,14 @@ class Hash $this->length = abs(substr($hash, -3)) >> 3; $this->algo = 'umac'; return; + case 'aes_cmac': + if ($oldHash != $this->hashParam) { + $this->recomputeAESKey = true; + } + $this->blockSize = 128; + $this->length = 16; + $this->algo = 'aes_cmac'; + return; case 'md2-96': case 'md5-96': case 'sha1-96': @@ -977,6 +994,69 @@ class Hash public function hash($text) { $algo = $this->algo; + // https://www.rfc-editor.org/rfc/rfc4493.html + // https://en.wikipedia.org/wiki/One-key_MAC + if ($algo == 'aes_cmac') { + $constZero = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + if ($this->recomputeAESKey) { + if (!is_string($this->key)) { + throw new InsufficientSetupException('No key has been set'); + } + if (strlen($this->key) != 16) { + throw new \LengthException('Key must be 16 bytes long'); + } + // Algorithm Generate_Subkey + $constRb = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87"; + $this->c = new AES('ecb'); + $this->c->setKey($this->key); + $this->c->disablePadding(); + $l = $this->c->encrypt($constZero); + $msb = ($l & "\x80") == "\x80"; + $l = new BigInteger($l, 256); + $l->setPrecision(128); + $l = $l->bitwise_leftShift(1)->toBytes(); + // make it constant time + $k1 = $msb ? $l ^ $constRb : $l | $constZero; + + $msb = ($k1 & "\x80") == "\x80"; + $k2 = new BigInteger($k1, 256); + $k2->setPrecision(128); + $k2 = $k2->bitwise_leftShift(1)->toBytes(); + // make it constant time + $k2 = $msb ? $k2 ^ $constRb : $k2 | $constZero; + + $this->k1 = $k1; + $this->k2 = $k2; + } + + $len = strlen($text); + $const_Bsize = 16; + $M = strlen($text) ? str_split($text, $const_Bsize) : ['']; + + // Step 2 + $n = ceil($len / $const_Bsize); + // Step 3 + if ($n == 0) { + $n = 1; + $flag = false; + } else { + $flag = $len % $const_Bsize == 0; + } + // Step 4 + $M_last = $flag ? + $M[$n - 1] ^ $k1 : + self::OMAC_padding($M[$n - 1], $const_Bsize) ^ $k2; + // Step 5 + $x = $constZero; + // Step 6 + $c = &$this->c; + for ($i = 0; $i < $n - 1; $i++) { + $y = $x ^ $M[$i]; + $x = $c->encrypt($y); + } + $y = $M_last ^ $x; + return $c->encrypt($y); + } if ($algo == 'umac') { if ($this->recomputeAESKey) { if (!is_string($this->nonce)) { @@ -1790,6 +1870,17 @@ class Hash return pack('J*', ...$hash); } + /** + * OMAC Padding + * + * @link https://www.rfc-editor.org/rfc/rfc4493.html#section-2.4 + */ + private static function OMAC_padding($m, $length) + { + $count = $length - strlen($m) - 1; + return "$m\x80" . str_repeat("\0", $count); + } + /** * __toString() magic method */ diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php index 61afbaeb6..36264080c 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php @@ -32,6 +32,7 @@ abstract class PublicKeyLoader * @return AsymmetricKey * @param string|array $key * @param string $password optional + * @throws NoKeyLoadedException if key is not valid */ public static function load($key, $password = false) { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC2.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC2.php index 654c90642..175c52e7b 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC2.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC2.php @@ -45,7 +45,7 @@ class RC2 extends BlockCipher /** * Block Length of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::block_size + * @see Common\SymmetricKey::block_size * @var int */ protected $block_size = 8; @@ -53,7 +53,7 @@ class RC2 extends BlockCipher /** * The Key * - * @see \phpseclib3\Crypt\Common\SymmetricKey::key + * @see Common\SymmetricKey::key * @see self::setKey() * @var string */ @@ -62,7 +62,7 @@ class RC2 extends BlockCipher /** * The Original (unpadded) Key * - * @see \phpseclib3\Crypt\Common\SymmetricKey::key + * @see Common\SymmetricKey::key * @see self::setKey() * @see self::encrypt() * @see self::decrypt() @@ -81,7 +81,7 @@ class RC2 extends BlockCipher /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'rc2'; @@ -89,7 +89,7 @@ class RC2 extends BlockCipher /** * Optimizing value while CFB-encrypting * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len + * @see Common\SymmetricKey::cfb_init_len * @var int */ protected $cfb_init_len = 500; @@ -261,7 +261,7 @@ class RC2 extends BlockCipher * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see Common\SymmetricKey::__construct() * @param int $engine * @return bool */ @@ -323,7 +323,7 @@ class RC2 extends BlockCipher * has more then 128 bytes in it, and set $key to a single null byte if * it is empty. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey() + * @see Common\SymmetricKey::setKey() * @param string $key * @param int|boolean $t1 optional Effective key length in bits. * @throws \LengthException if the key length isn't supported @@ -426,8 +426,8 @@ class RC2 extends BlockCipher /** * Encrypts a block * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encryptBlock() - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see Common\SymmetricKey::encryptBlock() + * @see Common\SymmetricKey::encrypt() * @param string $in * @return string */ @@ -470,8 +470,8 @@ class RC2 extends BlockCipher /** * Decrypts a block * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decryptBlock() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see Common\SymmetricKey::decryptBlock() + * @see Common\SymmetricKey::decrypt() * @param string $in * @return string */ @@ -514,7 +514,7 @@ class RC2 extends BlockCipher /** * Creates the key schedule * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey() + * @see Common\SymmetricKey::setupKey() */ protected function setupKey() { @@ -534,7 +534,7 @@ class RC2 extends BlockCipher /** * Setup the performance-optimized function for de/encrypt() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt() + * @see Common\SymmetricKey::setupInlineCrypt() */ protected function setupInlineCrypt() { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC4.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC4.php index 5f3bff2c0..98cf01165 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC4.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RC4.php @@ -72,7 +72,7 @@ class RC4 extends StreamCipher /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'arcfour'; @@ -98,7 +98,7 @@ class RC4 extends StreamCipher * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see Common\SymmetricKey::__construct() * @param int $engine * @return bool */ @@ -159,7 +159,7 @@ class RC4 extends StreamCipher /** * Encrypts a message. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see Common\SymmetricKey::decrypt() * @see self::crypt() * @param string $plaintext * @return string $ciphertext @@ -178,7 +178,7 @@ class RC4 extends StreamCipher * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see Common\SymmetricKey::encrypt() * @see self::crypt() * @param string $ciphertext * @return string $plaintext @@ -214,7 +214,7 @@ class RC4 extends StreamCipher /** * Setup the key (expansion) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey() + * @see Common\SymmetricKey::_setupKey() */ protected function setupKey() { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA.php index 9cbe6bfc7..0a11957b0 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA.php @@ -357,10 +357,9 @@ abstract class RSA extends AsymmetricKey if ($i != $num_primes) { $primes[$i] = BigInteger::randomPrime($regSize); } else { - extract(BigInteger::minMaxBits($bits)); - /** @var BigInteger $min - * @var BigInteger $max - */ + $minMax = BigInteger::minMaxBits($bits); + $min = $minMax['min']; + $max = $minMax['max']; list($min) = $min->divide($n); $min = $min->add(self::$one); list($max) = $max->divide($n); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php index b60e48ea5..035fc8c38 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php @@ -88,13 +88,11 @@ abstract class MSBLOB // PUBLICKEYSTRUC publickeystruc // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx - extract(unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8))); - /** - * @var string $type - * @var string $version - * @var integer $reserved - * @var integer $algo - */ + $unpacked = unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8)); + $type = $unpacked['type']; + $version = $unpacked['version']; + $reserved = $unpacked['reserved']; + $algo = $unpacked['algo']; switch (ord($type)) { case self::PUBLICKEYBLOB: case self::PUBLICKEYBLOBEX: @@ -121,12 +119,10 @@ abstract class MSBLOB // RSAPUBKEY rsapubkey // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit - extract(unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12))); - /** - * @var integer $magic - * @var integer $bitlen - * @var string $pubexp - */ + $unpacked = unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12)); + $magic = $unpacked['magic']; + $bitlen = $unpacked['bitlen']; + $pubexp = $unpacked['pubexp']; switch ($magic) { case self::RSA2: $components['isPublicKey'] = false; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php index 76335567f..68d92701e 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php @@ -96,6 +96,20 @@ abstract class PKCS1 extends Progenitor $components['isPublicKey'] = true; } + $components = $components + $key; + foreach ($components as &$val) { + if ($val instanceof BigInteger) { + $val = self::makePositive($val); + } + if (is_array($val)) { + foreach ($val as &$subval) { + if ($subval instanceof BigInteger) { + $subval = self::makePositive($subval); + } + } + } + } + return $components + $key; } @@ -157,4 +171,17 @@ abstract class PKCS1 extends Progenitor return self::wrapPublicKey($key, 'RSA'); } + + /** + * Negative numbers make no sense in RSA so convert them to positive + * + * @param BigInteger $x + * @return string + */ + private static function makePositive(BigInteger $x) + { + return $x->isNegative() ? + new BigInteger($x->toBytes(true), 256) : + $x; + } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php index 53918bc0d..30f63ff97 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php @@ -117,6 +117,6 @@ abstract class PKCS8 extends Progenitor { $key = PKCS1::savePublicKey($n, $e); $key = ASN1::extractBER($key); - return self::wrapPublicKey($key, null); + return self::wrapPublicKey($key, null, null, $options); } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php index 293903cef..8416758c2 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php @@ -56,7 +56,10 @@ abstract class PuTTY extends Progenitor if (!isset($components['private'])) { return $components; } - extract($components); + $type = $components['type']; + $comment = $components['comment']; + $public = $components['public']; + $private = $components['private']; unset($components['public'], $components['private']); $isPublicKey = false; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php index ff31f9c88..5ba7cf7fe 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php @@ -74,8 +74,8 @@ class Rijndael extends BlockCipher * or not for the current $block_size/$key_length. * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt - * @see \phpseclib3\Crypt\Common\SymmetricKey::engine + * @see Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::engine * @see self::isValidEngine() * @var string */ diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php index 0a35f478d..785e7aa2d 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php @@ -326,7 +326,7 @@ class Salsa20 extends StreamCipher foreach ($blocks as &$block) { $block ^= static::salsa20($this->p1 . pack('V', $i++) . $this->p2); } - + unset($block); return implode('', $blocks); } @@ -366,6 +366,7 @@ class Salsa20 extends StreamCipher foreach ($blocks as &$block) { $block ^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); } + unset($block); } $encrypted = implode('', $blocks); $temp = static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); @@ -388,6 +389,7 @@ class Salsa20 extends StreamCipher foreach ($blocks as &$block) { $block ^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); } + unset($block); $ciphertext .= implode('', $blocks); } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php index 1ff5ed02b..932b7c611 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php @@ -66,8 +66,8 @@ class TripleDES extends DES /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\DES::cipher_name_mcrypt - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see DES::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'tripledes'; @@ -75,7 +75,7 @@ class TripleDES extends DES /** * Optimizing value while CFB-encrypting * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len + * @see Common\SymmetricKey::cfb_init_len * @var int */ protected $cfb_init_len = 750; @@ -84,7 +84,7 @@ class TripleDES extends DES * max possible size of $key * * @see self::setKey() - * @see \phpseclib3\Crypt\DES::setKey() + * @see DES::setKey() * @var string */ protected $key_length_max = 24; @@ -126,8 +126,8 @@ class TripleDES extends DES * * - cbc3 (same as cbc) * - * @see \phpseclib3\Crypt\DES::__construct() - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see Crypt\DES::__construct() + * @see Common\SymmetricKey::__construct() * @param string $mode */ public function __construct($mode) @@ -169,7 +169,7 @@ class TripleDES extends DES * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see Common\SymmetricKey::__construct() * @param int $engine * @return bool */ @@ -189,7 +189,7 @@ class TripleDES extends DES * * SetIV is not required when \phpseclib3\Crypt\Common\SymmetricKey::MODE_ECB is being used. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setIV() + * @see Common\SymmetricKey::setIV() * @param string $iv */ public function setIV($iv) @@ -209,7 +209,7 @@ class TripleDES extends DES * * If you want to use a 64-bit key use DES.php * - * @see \phpseclib3\Crypt\Common\SymmetricKey:setKeyLength() + * @see Common\SymmetricKey:setKeyLength() * @throws \LengthException if the key length is invalid * @param int $length */ @@ -233,8 +233,8 @@ class TripleDES extends DES * * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. * - * @see \phpseclib3\Crypt\DES::setKey() - * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey() + * @see DES::setKey() + * @see Common\SymmetricKey::setKey() * @throws \LengthException if the key length is invalid * @param string $key */ @@ -270,7 +270,7 @@ class TripleDES extends DES /** * Encrypts a message. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see Common\SymmetricKey::encrypt() * @param string $plaintext * @return string $cipertext */ @@ -296,7 +296,7 @@ class TripleDES extends DES /** * Decrypts a message. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see Common\SymmetricKey::decrypt() * @param string $ciphertext * @return string $plaintext */ @@ -351,7 +351,7 @@ class TripleDES extends DES * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), * however, they are also less intuitive and more likely to cause you problems. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::enableContinuousBuffer() + * @see Common\SymmetricKey::enableContinuousBuffer() * @see self::disableContinuousBuffer() */ public function enableContinuousBuffer() @@ -369,7 +369,7 @@ class TripleDES extends DES * * The default behavior. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::disableContinuousBuffer() + * @see Common\SymmetricKey::disableContinuousBuffer() * @see self::enableContinuousBuffer() */ public function disableContinuousBuffer() @@ -385,8 +385,8 @@ class TripleDES extends DES /** * Creates the key schedule * - * @see \phpseclib3\Crypt\DES::setupKey() - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey() + * @see DES::setupKey() + * @see Common\SymmetricKey::setupKey() */ protected function setupKey() { @@ -419,8 +419,8 @@ class TripleDES extends DES /** * Sets the internal crypt engine * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() - * @see \phpseclib3\Crypt\Common\SymmetricKey::setPreferredEngine() + * @see Common\SymmetricKey::__construct() + * @see Common\SymmetricKey::setPreferredEngine() * @param int $engine */ public function setPreferredEngine($engine) diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php index bf765632a..141ad0141 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php @@ -49,7 +49,7 @@ class Twofish extends BlockCipher /** * The mcrypt specific name of the cipher * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt + * @see Common\SymmetricKey::cipher_name_mcrypt * @var string */ protected $cipher_name_mcrypt = 'twofish'; @@ -57,7 +57,7 @@ class Twofish extends BlockCipher /** * Optimizing value while CFB-encrypting * - * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len + * @see Common\SymmetricKey::cfb_init_len * @var int */ protected $cfb_init_len = 800; @@ -431,7 +431,7 @@ class Twofish extends BlockCipher /** * Setup the key (expansion) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey() + * @see Common\SymmetricKey::_setupKey() */ protected function setupKey() { @@ -700,7 +700,7 @@ class Twofish extends BlockCipher /** * Setup the performance-optimized function for de/encrypt() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt() + * @see Common\SymmetricKey::_setupInlineCrypt() */ protected function setupInlineCrypt() { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/ASN1.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/ASN1.php index c4b06a560..2f1fb8a67 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/ASN1.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/ASN1.php @@ -273,8 +273,7 @@ abstract class ASN1 // tags of indefinte length don't really have a header length; this length includes the tag $current += ['headerlength' => $length + 2]; $start += $length; - extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); - /** @var integer $length */ + $length = unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))['length']; } else { $current += ['headerlength' => 2]; } @@ -931,7 +930,19 @@ abstract class ASN1 an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)." */ if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) { - $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); + if ($child['constant'] <= 30) { + $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); + } else { + $constant = $child['constant']; + $subtag = ''; + while ($constant > 0) { + $subtagvalue = $constant & 0x7F; + $subtag = (chr(0x80 | $subtagvalue)) . $subtag; + $constant = $constant >> 7; + } + $subtag[strlen($subtag) - 1] = $subtag[strlen($subtag) - 1] & chr(0x7F); + $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | 0x1f) . $subtag; + } $temp = $subtag . self::encodeLength(strlen($temp)) . $temp; } else { $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']); @@ -1140,6 +1151,8 @@ abstract class ASN1 */ public static function decodeOID($content) { + // BigInteger's are used because of OIDs like 2.25.329800735698586629295641978511506172918 + // https://healthcaresecprivacy.blogspot.com/2011/02/creating-and-using-unique-id-uuid-oid.html elaborates. static $eighty; if (!$eighty) { $eighty = new BigInteger(80); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/X509.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/X509.php index f4d96a26e..80e0bab10 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/X509.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/File/X509.php @@ -519,11 +519,6 @@ class X509 ); } - if ($algorithm == 'rsaEncryption') { - $cert['signatureAlgorithm']['parameters'] = null; - $cert['tbsCertificate']['signature']['parameters'] = null; - } - $filters = []; $type_utf8_string = ['type' => ASN1::TYPE_UTF8_STRING]; $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string; @@ -631,7 +626,9 @@ class X509 $extensions = &$this->subArray($root, $path, !empty($this->extensionValues)); foreach ($this->extensionValues as $id => $data) { - extract($data); + $critical = $data['critical']; + $replace = $data['replace']; + $value = $data['value']; $newext = [ 'extnId' => $id, 'extnValue' => $value, @@ -1710,7 +1707,7 @@ class X509 * @param bool $withType optional * @return mixed */ - public function getDNProp($propName, array $dn = null, $withType = false) + public function getDNProp($propName, $dn = null, $withType = false) { if (!isset($dn)) { $dn = $this->dn; @@ -1815,7 +1812,7 @@ class X509 * @param array $dn optional * @return array|bool|string */ - public function getDN($format = self::DN_ARRAY, array $dn = null) + public function getDN($format = self::DN_ARRAY, $dn = null) { if (!isset($dn)) { $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn; @@ -1863,7 +1860,7 @@ class X509 $dn = $this->getDN(self::DN_CANON, $dn); $hash = new Hash('sha1'); $hash = $hash->hash($dn); - extract(unpack('Vhash', $hash)); + $hash = unpack('Vhash', $hash)['hash']; return strtolower(Strings::bin2hex(pack('N', $hash))); } @@ -2755,7 +2752,8 @@ class X509 [ 'version' => 'v1', 'subject' => $this->dn, - 'subjectPKInfo' => $publicKey + 'subjectPKInfo' => $publicKey, + 'attributes' => [] ], 'signatureAlgorithm' => $signatureAlgorithm, 'signature' => false // this is going to be overwritten later @@ -2993,7 +2991,10 @@ class X509 case 'sha256': case 'sha384': case 'sha512': - return ['algorithm' => $key->getHash() . 'WithRSAEncryption']; + return [ + 'algorithm' => $key->getHash() . 'WithRSAEncryption', + 'parameters' => null + ]; } throw new UnsupportedAlgorithmException('The only supported hash algorithms for RSA are: md2, md5, sha1, sha224, sha256, sha384, sha512'); } @@ -3163,7 +3164,7 @@ class X509 * @param bool $create optional * @return array|false */ - private function &subArray(array &$root = null, $path, $create = false) + private function &subArray(&$root, $path, $create = false) { $false = false; @@ -3198,7 +3199,7 @@ class X509 * @param bool $create optional * @return array|false */ - private function &extensions(array &$root = null, $path = null, $create = false) + private function &extensions(&$root, $path = null, $create = false) { if (!isset($root)) { $root = $this->currentCert; @@ -3285,7 +3286,7 @@ class X509 * @param string $path optional * @return mixed */ - private function getExtensionHelper($id, array $cert = null, $path = null) + private function getExtensionHelper($id, $cert = null, $path = null) { $extensions = $this->extensions($cert, $path); @@ -3309,7 +3310,7 @@ class X509 * @param string $path optional * @return array */ - private function getExtensionsHelper(array $cert = null, $path = null) + private function getExtensionsHelper($cert = null, $path = null) { $exts = $this->extensions($cert, $path); $extensions = []; @@ -3379,7 +3380,7 @@ class X509 * @param string $path * @return mixed */ - public function getExtension($id, array $cert = null, $path = null) + public function getExtension($id, $cert = null, $path = null) { return $this->getExtensionHelper($id, $cert, $path); } @@ -3391,7 +3392,7 @@ class X509 * @param string $path optional * @return array */ - public function getExtensions(array $cert = null, $path = null) + public function getExtensions($cert = null, $path = null) { return $this->getExtensionsHelper($cert, $path); } @@ -3467,7 +3468,7 @@ class X509 * @param array $csr optional * @return mixed */ - public function getAttribute($id, $disposition = self::ATTR_ALL, array $csr = null) + public function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null) { if (empty($csr)) { $csr = $this->currentCert; @@ -3500,13 +3501,35 @@ class X509 return false; } + /** + * Get all requested CSR extensions + * + * Returns the list of extensions if there are any and false if not + * + * @param array $csr optional + * @return mixed + */ + public function getRequestedCertificateExtensions($csr = null) + { + if (empty($csr)) { + $csr = $this->currentCert; + } + + $requestedExtensions = $this->getAttribute('pkcs-9-at-extensionRequest'); + if ($requestedExtensions === false) { + return false; + } + + return $this->getAttribute('pkcs-9-at-extensionRequest')[0]; + } + /** * Returns a list of all CSR attributes in use * * @param array $csr optional * @return array */ - public function getAttributes(array $csr = null) + public function getAttributes($csr = null) { if (empty($csr)) { $csr = $this->currentCert; @@ -3853,7 +3876,7 @@ class X509 * @param array $crl optional * @return array|bool */ - public function listRevoked(array $crl = null) + public function listRevoked($crl = null) { if (!isset($crl)) { $crl = $this->currentCert; @@ -3902,7 +3925,7 @@ class X509 * @param array $crl optional * @return mixed */ - public function getRevokedCertificateExtension($serial, $id, array $crl = null) + public function getRevokedCertificateExtension($serial, $id, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; @@ -3924,7 +3947,7 @@ class X509 * @param array $crl optional * @return array|bool */ - public function getRevokedCertificateExtensions($serial, array $crl = null) + public function getRevokedCertificateExtensions($serial, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger.php index 2a9cc0b43..965d7ff08 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger.php @@ -143,6 +143,11 @@ class BigInteger implements \JsonSerializable ['PHP64', ['DefaultEngine']], ['PHP32', ['DefaultEngine']] ]; + // per https://phpseclib.com/docs/speed PHP 8.4.0+ _significantly_ sped up BCMath + if (version_compare(PHP_VERSION, '8.4.0') >= 0) { + $engines[1][0] = 'BCMath'; + $engines[2][0] = 'PHP64'; + } foreach ($engines as $engine) { try { @@ -333,12 +338,10 @@ class BigInteger implements \JsonSerializable */ public function extendedGCD(BigInteger $n) { - extract($this->value->extendedGCD($n->value)); - /** - * @var BigInteger $gcd - * @var BigInteger $x - * @var BigInteger $y - */ + $extended = $this->value->extendedGCD($n->value); + $gcd = $extended['gcd']; + $x = $extended['x']; + $y = $extended['y']; return [ 'gcd' => new static($gcd), 'x' => new static($x), @@ -617,10 +620,9 @@ class BigInteger implements \JsonSerializable self::initialize_static_variables(); $class = self::$mainEngine; - extract($class::minMaxBits($bits)); - /** @var BigInteger $min - * @var BigInteger $max - */ + $minMax = $class::minMaxBits($bits); + $min = $minMax['min']; + $max = $minMax['max']; return [ 'min' => new static($min), 'max' => new static($max) diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php index e3a49906b..7b6283002 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php @@ -38,6 +38,11 @@ class BCMath extends Engine */ const ENGINE_DIR = 'BCMath'; + /** + * Test to see if bcmod() accepts 2 or 3 parameters + */ + const BCMOD_THREE_PARAMS = PHP_VERSION_ID >= 72000; + /** * Test for engine validity * @@ -148,7 +153,7 @@ class BCMath extends Engine } while (bccomp($current, '0', 0) > 0) { - $temp = bcmod($current, '16777216'); + $temp = self::BCMOD_THREE_PARAMS ? bcmod($current, '16777216', 0) : bcmod($current, '16777216'); $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $current = bcdiv($current, '16777216', 0); } @@ -167,7 +172,7 @@ class BCMath extends Engine public function add(BCMath $y) { $temp = new self(); - $temp->value = bcadd($this->value, $y->value); + $temp->value = bcadd($this->value, $y->value, 0); return $this->normalize($temp); } @@ -181,7 +186,7 @@ class BCMath extends Engine public function subtract(BCMath $y) { $temp = new self(); - $temp->value = bcsub($this->value, $y->value); + $temp->value = bcsub($this->value, $y->value, 0); return $this->normalize($temp); } @@ -195,7 +200,7 @@ class BCMath extends Engine public function multiply(BCMath $x) { $temp = new self(); - $temp->value = bcmul($this->value, $x->value); + $temp->value = bcmul($this->value, $x->value, 0); return $this->normalize($temp); } @@ -217,7 +222,7 @@ class BCMath extends Engine $remainder = new self(); $quotient->value = bcdiv($this->value, $y->value, 0); - $remainder->value = bcmod($this->value, $y->value); + $remainder->value = self::BCMOD_THREE_PARAMS ? bcmod($this->value, $y->value, 0) : bcmod($this->value, $y->value); if ($remainder->value[0] == '-') { $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); @@ -297,8 +302,7 @@ class BCMath extends Engine */ public function gcd(BCMath $n) { - extract($this->extendedGCD($n)); - /** @var BCMath $gcd */ + $gcd = $this->extendedGCD($n)['gcd']; return $gcd; } @@ -475,7 +479,7 @@ class BCMath extends Engine $result->bitmask = $this->bitmask; if ($result->bitmask !== false) { - $result->value = bcmod($result->value, $result->bitmask->value); + $result->value = self::BCMOD_THREE_PARAMS ? bcmod($result->value, $result->bitmask->value, 0) : bcmod($result->value, $result->bitmask->value); } return $result; @@ -523,7 +527,7 @@ class BCMath extends Engine protected function make_odd() { if (!$this->isOdd()) { - $this->value = bcadd($this->value, '1'); + $this->value = bcadd($this->value, '1', 0); } } @@ -547,7 +551,7 @@ class BCMath extends Engine $value = $this->value; foreach (self::PRIMES as $prime) { - $r = bcmod($this->value, $prime); + $r = self::BCMOD_THREE_PARAMS ? bcmod($this->value, $prime, 0) : bcmod($this->value, $prime); if ($r == '0') { return $this->value == $prime; } @@ -587,7 +591,7 @@ class BCMath extends Engine public function pow(BCMath $n) { $temp = new self(); - $temp->value = bcpow($this->value, $n->value); + $temp->value = bcpow($this->value, $n->value, 0); return $this->normalize($temp); } @@ -656,8 +660,9 @@ class BCMath extends Engine */ public function testBit($x) { + $divisor = bcpow('2', $x + 1, 0); return bccomp( - bcmod($this->value, bcpow('2', $x + 1, 0)), + self::BCMOD_THREE_PARAMS ? bcmod($this->value, $divisor, 0) : bcmod($this->value, $divisor), bcpow('2', $x, 0), 0 ) >= 0; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.php index fe21e0411..88cd93e94 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.php @@ -91,7 +91,7 @@ abstract class Base extends BCMath */ protected static function multiplyReduce($x, $y, $n, $class) { - return static::reduce(bcmul($x, $y), $n); + return static::reduce(bcmul($x, $y, 0), $n); } /** @@ -105,6 +105,6 @@ abstract class Base extends BCMath */ protected static function squareReduce($x, $n, $class) { - return static::reduce(bcmul($x, $x), $n); + return static::reduce(bcmul($x, $x, 0), $n); } } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php index b7ca8a2c6..f8bbcfa27 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php @@ -33,7 +33,7 @@ abstract class BuiltIn extends BCMath protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n) { $temp = new BCMath(); - $temp->value = bcpowmod($x->value, $e->value, $n->value); + $temp->value = bcpowmod($x->value, $e->value, $n->value, 0); return $x->normalize($temp); } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php index ec1d5caa7..1bec0a11f 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php @@ -66,8 +66,8 @@ abstract class Barrett extends Base $m_length = strlen($m); - if (strlen($n) >= 2 * $m_length) { - return bcmod($n, $m); + if (strlen($n) > 2 * $m_length) { + return self::BCMOD_THREE_PARAMS ? bcmod($n, $m, 0) : bcmod($n, $m); } // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced @@ -75,6 +75,13 @@ abstract class Barrett extends Base return self::regularBarrett($n, $m); } // n = 2 * m.length + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + $n .= '0'; + $m .= '0'; + $m_length++; + } if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); @@ -82,14 +89,16 @@ abstract class Barrett extends Base $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1)); $u = bcdiv($lhs, $m, 0); - $m1 = bcsub($lhs, bcmul($u, $m)); + $m1 = bcsub($lhs, bcmul($u, $m, 0), 0); $cache[self::DATA][] = [ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) 'm1' => $m1 // m.length ]; } else { - extract($cache[self::DATA][$key]); + $cacheValues = $cache[self::DATA][$key]; + $u = $cacheValues['u']; + $m1 = $cacheValues['m1']; } $cutoff = $m_length + ($m_length >> 1); @@ -97,8 +106,8 @@ abstract class Barrett extends Base $lsd = substr($n, -$cutoff); $msd = substr($n, 0, -$cutoff); - $temp = bcmul($msd, $m1); // m.length + (m.length >> 1) - $n = bcadd($lsd, $temp); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers) + $temp = bcmul($msd, $m1, 0); // m.length + (m.length >> 1) + $n = bcadd($lsd, $temp, 0); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers) //if ($m_length & 1) { // return self::regularBarrett($n, $m); //} @@ -107,31 +116,31 @@ abstract class Barrett extends Base $temp = substr($n, 0, -$m_length + 1); // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 - $temp = bcmul($temp, $u); + $temp = bcmul($temp, $u, 0); // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) $temp = substr($temp, 0, -($m_length >> 1) - 1); // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) - $temp = bcmul($temp, $m); + $temp = bcmul($temp, $m, 0); // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). - $result = bcsub($n, $temp); + $result = bcsub($n, $temp, 0); //if (bccomp($result, '0') < 0) { if ($result[0] == '-') { $temp = '1' . str_repeat('0', $m_length + 1); - $result = bcadd($result, $temp); + $result = bcadd($result, $temp, 0); } - while (bccomp($result, $m) >= 0) { - $result = bcsub($result, $m); + while (bccomp($result, $m, 0) >= 0) { + $result = bcsub($result, $m, 0); } - return $result; + return $correctionNeeded && $result != '0' ? substr($result, 0, -1) : $result; } /** @@ -154,7 +163,7 @@ abstract class Barrett extends Base $n_length = strlen($n); if (strlen($x) > 2 * $n_length) { - return bcmod($x, $n); + return self::BCMOD_THREE_PARAMS ? bcmod($x, $n, 0) : bcmod($x, $n); } if (($key = array_search($n, $cache[self::VARIABLE])) === false) { @@ -165,21 +174,21 @@ abstract class Barrett extends Base } $temp = substr($x, 0, -$n_length + 1); - $temp = bcmul($temp, $cache[self::DATA][$key]); + $temp = bcmul($temp, $cache[self::DATA][$key], 0); $temp = substr($temp, 0, -$n_length - 1); $r1 = substr($x, -$n_length - 1); - $r2 = substr(bcmul($temp, $n), -$n_length - 1); + $r2 = substr(bcmul($temp, $n, 0), -$n_length - 1); $result = bcsub($r1, $r2); //if (bccomp($result, '0') < 0) { if ($result[0] == '-') { $q = '1' . str_repeat('0', $n_length + 1); - $result = bcadd($result, $q); + $result = bcadd($result, $q, 0); } - while (bccomp($result, $n) >= 0) { - $result = bcsub($result, $n); + while (bccomp($result, $n, 0) >= 0) { + $result = bcsub($result, $n, 0); } return $result; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php index e033ba575..040d7b5a7 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php @@ -58,7 +58,7 @@ abstract class EvalBarrett extends Base $m_length = strlen($m); if ($m_length < 5) { - $code = 'return bcmod($x, $n);'; + $code = 'return self::BCMOD_THREE_PARAMS ? bcmod($x, $n, 0) : bcmod($x, $n);'; eval('$func = function ($n) { ' . $code . '};'); self::$custom_reduction = $func; return; @@ -66,7 +66,7 @@ abstract class EvalBarrett extends Base $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1)); $u = bcdiv($lhs, $m, 0); - $m1 = bcsub($lhs, bcmul($u, $m)); + $m1 = bcsub($lhs, bcmul($u, $m, 0), 0); $cutoff = $m_length + ($m_length >> 1); @@ -78,23 +78,23 @@ abstract class EvalBarrett extends Base $lsd = substr($n, -' . $cutoff . '); $msd = substr($n, 0, -' . $cutoff . '); - $temp = bcmul($msd, ' . $m1 . '); - $n = bcadd($lsd, $temp); + $temp = bcmul($msd, ' . $m1 . ', 0); + $n = bcadd($lsd, $temp, 0); $temp = substr($n, 0, ' . (-$m_length + 1) . '); - $temp = bcmul($temp, ' . $u . '); + $temp = bcmul($temp, ' . $u . ', 0); $temp = substr($temp, 0, ' . (-($m_length >> 1) - 1) . '); - $temp = bcmul($temp, ' . $m . '); + $temp = bcmul($temp, ' . $m . ', 0); - $result = bcsub($n, $temp); + $result = bcsub($n, $temp, 0); if ($result[0] == \'-\') { $temp = \'1' . str_repeat('0', $m_length + 1) . '\'; - $result = bcadd($result, $temp); + $result = bcadd($result, $temp, 0); } while (bccomp($result, ' . $m . ') >= 0) { - $result = bcsub($result, ' . $m . '); + $result = bcsub($result, ' . $m . ', 0); } return $result;'; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php index 474abe105..1892042c5 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php @@ -316,11 +316,9 @@ abstract class Engine implements \JsonSerializable return $this->normalize($n->subtract($temp)); } - extract($this->extendedGCD($n)); - /** - * @var Engine $gcd - * @var Engine $x - */ + $extended = $this->extendedGCD($n); + $gcd = $extended['gcd']; + $x = $extended['x']; if (!$gcd->equals(static::$one[static::class])) { return false; @@ -644,7 +642,7 @@ abstract class Engine implements \JsonSerializable return $this->normalize($temp->powModInner($e, $n)); } - if ($this->compare($n) > 0) { + if ($this->compare($n) > 0 || $this->isNegative()) { list(, $temp) = $this->divide($n); return $temp->powModInner($e, $n); } @@ -740,11 +738,9 @@ abstract class Engine implements \JsonSerializable */ public static function random($size) { - extract(static::minMaxBits($size)); - /** - * @var BigInteger $min - * @var BigInteger $max - */ + $minMax = static::minMaxBits($size); + $min = $minMax['min']; + $max = $minMax['max']; return static::randomRange($min, $max); } @@ -758,11 +754,9 @@ abstract class Engine implements \JsonSerializable */ public static function randomPrime($size) { - extract(static::minMaxBits($size)); - /** - * @var static $min - * @var static $max - */ + $minMax = static::minMaxBits($size); + $min = $minMax['min']; + $max = $minMax['max']; return static::randomRangePrime($min, $max); } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php index f61636297..0db43ae63 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php @@ -296,7 +296,10 @@ class GMP extends Engine */ public function extendedGCD(GMP $n) { - extract(gmp_gcdext($this->value, $n->value)); + $extended = gmp_gcdext($this->value, $n->value); + $g = $extended['g']; + $s = $extended['s']; + $t = $extended['t']; return [ 'gcd' => $this->normalize(new self($g)), diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php index 2d8959522..de556a3b2 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php @@ -533,6 +533,9 @@ abstract class PHP extends Engine $quotient = new static(); $remainder = new static(); $quotient->value = $q; + if ($this->is_negative) { + $r = $y->value[0] - $r; + } $remainder->value = [$r]; $quotient->is_negative = $this->is_negative != $y->is_negative; return [$this->normalize($quotient), $this->normalize($remainder)]; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php index 849374193..e624f3cad 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php @@ -56,7 +56,7 @@ abstract class Barrett extends Base $m_length = count($m); // if (self::compareHelper($n, $static::square($m)) >= 0) { - if (count($n) >= 2 * $m_length) { + if (count($n) > 2 * $m_length) { $lhs = new $class(); $rhs = new $class(); $lhs->value = $n; @@ -70,6 +70,13 @@ abstract class Barrett extends Base return self::regularBarrett($n, $m, $class); } // n = 2 * m.length + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + array_unshift($n, 0); + array_unshift($m, 0); + $m_length++; + } if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); @@ -91,7 +98,9 @@ abstract class Barrett extends Base 'm1' => $m1 // m.length ]; } else { - extract($cache[self::DATA][$key]); + $cacheValues = $cache[self::DATA][$key]; + $u = $cacheValues['u']; + $m1 = $cacheValues['m1']; } $cutoff = $m_length + ($m_length >> 1); @@ -109,6 +118,10 @@ abstract class Barrett extends Base $temp = array_slice($n[self::VALUE], $m_length - 1); // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 + // note that these are upper bounds. let's say m.length is 2. then you'd be multiplying a + // 3 digit number by a 1 digit number. if you're doing 999 * 9 (in base 10) the result will + // be a 4 digit number. but if you're multiplying 111 * 1 then the result will be a 3 digit + // number. $temp = $class::multiplyHelper($temp, false, $u, false); // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) @@ -116,17 +129,19 @@ abstract class Barrett extends Base // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) $temp = $class::multiplyHelper($temp, false, $m, false); - - // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit - // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop + // at this point, if m had an odd number of digits, we'd (probably) be subtracting a 2 * m.length - (m.length >> 1) + // digit number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). - $result = $class::subtractHelper($n[self::VALUE], false, $temp[self::VALUE], false); while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) { $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $m, false); } + if ($correctionNeeded) { + array_shift($result[self::VALUE]); + } + return $result[self::VALUE]; } diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php index 2cf69f2e8..01df0b611 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php @@ -74,6 +74,14 @@ abstract class EvalBarrett extends Base return $func; } + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + $m = clone $m; + array_unshift($m->value, 0); + $m_length++; + } + $lhs = new $class(); $lhs_value = &$lhs->value; @@ -99,8 +107,12 @@ abstract class EvalBarrett extends Base $cutoff = count($m) + (count($m) >> 1); - $code = ' - if (count($n) >= ' . (2 * count($m)) . ') { + $code = $correctionNeeded ? + 'array_unshift($n, 0);' : + ''; + + $code .= ' + if (count($n) > ' . (2 * count($m)) . ') { $lhs = new ' . $class . '(); $rhs = new ' . $class . '(); $lhs->value = $n; @@ -141,6 +153,10 @@ abstract class EvalBarrett extends Base $code .= self::generateInlineCompare($m, 'temp', $subcode); + if ($correctionNeeded) { + $code .= 'array_shift($temp);'; + } + $code .= 'return $temp;'; eval('$func = function ($n) { ' . $code . '};'); diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php index 1bd7aaf0f..1ebb2f5d7 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php @@ -54,20 +54,35 @@ class Integer extends Base /** * Zero * - * @var BigInteger + * @var BigInteger[] */ protected static $zero; + /** + * One + * + * @var BigInteger[] + */ + protected static $one; + + /** + * Two + * + * @var BigInteger[] + */ + protected static $two; + /** * Default constructor * * @param int $instanceID + * @param BigInteger $num */ - public function __construct($instanceID, BigInteger $num = null) + public function __construct($instanceID, $num = null) { $this->instanceID = $instanceID; if (!isset($num)) { - $this->value = clone static::$zero[static::class]; + $this->value = clone static::$zero[$instanceID]; } else { $reduce = static::$reduce[$instanceID]; $this->value = $reduce($num); @@ -94,8 +109,8 @@ class Integer extends Base public static function setRecurringModuloFunction($instanceID, callable $function) { static::$reduce[$instanceID] = $function; - if (!isset(static::$zero[static::class])) { - static::$zero[static::class] = new BigInteger(); + if (!isset(static::$zero[$instanceID])) { + static::$zero[$instanceID] = new BigInteger(); } } @@ -106,6 +121,9 @@ class Integer extends Base { unset(static::$modulo[$instanceID]); unset(static::$reduce[$instanceID]); + unset(static::$zero[$instanceID]); + unset(static::$one[$instanceID]); + unset(static::$two[$instanceID]); } /** @@ -239,32 +257,35 @@ class Integer extends Base */ public function squareRoot() { - static $one, $two; - if (!isset($one)) { - $one = new BigInteger(1); - $two = new BigInteger(2); + if (!isset(static::$one[$this->instanceID])) { + static::$one[$this->instanceID] = new BigInteger(1); + static::$two[$this->instanceID] = new BigInteger(2); } - $reduce = static::$reduce[$this->instanceID]; - $p_1 = static::$modulo[$this->instanceID]->subtract($one); + $one = &static::$one[$this->instanceID]; + $two = &static::$two[$this->instanceID]; + $modulo = &static::$modulo[$this->instanceID]; + $reduce = &static::$reduce[$this->instanceID]; + + $p_1 = $modulo->subtract($one); $q = clone $p_1; $s = BigInteger::scan1divide($q); list($pow) = $p_1->divide($two); - for ($z = $one; !$z->equals(static::$modulo[$this->instanceID]); $z = $z->add($one)) { - $temp = $z->powMod($pow, static::$modulo[$this->instanceID]); + for ($z = $one; !$z->equals($modulo); $z = $z->add($one)) { + $temp = $z->powMod($pow, $modulo); if ($temp->equals($p_1)) { break; } } $m = new BigInteger($s); - $c = $z->powMod($q, static::$modulo[$this->instanceID]); - $t = $this->value->powMod($q, static::$modulo[$this->instanceID]); + $c = $z->powMod($q, $modulo); + $t = $this->value->powMod($q, $modulo); list($temp) = $q->add($one)->divide($two); - $r = $this->value->powMod($temp, static::$modulo[$this->instanceID]); + $r = $this->value->powMod($temp, $modulo); while (!$t->equals($one)) { for ($i = clone $one; $i->compare($m) < 0; $i = $i->add($one)) { - if ($t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) { + if ($t->powMod($two->pow($i), $modulo)->equals($one)) { break; } } @@ -272,7 +293,7 @@ class Integer extends Base if ($i->compare($m) == 0) { return false; } - $b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), static::$modulo[$this->instanceID]); + $b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), $modulo); $m = $i; $c = $reduce($b->multiply($b)); $t = $reduce($t->multiply($c)); @@ -355,6 +376,8 @@ class Integer extends Base { $w++; + $zero = &static::$zero[$this->instanceID]; + $mask = new BigInteger((1 << $w) - 1); $sub = new BigInteger(1 << $w); //$sub = new BigInteger(1 << ($w - 1)); @@ -362,7 +385,7 @@ class Integer extends Base $d_i = []; $i = 0; - while ($d->compare(static::$zero[static::class]) > 0) { + while ($d->compare($zero) > 0) { if ($d->isOdd()) { // start mods @@ -376,7 +399,7 @@ class Integer extends Base } else { $d_i[$i] = 0; } - $shift = !$d->equals(static::$zero[static::class]) && $d->bitwise_and($mask)->equals(static::$zero[static::class]) ? $w : 1; // $w or $w + 1? + $shift = !$d->equals($zero) && $d->bitwise_and($mask)->equals($zero) ? $w : 1; // $w or $w + 1? $d = $d->bitwise_rightShift($shift); while (--$shift > 0) { $d_i[++$i] = 0; diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP.php index 1e61e0bb3..7e25544cf 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP.php @@ -836,6 +836,8 @@ class SFTP extends SSH2 return false; } + $path = (string) $path; + if (!$this->canonicalize_paths) { if ($this->pwd === true) { return '.'; @@ -923,6 +925,8 @@ class SFTP extends SSH2 return false; } + $dir = (string) $dir; + // assume current dir if $dir is empty if ($dir === '') { $dir = './'; @@ -3043,6 +3047,8 @@ class SFTP extends SSH2 */ protected function parseAttributes(&$response) { + $attr = []; + if ($this->version >= 4) { list($flags, $attr['type']) = Strings::unpackSSH2('NC', $response); } else { @@ -3353,8 +3359,7 @@ class SFTP extends SSH2 if (strlen($this->packet_buffer) < 4) { throw new \RuntimeException('Packet is too small'); } - extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4))); - /** @var integer $length */ + $length = unpack('Nlength', Strings::shift($this->packet_buffer, 4))['length']; $tempLength = $length; $tempLength -= strlen($this->packet_buffer); @@ -3384,7 +3389,7 @@ class SFTP extends SSH2 $this->packet_type = ord(Strings::shift($this->packet_buffer)); if ($this->use_request_id) { - extract(unpack('Npacket_id', Strings::shift($this->packet_buffer, 4))); // remove the request id + $packet_id = unpack('Npacket_id', Strings::shift($this->packet_buffer, 4))['packet_id']; // remove the request id $length -= 5; // account for the request id and the packet type } else { $length -= 1; // account for the packet type diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php index 24047b4b0..a1f2fa245 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php @@ -139,7 +139,15 @@ class Stream protected function parse_path($path) { $orig = $path; - extract(parse_url($path) + ['port' => 22]); + $url = parse_url($path) + ['port' => 22]; + + $keys = ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment']; + foreach ($keys as $key) { + if (isset($url[$key])) { + $$key = $url[$key]; + } + } + if (isset($query)) { $path .= '?' . $query; } elseif (preg_match('/(\?|\?#)$/', $orig)) { diff --git a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SSH2.php index 43ddbccd6..1c8a0e265 100644 --- a/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SSH2.php +++ b/lam/lib/3rdParty/composer/phpseclib/phpseclib/phpseclib/Net/SSH2.php @@ -151,6 +151,10 @@ class SSH2 * Outputs the message numbers real-time */ const LOG_SIMPLE_REALTIME = 5; + /* + * Dumps the message numbers real-time + */ + const LOG_REALTIME_SIMPLE = 5; /** * Make sure that the log never gets larger than this * @@ -1116,14 +1120,55 @@ class SSH2 private $errorOnMultipleChannels; /** - * Terrapin Countermeasure + * Bytes Transferred Since Last Key Exchange * - * "During initial KEX, terminate the connection if any unexpected or out-of-sequence packet is received" - * -- https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 + * Includes outbound and inbound totals * * @var int */ - private $extra_packets; + private $bytesTransferredSinceLastKEX = 0; + + /** + * After how many transferred byte should phpseclib initiate a key re-exchange? + * + * @var int + */ + private $doKeyReexchangeAfterXBytes = 1024 * 1024 * 1024; + + /** + * Has a key re-exchange been initialized? + * + * @var bool + * @access private + */ + private $keyExchangeInProgress = false; + + /** + * KEX Buffer + * + * If we're in the middle of a key exchange we want to buffer any additional packets we get until + * the key exchange is over + * + * @see self::_get_binary_packet() + * @see self::_key_exchange() + * @see self::exec() + * @var array + * @access private + */ + private $kex_buffer = []; + + /** + * Strict KEX Flag + * + * If kex-strict-s-v00@openssh.com is present in the first KEX packet it need not + * be present in subsequent packet + * + * @see self::_key_exchange() + * @see self::exec() + * @var array + * @access private + */ + private $strict_kex_flag = false; /** * Default Constructor. @@ -1432,7 +1477,7 @@ class SSH2 } if (defined('NET_SSH2_LOGGING')) { - $this->append_log('<- (network: ' . round($totalElapsed, 4) . ')', $line); + $this->append_log('<- (network: ' . round($totalElapsed, 4) . ')', $data); } if (feof($this->fsock)) { @@ -1442,7 +1487,13 @@ class SSH2 $extra = $matches[1]; - $this->server_identifier = trim($data, "\r\n"); + // earlier the SSH specs were quoted. + // "The server MAY send other lines of data before sending the version string." they said. + // the implication of this is that the lines of data before the server string are *not* a part of it + // getting this right is important because the correct server identifier needs to be fed into the + // exchange hash for the shared keys to be calculated correctly + $data = explode("\r\n", trim($data, "\r\n")); + $this->server_identifier = $data[count($data) - 1]; if (strlen($extra)) { $this->errors[] = $data; } @@ -1535,8 +1586,13 @@ class SSH2 */ private function key_exchange($kexinit_payload_server = false) { + $this->bytesTransferredSinceLastKEX = 0; + $preferred = $this->preferred; - $send_kex = true; + // for the initial key exchange $send_kex is true (no key re-exchange has been started) + // for phpseclib initiated key exchanges $send_kex is false + $send_kex = !$this->keyExchangeInProgress; + $this->keyExchangeInProgress = true; $kex_algorithms = isset($preferred['kex']) ? $preferred['kex'] : @@ -1616,11 +1672,20 @@ class SSH2 0 // reserved for future extension ); - if ($kexinit_payload_server === false) { + if ($kexinit_payload_server === false && $send_kex) { $this->send_binary_packet($kexinit_payload_client); - $this->extra_packets = 0; - $kexinit_payload_server = $this->get_binary_packet_or_close(NET_SSH2_MSG_KEXINIT); + while (true) { + $kexinit_payload_server = $this->get_binary_packet(); + switch (ord($kexinit_payload_server[0])) { + case NET_SSH2_MSG_KEXINIT: + break 2; + case NET_SSH2_MSG_DISCONNECT: + return $this->handleDisconnect($kexinit_payload_server); + } + $this->kex_buffer[] = $kexinit_payload_server; + } + $send_kex = false; } @@ -1642,8 +1707,13 @@ class SSH2 $first_kex_packet_follows ) = Strings::unpackSSH2('L10C', $response); if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) { - if ($this->session_id === false && $this->extra_packets) { - throw new \UnexpectedValueException('Possible Terrapin Attack detected'); + if ($this->session_id === false) { + // [kex-strict-s-v00@openssh.com is] only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored + // if [it is] present in subsequent SSH2_MSG_KEXINIT packets + $this->strict_kex_flag = true; + if (count($this->kex_buffer)) { + throw new \UnexpectedValueException('Possible Terrapin Attack detected'); + } } } @@ -1879,9 +1949,11 @@ class SSH2 $packet = pack('C', NET_SSH2_MSG_NEWKEYS); $this->send_binary_packet($packet); - $response = $this->get_binary_packet_or_close(NET_SSH2_MSG_NEWKEYS); + $this->get_binary_packet_or_close(NET_SSH2_MSG_NEWKEYS); - if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) { + $this->keyExchangeInProgress = false; + + if ($this->strict_kex_flag) { $this->get_seq_no = $this->send_seq_no = 0; } @@ -2792,11 +2864,12 @@ class SSH2 * In all likelihood, this is not a feature you want to be taking advantage of. * * @param string $command + * @param callable $callback * @return string|bool * @psalm-return ($callback is callable ? bool : string|bool) * @throws \RuntimeException on connection error */ - public function exec($command, callable $callback = null) + public function exec($command, $callback = null) { $this->curTimeout = $this->timeout; $this->is_timeout = false; @@ -2909,7 +2982,7 @@ class SSH2 */ protected function open_channel($channel, $skip_extended = false) { - if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) { + if (isset($this->channel_status[$channel])) { throw new \RuntimeException('Please close the channel (' . $channel . ') before trying to open it again'); } @@ -3278,6 +3351,27 @@ class SSH2 } } + /** + * Send EOF on a channel + * + * Sends an EOF to the stream; this is typically used to close standard + * input, while keeping output and error alive. + * + * @param int|null $channel Channel id returned by self::getInteractiveChannelId() + * @return void + */ + public function sendEOF($channel = null) + { + if ($channel === null) { + $channel = $this->get_interactive_channel(); + } + + $excludeStatuses = [NET_SSH2_MSG_CHANNEL_EOF, NET_SSH2_MSG_CHANNEL_CLOSE]; + if (isset($this->channel_status[$channel]) && !in_array($this->channel_status[$channel], $excludeStatuses)) { + $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$channel])); + } + } + /** * Is timeout? * @@ -3529,6 +3623,9 @@ class SSH2 if (!is_resource($this->fsock)) { throw new \InvalidArgumentException('fsock is not a resource.'); } + if (!$this->keyExchangeInProgress && count($this->kex_buffer)) { + return $this->filter(array_shift($this->kex_buffer)); + } if ($this->binary_packet_buffer == null) { // buffer the packet to permit continued reads across timeouts $this->binary_packet_buffer = (object) [ @@ -3651,10 +3748,15 @@ class SSH2 } $padding_length = 0; $payload = $packet->plain; - extract(unpack('Cpadding_length', Strings::shift($payload, 1))); + $padding_length = unpack('Cpadding_length', Strings::shift($payload, 1))['padding_length']; if ($padding_length > 0) { Strings::pop($payload, $padding_length); } + + if (!$this->keyExchangeInProgress) { + $this->bytesTransferredSinceLastKEX += $packet->packet_length + $padding_length + 5; + } + if (empty($payload)) { $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new ConnectionClosedException('Plaintext is too short'); @@ -3673,18 +3775,18 @@ class SSH2 $cmf = ord($payload[0]); $cm = $cmf & 0x0F; if ($cm != 8) { // deflate - user_error("Only CM = 8 ('deflate') is supported ($cm)"); + throw new UnsupportedAlgorithmException("Only CM = 8 ('deflate') is supported ($cm)"); } $cinfo = ($cmf & 0xF0) >> 4; if ($cinfo > 7) { - user_error("CINFO above 7 is not allowed ($cinfo)"); + throw new \RuntimeException("CINFO above 7 is not allowed ($cinfo)"); } $windowSize = 1 << ($cinfo + 8); $flg = ord($payload[1]); //$fcheck = $flg && 0x0F; if ((($cmf << 8) | $flg) % 31) { - user_error('fcheck failed'); + throw new \RuntimeException('fcheck failed'); } $fdict = boolval($flg & 0x20); $flevel = ($flg & 0xC0) >> 6; @@ -3708,6 +3810,10 @@ class SSH2 } $this->last_packet = microtime(true); + if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) { + $this->key_exchange(); + } + return $this->filter($payload); } @@ -3728,13 +3834,13 @@ class SSH2 switch ($this->decryptName) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': - extract(unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))); + $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length']; $packet->size = $packet_length_header_size + $packet_length + $this->decrypt_block_size; // expect tag break; case 'chacha20-poly1305@openssh.com': $this->lengthDecrypt->setNonce(pack('N2', 0, $this->get_seq_no)); $packet_length_header = $this->lengthDecrypt->decrypt(substr($packet->raw, 0, $packet_length_header_size)); - extract(unpack('Npacket_length', $packet_length_header)); + $packet_length = unpack('Npacket_length', $packet_length_header)['packet_length']; $packet->size = $packet_length_header_size + $packet_length + 16; // expect tag break; default: @@ -3743,17 +3849,17 @@ class SSH2 return; } $packet->plain = $this->decrypt->decrypt(substr($packet->raw, 0, $this->decrypt_block_size)); - extract(unpack('Npacket_length', Strings::shift($packet->plain, $packet_length_header_size))); + $packet_length = unpack('Npacket_length', Strings::shift($packet->plain, $packet_length_header_size))['packet_length']; $packet->size = $packet_length_header_size + $packet_length; $added_validation_length = $packet_length_header_size; } else { - extract(unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))); + $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length']; $packet->size = $packet_length_header_size + $packet_length; } break; } } else { - extract(unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))); + $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length']; $packet->size = $packet_length_header_size + $packet_length; $added_validation_length = $packet_length_header_size; } @@ -3773,6 +3879,25 @@ class SSH2 $packet->packet_length = $packet_length; } + /** + * Handle Disconnect + * + * Because some binary packets need to be ignored... + * + * @see self::filter() + * @see self::key_exchange() + * @return boolean + * @access private + */ + private function handleDisconnect($payload) + { + Strings::shift($payload, 1); + list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload); + $this->errors[] = 'SSH_MSG_DISCONNECT: ' . self::$disconnect_reasons[$reason_code] . "\r\n$message"; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); + throw new ConnectionClosedException('Connection closed by server'); + } + /** * Filter Binary Packets * @@ -3784,19 +3909,19 @@ class SSH2 */ private function filter($payload) { + if (ord($payload[0]) == NET_SSH2_MSG_DISCONNECT) { + return $this->handleDisconnect($payload); + } + + if ($this->session_id === false && $this->keyExchangeInProgress) { + return $payload; + } + switch (ord($payload[0])) { - case NET_SSH2_MSG_DISCONNECT: - Strings::shift($payload, 1); - list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload); - $this->errors[] = 'SSH_MSG_DISCONNECT: ' . self::$disconnect_reasons[$reason_code] . "\r\n$message"; - $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); - throw new ConnectionClosedException('Connection closed by server'); case NET_SSH2_MSG_IGNORE: - $this->extra_packets++; $payload = $this->get_binary_packet(); break; case NET_SSH2_MSG_DEBUG: - $this->extra_packets++; Strings::shift($payload, 2); // second byte is "always_display" list($message) = Strings::unpackSSH2('s', $payload); $this->errors[] = "SSH_MSG_DEBUG: $message"; @@ -3805,8 +3930,8 @@ class SSH2 case NET_SSH2_MSG_UNIMPLEMENTED: break; // return payload case NET_SSH2_MSG_KEXINIT: - // this is here for key re-exchanges after the initial key exchange - if ($this->session_id !== false) { + // this is here for server initiated key re-exchanges after the initial key exchange + if (!$this->keyExchangeInProgress && $this->session_id !== false) { if (!$this->key_exchange($payload)) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new ConnectionClosedException('Key exchange failed'); @@ -3826,6 +3951,26 @@ class SSH2 $payload = $this->get_binary_packet(); } + /* + Once a party has sent a SSH_MSG_KEXINIT message for key exchange or + re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section + 7.3), it MUST NOT send any messages other than: + + o Transport layer generic messages (1 to 19) (but + SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be + sent); + + o Algorithm negotiation messages (20 to 29) (but further + SSH_MSG_KEXINIT messages MUST NOT be sent); + + o Specific key exchange method messages (30 to 49). + + -- https://www.rfc-editor.org/rfc/rfc4253#section-7.1 + */ + if ($this->keyExchangeInProgress) { + return $payload; + } + // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { Strings::shift($payload, 1); @@ -3838,7 +3983,10 @@ class SSH2 switch (ord($payload[0])) { case NET_SSH2_MSG_CHANNEL_REQUEST: if (strlen($payload) == 31) { - extract(unpack('cpacket_type/Nchannel/Nlength', $payload)); + $unpacked = unpack('cpacket_type/Nchannel/Nlength', $payload); + $packet_type = $unpacked['packet_type']; + $channel = $unpacked['channel']; + $length = $unpacked['length']; if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) { if (ord(substr($payload, 9 + $length))) { // want reply $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel])); @@ -4002,7 +4150,8 @@ class SSH2 protected function get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { - switch ($this->channel_status[$client_channel]) { + // in phpseclib 4.0 this should be changed to $this->channel_status[$client_channel] ?? null + switch (isset($this->channel_status[$client_channel]) ? $this->channel_status[$client_channel] : null) { case NET_SSH2_MSG_CHANNEL_REQUEST: foreach ($this->channel_buffers[$client_channel] as $i => $packet) { switch (ord($packet[0])) { @@ -4070,7 +4219,7 @@ class SSH2 continue 2; case NET_SSH2_MSG_CHANNEL_REQUEST: - if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) { + if (!isset($this->channel_status[$channel])) { continue 2; } list($value) = Strings::unpackSSH2('s', $response); @@ -4088,10 +4237,14 @@ class SSH2 $this->errors[count($this->errors) - 1] .= "\r\n$error_message"; } - $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); + 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])); + } + $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; + $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; + } continue 3; case 'exit-status': @@ -4192,11 +4345,11 @@ class SSH2 $this->close_channel_bitmap($channel); - if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) { + if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); } - $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; + unset($this->channel_status[$channel]); $this->channelCount--; if ($client_channel == $channel) { @@ -4339,6 +4492,10 @@ class SSH2 $packet .= $this->encrypt && $this->encrypt->usesNonce() ? $this->encrypt->getTag() : $hmac; + if (!$this->keyExchangeInProgress) { + $this->bytesTransferredSinceLastKEX += strlen($packet); + } + $start = microtime(true); $sent = @fputs($this->fsock, $packet); $stop = microtime(true); @@ -4359,6 +4516,10 @@ class SSH2 "Only $sent of " . strlen($packet) . " bytes were sent"; throw new \RuntimeException($message); } + + if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) { + $this->key_exchange(); + } } /** @@ -4413,7 +4574,7 @@ class SSH2 protected function append_log_helper($constant, $message_number, $message, array &$message_number_log, array &$message_log, &$log_size, &$realtime_log_file, &$realtime_log_wrap, &$realtime_log_size) { // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) - if (strlen($message_number) > 2) { + if (!in_array(substr($message_number, 0, 4), ['<- (', '-> (']) && strlen($message_number) > 2) { Strings::shift($message); } @@ -4481,6 +4642,10 @@ class SSH2 $realtime_log_wrap = true; } fputs($realtime_log_file, $entry); + break; + case self::LOG_REALTIME_SIMPLE: + echo $message_number; + echo PHP_SAPI == 'cli' ? "\r\n" : '
    '; } } @@ -4549,27 +4714,24 @@ class SSH2 * @param bool $want_reply * @return void */ - private function close_channel($client_channel, $want_reply = false) + private function close_channel($client_channel) { // see http://tools.ietf.org/html/rfc4254#section-5.3 - $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); - - if (!$want_reply) { - $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); + if ($this->channel_status[$client_channel] != NET_SSH2_MSG_CHANNEL_EOF) { + $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); } + $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE; + $this->channelCount--; $this->curTimeout = 5; - while (!is_bool($this->get_channel_packet($client_channel))) { } - if ($want_reply) { - $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); - } + unset($this->channel_status[$client_channel]); $this->close_channel_bitmap($client_channel); } @@ -5089,41 +5251,65 @@ class SSH2 */ public function setPreferredAlgorithms(array $methods) { + $keys = ['client_to_server', 'server_to_client']; + + if (isset($methods['kex']) && is_string($methods['kex'])) { + $methods['kex'] = explode(',', $methods['kex']); + } + + if (isset($methods['hostkey']) && is_string($methods['hostkey'])) { + $methods['hostkey'] = explode(',', $methods['hostkey']); + } + + foreach ($keys as $key) { + if (isset($methods[$key])) { + $a = &$methods[$key]; + if (isset($a['crypt']) && is_string($a['crypt'])) { + $a['crypt'] = explode(',', $a['crypt']); + } + if (isset($a['comp']) && is_string($a['comp'])) { + $a['comp'] = explode(',', $a['comp']); + } + if (isset($a['mac']) && is_string($a['mac'])) { + $a['mac'] = explode(',', $a['mac']); + } + } + } + $preferred = $methods; if (isset($preferred['kex'])) { $preferred['kex'] = array_intersect( - is_string($preferred['kex']) ? [$preferred['kex']] : $preferred['kex'], + $preferred['kex'], static::getSupportedKEXAlgorithms() ); } if (isset($preferred['hostkey'])) { $preferred['hostkey'] = array_intersect( - is_string($preferred['hostkey']) ? [$preferred['hostkey']] : $preferred['hostkey'], + $preferred['hostkey'], static::getSupportedHostKeyAlgorithms() ); } - $keys = ['client_to_server', 'server_to_client']; foreach ($keys as $key) { if (isset($preferred[$key])) { $a = &$preferred[$key]; if (isset($a['crypt'])) { $a['crypt'] = array_intersect( - is_string($a['crypt']) ? [$a['crypt']] : $a['crypt'], + $a['crypt'], static::getSupportedEncryptionAlgorithms() ); } if (isset($a['comp'])) { $a['comp'] = array_intersect( - is_string($a['comp']) ? [$a['comp']] : $a['comp'], + $a['comp'], static::getSupportedCompressionAlgorithms() ); } if (isset($a['mac'])) { $a['mac'] = array_intersect( - is_string($a['mac']) ? [$a['mac']] : $a['mac'], + $a['mac'], static::getSupportedMACAlgorithms() ); } @@ -5434,4 +5620,14 @@ class SSH2 { $this->smartMFA = false; } + + /** + * How many bytes until the next key re-exchange? + * + * @param int $bytes + */ + public function bytesUntilKeyReexchange($bytes) + { + $this->doKeyReexchangeAfterXBytes = $bytes; + } } diff --git a/lam/lib/3rdParty/composer/psr/cache/CHANGELOG.md b/lam/lib/3rdParty/composer/psr/cache/CHANGELOG.md new file mode 100644 index 000000000..58ddab05a --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/cache/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.0.1 - 2016-08-06 + +### Fixed + +- Make spacing consistent in phpdoc annotations php-fig/cache#9 - chalasr +- Fix grammar in phpdoc annotations php-fig/cache#10 - chalasr +- Be more specific in docblocks that `getItems()` and `deleteItems()` take an array of strings (`string[]`) compared to just `array` php-fig/cache#8 - GrahamCampbell +- For `expiresAt()` and `expiresAfter()` in CacheItemInterface fix docblock to specify null as a valid parameters as well as an implementation of DateTimeInterface php-fig/cache#7 - GrahamCampbell + +## 1.0.0 - 2015-12-11 + +Initial stable release; reflects accepted PSR-6 specification diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/LICENSE.txt b/lam/lib/3rdParty/composer/psr/cache/LICENSE.txt similarity index 94% rename from lam/lib/3rdParty/composer/voku/portable-ascii/LICENSE.txt rename to lam/lib/3rdParty/composer/psr/cache/LICENSE.txt index b6ba47eae..b1c2c97b9 100644 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/LICENSE.txt +++ b/lam/lib/3rdParty/composer/psr/cache/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (C) 2019 Lars Moelleken +Copyright (c) 2015 PHP Framework Interoperability Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/psr/cache/README.md b/lam/lib/3rdParty/composer/psr/cache/README.md new file mode 100644 index 000000000..9855a318b --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/cache/README.md @@ -0,0 +1,12 @@ +Caching Interface +============== + +This repository holds all interfaces related to [PSR-6 (Caching Interface)][psr-url]. + +Note that this is not a Caching implementation of its own. It is merely interfaces that describe the components of a Caching mechanism. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-6/ +[package-url]: https://packagist.org/packages/psr/cache +[implementation-url]: https://packagist.org/providers/psr/cache-implementation diff --git a/lam/lib/3rdParty/composer/psr/cache/composer.json b/lam/lib/3rdParty/composer/psr/cache/composer.json new file mode 100644 index 000000000..4b687971e --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/cache/composer.json @@ -0,0 +1,25 @@ +{ + "name": "psr/cache", + "description": "Common interface for caching libraries", + "keywords": ["psr", "psr-6", "cache"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/psr/cache/src/CacheException.php b/lam/lib/3rdParty/composer/psr/cache/src/CacheException.php new file mode 100644 index 000000000..bb785f46c --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/cache/src/CacheException.php @@ -0,0 +1,10 @@ +=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/psr/event-dispatcher/src/EventDispatcherInterface.php b/lam/lib/3rdParty/composer/psr/event-dispatcher/src/EventDispatcherInterface.php new file mode 100644 index 000000000..4306fa915 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/event-dispatcher/src/EventDispatcherInterface.php @@ -0,0 +1,21 @@ +=5.3.0" + "php": ">=8.0.0" }, "autoload": { "psr-4": { @@ -19,7 +19,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0.x-dev" } } } diff --git a/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheException.php b/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheException.php index eba53815c..f61b24c2b 100644 --- a/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheException.php +++ b/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheException.php @@ -5,6 +5,6 @@ namespace Psr\SimpleCache; /** * Interface used for all types of exceptions thrown by the implementing library. */ -interface CacheException +interface CacheException extends \Throwable { } diff --git a/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheInterface.php b/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheInterface.php index 99e8d9574..671e340c5 100644 --- a/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheInterface.php +++ b/lam/lib/3rdParty/composer/psr/simple-cache/src/CacheInterface.php @@ -15,7 +15,7 @@ interface CacheInterface * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function get($key, $default = null); + public function get(string $key, mixed $default = null): mixed; /** * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. @@ -31,7 +31,7 @@ interface CacheInterface * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function set($key, $value, $ttl = null); + public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool; /** * Delete an item from the cache by its unique key. @@ -43,28 +43,28 @@ interface CacheInterface * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function delete($key); + public function delete(string $key): bool; /** * Wipes clean the entire cache's keys. * * @return bool True on success and false on failure. */ - public function clear(); + public function clear(): bool; /** * Obtains multiple cache items by their unique keys. * - * @param iterable $keys A list of keys that can obtained in a single operation. - * @param mixed $default Default value to return for keys that do not exist. + * @param iterable $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. * - * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. * * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ - public function getMultiple($keys, $default = null); + public function getMultiple(iterable $keys, mixed $default = null): iterable; /** * Persists a set of key => value pairs in the cache, with an optional TTL. @@ -80,12 +80,12 @@ interface CacheInterface * MUST be thrown if $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ - public function setMultiple($values, $ttl = null); + public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null): bool; /** * Deletes multiple cache items in a single operation. * - * @param iterable $keys A list of string-based keys to be deleted. + * @param iterable $keys A list of string-based keys to be deleted. * * @return bool True if the items were successfully removed. False if there was an error. * @@ -93,7 +93,7 @@ interface CacheInterface * MUST be thrown if $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ - public function deleteMultiple($keys); + public function deleteMultiple(iterable $keys): bool; /** * Determines whether an item is present in the cache. @@ -110,5 +110,5 @@ interface CacheInterface * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ - public function has($key); + public function has(string $key): bool; } diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/CONTRIBUTING.md new file mode 100644 index 000000000..b08c76c1f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# Contributing + +First of all, **thank you** for contributing. + +Bugs or feature requests can be posted online on the GitHub issues section of the project. + +Few rules to ease code reviews and merges: + +- You MUST follow the [PSR-12](http://www.php-fig.org/psr/psr-12/) coding standard. +- You MUST run the test suite. +- You MUST write (or update) unit tests when bugs are fixed or features are added. +- You SHOULD write documentation. + +To contribute use [Pull Requests](https://help.github.com/articles/using-pull-requests), please, write commit messages that make sense, and rebase your branch before submitting your PR. + +May be asked to squash your commits too. This is used to "clean" your Pull Request before merging it, avoiding commits such as fix tests, fix 2, fix 3, etc. + +Run test suite +------------ + +* install composer: `curl -s http://getcomposer.org/installer | php` +* install dependencies: `php composer.phar install` +* run tests: `vendor/bin/phpunit` diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/FUNDING.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/FUNDING.yml new file mode 100644 index 000000000..726574c1f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: Spomky +patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/1_Bug_report.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/1_Bug_report.md new file mode 100644 index 000000000..3a3e9fd4d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/1_Bug_report.md @@ -0,0 +1,21 @@ +--- +name: 🐛 Bug Report +about: ⚠️ See below for security reports +labels: Bug + +--- + +**Version(s) affected**: x.y.z + +**Description** + + +**How to reproduce** + + +**Possible Solution** + + +**Additional context** + diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/2_Feature_request.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/2_Feature_request.md new file mode 100644 index 000000000..8ffd9746d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/2_Feature_request.md @@ -0,0 +1,12 @@ +--- +name: 🚀 Feature Request +about: Ideas for new features and improvements + +--- + +**Description** + + +**Example** + diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/3_Support_question.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/3_Support_question.md new file mode 100644 index 000000000..6b4f0609a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/3_Support_question.md @@ -0,0 +1,11 @@ +--- +name: ⛔ Support Question +about: We usually do not provide support. Please ask your question on https://stackoverflow.com/ + +--- + +We use GitHub issues only to discuss bugs and new features. +For this kind of questions about using the library or the bundle, please use +https://stackoverflow.com/ using the tags `[aes]` and `[php]` + +Thanks! \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/4_Documentation_issue.md new file mode 100644 index 000000000..26cd199c1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/ISSUE_TEMPLATE/4_Documentation_issue.md @@ -0,0 +1,5 @@ +--- +name: 📖 Documentation Issue +about: To report typo or obsolete section in the documentation + +--- diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/PULL_REQUEST_TEMPLATE.md b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..1beb0a38b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,19 @@ +| Q | A +| ------------- | --- +| Branch? | +| Bug fix? | yes/no +| New feature? | yes/no +| Deprecations? | yes/no +| Tickets | Fix #... +| License | MIT + \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/stale.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/coding-standards.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/coding-standards.yml new file mode 100644 index 000000000..68fe9d1e1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/coding-standards.yml @@ -0,0 +1,32 @@ +name: Coding Standards + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.0'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: json, mbstring, openssl, sqlite3 + coverage: xdebug + + - name: Install Composer dependencies + run: | + composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader + + - name: CONDING STANDARDS + run: make ci-cs diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/mutation-tests.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/mutation-tests.yml new file mode 100644 index 000000000..132555a26 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/mutation-tests.yml @@ -0,0 +1,35 @@ +name: Mutation Testing + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.0'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: json, mbstring, openssl, sqlite3 + coverage: xdebug + + - name: Install Composer dependencies + run: | + composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader + + - name: Fetch Git base reference + run: git fetch --depth=1 origin $GITHUB_BASE_REF + + - name: Infection + run: make ci-mu diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/rector_checkstyle.yaml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/rector_checkstyle.yaml new file mode 100644 index 000000000..e0d3f9c16 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/rector_checkstyle.yaml @@ -0,0 +1,29 @@ +name: Rector Checkstyle + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php-versions: [ '8.0' ] + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: json, mbstring, openssl, sqlite3 + coverage: none + + - name: Install Composer dependencies + run: composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader + + - name: Rector + run: make rector diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/static-analyze.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/static-analyze.yml new file mode 100644 index 000000000..45dedcf97 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/static-analyze.yml @@ -0,0 +1,32 @@ +name: Static Analyze + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ubuntu-latest] + php-versions: ['8.0'] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: json, mbstring, openssl, sqlite3 + coverage: xdebug + + - name: Install Composer dependencies + run: | + composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader + + - name: PHPStan + run: make st diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/tests.yml b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/tests.yml new file mode 100644 index 000000000..740fc75ce --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: Unit and Functional Tests + +on: [push] + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ ubuntu-latest ] + php-versions: [ '8.0', '8.1' ] + name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: json, mbstring, openssl, sqlite3 + coverage: xdebug + + - name: Install Composer dependencies + run: | + composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader + + - name: Run tests + run: make ci-cc diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.php_cs.dist b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.php_cs.dist new file mode 100644 index 000000000..b574ef064 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/.php_cs.dist @@ -0,0 +1,69 @@ +in(__DIR__.'/src') + ->in(__DIR__.'/tests') +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR1' => true, + '@PSR2' => true, + '@PhpCsFixer' => true, + '@Symfony' => true, + '@DoctrineAnnotation' => true, + '@PHP70Migration' => true, + '@PHP71Migration' => true, + 'strict_param' => true, + 'strict_comparison' => true, + 'array_syntax' => ['syntax' => 'short'], + 'array_indentation' => true, + 'ordered_imports' => true, + 'protected_to_private' => true, + 'declare_strict_types' => true, + 'native_function_invocation' => [ + 'include' => ['@compiler_optimized'], + 'scope' => 'namespaced', + 'strict' => true, + ], + 'mb_str_functions' => true, + 'linebreak_after_opening_tag' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'compact_nullable_typehint' => true, + 'no_superfluous_elseif' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_order' => true, + 'pow_to_exponentiation' => true, + 'simplified_null_return' => true, + 'header_comment' => [ + 'header' => $header, + ], + 'align_multiline_comment' => [ + 'comment_type' => 'all_multiline', + ], + 'php_unit_test_annotation' => [ + 'case' => 'snake', + 'style' => 'annotation', + ], + 'php_unit_test_case_static_method_calls' => true, + 'method_chaining_indentation' => true, + 'php_unit_expectation' => true, + 'php_unit_test_class_requires_covers' => false, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + ]) + ->setRiskyAllowed(true) + ->setUsingCache(true) + ->setFinder($finder) + ; diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/LICENSE b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/LICENSE new file mode 100644 index 000000000..c1c9c423a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Spomky-Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/Makefile b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/Makefile new file mode 100644 index 000000000..1ca240e2e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/Makefile @@ -0,0 +1,50 @@ +mu: vendor ## Mutation tests + vendor/bin/infection -s --threads=$(nproc) --min-msi=75 --min-covered-msi=75 + +tests: vendor ## Run all tests + vendor/bin/phpunit --color + +cc: vendor ## Show test coverage rates (HTML) + vendor/bin/phpunit --coverage-html ./build + +cs: vendor ## Fix all files using defined ECS rules + vendor/bin/ecs check --fix + +tu: vendor ## Run only unit tests + vendor/bin/phpunit --color --group Unit + +ti: vendor ## Run only integration tests + vendor/bin/phpunit --color --group Integration + +tf: vendor ## Run only functional tests + vendor/bin/phpunit --color --group Functional + +st: vendor ## Run static analyse + vendor/bin/phpstan analyse + + +################################################ + +ci-mu: vendor ## Mutation tests (for Github only) + vendor/bin/infection --logger-github -s --threads=$(nproc) --min-msi=75 --min-covered-msi=75 + +ci-cc: vendor ## Show test coverage rates (console) + vendor/bin/phpunit --coverage-text + +ci-cs: vendor ## Check all files using defined ECS rules + vendor/bin/ecs check + +################################################ + + +vendor: composer.json composer.lock + composer validate + composer install + +rector: vendor ## Check all files using Rector + vendor/bin/rector process --ansi --dry-run --xdebug + +.DEFAULT_GOAL := help +help: + @grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' +.PHONY: help diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/composer.json b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/composer.json new file mode 100644 index 000000000..025ada563 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/composer.json @@ -0,0 +1,41 @@ +{ + "name": "spomky-labs/aes-key-wrap", + "description": "AES Key Wrap for PHP.", + "type": "library", + "license": "MIT", + "keywords": ["A128KW", "A192KW", "A256KW", "AES", "Key", "Wrap", "Padding", "RFC3394", "RFC5649"], + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/aes-key-wrap/contributors" + } + ], + "autoload": { + "psr-4": { + "AESKW\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "AESKW\\Tests\\": "tests/" + } + }, + "require": { + "php": ">=8.0", + "ext-mbstring": "*", + "ext-openssl": "*" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-beberlei-assert": "^1.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpstan/extension-installer": "^1.1", + "symplify/easy-coding-standard": "^10.0", + "rector/rector": "^0.12.5", + "infection/infection": "^0.25.4" + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/ecs.php b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/ecs.php new file mode 100644 index 000000000..d489c2906 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/ecs.php @@ -0,0 +1,124 @@ +import(SetList::PSR_12); + $containerConfigurator->import(SetList::PHP_CS_FIXER); + $containerConfigurator->import(SetList::PHP_CS_FIXER_RISKY); + $containerConfigurator->import(SetList::CLEAN_CODE); + $containerConfigurator->import(SetList::SYMFONY); + $containerConfigurator->import(SetList::DOCTRINE_ANNOTATIONS); + $containerConfigurator->import(SetList::SPACES); + $containerConfigurator->import(SetList::PHPUNIT); + $containerConfigurator->import(SetList::SYMPLIFY); + $containerConfigurator->import(SetList::ARRAY); + $containerConfigurator->import(SetList::COMMON); + $containerConfigurator->import(SetList::COMMENTS); + $containerConfigurator->import(SetList::CONTROL_STRUCTURES); + $containerConfigurator->import(SetList::DOCBLOCK); + $containerConfigurator->import(SetList::NAMESPACES); + $containerConfigurator->import(SetList::STRICT); + + $services = $containerConfigurator->services(); + $services->set(StrictParamFixer::class); + $services->set(StrictComparisonFixer::class); + $services->set(ArraySyntaxFixer::class) + ->call('configure', [[ + 'syntax' => 'short', + ]]) + ; + $services->set(ArrayIndentationFixer::class); + $services->set(OrderedImportsFixer::class); + $services->set(ProtectedToPrivateFixer::class); + $services->set(DeclareStrictTypesFixer::class); + $services->set(NativeConstantInvocationFixer::class); + $services->set(NativeFunctionInvocationFixer::class) + ->call('configure', [[ + 'include' => ['@compiler_optimized'], + 'scope' => 'namespaced', + 'strict' => true, + ]]) + ; + $services->set(MbStrFunctionsFixer::class); + $services->set(LinebreakAfterOpeningTagFixer::class); + $services->set(CombineConsecutiveIssetsFixer::class); + $services->set(CombineConsecutiveUnsetsFixer::class); + $services->set(CompactNullableTypehintFixer::class); + $services->set(NoSuperfluousElseifFixer::class); + $services->set(NoSuperfluousPhpdocTagsFixer::class); + $services->set(PhpdocTrimConsecutiveBlankLineSeparationFixer::class); + $services->set(PhpdocOrderFixer::class); + $services->set(SimplifiedNullReturnFixer::class); + $services->set(HeaderCommentFixer::class) + ->call('configure', [[ + 'header' => $header, + ]]) + ; + $services->set(AlignMultilineCommentFixer::class) + ->call('configure', [[ + 'comment_type' => 'all_multiline', + ]]) + ; + $services->set(PhpUnitTestAnnotationFixer::class) + ->call('configure', [[ + 'style' => 'annotation', + ]]) + ; + $services->set(PhpUnitTestCaseStaticMethodCallsFixer::class); + $services->set(GlobalNamespaceImportFixer::class) + ->call('configure', [[ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ]]) + ; + + $services->remove(PhpUnitTestClassRequiresCoversFixer::class); + + $parameters = $containerConfigurator->parameters(); + $parameters + ->set(Option::PARALLEL, true) + ->set(Option::PATHS, [__DIR__]) + ->set(Option::SKIP, [ + __DIR__ . '/src/Kernel.php', + __DIR__ . '/assets', + __DIR__ . '/bin', + __DIR__ . '/config', + __DIR__ . '/heroku', + __DIR__ . '/public', + __DIR__ . '/var', + ]) + ; +}; diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.json b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.json new file mode 100644 index 000000000..17bf97681 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.json @@ -0,0 +1,15 @@ +{ + "source": { + "directories": [ + "src" + ] + }, + "timeout": 3, + "logs": { + "text": "infection.txt" + }, + "mutators": { + "@default": true, + "@function_signature": true + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.txt b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.txt new file mode 100644 index 000000000..4a97421d7 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/infection.txt @@ -0,0 +1,721 @@ +Escaped mutants: +================ + +1) /home/florent/PhpstormProjects/aes-key-wrap/src/A128KW.php:11 [M] ProtectedVisibility + +--- Original ++++ New +@@ @@ + final class A128KW implements Wrapper + { + use AESKW; +- protected static function getMethod() : string ++ private static function getMethod() : string + { + return 'aes-128-ecb'; + } + } + + +2) /home/florent/PhpstormProjects/aes-key-wrap/src/A192KW.php:11 [M] ProtectedVisibility + +--- Original ++++ New +@@ @@ + final class A192KW implements Wrapper + { + use AESKW; +- protected static function getMethod() : string ++ private static function getMethod() : string + { + return 'aes-192-ecb'; + } + } + + +3) /home/florent/PhpstormProjects/aes-key-wrap/src/A256KW.php:11 [M] ProtectedVisibility + +--- Original ++++ New +@@ @@ + final class A256KW implements Wrapper + { + use AESKW; +- protected static function getMethod() : string ++ private static function getMethod() : string + { + return 'aes-256-ecb'; + } + } + + +4) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:31 [M] MBString + +--- Original ++++ New +@@ @@ + { + $A = self::getInitialValue($key, $padding_enabled); + self::checkKeySize($key, $padding_enabled); +- $P = mb_str_split($key, 8, '8bit'); ++ $P = str_split($key, 8); + $N = count($P); + $C = []; + if ($N === 1) { + + +5) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:38 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + if ($N === 1) { + $B = self::encrypt($kek, $A . $P[0]); + $C[0] = self::getMSB($B); +- $C[1] = self::getLSB($B); ++ $C[2] = self::getLSB($B); + } elseif ($N > 1) { + $R = $P; + for ($j = 0; $j <= 5; ++$j) { + + +6) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:39 [M] GreaterThan + +--- Original ++++ New +@@ @@ + $B = self::encrypt($kek, $A . $P[0]); + $C[0] = self::getMSB($B); + $C[1] = self::getLSB($B); +- } elseif ($N > 1) { ++ } elseif ($N >= 1) { + $R = $P; + for ($j = 0; $j <= 5; ++$j) { + for ($i = 1; $i <= $N; ++$i) { + + +7) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:62 [M] FalseValue + +--- Original ++++ New +@@ @@ + * + * @return string The key unwrapped + */ +- public static function unwrap(string $kek, string $key, bool $padding_enabled = false) : string ++ public static function unwrap(string $kek, string $key, bool $padding_enabled = true) : string + { + $P = mb_str_split($key, 8, '8bit'); + $A = $P[0]; + + +8) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:64 [M] MBString + +--- Original ++++ New +@@ @@ + */ + public static function unwrap(string $kek, string $key, bool $padding_enabled = false) : string + { +- $P = mb_str_split($key, 8, '8bit'); ++ $P = str_split($key, 8); + $A = $P[0]; + $N = count($P); + if ($N < 2) { + + +9) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:110 [M] FalseValue + +--- Original ++++ New +@@ @@ + { + if ($padding_enabled === false) { + $bin = hex2bin('A6A6A6A6A6A6A6A6'); +- if ($bin === false) { ++ if ($bin === true) { + throw new InvalidArgumentException('Unable to convert the data'); + } + return $bin; + + +10) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:117 [M] MBString + +--- Original ++++ New +@@ @@ + } + return $bin; + } +- $MLI = mb_strlen($key, '8bit'); ++ $MLI = strlen($key); + $iv = hex2bin('A65959A6') . self::toXBits(32, $MLI); + $n = (int) ceil($MLI / 8); + $key = str_pad($key, 8 * $n, "\x00", STR_PAD_RIGHT); + + +11) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:120 [M] DecrementInteger + +--- Original ++++ New +@@ @@ + } + $MLI = mb_strlen($key, '8bit'); + $iv = hex2bin('A65959A6') . self::toXBits(32, $MLI); +- $n = (int) ceil($MLI / 8); ++ $n = (int) ceil($MLI / 7); + $key = str_pad($key, 8 * $n, "\x00", STR_PAD_RIGHT); + return $iv; + } + + +12) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:120 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + } + $MLI = mb_strlen($key, '8bit'); + $iv = hex2bin('A65959A6') . self::toXBits(32, $MLI); +- $n = (int) ceil($MLI / 8); ++ $n = (int) ceil($MLI / 9); + $key = str_pad($key, 8 * $n, "\x00", STR_PAD_RIGHT); + return $iv; + } + + +13) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:120 [M] RoundingFamily + +--- Original ++++ New +@@ @@ + } + $MLI = mb_strlen($key, '8bit'); + $iv = hex2bin('A65959A6') . self::toXBits(32, $MLI); +- $n = (int) ceil($MLI / 8); ++ $n = (int) round($MLI / 8); + $key = str_pad($key, 8 * $n, "\x00", STR_PAD_RIGHT); + return $iv; + } + + +14) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:143 [M] MBString + +--- Original ++++ New +@@ @@ + if (hex2bin('A65959A6') !== self::getMSB($iv)) { + return false; + } +- $n = mb_strlen($key, '8bit') / 8; ++ $n = strlen($key) / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + + +15) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:143 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + if (hex2bin('A65959A6') !== self::getMSB($iv)) { + return false; + } +- $n = mb_strlen($key, '8bit') / 8; ++ $n = mb_strlen($key, '8bit') / 9; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + + +16) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:144 [M] UnwrapLtrim + +--- Original ++++ New +@@ @@ + return false; + } + $n = mb_strlen($key, '8bit') / 8; +- $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); ++ $MLI = (int) hexdec(bin2hex(self::getLSB($iv))); + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } + + +17) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:144 [M] CastInt + +--- Original ++++ New +@@ @@ + return false; + } + $n = mb_strlen($key, '8bit') / 8; +- $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); ++ $MLI = hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } + + +18) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] DecrementInteger + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(7 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +19) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(9 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +20) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 2) < $MLI && $MLI <= 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +21) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] LessThan + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 1) <= $MLI && $MLI <= 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +22) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] DecrementInteger + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 1) < $MLI && $MLI <= 7 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +23) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] IncrementInteger + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 1) < $MLI && $MLI <= 9 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +24) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] LessThanOrEqualTo + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 1) < $MLI && $MLI < 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +25) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:146 [M] LogicalAnd + +--- Original ++++ New +@@ @@ + } + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); +- if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { ++ if (!(8 * ($n - 1) < $MLI || $MLI <= 8 * $n)) { + return false; + } + $b = 8 * $n - $MLI; + + +26) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:150 [M] DecrementInteger + +--- Original ++++ New +@@ @@ + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } +- $b = 8 * $n - $MLI; ++ $b = 7 * $n - $MLI; + for ($i = 0; $i < $b; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { + return false; + + +27) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:150 [M] Multiplication + +--- Original ++++ New +@@ @@ + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } +- $b = 8 * $n - $MLI; ++ $b = 8 / $n - $MLI; + for ($i = 0; $i < $b; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { + return false; + + +28) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:151 [M] LessThanNegotiation + +--- Original ++++ New +@@ @@ + return false; + } + $b = 8 * $n - $MLI; +- for ($i = 0; $i < $b; ++$i) { ++ for ($i = 0; $i >= $b; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { + return false; + } + + +29) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:151 [M] For_ + +--- Original ++++ New +@@ @@ + return false; + } + $b = 8 * $n - $MLI; +- for ($i = 0; $i < $b; ++$i) { ++ for ($i = 0; false; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { + return false; + } + + +30) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:152 [M] MBString + +--- Original ++++ New +@@ @@ + } + $b = 8 * $n - $MLI; + for ($i = 0; $i < $b; ++$i) { +- if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { ++ if (substr($key, $MLI + $i, 1) !== "\x00") { + return false; + } + } + + +31) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:156 [M] MBString + +--- Original ++++ New +@@ @@ + return false; + } + } +- $key = mb_substr($key, 0, $MLI, '8bit'); ++ $key = substr($key, 0, $MLI); + return true; + } + private static function checkKeySize(string $key, bool $padding_enabled) : void + + +32) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:166 [M] MBString + +--- Original ++++ New +@@ @@ + if ($key === '') { + throw new InvalidArgumentException('Bad key size'); + } +- if ($padding_enabled === false && mb_strlen($key, '8bit') % 8 !== 0) { ++ if ($padding_enabled === false && strlen($key) % 8 !== 0) { + throw new InvalidArgumentException('Bad key size'); + } + } + + +33) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:174 [M] FalseValue + +--- Original ++++ New +@@ @@ + private static function toXBits(int $bits, int $value) : string + { + $bin = hex2bin(str_pad(dechex($value), $bits / 4, '0', STR_PAD_LEFT)); +- if ($bin === false) { ++ if ($bin === true) { + throw new InvalidArgumentException('Unable to convert the data'); + } + return $bin; + + +34) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:183 [M] MBString + +--- Original ++++ New +@@ @@ + } + private static function getMSB(string $value) : string + { +- return mb_substr($value, 0, mb_strlen($value, '8bit') / 2, '8bit'); ++ return mb_substr($value, 0, strlen($value) / 2, '8bit'); + } + private static function getLSB(string $value) : string + { + + +35) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:183 [M] MBString + +--- Original ++++ New +@@ @@ + } + private static function getMSB(string $value) : string + { +- return mb_substr($value, 0, mb_strlen($value, '8bit') / 2, '8bit'); ++ return substr($value, 0, mb_strlen($value, '8bit') / 2); + } + private static function getLSB(string $value) : string + { + + +36) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:188 [M] MBString + +--- Original ++++ New +@@ @@ + } + private static function getLSB(string $value) : string + { +- return mb_substr($value, mb_strlen($value, '8bit') / 2, null, '8bit'); ++ return mb_substr($value, strlen($value) / 2, null, '8bit'); + } + private static function encrypt(string $kek, string $data) : string + { + + +37) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:188 [M] MBString + +--- Original ++++ New +@@ @@ + } + private static function getLSB(string $value) : string + { +- return mb_substr($value, mb_strlen($value, '8bit') / 2, null, '8bit'); ++ return substr($value, mb_strlen($value, '8bit') / 2, null); + } + private static function encrypt(string $kek, string $data) : string + { + + +38) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:194 [M] FalseValue + +--- Original ++++ New +@@ @@ + private static function encrypt(string $kek, string $data) : string + { + $result = openssl_encrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); +- if ($result === false) { ++ if ($result === true) { + throw new InvalidArgumentException('Unable to encrypt the data'); + } + return $result; + + +39) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:204 [M] FalseValue + +--- Original ++++ New +@@ @@ + private static function decrypt(string $kek, string $data) : string + { + $result = openssl_decrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); +- if ($result === false) { ++ if ($result === true) { + throw new InvalidArgumentException('Unable to decrypt the data'); + } + return $result; + } + } + + +Timed Out mutants: +================== + +1) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:41 [M] Increment + +--- Original ++++ New +@@ @@ + $C[1] = self::getLSB($B); + } elseif ($N > 1) { + $R = $P; +- for ($j = 0; $j <= 5; ++$j) { ++ for ($j = 0; $j <= 5; --$j) { + for ($i = 1; $i <= $N; ++$i) { + $B = self::encrypt($kek, $A . $R[$i - 1]); + $t = $i + $j * $N; + + +2) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:77 [M] Decrement + +--- Original ++++ New +@@ @@ + $A = self::getMSB($B); + } else { + $R = $P; +- for ($j = 5; $j >= 0; --$j) { ++ for ($j = 5; $j >= 0; ++$j) { + for ($i = $N - 1; $i >= 1; --$i) { + $t = $i + $j * ($N - 1); + $B = self::decrypt($kek, (self::toXBits(64, $t) ^ $A) . $R[$i]); + + +Skipped mutants: +================ + +Not Covered mutants: +==================== + +1) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:111 [M] Throw_ + +--- Original ++++ New +@@ @@ + if ($padding_enabled === false) { + $bin = hex2bin('A6A6A6A6A6A6A6A6'); + if ($bin === false) { +- throw new InvalidArgumentException('Unable to convert the data'); ++ new InvalidArgumentException('Unable to convert the data'); + } + return $bin; + } + + +2) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:147 [M] FalseValue + +--- Original ++++ New +@@ @@ + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\x00"))); + if (!(8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { +- return false; ++ return true; + } + $b = 8 * $n - $MLI; + for ($i = 0; $i < $b; ++$i) { + + +3) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:153 [M] FalseValue + +--- Original ++++ New +@@ @@ + $b = 8 * $n - $MLI; + for ($i = 0; $i < $b; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\x00") { +- return false; ++ return true; + } + } + $key = mb_substr($key, 0, $MLI, '8bit'); + + +4) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:175 [M] Throw_ + +--- Original ++++ New +@@ @@ + { + $bin = hex2bin(str_pad(dechex($value), $bits / 4, '0', STR_PAD_LEFT)); + if ($bin === false) { +- throw new InvalidArgumentException('Unable to convert the data'); ++ new InvalidArgumentException('Unable to convert the data'); + } + return $bin; + } + + +5) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:195 [M] Throw_ + +--- Original ++++ New +@@ @@ + { + $result = openssl_encrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); + if ($result === false) { +- throw new InvalidArgumentException('Unable to encrypt the data'); ++ new InvalidArgumentException('Unable to encrypt the data'); + } + return $result; + } + + +6) /home/florent/PhpstormProjects/aes-key-wrap/src/AESKW.php:205 [M] Throw_ + +--- Original ++++ New +@@ @@ + { + $result = openssl_decrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); + if ($result === false) { +- throw new InvalidArgumentException('Unable to decrypt the data'); ++ new InvalidArgumentException('Unable to decrypt the data'); + } + return $result; + } + } diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/phpstan.neon b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/phpstan.neon new file mode 100644 index 000000000..e4d68ffb1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/phpstan.neon @@ -0,0 +1,11 @@ +parameters: + level: max + paths: + - src + ignoreErrors: + - + message: '#Comparison operation .* between .* and 1 is always true\.#' + count: 3 + path: src/AESKW.php +includes: + - vendor/phpstan/phpstan/conf/bleedingEdge.neon diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/rector.php b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/rector.php new file mode 100644 index 000000000..762ee5bf3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/rector.php @@ -0,0 +1,26 @@ +import(SetList::DEAD_CODE); + $containerConfigurator->import(SetList::PHP_80); + $containerConfigurator->import(SymfonySetList::SYMFONY_52); + $containerConfigurator->import(SymfonySetList::SYMFONY_CODE_QUALITY); + $parameters = $containerConfigurator->parameters(); + $parameters->set(Option::PATHS, [__DIR__ . '/src', __DIR__ . '/tests']); + $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_80); + $parameters->set(Option::AUTO_IMPORT_NAMES, true); + $parameters->set(Option::IMPORT_SHORT_CLASSES, false); + $parameters->set(Option::IMPORT_DOC_BLOCKS, false); + + $services = $containerConfigurator->services(); + $services->set(TypedPropertyRector::class); +}; diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/A128KW.php b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/A128KW.php new file mode 100644 index 000000000..73f97e14f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/A128KW.php @@ -0,0 +1,15 @@ + 1) { + $R = $P; + for ($j = 0; $j <= 5; ++$j) { + for ($i = 1; $i <= $N; ++$i) { + $B = self::encrypt($kek, $A . $R[$i - 1]); + $t = $i + $j * $N; + $A = self::toXBits(64, $t) ^ self::getMSB($B); + $R[$i - 1] = self::getLSB($B); + } + } + $C = array_merge([$A], $R); + } + + return implode('', $C); + } + + /** + * @param string $kek The Key Encryption Key + * @param string $key The key to unwrap + * @param bool $padding_enabled If false, the AIV check must be RFC3394 compliant, else it must be RFC5649 or RFC3394 compliant + * + * @return string The key unwrapped + */ + public static function unwrap(string $kek, string $key, bool $padding_enabled = false): string + { + $P = mb_str_split($key, 8, '8bit'); + $A = $P[0]; + $N = count($P); + + if ($N < 2) { + throw new InvalidArgumentException('Bad data'); + } + if ($N === 2) { + $B = self::decrypt($kek, $P[0] . $P[1]); + $unwrapped = self::getLSB($B); + $A = self::getMSB($B); + } else { + $R = $P; + for ($j = 5; $j >= 0; --$j) { + for ($i = $N - 1; $i >= 1; --$i) { + $t = $i + $j * ($N - 1); + $B = self::decrypt($kek, (self::toXBits(64, $t) ^ $A) . $R[$i]); + $A = self::getMSB($B); + $R[$i] = self::getLSB($B); + } + } + unset($R[0]); + + $unwrapped = implode('', $R); + } + if (self::checkInitialValue($unwrapped, $padding_enabled, $A) === false) { + throw new InvalidArgumentException('Integrity check failed!'); + } + + return $unwrapped; + } + + /** + * The initial value used to wrap the key and check the integrity when unwrapped. The RFC3394 set this value to + * 0xA6A6A6A6A6A6A6A6 The RFC5649 set this value to 0xA65959A6XXXXXXXX (The part with XXXXXXXX is the MLI, depends + * on the padding). + * + * @param string $key The key + * @param bool $padding_enabled Enable padding (RFC5649) + * + * @see https://tools.ietf.org/html/rfc3394#section-2.2.3.1 + */ + private static function getInitialValue(string &$key, bool $padding_enabled): string + { + if ($padding_enabled === false) { + $bin = hex2bin('A6A6A6A6A6A6A6A6'); + if ($bin === false) { + throw new InvalidArgumentException('Unable to convert the data'); + } + + return $bin; + } + + $MLI = mb_strlen($key, '8bit'); + $iv = hex2bin('A65959A6') . self::toXBits(32, $MLI); + + $n = (int) ceil($MLI / 8); + $key = str_pad($key, 8 * $n, "\0", STR_PAD_RIGHT); + + return $iv; + } + + private static function checkInitialValue(string &$key, bool $padding_enabled, string $iv): bool + { + // RFC3394 compliant + if ($iv === hex2bin('A6A6A6A6A6A6A6A6')) { + return true; + } + + // The RFC3394 is required but the previous check is not satisfied => invalid + if ($padding_enabled === false) { + return false; + } + + // The high-order half of the AIV according to the RFC5649 + if (hex2bin('A65959A6') !== self::getMSB($iv)) { + return false; + } + + $n = mb_strlen($key, '8bit') / 8; + $MLI = (int) hexdec(bin2hex(ltrim(self::getLSB($iv), "\0"))); + + if (! (8 * ($n - 1) < $MLI && $MLI <= 8 * $n)) { + return false; + } + + $b = 8 * $n - $MLI; + for ($i = 0; $i < $b; ++$i) { + if (mb_substr($key, $MLI + $i, 1, '8bit') !== "\0") { + return false; + } + } + $key = mb_substr($key, 0, $MLI, '8bit'); + + return true; + } + + private static function checkKeySize(string $key, bool $padding_enabled): void + { + if ($key === '') { + throw new InvalidArgumentException('Bad key size'); + } + if ($padding_enabled === false && mb_strlen($key, '8bit') % 8 !== 0) { + throw new InvalidArgumentException('Bad key size'); + } + } + + private static function toXBits(int $bits, int $value): string + { + $bin = hex2bin(str_pad(dechex($value), $bits / 4, '0', STR_PAD_LEFT)); + if ($bin === false) { + throw new InvalidArgumentException('Unable to convert the data'); + } + + return $bin; + } + + private static function getMSB(string $value): string + { + return mb_substr($value, 0, mb_strlen($value, '8bit') / 2, '8bit'); + } + + private static function getLSB(string $value): string + { + return mb_substr($value, mb_strlen($value, '8bit') / 2, null, '8bit'); + } + + private static function encrypt(string $kek, string $data): string + { + $result = openssl_encrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); + if ($result === false) { + throw new InvalidArgumentException('Unable to encrypt the data'); + } + + return $result; + } + + private static function decrypt(string $kek, string $data): string + { + $result = openssl_decrypt($data, self::getMethod(), $kek, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA); + if ($result === false) { + throw new InvalidArgumentException('Unable to decrypt the data'); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/Wrapper.php b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/Wrapper.php new file mode 100644 index 000000000..446d811cd --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/aes-key-wrap/src/Wrapper.php @@ -0,0 +1,26 @@ +=8.0", "ext-mbstring": "*", - "brick/math": "^0.9|^0.10|^0.11|^0.12" + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13" }, "require-dev": { "ext-json": "*", - "ekino/phpstan-banned-code": "^1.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", "infection/infection": "^0.29", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^10.1|^11.0", - "rector/rector": "^1.0", + "phpstan/phpstan": "^1.0|^2.0", + "phpstan/phpstan-beberlei-assert": "^1.0|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.0|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", "roave/security-advisories": "dev-latest", "symfony/var-dumper": "^6.0|^7.0", "symplify/easy-coding-standard": "^12.0", "php-parallel-lint/php-parallel-lint": "^1.3", - "qossmic/deptrac": "^2.0" + "deptrac/deptrac": "^3.0" }, "config": { "sort-packages": true, diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Decoder.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Decoder.php index 2e8fd2040..4f3c27327 100644 --- a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Decoder.php +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Decoder.php @@ -35,6 +35,7 @@ use CBOR\Tag\UriTag; use InvalidArgumentException; use RuntimeException; use function ord; +use function sprintf; use const STR_PAD_LEFT; final class Decoder implements DecoderInterface diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/StringStream.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/StringStream.php index 82267f6a8..a6858e099 100644 --- a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/StringStream.php +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/StringStream.php @@ -6,6 +6,7 @@ namespace CBOR; use InvalidArgumentException; use RuntimeException; +use function sprintf; use function strlen; final class StringStream implements Stream diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/LICENSE b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/LICENSE new file mode 100644 index 000000000..d6feca7c8 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2016-2019 Joni Eskelinen +Copyright (c) 2022 Spomky-Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/README.md b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/README.md new file mode 100644 index 000000000..911e3d4a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/README.md @@ -0,0 +1,34 @@ +# Public Key Infrastructure + +> **Note** +> The code in this framework is the same as the one available in https://github.com/sop, +> but modified to fulfil with the Spomky-Labs requirements. +> All credits go to the original developer + +A PHP Framework + +* X.509 public key certificates, attribute certificates, +* X.690 Abstract Syntax Notation One (ASN.1) Distinguished Encoding Rules (DER) encoding and decoding +* X.501 ASN.1 types, X.520 attributes and DN parsing. +* [RFC 7468](https://tools.ietf.org/html/rfc7468) textual encodings of cryptographic structures _(PEM)_. +* Various ASN.1 types for cryptographic applications. +* Cryptography support for various PKCS applications. + +## Requirements + +- PHP >=8.1 +- `mbstring` + +The extension `gmp` or `bcmath` is highly recommended + +## Installation + +This library is available on [Github](https://github.com/Spomky-Labs/pki-framework). + +```sh +composer require spomky-labs/pki-framework +``` + +## License + +This project is licensed under the MIT License. diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/SECURITY.md b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/SECURITY.md new file mode 100644 index 000000000..782948c98 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------| ------------------ | +| 1.0.x | :white_check_mark: | +| < 1.0.0 | :x: | + +## Reporting a Vulnerability + +If you think you have found a security issue, DO NOT open an issue. You MUST email your issue: security AT +spomky-labs.com. diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/composer.json b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/composer.json new file mode 100644 index 000000000..1c008097e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/composer.json @@ -0,0 +1,95 @@ +{ + "name": "spomky-labs/pki-framework", + "description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.", + "homepage": "https://github.com/spomky-labs/pki-framework", + "license": "MIT", + "type": "library", + "keywords": [ + "x509", + "x.509", + "certificate", + "attribute certificate", + "ac", + "certification request", + "csr", + "pem", + "public key", + "private key", + "certificate", + "cryptography", + "asn1", + "algorithm identifier", + "rsa", + "ec", + "public key", + "private key", + "signature", + "pkcs", + "cryptography", + "encrypt", + "decrypt", + "sign", + "verify", + "asn1", + "asn.1", + "x690", + "x.690", + "der" + ], + "authors": [ + { + "name": "Joni Eskelinen", + "email": "jonieske@gmail.com", + "role": "Original developer" + }, + { + "name": "Florent Morselli", + "email": "florent.morselli@spomky-labs.com", + "role": "Spomky-Labs PKI Framework developer" + } + ], + "require": { + "php": ">=8.1", + "ext-mbstring": "*", + "brick/math": "^0.10|^0.11|^0.12|^0.13" + }, + "require-dev": { + "ext-gmp": "*", + "ext-openssl": "*", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", + "infection/infection": "^0.28|^0.29", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "^1.3|^2.0", + "phpstan/phpstan": "^1.8|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.3|^2.0", + "rector/rector": "^1.0|^2.0", + "roave/security-advisories": "dev-latest", + "symfony/string": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0" + }, + "suggest": { + "ext-openssl": "For OpenSSL based cyphering", + "ext-gmp": "For better performance (or BCMath)", + "ext-bcmath": "For better performance (or GMP)" + }, + "autoload": { + "psr-4": { + "SpomkyLabs\\Pki\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "SpomkyLabs\\Pki\\Test\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "infection/extension-installer": true, + "phpstan/extension-installer": true + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Identifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Identifier.php new file mode 100644 index 000000000..dc21d7948 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Identifier.php @@ -0,0 +1,278 @@ + + */ + private const MAP_CLASS_TO_NAME = [ + self::CLASS_UNIVERSAL => 'UNIVERSAL', + self::CLASS_APPLICATION => 'APPLICATION', + self::CLASS_CONTEXT_SPECIFIC => 'CONTEXT SPECIFIC', + self::CLASS_PRIVATE => 'PRIVATE', + ]; + + /** + * Type class. + */ + private int $_class; + + /** + * Primitive or Constructed. + */ + private readonly int $_pc; + + /** + * Content type tag. + */ + private BigInt $_tag; + + /** + * @param int $class Type class + * @param int $pc Primitive / Constructed + * @param BigInteger|int $tag Type tag number + */ + private function __construct(int $class, int $pc, BigInteger|int $tag) + { + $this->_class = 0b11 & $class; + $this->_pc = 0b1 & $pc; + $this->_tag = BigInt::create($tag); + } + + public static function create(int $class, int $pc, BigInteger|int $tag): self + { + return new self($class, $pc, $tag); + } + + /** + * Decode identifier component from DER data. + * + * @param string $data DER encoded data + * @param null|int $offset Reference to the variable that contains offset + * into the data where to start parsing. + * Variable is updated to the offset next to the + * parsed identifier. If null, start from offset 0. + */ + public static function fromDER(string $data, ?int &$offset = null): self + { + $idx = $offset ?? 0; + $datalen = mb_strlen($data, '8bit'); + if ($idx >= $datalen) { + throw new DecodeException('Invalid offset.'); + } + $byte = ord($data[$idx++]); + // bits 8 and 7 (class) + // 0 = universal, 1 = application, 2 = context-specific, 3 = private + $class = (0b11000000 & $byte) >> 6; + // bit 6 (0 = primitive / 1 = constructed) + $pc = (0b00100000 & $byte) >> 5; + // bits 5 to 1 (tag number) + $tag = (0b00011111 & $byte); + // long-form identifier + if ($tag === 0x1f) { + $tag = self::decodeLongFormTag($data, $idx); + } + if (isset($offset)) { + $offset = $idx; + } + return self::create($class, $pc, $tag); + } + + public function toDER(): string + { + $bytes = []; + $byte = $this->_class << 6 | $this->_pc << 5; + $tag = $this->_tag->getValue(); + if ($tag->isLessThan(0x1f)) { + $bytes[] = $byte | $tag->toInt(); + } // long-form identifier + else { + $bytes[] = $byte | 0x1f; + $octets = []; + for (; $tag->isGreaterThan(0); $tag = $tag->shiftedRight(7)) { + $octets[] = 0x80 | $tag->and(0x7f)->toInt(); + } + // last octet has bit 8 set to zero + $octets[0] &= 0x7f; + foreach (array_reverse($octets) as $octet) { + $bytes[] = $octet; + } + } + return pack('C*', ...$bytes); + } + + /** + * Get class of the type. + */ + public function typeClass(): int + { + return $this->_class; + } + + public function pc(): int + { + return $this->_pc; + } + + /** + * Get the tag number. + * + * @return string Base 10 integer string + */ + public function tag(): string + { + return $this->_tag->base10(); + } + + /** + * Get the tag as an integer. + */ + public function intTag(): int + { + return $this->_tag->toInt(); + } + + /** + * Check whether type is of an universal class. + */ + public function isUniversal(): bool + { + return $this->_class === self::CLASS_UNIVERSAL; + } + + /** + * Check whether type is of an application class. + */ + public function isApplication(): bool + { + return $this->_class === self::CLASS_APPLICATION; + } + + /** + * Check whether type is of a context specific class. + */ + public function isContextSpecific(): bool + { + return $this->_class === self::CLASS_CONTEXT_SPECIFIC; + } + + /** + * Check whether type is of a private class. + */ + public function isPrivate(): bool + { + return $this->_class === self::CLASS_PRIVATE; + } + + /** + * Check whether content is primitive type. + */ + public function isPrimitive(): bool + { + return $this->_pc === self::PRIMITIVE; + } + + /** + * Check hether content is constructed type. + */ + public function isConstructed(): bool + { + return $this->_pc === self::CONSTRUCTED; + } + + /** + * Get self with given type class. + * + * @param int $class One of `CLASS_*` enumerations + */ + public function withClass(int $class): self + { + $obj = clone $this; + $obj->_class = 0b11 & $class; + return $obj; + } + + /** + * Get self with given type tag. + * + * @param int $tag Tag number + */ + public function withTag(int $tag): self + { + $obj = clone $this; + $obj->_tag = BigInt::create($tag); + return $obj; + } + + /** + * Get human readable name of the type class. + */ + public static function classToName(int $class): string + { + if (! array_key_exists($class, self::MAP_CLASS_TO_NAME)) { + return "CLASS {$class}"; + } + return self::MAP_CLASS_TO_NAME[$class]; + } + + /** + * Parse long form tag. + * + * @param string $data DER data + * @param int $offset Reference to the variable containing offset to data + * + * @return BigInteger Tag number + */ + private static function decodeLongFormTag(string $data, int &$offset): BigInteger + { + $datalen = mb_strlen($data, '8bit'); + $tag = BigInteger::of(0); + while (true) { + if ($offset >= $datalen) { + throw new DecodeException('Unexpected end of data while decoding long form identifier.'); + } + $byte = ord($data[$offset++]); + $tag = $tag->shiftedLeft(7); + $tag = $tag->or(0x7f & $byte); + // last byte has bit 8 set to zero + if ((0x80 & $byte) === 0) { + break; + } + } + return $tag; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Length.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Length.php new file mode 100644 index 000000000..e69e92daa --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Component/Length.php @@ -0,0 +1,205 @@ +_length = BigInt::create($length); + } + + public static function create(BigInteger|int $length, bool $_indefinite = false): self + { + return new self($length, $_indefinite); + } + + /** + * Decode length component from DER data. + * + * @param string $data DER encoded data + * @param null|int $offset Reference to the variable that contains offset + * into the data where to start parsing. + * Variable is updated to the offset next to the + * parsed length component. If null, start from offset 0. + */ + public static function fromDER(string $data, ?int &$offset = null): self + { + $idx = $offset ?? 0; + $datalen = mb_strlen($data, '8bit'); + if ($idx >= $datalen) { + throw new DecodeException('Unexpected end of data while decoding length.'); + } + $indefinite = false; + $byte = ord($data[$idx++]); + // bits 7 to 1 + $length = (0x7f & $byte); + // long form + if ((0x80 & $byte) !== 0) { + if ($length === 0) { + $indefinite = true; + } else { + if ($idx + $length > $datalen) { + throw new DecodeException('Unexpected end of data while decoding long form length.'); + } + $length = self::decodeLongFormLength($length, $data, $idx); + } + } + if (isset($offset)) { + $offset = $idx; + } + return self::create($length, $indefinite); + } + + /** + * Decode length from DER. + * + * Throws an exception if length doesn't match with expected or if data doesn't contain enough bytes. + * + * Requirement of definite length is relaxed contrary to the specification (sect. 10.1). + * + * @param string $data DER data + * @param int $offset Reference to the offset variable + * @param null|int $expected Expected length, null to bypass checking + * @see self::fromDER + */ + public static function expectFromDER(string $data, int &$offset, ?int $expected = null): self + { + $idx = $offset; + $length = self::fromDER($data, $idx); + // if certain length was expected + if (isset($expected)) { + if ($length->isIndefinite()) { + throw new DecodeException(sprintf('Expected length %d, got indefinite.', $expected)); + } + if ($expected !== $length->intLength()) { + throw new DecodeException(sprintf('Expected length %d, got %d.', $expected, $length->intLength())); + } + } + // check that enough data is available + if (! $length->isIndefinite() + && mb_strlen($data, '8bit') < $idx + $length->intLength()) { + throw new DecodeException( + sprintf( + 'Length %d overflows data, %d bytes left.', + $length->intLength(), + mb_strlen($data, '8bit') - $idx + ) + ); + } + $offset = $idx; + return $length; + } + + public function toDER(): string + { + $bytes = []; + if ($this->_indefinite) { + $bytes[] = 0x80; + } else { + $num = $this->_length->getValue(); + // long form + if ($num->isGreaterThan(127)) { + $octets = []; + for (; $num->isGreaterThan(0); $num = $num->shiftedRight(8)) { + $octets[] = BigInteger::of(0xff)->and($num)->toInt(); + } + $count = count($octets); + // first octet must not be 0xff + if ($count >= 127) { + throw new DomainException('Too many length octets.'); + } + $bytes[] = 0x80 | $count; + foreach (array_reverse($octets) as $octet) { + $bytes[] = $octet; + } + } // short form + else { + $bytes[] = $num->toInt(); + } + } + return pack('C*', ...$bytes); + } + + /** + * Get the length. + * + * @return string Length as an integer string + */ + public function length(): string + { + if ($this->_indefinite) { + throw new LogicException('Length is indefinite.'); + } + return $this->_length->base10(); + } + + /** + * Get the length as an integer. + */ + public function intLength(): int + { + if ($this->_indefinite) { + throw new LogicException('Length is indefinite.'); + } + return $this->_length->toInt(); + } + + /** + * Whether length is indefinite. + */ + public function isIndefinite(): bool + { + return $this->_indefinite; + } + + /** + * Decode long form length. + * + * @param int $length Number of octets + * @param string $data Data + * @param int $offset reference to the variable containing offset to the data + */ + private static function decodeLongFormLength(int $length, string $data, int &$offset): BigInteger + { + // first octet must not be 0xff (spec 8.1.3.5c) + if ($length === 127) { + throw new DecodeException('Invalid number of length octets.'); + } + $num = BigInteger::of(0); + while (--$length >= 0) { + $byte = ord($data[$offset++]); + $num = $num->shiftedLeft(8) + ->or($byte); + } + + return $num; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/DERData.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/DERData.php new file mode 100644 index 000000000..527081898 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/DERData.php @@ -0,0 +1,81 @@ +identifier = Identifier::fromDER($data, $this->contentOffset); + // check that length encoding is valid + Length::expectFromDER($data, $this->contentOffset); + $this->der = $data; + parent::__construct($this->identifier->intTag()); + } + + public static function create(string $data): self + { + return new self($data); + } + + public function typeClass(): int + { + return $this->identifier->typeClass(); + } + + public function isConstructed(): bool + { + return $this->identifier->isConstructed(); + } + + public function toDER(): string + { + return $this->der; + } + + protected function encodedAsDER(): string + { + // if there's no content payload + if (mb_strlen($this->der, '8bit') === $this->contentOffset) { + return ''; + } + return mb_substr($this->der, $this->contentOffset, null, '8bit'); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + throw new BadMethodCallException(__METHOD__ . ' must be implemented in derived class.'); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Element.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Element.php new file mode 100644 index 000000000..fa7795c00 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Element.php @@ -0,0 +1,476 @@ + + */ + private const MAP_TAG_TO_CLASS = [ + self::TYPE_EOC => EOC::class, + self::TYPE_BOOLEAN => Boolean::class, + self::TYPE_INTEGER => Integer::class, + self::TYPE_BIT_STRING => BitString::class, + self::TYPE_OCTET_STRING => OctetString::class, + self::TYPE_NULL => NullType::class, + self::TYPE_OBJECT_IDENTIFIER => ObjectIdentifier::class, + self::TYPE_OBJECT_DESCRIPTOR => ObjectDescriptor::class, + self::TYPE_REAL => Real::class, + self::TYPE_ENUMERATED => Enumerated::class, + self::TYPE_UTF8_STRING => UTF8String::class, + self::TYPE_RELATIVE_OID => RelativeOID::class, + self::TYPE_SEQUENCE => Sequence::class, + self::TYPE_SET => Set::class, + self::TYPE_NUMERIC_STRING => NumericString::class, + self::TYPE_PRINTABLE_STRING => PrintableString::class, + self::TYPE_T61_STRING => T61String::class, + self::TYPE_VIDEOTEX_STRING => VideotexString::class, + self::TYPE_IA5_STRING => IA5String::class, + self::TYPE_UTC_TIME => UTCTime::class, + self::TYPE_GENERALIZED_TIME => GeneralizedTime::class, + self::TYPE_GRAPHIC_STRING => GraphicString::class, + self::TYPE_VISIBLE_STRING => VisibleString::class, + self::TYPE_GENERAL_STRING => GeneralString::class, + self::TYPE_UNIVERSAL_STRING => UniversalString::class, + self::TYPE_CHARACTER_STRING => CharacterString::class, + self::TYPE_BMP_STRING => BMPString::class, + ]; + + /** + * Mapping from universal type tag to human-readable name. + * + * @internal + * + * @var array + */ + private const MAP_TYPE_TO_NAME = [ + self::TYPE_EOC => 'EOC', + self::TYPE_BOOLEAN => 'BOOLEAN', + self::TYPE_INTEGER => 'INTEGER', + self::TYPE_BIT_STRING => 'BIT STRING', + self::TYPE_OCTET_STRING => 'OCTET STRING', + self::TYPE_NULL => 'NULL', + self::TYPE_OBJECT_IDENTIFIER => 'OBJECT IDENTIFIER', + self::TYPE_OBJECT_DESCRIPTOR => 'ObjectDescriptor', + self::TYPE_EXTERNAL => 'EXTERNAL', + self::TYPE_REAL => 'REAL', + self::TYPE_ENUMERATED => 'ENUMERATED', + self::TYPE_EMBEDDED_PDV => 'EMBEDDED PDV', + self::TYPE_UTF8_STRING => 'UTF8String', + self::TYPE_RELATIVE_OID => 'RELATIVE-OID', + self::TYPE_SEQUENCE => 'SEQUENCE', + self::TYPE_SET => 'SET', + self::TYPE_NUMERIC_STRING => 'NumericString', + self::TYPE_PRINTABLE_STRING => 'PrintableString', + self::TYPE_T61_STRING => 'T61String', + self::TYPE_VIDEOTEX_STRING => 'VideotexString', + self::TYPE_IA5_STRING => 'IA5String', + self::TYPE_UTC_TIME => 'UTCTime', + self::TYPE_GENERALIZED_TIME => 'GeneralizedTime', + self::TYPE_GRAPHIC_STRING => 'GraphicString', + self::TYPE_VISIBLE_STRING => 'VisibleString', + self::TYPE_GENERAL_STRING => 'GeneralString', + self::TYPE_UNIVERSAL_STRING => 'UniversalString', + self::TYPE_CHARACTER_STRING => 'CHARACTER STRING', + self::TYPE_BMP_STRING => 'BMPString', + self::TYPE_STRING => 'Any String', + self::TYPE_TIME => 'Any Time', + self::TYPE_CONSTRUCTED_STRING => 'Constructed String', + ]; + + /** + * @param bool $indefiniteLength Whether type shall be encoded with indefinite length. + */ + protected function __construct( + protected readonly int $typeTag, + protected bool $indefiniteLength = false + ) { + } + + abstract public function typeClass(): int; + + abstract public function isConstructed(): bool; + + /** + * Decode element from DER data. + * + * @param string $data DER encoded data + * @param null|int $offset Reference to the variable that contains offset + * into the data where to start parsing. + * Variable is updated to the offset next to the + * parsed element. If null, start from offset 0. + */ + public static function fromDER(string $data, ?int &$offset = null): static + { + $idx = $offset ?? 0; + // decode identifier + $identifier = Identifier::fromDER($data, $idx); + // determine class that implements type specific decoding + $cls = self::determineImplClass($identifier); + // decode remaining element + $element = $cls::decodeFromDER($identifier, $data, $idx); + // if called in the context of a concrete class, check + // that decoded type matches the type of calling class + $called_class = static::class; + if ($called_class !== self::class) { + if (! $element instanceof $called_class) { + throw new UnexpectedValueException(sprintf('%s expected, got %s.', $called_class, $element::class)); + } + } + // update offset for the caller + if (isset($offset)) { + $offset = $idx; + } + return $element; + } + + public function toDER(): string + { + $identifier = Identifier::create( + $this->typeClass(), + $this->isConstructed() ? Identifier::CONSTRUCTED : Identifier::PRIMITIVE, + $this->typeTag + ); + $content = $this->encodedAsDER(); + if ($this->indefiniteLength) { + $length = Length::create(0, true); + $eoc = EOC::create(); + return $identifier->toDER() . $length->toDER() . $content . $eoc->toDER(); + } + $length = Length::create(mb_strlen($content, '8bit')); + return $identifier->toDER() . $length->toDER() . $content; + } + + public function tag(): int + { + return $this->typeTag; + } + + public function isType(int $tag): bool + { + // if element is context specific + if ($this->typeClass() === Identifier::CLASS_CONTEXT_SPECIFIC) { + return false; + } + // negative tags identify an abstract pseudotype + if ($tag < 0) { + return $this->isPseudoType($tag); + } + return $this->isConcreteType($tag); + } + + public function expectType(int $tag): ElementBase + { + if (! $this->isType($tag)) { + throw new UnexpectedValueException( + sprintf('%s expected, got %s.', self::tagToName($tag), $this->typeDescriptorString()) + ); + } + return $this; + } + + public function isTagged(): bool + { + return $this instanceof TaggedType; + } + + public function expectTagged(?int $tag = null): TaggedType + { + if (! $this->isTagged()) { + throw new UnexpectedValueException( + sprintf('Context specific element expected, got %s.', Identifier::classToName($this->typeClass())) + ); + } + if (isset($tag) && $this->tag() !== $tag) { + throw new UnexpectedValueException(sprintf('Tag %d expected, got %d.', $tag, $this->tag())); + } + return $this; + } + + /** + * Whether element has indefinite length. + */ + public function hasIndefiniteLength(): bool + { + return $this->indefiniteLength; + } + + /** + * Get self with indefinite length encoding set. + * + * @param bool $indefinite True for indefinite length, false for definite length + */ + public function withIndefiniteLength(bool $indefinite = true): self + { + $obj = clone $this; + $obj->indefiniteLength = $indefinite; + return $obj; + } + + final public function asElement(): self + { + return $this; + } + + /** + * Get element decorated with `UnspecifiedType` object. + */ + public function asUnspecified(): UnspecifiedType + { + return UnspecifiedType::create($this); + } + + /** + * Get human readable name for an universal tag. + */ + public static function tagToName(int $tag): string + { + if (! array_key_exists($tag, self::MAP_TYPE_TO_NAME)) { + return "TAG {$tag}"; + } + return self::MAP_TYPE_TO_NAME[$tag]; + } + + /** + * Get the content encoded in DER. + * + * Returns the DER encoded content without identifier and length header octets. + */ + abstract protected function encodedAsDER(): string; + + /** + * Decode type-specific element from DER. + * + * @param Identifier $identifier Pre-parsed identifier + * @param string $data DER data + * @param int $offset Offset in data to the next byte after identifier + */ + abstract protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase; + + /** + * Determine the class that implements the type. + * + * @return string Class name + */ + protected static function determineImplClass(Identifier $identifier): string + { + switch ($identifier->typeClass()) { + case Identifier::CLASS_UNIVERSAL: + $cls = self::determineUniversalImplClass($identifier->intTag()); + // constructed strings may be present in BER + if ($identifier->isConstructed() + && is_subclass_of($cls, StringType::class)) { + $cls = ConstructedString::class; + } + return $cls; + case Identifier::CLASS_CONTEXT_SPECIFIC: + return ContextSpecificType::class; + case Identifier::CLASS_APPLICATION: + return ApplicationType::class; + case Identifier::CLASS_PRIVATE: + return PrivateType::class; + } + throw new UnexpectedValueException(sprintf( + '%s %d not implemented.', + Identifier::classToName($identifier->typeClass()), + $identifier->tag() + )); + } + + /** + * Determine the class that implements an universal type of the given tag. + * + * @return string Class name + */ + protected static function determineUniversalImplClass(int $tag): string + { + if (! array_key_exists($tag, self::MAP_TAG_TO_CLASS)) { + throw new UnexpectedValueException("Universal tag {$tag} not implemented."); + } + return self::MAP_TAG_TO_CLASS[$tag]; + } + + /** + * Get textual description of the type for debugging purposes. + */ + protected function typeDescriptorString(): string + { + if ($this->typeClass() === Identifier::CLASS_UNIVERSAL) { + return self::tagToName($this->typeTag); + } + return sprintf('%s TAG %d', Identifier::classToName($this->typeClass()), $this->typeTag); + } + + /** + * Check whether the element is a concrete type of given tag. + */ + private function isConcreteType(int $tag): bool + { + // if tag doesn't match + if ($this->tag() !== $tag) { + return false; + } + // if type is universal check that instance is of a correct class + if ($this->typeClass() === Identifier::CLASS_UNIVERSAL) { + $cls = self::determineUniversalImplClass($tag); + if (! $this instanceof $cls) { + return false; + } + } + return true; + } + + /** + * Check whether the element is a pseudotype. + */ + private function isPseudoType(int $tag): bool + { + return match ($tag) { + self::TYPE_STRING => $this instanceof StringType, + self::TYPE_TIME => $this instanceof TimeType, + self::TYPE_CONSTRUCTED_STRING => $this instanceof ConstructedString, + default => false, + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Exception/DecodeException.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Exception/DecodeException.php new file mode 100644 index 000000000..400ff9bb5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Exception/DecodeException.php @@ -0,0 +1,14 @@ +validateString($string)) { + throw new InvalidArgumentException(sprintf('Not a valid %s string.', self::tagToName($this->typeTag))); + } + $this->string = $string; + } + + public function __toString(): string + { + return $this->string(); + } + + /** + * Get the string value. + */ + public function string(): string + { + return $this->string; + } + + protected function encodedAsDER(): string + { + return $this->string; + } + + /** + * Check whether string is valid for the concrete type. + */ + protected function validateString(string $string): bool + { + // Override in derived classes + return true; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/BaseTime.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/BaseTime.php new file mode 100644 index 000000000..61b4e1169 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/BaseTime.php @@ -0,0 +1,59 @@ +string(); + } + + /** + * Initialize from datetime string. + * + * @see http://php.net/manual/en/datetime.formats.php + * + * @param string $time Time string + */ + abstract public static function fromString(string $time): static; + + /** + * Get the date and time. + */ + public function dateTime(): DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Get the date and time as a type specific string. + */ + public function string(): string + { + return $this->encodedAsDER(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/ConstructedString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/ConstructedString.php new file mode 100644 index 000000000..f03cac79d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/ConstructedString.php @@ -0,0 +1,156 @@ +string(); + } + + /** + * Create from a list of string type elements. + * + * All strings must have the same type. + */ + public static function create(StringType ...$elements): self + { + if (count($elements) === 0) { + throw new LogicException('No elements, unable to determine type tag.'); + } + $tag = $elements[0]->tag(); + + return self::createWithTag($tag, ...$elements); + } + + /** + * Create from strings with a given type tag. + * + * Does not perform any validation on types. + * + * @param int $tag Type tag for the constructed string element + * @param StringType ...$elements Any number of elements + */ + public static function createWithTag(int $tag, StringType ...$elements): self + { + foreach ($elements as $el) { + if ($el->tag() !== $tag) { + throw new LogicException('All elements in constructed string must have the same type.'); + } + } + + return new self($tag, ...$elements); + } + + /** + * Get a list of strings in this structure. + * + * @return string[] + */ + public function strings(): array + { + return array_map(static fn (Element $el): string => $el->string(), $this->elements); + } + + /** + * Get the contained strings concatenated together. + * + * NOTE: It's unclear how bit strings with unused bits should be concatenated. + */ + public function string(): string + { + return implode('', $this->strings()); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): self + { + if (! $identifier->isConstructed()) { + throw new DecodeException('Structured element must have constructed bit set.'); + } + $idx = $offset; + $length = Length::expectFromDER($data, $idx); + if ($length->isIndefinite()) { + $type = self::decodeIndefiniteLength($identifier->intTag(), $data, $idx); + } else { + $type = self::decodeDefiniteLength($identifier->intTag(), $data, $idx, $length->intLength()); + } + $offset = $idx; + + return $type; + } + + /** + * Decode elements for a definite length. + * + * @param string $data DER data + * @param int $offset Offset to data + * @param int $length Number of bytes to decode + */ + protected static function decodeDefiniteLength(int $typeTag, string $data, int &$offset, int $length): self + { + $idx = $offset; + $end = $idx + $length; + $elements = []; + while ($idx < $end) { + $elements[] = Element::fromDER($data, $idx); + // check that element didn't overflow length + if ($idx > $end) { + throw new DecodeException("Structure's content overflows length."); + } + } + $offset = $idx; + // return instance by static late binding + return self::createWithTag($typeTag, ...$elements); + } + + /** + * Decode elements for an indefinite length. + * + * @param string $data DER data + * @param int $offset Offset to data + */ + protected static function decodeIndefiniteLength(int $typeTag, string $data, int &$offset): self + { + $idx = $offset; + $elements = []; + $end = mb_strlen($data, '8bit'); + while (true) { + if ($idx >= $end) { + throw new DecodeException('Unexpected end of data while decoding indefinite length structure.'); + } + $el = Element::fromDER($data, $idx); + if ($el->isType(self::TYPE_EOC)) { + break; + } + $elements[] = $el; + } + $offset = $idx; + $type = self::createWithTag($typeTag, ...$elements); + $type->indefiniteLength = true; + return $type; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Sequence.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Sequence.php new file mode 100644 index 000000000..8072f90ae --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Sequence.php @@ -0,0 +1,92 @@ +isConstructed()) { + throw new DecodeException('Structured element must have constructed bit set.'); + } + $idx = $offset; + $length = Length::expectFromDER($data, $idx); + if ($length->isIndefinite()) { + $type = self::decodeIndefiniteLength($data, $idx); + } else { + $type = self::decodeDefiniteLength($data, $idx, $length->intLength()); + } + $offset = $idx; + return $type; + } + + /** + * Decode elements for a definite length. + * + * @param string $data DER data + * @param int $offset Offset to data + * @param int $length Number of bytes to decode + */ + protected static function decodeDefiniteLength(string $data, int &$offset, int $length): self + { + $idx = $offset; + $end = $idx + $length; + $elements = []; + while ($idx < $end) { + $elements[] = Element::fromDER($data, $idx); + // check that element didn't overflow length + if ($idx > $end) { + throw new DecodeException("Structure's content overflows length."); + } + } + $offset = $idx; + // return instance by static late binding + return self::create(...$elements); + } + + /** + * Decode elements for an indefinite length. + * + * @param string $data DER data + * @param int $offset Offset to data + */ + protected static function decodeIndefiniteLength(string $data, int &$offset): self + { + $idx = $offset; + $elements = []; + $end = mb_strlen($data, '8bit'); + while (true) { + if ($idx >= $end) { + throw new DecodeException('Unexpected end of data while decoding indefinite length structure.'); + } + $el = Element::fromDER($data, $idx); + if ($el->isType(self::TYPE_EOC)) { + break; + } + $elements[] = $el; + } + $offset = $idx; + $type = self::create(...$elements); + $type->indefiniteLength = true; + return $type; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Set.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Set.php new file mode 100644 index 000000000..dadce1b47 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Constructed/Set.php @@ -0,0 +1,135 @@ +elements, + function (Element $a, Element $b) { + if ($a->typeClass() !== $b->typeClass()) { + return $a->typeClass() < $b->typeClass() ? -1 : 1; + } + return $a->tag() <=> $b->tag(); + } + ); + return $obj; + } + + /** + * Sort by encoding ascending order. + * + * Used for DER encoding of *SET OF* type. + */ + public function sortedSetOf(): self + { + $obj = clone $this; + usort( + $obj->elements, + function (Element $a, Element $b) { + $a_der = $a->toDER(); + $b_der = $b->toDER(); + return strcmp($a_der, $b_der); + } + ); + return $obj; + } + + /** + * @return self + */ + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + if (! $identifier->isConstructed()) { + throw new DecodeException('Structured element must have constructed bit set.'); + } + $idx = $offset; + $length = Length::expectFromDER($data, $idx); + if ($length->isIndefinite()) { + $type = self::decodeIndefiniteLength($data, $idx); + } else { + $type = self::decodeDefiniteLength($data, $idx, $length->intLength()); + } + $offset = $idx; + return $type; + } + + /** + * Decode elements for a definite length. + * + * @param string $data DER data + * @param int $offset Offset to data + * @param int $length Number of bytes to decode + */ + protected static function decodeDefiniteLength(string $data, int &$offset, int $length): ElementBase + { + $idx = $offset; + $end = $idx + $length; + $elements = []; + while ($idx < $end) { + $elements[] = Element::fromDER($data, $idx); + // check that element didn't overflow length + if ($idx > $end) { + throw new DecodeException("Structure's content overflows length."); + } + } + $offset = $idx; + // return instance by static late binding + return self::create(...$elements); + } + + /** + * Decode elements for an indefinite length. + * + * @param string $data DER data + * @param int $offset Offset to data + */ + protected static function decodeIndefiniteLength(string $data, int &$offset): ElementBase + { + $idx = $offset; + $elements = []; + $end = mb_strlen($data, '8bit'); + while (true) { + if ($idx >= $end) { + throw new DecodeException('Unexpected end of data while decoding indefinite length structure.'); + } + $el = Element::fromDER($data, $idx); + if ($el->isType(self::TYPE_EOC)) { + break; + } + $elements[] = $el; + } + $offset = $idx; + $type = self::create(...$elements); + $type->indefiniteLength = true; + return $type; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/BMPString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/BMPString.php new file mode 100644 index 000000000..2c2dccdc4 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/BMPString.php @@ -0,0 +1,35 @@ +string(), '8bit') * 8 - $this->unusedBits; + } + + /** + * Get the number of unused bits in the last octet of the string. + */ + public function unusedBits(): int + { + return $this->unusedBits; + } + + /** + * Test whether bit is set. + * + * @param int $idx Bit index. Most significant bit of the first octet is index 0. + */ + public function testBit(int $idx): bool + { + // octet index + $oi = (int) floor($idx / 8); + // if octet is outside range + if ($oi < 0 || $oi >= mb_strlen($this->string(), '8bit')) { + throw new OutOfBoundsException('Index is out of bounds.'); + } + // bit index + $bi = $idx % 8; + // if tested bit is last octet's unused bit + if ($oi === mb_strlen($this->string(), '8bit') - 1) { + if ($bi >= 8 - $this->unusedBits) { + throw new OutOfBoundsException('Index refers to an unused bit.'); + } + } + $byte = $this->string()[$oi]; + // index 0 is the most significant bit in byte + $mask = 0x01 << (7 - $bi); + return (ord($byte) & $mask) > 0; + } + + /** + * Get range of bits. + * + * @param int $start Index of first bit + * @param int $length Number of bits in range + * + * @return string Integer of $length bits + */ + public function range(int $start, int $length): string + { + if ($length === 0) { + return '0'; + } + if ($start + $length > $this->numBits()) { + throw new OutOfBoundsException('Not enough bits.'); + } + $bits = BigInteger::of(0); + $idx = $start; + $end = $start + $length; + while (true) { + $bit = $this->testBit($idx) ? 1 : 0; + $bits = $bits->or($bit); + if (++$idx >= $end) { + break; + } + $bits = $bits->shiftedLeft(1); + } + return $bits->toBase(10); + } + + /** + * Get a copy of the bit string with trailing zeroes removed. + */ + public function withoutTrailingZeroes(): self + { + // if bit string was empty + if ($this->string() === '') { + return self::create(''); + } + $bits = $this->string(); + // count number of empty trailing octets + $unused_octets = 0; + for ($idx = mb_strlen($bits, '8bit') - 1; $idx >= 0; --$idx, ++$unused_octets) { + if ($bits[$idx] !== "\x0") { + break; + } + } + // strip trailing octets + if ($unused_octets !== 0) { + $bits = mb_substr($bits, 0, -$unused_octets, '8bit'); + } + // if bit string was full of zeroes + if ($bits === '') { + return self::create(''); + } + // count number of trailing zeroes in the last octet + $unused_bits = 0; + $byte = ord($bits[mb_strlen($bits, '8bit') - 1]); + while (0 === ($byte & 0x01)) { + ++$unused_bits; + $byte >>= 1; + } + return self::create($bits, $unused_bits); + } + + protected function encodedAsDER(): string + { + $der = chr($this->unusedBits); + $der .= $this->string(); + if ($this->unusedBits !== 0) { + $octet = $der[mb_strlen($der, '8bit') - 1]; + // set unused bits to zero + $octet &= chr(0xff & ~((1 << $this->unusedBits) - 1)); + $der[mb_strlen($der, '8bit') - 1] = $octet; + } + return $der; + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx); + if ($length->intLength() < 1) { + throw new DecodeException('Bit string length must be at least 1.'); + } + $unused_bits = ord($data[$idx++]); + if ($unused_bits > 7) { + throw new DecodeException('Unused bits in a bit string must be less than 8.'); + } + $str_len = $length->intLength() - 1; + if ($str_len !== 0) { + $str = mb_substr($data, $idx, $str_len, '8bit'); + if ($unused_bits !== 0) { + $mask = (1 << $unused_bits) - 1; + if (($mask & ord($str[mb_strlen($str, '8bit') - 1])) !== 0) { + throw new DecodeException('DER encoded bit string must have zero padding.'); + } + } + } else { + $str = ''; + } + $offset = $idx + $str_len; + return self::create($str, $unused_bits); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Boolean.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Boolean.php new file mode 100644 index 000000000..aa2e9b47f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Boolean.php @@ -0,0 +1,62 @@ +_bool; + } + + protected function encodedAsDER(): string + { + return $this->_bool ? chr(0xff) : chr(0); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + Length::expectFromDER($data, $idx, 1); + $byte = ord($data[$idx++]); + if ($byte !== 0) { + if ($byte !== 0xff) { + throw new DecodeException('DER encoded boolean true must have all bits set to 1.'); + } + } + $offset = $idx; + return self::create($byte !== 0); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/CharacterString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/CharacterString.php new file mode 100644 index 000000000..d49fb89f2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/CharacterString.php @@ -0,0 +1,26 @@ +isPrimitive()) { + throw new DecodeException('EOC value must be primitive.'); + } + // EOC type has always zero length + Length::expectFromDER($data, $idx, 0); + $offset = $idx; + return self::create(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Enumerated.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Enumerated.php new file mode 100644 index 000000000..ebba75f7e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Enumerated.php @@ -0,0 +1,34 @@ +intLength(); + $bytes = mb_substr($data, $idx, $length, '8bit'); + $idx += $length; + $num = BigInt::fromSignedOctets($bytes)->getValue(); + $offset = $idx; + // late static binding since enumerated extends integer type + return self::create($num); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GeneralString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GeneralString.php new file mode 100644 index 000000000..a3ae69a02 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GeneralString.php @@ -0,0 +1,32 @@ +_formatted = null; + } + + public static function create(DateTimeImmutable $dt): self + { + return new self($dt); + } + + public static function fromString(string $time, ?string $tz = null): static + { + return new static(new DateTimeImmutable($time, self::createTimeZone($tz))); + } + + protected function encodedAsDER(): string + { + if (! isset($this->_formatted)) { + $dt = $this->dateTime->setTimezone(new DateTimeZone('UTC')); + $this->_formatted = $dt->format('YmdHis'); + // if fractions were used + $frac = $dt->format('u'); + if (intval($frac) !== 0) { + $frac = rtrim($frac, '0'); + $this->_formatted .= ".{$frac}"; + } + // timezone + $this->_formatted .= 'Z'; + } + return $this->_formatted; + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx)->intLength(); + $str = mb_substr($data, $idx, $length, '8bit'); + $idx += $length; + if (preg_match(self::REGEX, $str, $match) !== 1) { + throw new DecodeException('Invalid GeneralizedTime format.'); + } + [, $year, $month, $day, $hour, $minute, $second] = $match; + // if fractions match, there's at least one digit + if (isset($match[7])) { + $frac = $match[7]; + // DER restricts trailing zeroes in fractional seconds component + if ($frac[mb_strlen($frac, '8bit') - 1] === '0') { + throw new DecodeException('Fractional seconds must omit trailing zeroes.'); + } + } else { + $frac = '0'; + } + $time = $year . $month . $day . $hour . $minute . $second . '.' . $frac . + self::TZ_UTC; + $dt = DateTimeImmutable::createFromFormat('!YmdHis.uT', $time, new DateTimeZone('UTC')); + if ($dt === false) { + throw new DecodeException('Failed to decode GeneralizedTime'); + } + $offset = $idx; + return self::create($dt); + } + + /** + * Create `DateTimeZone` object from string. + */ + private static function createTimeZone(?string $tz): DateTimeZone + { + try { + return new DateTimeZone($tz ?? 'UTC'); + } catch (Throwable $e) { + throw new UnexpectedValueException('Invalid timezone.', 0, $e); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GraphicString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GraphicString.php new file mode 100644 index 000000000..7fba4155b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/GraphicString.php @@ -0,0 +1,32 @@ +_number = BigInt::create($number); + } + + public static function create(BigInteger|int|string $number): static + { + return new static($number, self::TYPE_INTEGER); + } + + /** + * Get the number as a base 10. + * + * @return string Integer as a string + */ + public function number(): string + { + return $this->_number->base10(); + } + + public function getValue(): BigInteger + { + return $this->_number->getValue(); + } + + /** + * Get the number as an integer type. + */ + public function intNumber(): int + { + return $this->_number->toInt(); + } + + protected function encodedAsDER(): string + { + return $this->_number->signedOctets(); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx)->intLength(); + $bytes = mb_substr($data, $idx, $length, '8bit'); + $idx += $length; + $num = BigInt::fromSignedOctets($bytes)->getValue(); + $offset = $idx; + // late static binding since enumerated extends integer type + return static::create($num); + } + + /** + * Test that number is valid for this context. + */ + private static function validateNumber(mixed $num): bool + { + if (is_int($num)) { + return true; + } + if (is_string($num) && preg_match('/-?\d+/', $num) === 1) { + return true; + } + if ($num instanceof BigInteger) { + return true; + } + return false; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NullType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NullType.php new file mode 100644 index 000000000..66f1671e1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NullType.php @@ -0,0 +1,49 @@ +isPrimitive()) { + throw new DecodeException('Null value must be primitive.'); + } + // null type has always zero length + Length::expectFromDER($data, $idx, 0); + $offset = $idx; + return self::create(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Number.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Number.php new file mode 100644 index 000000000..8fe2afc7a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/Number.php @@ -0,0 +1,89 @@ +number = BigInt::create($number); + } + + abstract public static function create(BigInteger|int|string $number): self; + + /** + * Get the number as a base 10. + * + * @return string Integer as a string + */ + public function number(): string + { + return $this->number->base10(); + } + + public function getValue(): BigInteger + { + return $this->number->getValue(); + } + + /** + * Get the number as an integer type. + */ + public function intNumber(): int + { + return $this->number->toInt(); + } + + protected function encodedAsDER(): string + { + return $this->number->signedOctets(); + } + + /** + * Test that number is valid for this context. + */ + private static function validateNumber(mixed $num): bool + { + if (is_int($num)) { + return true; + } + if (is_string($num) && preg_match('/-?\d+/', $num) === 1) { + return true; + } + if ($num instanceof BigInteger) { + return true; + } + return false; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NumericString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NumericString.php new file mode 100644 index 000000000..d48d4cc7e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/NumericString.php @@ -0,0 +1,31 @@ +string(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/ObjectIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/ObjectIdentifier.php new file mode 100644 index 000000000..3a4c003f0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/ObjectIdentifier.php @@ -0,0 +1,199 @@ +subids = self::explodeDottedOID($oid); + // if OID is non-empty + if (count($this->subids) > 0) { + // check that at least two nodes are set + if (count($this->subids) < 2) { + throw new UnexpectedValueException('OID must have at least two nodes.'); + } + // check that root arc is in 0..2 range + if ($this->subids[0]->isGreaterThan(2)) { + throw new UnexpectedValueException('Root arc must be in range of 0..2.'); + } + // if root arc is 0 or 1, second node must be in 0..39 range + if ($this->subids[0]->isLessThan(2) && $this->subids[1]->isGreaterThanOrEqualTo(40)) { + throw new UnexpectedValueException('Second node must be in 0..39 range for root arcs 0 and 1.'); + } + } + parent::__construct($typeTag ?? self::TYPE_OBJECT_IDENTIFIER); + } + + public static function create(string $oid, ?int $typeTag = null): self + { + return new self($oid, $typeTag); + } + + /** + * Get OID in dotted format. + */ + public function oid(): string + { + return $this->oid; + } + + protected function encodedAsDER(): string + { + $subids = $this->subids; + // encode first two subids to one according to spec section 8.19.4 + if (count($subids) >= 2) { + $num = $subids[0]->multipliedBy(40)->plus($subids[1]); + array_splice($subids, 0, 2, [$num]); + } + return self::encodeSubIDs(...$subids); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $len = Length::expectFromDER($data, $idx)->intLength(); + $subids = self::decodeSubIDs(mb_substr($data, $idx, $len, '8bit')); + $idx += $len; + // decode first subidentifier according to spec section 8.19.4 + if (isset($subids[0])) { + if ($subids[0]->isLessThan(80)) { + [$x, $y] = $subids[0]->quotientAndRemainder(40); + } else { + $x = BigInteger::of(2); + $y = $subids[0]->minus(80); + } + array_splice($subids, 0, 1, [$x, $y]); + } + $offset = $idx; + return self::create(self::implodeSubIDs(...$subids)); + } + + /** + * Explode dotted OID to an array of sub ID's. + * + * @param string $oid OID in dotted format + * + * @return BigInteger[] Array of BigInteger numbers + */ + protected static function explodeDottedOID(string $oid): array + { + $subids = []; + if ($oid !== '') { + foreach (explode('.', $oid) as $subid) { + try { + $n = BigInteger::of($subid); + $subids[] = $n; + } catch (Throwable $e) { + throw new UnexpectedValueException(sprintf('"%s" is not a number.', $subid), 0, $e); + } + } + } + return $subids; + } + + /** + * Implode an array of sub IDs to dotted OID format. + */ + protected static function implodeSubIDs(BigInteger ...$subids): string + { + return implode('.', array_map(static fn ($num) => $num->toBase(10), $subids)); + } + + /** + * Encode sub ID's to DER. + */ + protected static function encodeSubIDs(BigInteger ...$subids): string + { + $data = ''; + foreach ($subids as $subid) { + // if number fits to one base 128 byte + if ($subid->isLessThan(128)) { + $data .= chr($subid->toInt()); + } else { // encode to multiple bytes + $bytes = []; + do { + array_unshift($bytes, 0x7f & $subid->toInt()); + $subid = $subid->shiftedRight(7); + } while ($subid->isGreaterThan(0)); + // all bytes except last must have bit 8 set to one + foreach (array_splice($bytes, 0, -1) as $byte) { + $data .= chr(0x80 | $byte); + } + $byte = reset($bytes); + if (! is_int($byte)) { + throw new RuntimeException('Encoding failed'); + } + $data .= chr($byte); + } + } + return $data; + } + + /** + * Decode sub ID's from DER data. + * + * @return BigInteger[] Array of BigInteger numbers + */ + protected static function decodeSubIDs(string $data): array + { + $subids = []; + $idx = 0; + $end = mb_strlen($data, '8bit'); + while ($idx < $end) { + $num = BigInteger::of(0); + while (true) { + if ($idx >= $end) { + throw new DecodeException('Unexpected end of data.'); + } + $byte = ord($data[$idx++]); + $num = $num->or($byte & 0x7f); + // bit 8 of the last octet is zero + if (0 === ($byte & 0x80)) { + break; + } + $num = $num->shiftedLeft(7); + } + $subids[] = $num; + } + return $subids; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/OctetString.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/OctetString.php new file mode 100644 index 000000000..20c16b386 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/OctetString.php @@ -0,0 +1,26 @@ +[+\-])?' . // sign + '(?\d+)' . // integer + '$/'; + + /** + * Regex pattern to parse NR2 form number. + * + * @var string + */ + final public const NR2_REGEX = '/^\s*' . + '(?[+\-])?' . // sign + '(?(?:\d+[\.,]\d*)|(?:\d*[\.,]\d+))' . // decimal number + '$/'; + + /** + * Regex pattern to parse NR3 form number. + * + * @var string + */ + final public const NR3_REGEX = '/^\s*' . + '(?[+\-])?' . // mantissa sign + '(?(?:\d+[\.,]\d*)|(?:\d*[\.,]\d+))' . // mantissa + '[Ee](?[+\-])?' . // exponent sign + '(?\d+)' . // exponent + '$/'; + + /** + * Regex pattern to parse PHP exponent number format. + * + * @see http://php.net/manual/en/language.types.float.php + * + * @var string + */ + final public const PHP_EXPONENT_DNUM = '/^' . + '(?[+\-])?' . // sign + '(?' . + '\d+' . // LNUM + '|' . + '(?:\d*\.\d+|\d+\.\d*)' . // DNUM + ')[eE]' . + '(?[+\-])?(?\d+)' . // exponent + '$/'; + + /** + * Exponent when value is positive or negative infinite. + * + * @var int + */ + final public const INF_EXPONENT = 2047; + + /** + * Exponent bias for IEEE 754 double precision float. + * + * @var int + */ + final public const EXP_BIAS = -1023; + + /** + * Signed integer mantissa. + */ + private readonly BigInt $_mantissa; + + /** + * Signed integer exponent. + */ + private readonly BigInt $_exponent; + + /** + * Abstract value base. + * + * Must be 2 or 10. + */ + private readonly int $_base; + + /** + * Whether to encode strictly in DER. + */ + private bool $_strictDer; + + /** + * Number as a native float. + * + * @internal Lazily initialized + */ + private ?float $_float = null; + + /** + * @param BigInteger|int|string $mantissa Integer mantissa + * @param BigInteger|int|string $exponent Integer exponent + * @param int $base Base, 2 or 10 + */ + private function __construct(BigInteger|int|string $mantissa, BigInteger|int|string $exponent, int $base = 10) + { + if ($base !== 10 && $base !== 2) { + throw new UnexpectedValueException('Base must be 2 or 10.'); + } + parent::__construct(self::TYPE_REAL); + $this->_strictDer = true; + $this->_mantissa = BigInt::create($mantissa); + $this->_exponent = BigInt::create($exponent); + $this->_base = $base; + } + + public function __toString(): string + { + return sprintf('%g', $this->floatVal()); + } + + public static function create( + BigInteger|int|string $mantissa, + BigInteger|int|string $exponent, + int $base = 10 + ): self { + return new self($mantissa, $exponent, $base); + } + + /** + * Create base 2 real number from float. + */ + public static function fromFloat(float $number): self + { + if (is_infinite($number)) { + return self::fromInfinite($number); + } + if (is_nan($number)) { + throw new UnexpectedValueException('NaN values not supported.'); + } + [$m, $e] = self::parse754Double(pack('E', $number)); + return self::create($m, $e, 2); + } + + /** + * Create base 10 real number from string. + * + * @param string $number Real number in base-10 textual form + */ + public static function fromString(string $number): self + { + [$m, $e] = self::parseString($number); + return self::create($m, $e, 10); + } + + /** + * Get self with strict DER flag set or unset. + * + * @param bool $strict whether to encode strictly in DER + */ + public function withStrictDER(bool $strict): self + { + $obj = clone $this; + $obj->_strictDer = $strict; + return $obj; + } + + /** + * Get the mantissa. + */ + public function mantissa(): BigInt + { + return $this->_mantissa; + } + + /** + * Get the exponent. + */ + public function exponent(): BigInt + { + return $this->_exponent; + } + + /** + * Get the base. + */ + public function base(): int + { + return $this->_base; + } + + /** + * Get number as a float. + */ + public function floatVal(): float + { + if (! isset($this->_float)) { + $m = $this->_mantissa->toInt(); + $e = $this->_exponent->toInt(); + $this->_float = (float) ($m * $this->_base ** $e); + } + return $this->_float; + } + + /** + * Get number as a NR3 form string conforming to DER rules. + */ + public function nr3Val(): string + { + // convert to base 10 + if ($this->_base === 2) { + [$m, $e] = self::parseString(sprintf('%15E', $this->floatVal())); + } else { + $m = $this->_mantissa->getValue(); + $e = $this->_exponent->getValue(); + } + $zero = BigInteger::of(0); + $ten = BigInteger::of(10); + + // shift trailing zeroes from the mantissa to the exponent + // (X.690 07-2002, section 11.3.2.4) + while (! $m->isEqualTo($zero) && $m->mod($ten)->isEqualTo($zero)) { + $m = $m->dividedBy($ten); + $e = $e->plus(1); + } + // if exponent is zero, it must be prefixed with a "+" sign + // (X.690 07-2002, section 11.3.2.6) + if ($e->isEqualTo(0)) { + $es = '+'; + } else { + $es = $e->isLessThan(0) ? '-' : ''; + } + return sprintf('%s.E%s%s', $m->toBase(10), $es, $e->abs()->toBase(10)); + } + + protected function encodedAsDER(): string + { + $infExponent = BigInteger::of(self::INF_EXPONENT); + if ($this->_exponent->getValue()->isEqualTo($infExponent)) { + return $this->encodeSpecial(); + } + // if the real value is the value zero, there shall be no contents + // octets in the encoding. (X.690 07-2002, section 8.5.2) + if ($this->_mantissa->getValue()->toBase(10) === '0') { + return ''; + } + if ($this->_base === 10) { + return $this->encodeDecimal(); + } + return $this->encodeBinary(); + } + + /** + * Encode in binary format. + */ + protected function encodeBinary(): string + { + /** @var BigInteger $m */ + /** @var BigInteger $e */ + /** @var int $sign */ + [$base, $sign, $m, $e] = $this->prepareBinaryEncoding(); + $zero = BigInteger::of(0); + $byte = 0x80; + if ($sign < 0) { + $byte |= 0x40; + } + // normalization: mantissa must be 0 or odd + if ($base === 2) { + // while last bit is zero + while ($m->isGreaterThan(0) && $m->and(0x01)->isEqualTo($zero)) { + $m = $m->shiftedRight(1); + $e = $e->plus(1); + } + } elseif ($base === 8) { + $byte |= 0x10; + // while last 3 bits are zero + while ($m->isGreaterThan(0) && $m->and(0x07)->isEqualTo($zero)) { + $m = $m->shiftedRight(3); + $e = $e->plus(1); + } + } else { // base === 16 + $byte |= 0x20; + // while last 4 bits are zero + while ($m->isGreaterThan(0) && $m->and(0x0f)->isEqualTo($zero)) { + $m = $m->shiftedRight(4); + $e = $e->plus(1); + } + } + // scale factor + $scale = 0; + while ($m->isGreaterThan(0) && $m->and(0x01)->isEqualTo($zero)) { + $m = $m->shiftedRight(1); + ++$scale; + } + $byte |= ($scale & 0x03) << 2; + // encode exponent + $exp_bytes = (BigInt::create($e))->signedOctets(); + $exp_len = mb_strlen($exp_bytes, '8bit'); + if ($exp_len > 0xff) { + throw new RangeException('Exponent encoding is too long.'); + } + if ($exp_len <= 3) { + $byte |= ($exp_len - 1) & 0x03; + $bytes = chr($byte); + } else { + $byte |= 0x03; + $bytes = chr($byte) . chr($exp_len); + } + $bytes .= $exp_bytes; + // encode mantissa + $bytes .= (BigInt::create($m))->unsignedOctets(); + return $bytes; + } + + /** + * Encode in decimal format. + */ + protected function encodeDecimal(): string + { + // encode in NR3 decimal encoding + return chr(0x03) . $this->nr3Val(); + } + + /** + * Encode special value. + */ + protected function encodeSpecial(): string + { + return match ($this->_mantissa->toInt()) { + 1 => chr(0x40), + -1 => chr(0x41), + default => throw new LogicException('Invalid special value.'), + }; + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx)->intLength(); + // if length is zero, value is zero (spec 8.5.2) + if ($length === 0) { + $obj = self::create(0, 0, 10); + } else { + $bytes = mb_substr($data, $idx, $length, '8bit'); + $byte = ord($bytes[0]); + if ((0x80 & $byte) !== 0) { // bit 8 = 1 + $obj = self::decodeBinaryEncoding($bytes); + } elseif ($byte >> 6 === 0x00) { // bit 8 = 0, bit 7 = 0 + $obj = self::decodeDecimalEncoding($bytes); + } else { // bit 8 = 0, bit 7 = 1 + $obj = self::decodeSpecialRealValue($bytes); + } + } + $offset = $idx + $length; + return $obj; + } + + /** + * Decode binary encoding. + */ + protected static function decodeBinaryEncoding(string $data): self + { + $byte = ord($data[0]); + // bit 7 is set if mantissa is negative + $neg = (bool) (0x40 & $byte); + $base = match (($byte >> 4) & 0x03) { + 0b00 => 2, + 0b01 => 8, + 0b10 => 16, + default => throw new DecodeException('Reserved REAL binary encoding base not supported.'), + }; + // scaling factor in bits 4 and 3 + $scale = ($byte >> 2) & 0x03; + $idx = 1; + // content length in bits 2 and 1 + $len = ($byte & 0x03) + 1; + // if both bits are set, the next octet encodes the length + if ($len > 3) { + if (mb_strlen($data, '8bit') < 2) { + throw new DecodeException('Unexpected end of data while decoding REAL exponent length.'); + } + $len = ord($data[1]); + $idx = 2; + } + if (mb_strlen($data, '8bit') < $idx + $len) { + throw new DecodeException('Unexpected end of data while decoding REAL exponent.'); + } + // decode exponent + $octets = mb_substr($data, $idx, $len, '8bit'); + $exp = BigInt::fromSignedOctets($octets)->getValue(); + if ($base === 8) { + $exp = $exp->multipliedBy(3); + } elseif ($base === 16) { + $exp = $exp->multipliedBy(4); + } + if (mb_strlen($data, '8bit') <= $idx + $len) { + throw new DecodeException('Unexpected end of data while decoding REAL mantissa.'); + } + // decode mantissa + $octets = mb_substr($data, $idx + $len, null, '8bit'); + $n = BigInt::fromUnsignedOctets($octets)->getValue(); + $n = $n->multipliedBy(2 ** $scale); + if ($neg) { + $n = $n->negated(); + } + return self::create($n, $exp, 2); + } + + /** + * Decode decimal encoding. + */ + protected static function decodeDecimalEncoding(string $data): self + { + $nr = ord($data[0]) & 0x3f; + if (! in_array($nr, [1, 2, 3], true)) { + throw new DecodeException('Unsupported decimal encoding form.'); + } + $str = mb_substr($data, 1, null, '8bit'); + return self::fromString($str); + } + + /** + * Decode special encoding. + */ + protected static function decodeSpecialRealValue(string $data): self + { + if (mb_strlen($data, '8bit') !== 1) { + throw new DecodeException('SpecialRealValue must have one content octet.'); + } + $byte = ord($data[0]); + if ($byte === 0x40) { // positive infinity + return self::fromInfinite(INF); + } + if ($byte === 0x41) { // negative infinity + return self::fromInfinite(-INF); + } + throw new DecodeException('Invalid SpecialRealValue encoding.'); + } + + /** + * Prepare value for binary encoding. + * + * @return array (int) base, (int) sign, (BigInteger) mantissa and (BigInteger) exponent + */ + protected function prepareBinaryEncoding(): array + { + $base = 2; + $m = $this->_mantissa->getValue(); + $ms = $m->getSign(); + $m = BigInteger::of($m->abs()); + $e = $this->_exponent->getValue(); + $es = $e->getSign(); + $e = BigInteger::of($e->abs()); + $zero = BigInteger::of(0); + $three = BigInteger::of(3); + $four = BigInteger::of(4); + // DER uses only base 2 binary encoding + if (! $this->_strictDer) { + if ($e->mod($four)->isEqualTo($zero)) { + $base = 16; + $e = $e->dividedBy(4); + } elseif ($e->mod($three)->isEqualTo($zero)) { + $base = 8; + $e = $e->dividedBy(3); + } + } + return [$base, $ms, $m, $e->multipliedBy($es)]; + } + + /** + * Initialize from INF or -INF. + */ + private static function fromInfinite(float $inf): self + { + return self::create($inf === -INF ? -1 : 1, self::INF_EXPONENT, 2); + } + + /** + * Parse IEEE 754 big endian formatted double precision float to base 2 mantissa and exponent. + * + * @param string $octets 64 bits + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parse754Double(string $octets): array + { + $n = BigInteger::fromBytes($octets, false); + // sign bit + $neg = $n->testBit(63); + // 11 bits of biased exponent + $exponentMask = BigInteger::fromBase('7ff0000000000000', 16); + $exp = $n->and($exponentMask) + ->shiftedRight(52) + ->plus(self::EXP_BIAS); + + // 52 bits of mantissa + $mantissaMask = BigInteger::fromBase('fffffffffffff', 16); + $man = $n->and($mantissaMask); + // zero, ASN.1 doesn't differentiate -0 from +0 + $zero = BigInteger::of(0); + if ($exp->isEqualTo(self::EXP_BIAS) && $man->isEqualTo($zero)) { + return [BigInteger::of(0), BigInteger::of(0)]; + } + // denormalized value, shift binary point + if ($exp->isEqualTo(self::EXP_BIAS)) { + $exp = $exp->plus(1); + } // normalized value, insert implicit leading one before the binary point + else { + $man = $man->or(BigInteger::of(1)->shiftedLeft(52)); + } + + // find the last fraction bit that is set + $last = 0; + while (! $man->testBit($last) && $last !== 52) { + $last++; + } + + $bits_for_fraction = 52 - $last; + // adjust mantissa and exponent so that we have integer values + $man = $man->shiftedRight($last); + $exp = $exp->minus($bits_for_fraction); + // negate mantissa if number was negative + if ($neg) { + $man = $man->negated(); + } + return [$man, $exp]; + } + + /** + * Parse textual REAL number to base 10 mantissa and exponent. + * + * @param string $str Number + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parseString(string $str): array + { + // PHP exponent format + if (preg_match(self::PHP_EXPONENT_DNUM, $str, $match) === 1) { + [$m, $e] = self::parsePHPExponentMatch($match); + } // NR3 format + elseif (preg_match(self::NR3_REGEX, $str, $match) === 1) { + [$m, $e] = self::parseNR3Match($match); + } // NR2 format + elseif (preg_match(self::NR2_REGEX, $str, $match) === 1) { + [$m, $e] = self::parseNR2Match($match); + } // NR1 format + elseif (preg_match(self::NR1_REGEX, $str, $match) === 1) { + [$m, $e] = self::parseNR1Match($match); + } // invalid number + else { + throw new UnexpectedValueException("{$str} could not be parsed to REAL."); + } + // normalize so that mantissa has no trailing zeroes + $zero = BigInteger::of(0); + $ten = BigInteger::of(10); + while (! $m->isEqualTo($zero) && $m->mod($ten)->isEqualTo($zero)) { + $m = $m->dividedBy($ten); + $e = $e->plus(1); + } + return [$m, $e]; + } + + /** + * Parse PHP form float to base 10 mantissa and exponent. + * + * @param array $match Regexp match + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parsePHPExponentMatch(array $match): array + { + // mantissa sign + $ms = $match['ms'] === '-' ? -1 : 1; + $m_parts = explode('.', $match['m']); + // integer part of the mantissa + $int = ltrim($m_parts[0], '0'); + // exponent sign + $es = $match['es'] === '-' ? -1 : 1; + // signed exponent + $e = BigInteger::of($match['e'])->multipliedBy($es); + // if mantissa had fractional part + if (count($m_parts) === 2) { + $frac = rtrim($m_parts[1], '0'); + $e = $e->minus(mb_strlen($frac, '8bit')); + $int .= $frac; + } + $m = BigInteger::of($int)->multipliedBy($ms); + return [$m, $e]; + } + + /** + * Parse NR3 form number to base 10 mantissa and exponent. + * + * @param array $match Regexp match + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parseNR3Match(array $match): array + { + // mantissa sign + $ms = $match['ms'] === '-' ? -1 : 1; + // explode mantissa to integer and fraction parts + [$int, $frac] = explode('.', str_replace(',', '.', $match['m'])); + $int = ltrim($int, '0'); + $frac = rtrim($frac, '0'); + // exponent sign + $es = $match['es'] === '-' ? -1 : 1; + // signed exponent + $e = BigInteger::of($match['e'])->multipliedBy($es); + // shift exponent by the number of base 10 fractions + $e = $e->minus(mb_strlen($frac, '8bit')); + // insert fractions to integer part and produce signed mantissa + $int .= $frac; + if ($int === '') { + $int = '0'; + } + $m = BigInteger::of($int)->multipliedBy($ms); + return [$m, $e]; + } + + /** + * Parse NR2 form number to base 10 mantissa and exponent. + * + * @param array $match Regexp match + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parseNR2Match(array $match): array + { + $sign = $match['s'] === '-' ? -1 : 1; + // explode decimal number to integer and fraction parts + [$int, $frac] = explode('.', str_replace(',', '.', $match['d'])); + $int = ltrim($int, '0'); + $frac = rtrim($frac, '0'); + // shift exponent by the number of base 10 fractions + $e = BigInteger::of(0); + $e = $e->minus(mb_strlen($frac, '8bit')); + // insert fractions to integer part and produce signed mantissa + $int .= $frac; + if ($int === '') { + $int = '0'; + } + $m = BigInteger::of($int)->multipliedBy($sign); + return [$m, $e]; + } + + /** + * Parse NR1 form number to base 10 mantissa and exponent. + * + * @param array $match Regexp match + * + * @return BigInteger[] Tuple of mantissa and exponent + */ + private static function parseNR1Match(array $match): array + { + $sign = $match['s'] === '-' ? -1 : 1; + $int = ltrim($match['i'], '0'); + if ($int === '') { + $int = '0'; + } + $m = BigInteger::of($int)->multipliedBy($sign); + return [$m, BigInteger::of(0)]; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/RelativeOID.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/RelativeOID.php new file mode 100644 index 000000000..5f308817f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/RelativeOID.php @@ -0,0 +1,164 @@ +subids = self::explodeDottedOID($oid); + } + + public static function create(string $oid): self + { + return new self($oid); + } + + /** + * Get OID in dotted format. + */ + public function oid(): string + { + return $this->oid; + } + + protected function encodedAsDER(): string + { + return self::encodeSubIDs(...$this->subids); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $len = Length::expectFromDER($data, $idx)->intLength(); + $subids = self::decodeSubIDs(mb_substr($data, $idx, $len, '8bit')); + $offset = $idx + $len; + return self::create(self::implodeSubIDs(...$subids)); + } + + /** + * Explode dotted OID to an array of sub ID's. + * + * @param string $oid OID in dotted format + * + * @return BigInteger[] Array of BigInteger numbers + */ + protected static function explodeDottedOID(string $oid): array + { + $subids = []; + if ($oid !== '') { + foreach (explode('.', $oid) as $subid) { + try { + $n = BigInteger::of($subid); + $subids[] = $n; + } catch (Throwable $e) { + throw new UnexpectedValueException(sprintf('"%s" is not a number.', $subid), 0, $e); + } + } + } + return $subids; + } + + /** + * Implode an array of sub IDs to dotted OID format. + */ + protected static function implodeSubIDs(BigInteger ...$subids): string + { + return implode('.', array_map(static fn ($num) => $num->toBase(10), $subids)); + } + + /** + * Encode sub ID's to DER. + */ + protected static function encodeSubIDs(BigInteger ...$subids): string + { + $data = ''; + foreach ($subids as $subid) { + // if number fits to one base 128 byte + if ($subid->isLessThan(128)) { + $data .= chr($subid->toInt()); + } else { // encode to multiple bytes + $bytes = []; + do { + array_unshift($bytes, 0x7f & $subid->toInt()); + $subid = $subid->shiftedRight(7); + } while ($subid->isGreaterThan(0)); + // all bytes except last must have bit 8 set to one + foreach (array_splice($bytes, 0, -1) as $byte) { + $data .= chr(0x80 | $byte); + } + $byte = reset($bytes); + if (! is_int($byte)) { + throw new RuntimeException('Encoding failed'); + } + $data .= chr($byte); + } + } + return $data; + } + + /** + * Decode sub ID's from DER data. + * + * @return BigInteger[] Array of BigInteger numbers + */ + protected static function decodeSubIDs(string $data): array + { + $subids = []; + $idx = 0; + $end = mb_strlen($data, '8bit'); + while ($idx < $end) { + $num = BigInteger::of(0); + while (true) { + if ($idx >= $end) { + throw new DecodeException('Unexpected end of data.'); + } + $byte = ord($data[$idx++]); + $num = $num->or($byte & 0x7f); + // bit 8 of the last octet is zero + if (0 === ($byte & 0x80)) { + break; + } + $num = $num->shiftedLeft(7); + } + $subids[] = $num; + } + return $subids; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/T61String.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/T61String.php new file mode 100644 index 000000000..92ac2f29f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/T61String.php @@ -0,0 +1,33 @@ +dateTime->setTimezone(new DateTimeZone('UTC')); + return $dt->format('ymdHis\\Z'); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx)->intLength(); + $str = mb_substr($data, $idx, $length, '8bit'); + $idx += $length; + if (preg_match(self::REGEX, $str, $match) !== 1) { + throw new DecodeException('Invalid UTCTime format.'); + } + [, $year, $month, $day, $hour, $minute, $second] = $match; + $time = $year . $month . $day . $hour . $minute . $second . self::TZ_UTC; + $dt = DateTimeImmutable::createFromFormat('!ymdHisT', $time, new DateTimeZone('UTC')); + if ($dt === false) { + throw new DecodeException('Failed to decode UTCTime'); + } + $offset = $idx; + return self::create($dt); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/UTF8String.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/UTF8String.php new file mode 100644 index 000000000..8d40315ad --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Primitive/UTF8String.php @@ -0,0 +1,33 @@ +isPrimitive()) { + throw new DecodeException('DER encoded string must be primitive.'); + } + $length = Length::expectFromDER($data, $idx)->intLength(); + $str = $length === 0 ? '' : mb_substr($data, $idx, $length, '8bit'); + $offset = $idx + $length; + try { + return static::create($str); + } catch (InvalidArgumentException $e) { + throw new DecodeException($e->getMessage(), 0, $e); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/PrimitiveType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/PrimitiveType.php new file mode 100644 index 000000000..4a3ac2fe3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/PrimitiveType.php @@ -0,0 +1,19 @@ +elements = array_map(static fn (ElementBase $el) => $el->asElement(), $elements); + } + + /** + * Clone magic method. + */ + public function __clone() + { + // clear cache-variables + $this->taggedMap = null; + $this->unspecifiedTypes = null; + } + + public function isConstructed(): bool + { + return true; + } + + /** + * Explode DER structure to DER encoded components that it contains. + * + * @return string[] + */ + public static function explodeDER(string $data): array + { + $offset = 0; + $identifier = Identifier::fromDER($data, $offset); + if (! $identifier->isConstructed()) { + throw new DecodeException('Element is not constructed.'); + } + $length = Length::expectFromDER($data, $offset); + if ($length->isIndefinite()) { + throw new DecodeException('Explode not implemented for indefinite length encoding.'); + } + $end = $offset + $length->intLength(); + $parts = []; + while ($offset < $end) { + // start of the element + $idx = $offset; + // skip identifier + Identifier::fromDER($data, $offset); + // decode element length + $length = Length::expectFromDER($data, $offset)->intLength(); + // extract der encoding of the element + $parts[] = mb_substr($data, $idx, $offset - $idx + $length, '8bit'); + // update offset over content + $offset += $length; + } + return $parts; + } + + /** + * Get self with an element at the given index replaced by another. + * + * @param int $idx Element index + * @param Element $el New element to insert into the structure + */ + public function withReplaced(int $idx, Element $el): self + { + if (! isset($this->elements[$idx])) { + throw new OutOfBoundsException("Structure doesn't have element at index {$idx}."); + } + $obj = clone $this; + $obj->elements[$idx] = $el; + return $obj; + } + + /** + * Get self with an element inserted before the given index. + * + * @param int $idx Element index + * @param Element $el New element to insert into the structure + */ + public function withInserted(int $idx, Element $el): self + { + if (count($this->elements) < $idx || $idx < 0) { + throw new OutOfBoundsException("Index {$idx} is out of bounds."); + } + $obj = clone $this; + array_splice($obj->elements, $idx, 0, [$el]); + return $obj; + } + + /** + * Get self with an element appended to the end. + * + * @param Element $el Element to insert into the structure + */ + public function withAppended(Element $el): self + { + $obj = clone $this; + array_push($obj->elements, $el); + return $obj; + } + + /** + * Get self with an element prepended in the beginning. + * + * @param Element $el Element to insert into the structure + */ + public function withPrepended(Element $el): self + { + $obj = clone $this; + array_unshift($obj->elements, $el); + return $obj; + } + + /** + * Get self with an element at the given index removed. + * + * @param int $idx Element index + */ + public function withoutElement(int $idx): self + { + if (! isset($this->elements[$idx])) { + throw new OutOfBoundsException("Structure doesn't have element at index {$idx}."); + } + $obj = clone $this; + array_splice($obj->elements, $idx, 1); + return $obj; + } + + /** + * Get elements in the structure. + * + * @return UnspecifiedType[] + */ + public function elements(): array + { + if (! isset($this->unspecifiedTypes)) { + $this->unspecifiedTypes = array_map( + static fn (Element $el) => UnspecifiedType::create($el), + $this->elements + ); + } + return $this->unspecifiedTypes; + } + + /** + * Check whether the structure has an element at the given index, optionally satisfying given tag expectation. + * + * @param int $idx Index 0..n + * @param null|int $expectedTag Optional type tag expectation + */ + public function has(int $idx, ?int $expectedTag = null): bool + { + if (! isset($this->elements[$idx])) { + return false; + } + if (isset($expectedTag)) { + if (! $this->elements[$idx]->isType($expectedTag)) { + return false; + } + } + return true; + } + + /** + * Get the element at the given index, optionally checking that the element has a given tag. + * + * @param int $idx Index 0..n + */ + public function at(int $idx): UnspecifiedType + { + if (! isset($this->elements[$idx])) { + throw new OutOfBoundsException("Structure doesn't have an element at index {$idx}."); + } + return UnspecifiedType::create($this->elements[$idx]); + } + + /** + * Check whether the structure contains a context specific element with a given tag. + * + * @param int $tag Tag number + */ + public function hasTagged(int $tag): bool + { + // lazily build lookup map + if (! isset($this->taggedMap)) { + $this->taggedMap = []; + foreach ($this->elements as $element) { + if ($element->isTagged()) { + $this->taggedMap[$element->tag()] = $element; + } + } + } + return isset($this->taggedMap[$tag]); + } + + /** + * Get a context specific element tagged with a given tag. + */ + public function getTagged(int $tag): TaggedType + { + if (! $this->hasTagged($tag)) { + throw new LogicException("No tagged element for tag {$tag}."); + } + return $this->taggedMap[$tag]; + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->elements); + } + + /** + * Get an iterator for the `UnspecifiedElement` objects. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->elements()); + } + + protected function encodedAsDER(): string + { + $data = ''; + foreach ($this->elements as $element) { + $data .= $element->toDER(); + } + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ApplicationType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ApplicationType.php new file mode 100644 index 000000000..0505048b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ApplicationType.php @@ -0,0 +1,12 @@ +intTag(), $indefinite_length); + } + + public static function create( + Identifier $_identifier, + string $_data, + int $_offset, + int $_valueOffset, + int $_valueLength, + bool $indefinite_length + ): static { + return new static($_identifier, $_data, $_offset, $_valueOffset, $_valueLength, $indefinite_length); + } + + public function typeClass(): int + { + return $this->_identifier->typeClass(); + } + + public function isConstructed(): bool + { + return $this->_identifier->isConstructed(); + } + + public function implicit(int $tag, int $class = Identifier::CLASS_UNIVERSAL): UnspecifiedType + { + $identifier = $this->_identifier->withClass($class) + ->withTag($tag); + $cls = self::determineImplClass($identifier); + $idx = $this->_offset; + /** @var ElementBase $element */ + $element = $cls::decodeFromDER($identifier, $this->_data, $idx); + return $element->asUnspecified(); + } + + public function explicit(): UnspecifiedType + { + $idx = $this->_valueOffset; + return Element::fromDER($this->_data, $idx)->asUnspecified(); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + $idx = $offset; + $length = Length::expectFromDER($data, $idx); + // offset to inner value + $value_offset = $idx; + if ($length->isIndefinite()) { + if ($identifier->isPrimitive()) { + throw new DecodeException('Primitive type with indefinite length is not supported.'); + } + // EOC consists of two octets. + $value_length = $idx - $value_offset - 2; + } else { + $value_length = $length->intLength(); + $idx += $value_length; + } + // late static binding since ApplicationType and PrivateType extend this class + $type = static::create($identifier, $data, $offset, $value_offset, $value_length, $length->isIndefinite()); + $offset = $idx; + return $type; + } + + protected function encodedAsDER(): string + { + return mb_substr($this->_data, $this->_valueOffset, $this->_valueLength, '8bit'); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ExplicitTagging.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ExplicitTagging.php new file mode 100644 index 000000000..bbbc26f37 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ExplicitTagging.php @@ -0,0 +1,19 @@ +element->asUnspecified(); + } + + protected function encodedAsDER(): string + { + // get the full encoding of the wrapped element + return $this->element->toDER(); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + throw new BadMethodCallException(__METHOD__ . ' must be implemented in derived class.'); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ImplicitTagging.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ImplicitTagging.php new file mode 100644 index 000000000..7ad8372c7 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/ImplicitTagging.php @@ -0,0 +1,23 @@ +element->isConstructed(); + } + + public function implicit(int $tag, int $class = Identifier::CLASS_UNIVERSAL): UnspecifiedType + { + $this->element->expectType($tag); + if ($this->element->typeClass() !== $class) { + throw new UnexpectedValueException( + sprintf( + 'Type class %s expected, got %s.', + Identifier::classToName($class), + Identifier::classToName($this->element->typeClass()) + ) + ); + } + return $this->element->asUnspecified(); + } + + protected function encodedAsDER(): string + { + // get only the content of the wrapped element. + return $this->element->encodedAsDER(); + } + + protected static function decodeFromDER(Identifier $identifier, string $data, int &$offset): ElementBase + { + throw new BadMethodCallException(__METHOD__ . ' must be implemented in derived class.'); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/PrivateType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/PrivateType.php new file mode 100644 index 000000000..8d59ebb59 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/Tagged/PrivateType.php @@ -0,0 +1,12 @@ +class; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TaggedType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TaggedType.php new file mode 100644 index 000000000..7ecf07fd9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TaggedType.php @@ -0,0 +1,78 @@ +expectTagged($expectedTag); + } + return $el; + } + + /** + * Get the wrapped inner element employing explicit tagging. + * + * @param null|int $expectedTag Optional outer tag expectation + */ + public function asExplicit(?int $expectedTag = null): UnspecifiedType + { + return $this->expectExplicit($expectedTag) + ->explicit(); + } + + /** + * Check whether element supports implicit tagging. + * + * @param null|int $expectedTag Optional outer tag expectation + */ + public function expectImplicit(?int $expectedTag = null): ImplicitTagging + { + $el = $this; + if (! $el instanceof ImplicitTagging) { + throw new UnexpectedValueException("Element doesn't implement implicit tagging."); + } + if (isset($expectedTag)) { + $el->expectTagged($expectedTag); + } + return $el; + } + + /** + * Get the wrapped inner element employing implicit tagging. + * + * @param int $tag Type tag of the inner element + * @param null|int $expectedTag Optional outer tag expectation + * @param int $expectedClass Optional inner type class expectation + */ + public function asImplicit( + int $tag, + ?int $expectedTag = null, + int $expectedClass = Identifier::CLASS_UNIVERSAL + ): UnspecifiedType { + return $this->expectImplicit($expectedTag) + ->implicit($tag, $expectedClass); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TimeType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TimeType.php new file mode 100644 index 000000000..75e35287f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Type/TimeType.php @@ -0,0 +1,18 @@ +asUnspecified(); + } + + /** + * Initialize from `ElementBase` interface. + */ + public static function fromElementBase(ElementBase $el): self + { + // if element is already wrapped + if ($el instanceof self) { + return $el; + } + return self::create($el->asElement()); + } + + /** + * Get the wrapped element as a context specific tagged type. + */ + public function asTagged(): TaggedType + { + if (! $this->element instanceof TaggedType) { + throw new UnexpectedValueException('Tagged element expected, got ' . $this->typeDescriptorString()); + } + return $this->element; + } + + /** + * Get the wrapped element as an application specific type. + */ + public function asApplication(): ApplicationType + { + if (! $this->element instanceof ApplicationType) { + throw new UnexpectedValueException('Application type expected, got ' . $this->typeDescriptorString()); + } + return $this->element; + } + + /** + * Get the wrapped element as a private tagged type. + */ + public function asPrivate(): PrivateType + { + if (! $this->element instanceof PrivateType) { + throw new UnexpectedValueException('Private type expected, got ' . $this->typeDescriptorString()); + } + return $this->element; + } + + /** + * Get the wrapped element as a boolean type. + */ + public function asBoolean(): Boolean + { + if (! $this->element instanceof Boolean) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_BOOLEAN)); + } + return $this->element; + } + + /** + * Get the wrapped element as an integer type. + */ + public function asInteger(): Integer + { + if (! $this->element instanceof Integer) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_INTEGER)); + } + return $this->element; + } + + /** + * Get the wrapped element as a bit string type. + */ + public function asBitString(): BitString + { + if (! $this->element instanceof BitString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_BIT_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as an octet string type. + */ + public function asOctetString(): OctetString + { + if (! $this->element instanceof OctetString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_OCTET_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a null type. + */ + public function asNull(): NullType + { + if (! $this->element instanceof NullType) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_NULL)); + } + return $this->element; + } + + /** + * Get the wrapped element as an object identifier type. + */ + public function asObjectIdentifier(): ObjectIdentifier + { + if (! $this->element instanceof ObjectIdentifier) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_OBJECT_IDENTIFIER)); + } + return $this->element; + } + + /** + * Get the wrapped element as an object descriptor type. + */ + public function asObjectDescriptor(): ObjectDescriptor + { + if (! $this->element instanceof ObjectDescriptor) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_OBJECT_DESCRIPTOR)); + } + return $this->element; + } + + /** + * Get the wrapped element as a real type. + */ + public function asReal(): Real + { + if (! $this->element instanceof Real) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_REAL)); + } + return $this->element; + } + + /** + * Get the wrapped element as an enumerated type. + */ + public function asEnumerated(): Enumerated + { + if (! $this->element instanceof Enumerated) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_ENUMERATED)); + } + return $this->element; + } + + /** + * Get the wrapped element as a UTF8 string type. + */ + public function asUTF8String(): UTF8String + { + if (! $this->element instanceof UTF8String) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_UTF8_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a relative OID type. + */ + public function asRelativeOID(): RelativeOID + { + if (! $this->element instanceof RelativeOID) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_RELATIVE_OID)); + } + return $this->element; + } + + /** + * Get the wrapped element as a sequence type. + */ + public function asSequence(): Sequence + { + if (! $this->element instanceof Sequence) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_SEQUENCE)); + } + return $this->element; + } + + /** + * Get the wrapped element as a set type. + */ + public function asSet(): Set + { + if (! $this->element instanceof Set) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_SET)); + } + return $this->element; + } + + /** + * Get the wrapped element as a numeric string type. + */ + public function asNumericString(): NumericString + { + if (! $this->element instanceof NumericString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_NUMERIC_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a printable string type. + */ + public function asPrintableString(): PrintableString + { + if (! $this->element instanceof PrintableString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_PRINTABLE_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a T61 string type. + */ + public function asT61String(): T61String + { + if (! $this->element instanceof T61String) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_T61_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a videotex string type. + */ + public function asVideotexString(): VideotexString + { + if (! $this->element instanceof VideotexString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_VIDEOTEX_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a IA5 string type. + */ + public function asIA5String(): IA5String + { + if (! $this->element instanceof IA5String) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_IA5_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as an UTC time type. + */ + public function asUTCTime(): UTCTime + { + if (! $this->element instanceof UTCTime) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_UTC_TIME)); + } + return $this->element; + } + + /** + * Get the wrapped element as a generalized time type. + */ + public function asGeneralizedTime(): GeneralizedTime + { + if (! $this->element instanceof GeneralizedTime) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_GENERALIZED_TIME)); + } + return $this->element; + } + + /** + * Get the wrapped element as a graphic string type. + */ + public function asGraphicString(): GraphicString + { + if (! $this->element instanceof GraphicString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_GRAPHIC_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a visible string type. + */ + public function asVisibleString(): VisibleString + { + if (! $this->element instanceof VisibleString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_VISIBLE_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a general string type. + */ + public function asGeneralString(): GeneralString + { + if (! $this->element instanceof GeneralString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_GENERAL_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a universal string type. + */ + public function asUniversalString(): UniversalString + { + if (! $this->element instanceof UniversalString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_UNIVERSAL_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a character string type. + */ + public function asCharacterString(): CharacterString + { + if (! $this->element instanceof CharacterString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_CHARACTER_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a BMP string type. + */ + public function asBMPString(): BMPString + { + if (! $this->element instanceof BMPString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_BMP_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as a constructed string type. + */ + public function asConstructedString(): ConstructedString + { + if (! $this->element instanceof ConstructedString) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_CONSTRUCTED_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as any string type. + */ + public function asString(): StringType + { + if (! $this->element instanceof StringType) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_STRING)); + } + return $this->element; + } + + /** + * Get the wrapped element as any time type. + */ + public function asTime(): TimeType + { + if (! $this->element instanceof TimeType) { + throw new UnexpectedValueException($this->generateExceptionMessage(Element::TYPE_TIME)); + } + return $this->element; + } + + public function asElement(): Element + { + return $this->element; + } + + public function asUnspecified(): self + { + return $this; + } + + public function toDER(): string + { + return $this->element->toDER(); + } + + public function typeClass(): int + { + return $this->element->typeClass(); + } + + public function tag(): int + { + return $this->element->tag(); + } + + public function isConstructed(): bool + { + return $this->element->isConstructed(); + } + + public function isType(int $tag): bool + { + return $this->element->isType($tag); + } + + public function isTagged(): bool + { + return $this->element->isTagged(); + } + + /** + * {@inheritdoc} + * + * Consider using any of the `as*` accessor methods instead. + */ + public function expectType(int $tag): ElementBase + { + return $this->element->expectType($tag); + } + + /** + * {@inheritdoc} + * + * Consider using `asTagged()` method instead and chaining + * with `TaggedType::asExplicit()` or `TaggedType::asImplicit()`. + */ + public function expectTagged(?int $tag = null): TaggedType + { + return $this->element->expectTagged($tag); + } + + /** + * Generate message for exceptions thrown by `as*` methods. + * + * @param int $tag Type tag of the expected element + */ + private function generateExceptionMessage(int $tag): string + { + return sprintf('%s expected, got %s.', Element::tagToName($tag), $this->typeDescriptorString()); + } + + /** + * Get textual description of the wrapped element for debugging purposes. + */ + private function typeDescriptorString(): string + { + $type_cls = $this->element->typeClass(); + $tag = $this->element->tag(); + $str = $this->element->isConstructed() ? 'constructed ' : 'primitive '; + if ($type_cls === Identifier::CLASS_UNIVERSAL) { + $str .= Element::tagToName($tag); + } else { + $str .= Identifier::classToName($type_cls) . " TAG {$tag}"; + } + return $str; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/BigInt.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/BigInt.php new file mode 100644 index 000000000..5657085a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/BigInt.php @@ -0,0 +1,126 @@ +value = $num; + } + + public function __toString(): string + { + return $this->base10(); + } + + public static function create(BigInteger|int|string $num): self + { + return new self($num); + } + + /** + * Initialize from an arbitrary length of octets as an unsigned integer. + */ + public static function fromUnsignedOctets(string $octets): self + { + if (mb_strlen($octets, '8bit') === 0) { + throw new InvalidArgumentException('Empty octets.'); + } + return self::create(BigInteger::fromBytes($octets, false)); + } + + /** + * Initialize from an arbitrary length of octets as an signed integer having two's complement encoding. + */ + public static function fromSignedOctets(string $octets): self + { + if (mb_strlen($octets, '8bit') === 0) { + throw new InvalidArgumentException('Empty octets.'); + } + + return self::create(BigInteger::fromBytes($octets)); + } + + /** + * Get the number as a base 10 integer string. + */ + public function base10(): string + { + if ($this->number === null) { + $this->number = $this->value->toBase(10); + } + return $this->number; + } + + /** + * Get the number as an integer. + */ + public function toInt(): int + { + if (! isset($this->_intNum)) { + $this->_intNum = $this->value->toInt(); + } + return $this->_intNum; + } + + public function getValue(): BigInteger + { + return $this->value; + } + + /** + * Get the number as an unsigned integer encoded in binary. + */ + public function unsignedOctets(): string + { + return $this->value->toBytes(false); + } + + /** + * Get the number as a signed integer encoded in two's complement binary. + */ + public function signedOctets(): string + { + return $this->value->toBytes(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/Flags.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/Flags.php new file mode 100644 index 000000000..cc8cbacea --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/ASN1/Util/Flags.php @@ -0,0 +1,148 @@ +_flags = ''; + return; + } + + // calculate number of unused bits in last octet + $last_octet_bits = $_width % 8; + $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; + // mask bits outside bitfield width + $num = BigInteger::of($flags); + $mask = BigInteger::of(1)->shiftedLeft($_width)->minus(1); + $num = $num->and($mask); + + // shift towards MSB if needed + $data = $num->shiftedLeft($unused_bits) + ->toBytes(false); + $octets = unpack('C*', $data); + assert(is_array($octets), new RuntimeException('unpack() failed')); + $bits = count($octets) * 8; + // pad with zeroes + while ($bits < $_width) { + array_unshift($octets, 0); + $bits += 8; + } + $this->_flags = pack('C*', ...$octets); + } + + public static function create(BigInteger|int|string $flags, int $_width): self + { + return new self($flags, $_width); + } + + /** + * Initialize from `BitString`. + */ + public static function fromBitString(BitString $bs, int $width): self + { + $num_bits = $bs->numBits(); + $data = $bs->string(); + $num = $data === '' ? BigInteger::of(0) : BigInteger::fromBytes($bs->string(), false); + $num = $num->shiftedRight($bs->unusedBits()); + if ($num_bits < $width) { + $num = $num->shiftedLeft($width - $num_bits); + } + return self::create($num, $width); + } + + /** + * Check whether a bit at given index is set. + * + * Index 0 is the leftmost bit. + */ + public function test(int $idx): bool + { + if ($idx >= $this->_width) { + throw new OutOfBoundsException('Index is out of bounds.'); + } + // octet index + $oi = (int) floor($idx / 8); + $byte = $this->_flags[$oi]; + // bit index + $bi = $idx % 8; + // index 0 is the most significant bit in byte + $mask = 0x01 << (7 - $bi); + return (ord($byte) & $mask) > 0; + } + + /** + * Get flags as an octet string. + * + * Zeroes are appended to the last octet if width is not divisible by 8. + */ + public function string(): string + { + return $this->_flags; + } + + /** + * Get flags as a base 10 integer. + * + * @return string Integer as a string + */ + public function number(): string + { + $num = BigInteger::fromBytes($this->_flags, false); + $last_octet_bits = $this->_width % 8; + $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; + $num = $num->shiftedRight($unused_bits); + return $num->toBase(10); + } + + /** + * Get flags as an integer. + */ + public function intNumber(): int + { + $num = BigInt::create($this->number()); + return $num->toInt(); + } + + /** + * Get flags as a `BitString` object. + * + * Unused bits are set accordingly. Trailing zeroes are not stripped. + */ + public function bitString(): BitString + { + $last_octet_bits = $this->_width % 8; + $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; + return BitString::create($this->_flags, $unused_bits); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoBridge/Crypto.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoBridge/Crypto.php new file mode 100644 index 000000000..c70e898e9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoBridge/Crypto.php @@ -0,0 +1,90 @@ + + */ + private const MAP_DIGEST_OID = [ + AlgorithmIdentifier::OID_MD4_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD4, + AlgorithmIdentifier::OID_MD5_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD5, + AlgorithmIdentifier::OID_SHA1_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA1, + AlgorithmIdentifier::OID_SHA224_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA224, + AlgorithmIdentifier::OID_SHA256_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA256, + AlgorithmIdentifier::OID_SHA384_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA384, + AlgorithmIdentifier::OID_SHA512_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA512, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA1 => OPENSSL_ALGO_SHA1, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA224 => OPENSSL_ALGO_SHA224, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA256 => OPENSSL_ALGO_SHA256, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA384 => OPENSSL_ALGO_SHA384, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA512 => OPENSSL_ALGO_SHA512, + ]; + + /** + * Mapping from algorithm OID to OpenSSL cipher method name. + * + * @internal + * + * @var array + */ + private const MAP_CIPHER_OID = [ + AlgorithmIdentifier::OID_DES_CBC => 'des-cbc', + AlgorithmIdentifier::OID_DES_EDE3_CBC => 'des-ede3-cbc', + AlgorithmIdentifier::OID_AES_128_CBC => 'aes-128-cbc', + AlgorithmIdentifier::OID_AES_192_CBC => 'aes-192-cbc', + AlgorithmIdentifier::OID_AES_256_CBC => 'aes-256-cbc', + ]; + + public function sign( + string $data, + PrivateKeyInfo $privkey_info, + SignatureAlgorithmIdentifier $algo + ): Signature { + $this->_checkSignatureAlgoAndKey($algo, $privkey_info->algorithmIdentifier()); + $result = openssl_sign($data, $signature, (string) $privkey_info->toPEM(), $this->_algoToDigest($algo)); + if ($result === false) { + throw new RuntimeException('openssl_sign() failed: ' . $this->_getLastError()); + } + return Signature::fromSignatureData($signature, $algo); + } + + public function verify( + string $data, + Signature $signature, + PublicKeyInfo $pubkey_info, + SignatureAlgorithmIdentifier $algo + ): bool { + $this->_checkSignatureAlgoAndKey($algo, $pubkey_info->algorithmIdentifier()); + $result = openssl_verify( + $data, + $signature->bitString() + ->string(), + (string) $pubkey_info->toPEM(), + $this->_algoToDigest($algo) + ); + if ($result === -1) { + throw new RuntimeException('openssl_verify() failed: ' . $this->_getLastError()); + } + return $result === 1; + } + + public function encrypt(string $data, string $key, CipherAlgorithmIdentifier $algo): string + { + $this->_checkCipherKeySize($algo, $key); + $iv = $algo->initializationVector(); + $result = openssl_encrypt( + $data, + $this->_algoToCipher($algo), + $key, + OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, + $iv + ); + if ($result === false) { + throw new RuntimeException('openssl_encrypt() failed: ' . $this->_getLastError()); + } + return $result; + } + + public function decrypt(string $data, string $key, CipherAlgorithmIdentifier $algo): string + { + $this->_checkCipherKeySize($algo, $key); + $iv = $algo->initializationVector(); + $result = openssl_decrypt( + $data, + $this->_algoToCipher($algo), + $key, + OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, + $iv + ); + if ($result === false) { + throw new RuntimeException('openssl_decrypt() failed: ' . $this->_getLastError()); + } + return $result; + } + + /** + * Validate cipher algorithm key size. + */ + protected function _checkCipherKeySize(CipherAlgorithmIdentifier $algo, string $key): void + { + if ($algo instanceof BlockCipherAlgorithmIdentifier) { + if (mb_strlen($key, '8bit') !== $algo->keySize()) { + throw new UnexpectedValueException( + sprintf( + 'Key length for %s must be %d, %d given.', + $algo->name(), + $algo->keySize(), + mb_strlen($key, '8bit') + ) + ); + } + } + } + + /** + * Get last OpenSSL error message. + */ + protected function _getLastError(): ?string + { + // pump error message queue + $msg = null; + while (false !== ($err = openssl_error_string())) { + $msg = $err; + } + return $msg; + } + + /** + * Check that given signature algorithm supports key of given type. + * + * @param SignatureAlgorithmIdentifier $sig_algo Signature algorithm + * @param AlgorithmIdentifier $key_algo Key algorithm + */ + protected function _checkSignatureAlgoAndKey( + SignatureAlgorithmIdentifier $sig_algo, + AlgorithmIdentifier $key_algo + ): void { + if (! $sig_algo->supportsKeyAlgorithm($key_algo)) { + throw new UnexpectedValueException( + sprintf( + 'Signature algorithm %s does not support key algorithm %s.', + $sig_algo->name(), + $key_algo->name() + ) + ); + } + } + + /** + * Get OpenSSL digest method for given signature algorithm identifier. + */ + protected function _algoToDigest(SignatureAlgorithmIdentifier $algo): int + { + $oid = $algo->oid(); + if (! array_key_exists($oid, self::MAP_DIGEST_OID)) { + throw new UnexpectedValueException(sprintf('Digest method %s not supported.', $algo->name())); + } + return self::MAP_DIGEST_OID[$oid]; + } + + /** + * Get OpenSSL cipher method for given cipher algorithm identifier. + */ + protected function _algoToCipher(CipherAlgorithmIdentifier $algo): string + { + $oid = $algo->oid(); + if (array_key_exists($oid, self::MAP_CIPHER_OID)) { + return self::MAP_CIPHER_OID[$oid]; + } + if ($oid === AlgorithmIdentifier::OID_RC2_CBC) { + if (! $algo instanceof RC2CBCAlgorithmIdentifier) { + throw new UnexpectedValueException('Not an RC2-CBC algorithm.'); + } + return $this->_rc2AlgoToCipher($algo); + } + throw new UnexpectedValueException(sprintf('Cipher method %s not supported.', $algo->name())); + } + + /** + * Get OpenSSL cipher method for given RC2 algorithm identifier. + */ + protected function _rc2AlgoToCipher(RC2CBCAlgorithmIdentifier $algo): string + { + return match ($algo->effectiveKeyBits()) { + 128 => 'rc2-cbc', + 64 => 'rc2-64-cbc', + 40 => 'rc2-40-cbc', + default => throw new UnexpectedValueException($algo->effectiveKeyBits() . ' bit RC2 not supported.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEM.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEM.php new file mode 100644 index 000000000..30ff39274 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEM.php @@ -0,0 +1,138 @@ +string(); + } + + public static function create(string $_type, string $_data): self + { + return new self($_type, $_data); + } + + /** + * Initialize from a PEM-formatted string. + */ + public static function fromString(string $str): self + { + if (preg_match(self::PEM_REGEX, $str, $match) !== 1) { + throw new UnexpectedValueException('Not a PEM formatted string.'); + } + $payload = preg_replace('/\s+/', '', $match[2]); + if (! is_string($payload)) { + throw new UnexpectedValueException('Failed to decode PEM data.'); + } + $data = base64_decode($payload, true); + if ($data === false) { + throw new UnexpectedValueException('Failed to decode PEM data.'); + } + return self::create($match[1], $data); + } + + /** + * Initialize from a file. + * + * @param string $filename Path to file + */ + public static function fromFile(string $filename): self + { + if (! is_readable($filename)) { + throw new RuntimeException("Failed to read {$filename}."); + } + $str = file_get_contents($filename); + if ($str === false) { + throw new RuntimeException("Failed to read {$filename}."); + } + return self::fromString($str); + } + + /** + * Get content type. + */ + public function type(): string + { + return $this->type; + } + + public function data(): string + { + return $this->data; + } + + /** + * Encode to PEM string. + */ + public function string(): string + { + return "-----BEGIN {$this->type}-----\n" . + trim(chunk_split(base64_encode($this->data), 64, "\n")) . "\n" . + "-----END {$this->type}-----"; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEMBundle.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEMBundle.php new file mode 100644 index 000000000..3411004aa --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoEncoding/PEMBundle.php @@ -0,0 +1,155 @@ +pems = $pems; + } + + public function __toString(): string + { + return $this->string(); + } + + public static function create(PEM ...$pems): self + { + return new self(...$pems); + } + + /** + * Initialize from a string. + */ + public static function fromString(string $str): self + { + $hasMatches = preg_match_all(PEM::PEM_REGEX, $str, $matches, PREG_SET_ORDER); + if ($hasMatches === false || $hasMatches === 0) { + throw new UnexpectedValueException('No PEM blocks.'); + } + $pems = array_map( + static function ($match) { + $payload = preg_replace('/\s+/', '', $match[2]); + if (! is_string($payload)) { + throw new UnexpectedValueException('Failed to decode PEM data.'); + } + $data = base64_decode($payload, true); + if ($data === false) { + throw new UnexpectedValueException('Failed to decode PEM data.'); + } + return PEM::create($match[1], $data); + }, + $matches + ); + return self::create(...$pems); + } + + /** + * Initialize from a file. + */ + public static function fromFile(string $filename): self + { + if (! is_readable($filename)) { + throw new RuntimeException("Failed to read {$filename}."); + } + $str = file_get_contents($filename); + if ($str === false) { + throw new RuntimeException("Failed to read {$filename}."); + } + return self::fromString($str); + } + + /** + * Get self with PEM objects appended. + */ + public function withPEMs(PEM ...$pems): self + { + $obj = clone $this; + $obj->pems = array_merge($obj->pems, $pems); + return $obj; + } + + /** + * Get all PEMs in a bundle. + * + * @return PEM[] + */ + public function all(): array + { + return $this->pems; + } + + /** + * Get the first PEM in a bundle. + */ + public function first(): PEM + { + if (count($this->pems) === 0) { + throw new LogicException('No PEMs.'); + } + return $this->pems[0]; + } + + /** + * Get the last PEM in a bundle. + */ + public function last(): PEM + { + if (count($this->pems) === 0) { + throw new LogicException('No PEMs.'); + } + return $this->pems[count($this->pems) - 1]; + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->pems); + } + + /** + * Get iterator for PEMs. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->pems); + } + + /** + * Encode bundle to a string of contiguous PEM blocks. + */ + public function string(): string + { + return implode("\n", array_map(static fn (PEM $pem) => $pem->string(), $this->pems)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifier.php new file mode 100644 index 000000000..c78e174c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifier.php @@ -0,0 +1,137 @@ +parse($seq); + } + + public function oid(): string + { + return $this->oid; + } + + public function toASN1(): Sequence + { + $elements = [ObjectIdentifier::create($this->oid)]; + $params = $this->paramsASN1(); + if (isset($params)) { + $elements[] = $params; + } + return Sequence::create(...$elements); + } + + /** + * Get algorithm identifier parameters as ASN.1. + * + * If type allows parameters to be omitted, return null. + */ + abstract protected function paramsASN1(): ?Element; +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierFactory.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierFactory.php new file mode 100644 index 000000000..175b26644 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierFactory.php @@ -0,0 +1,158 @@ + + */ + private const MAP_OID_TO_CLASS = [ + AlgorithmIdentifier::OID_RSA_ENCRYPTION => RSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_EC_PUBLIC_KEY => ECPublicKeyAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_X25519 => X25519AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_X448 => X448AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ED25519 => Ed25519AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ED448 => Ed448AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_DES_CBC => DESCBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_DES_EDE3_CBC => DESEDE3CBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_RC2_CBC => RC2CBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_AES_128_CBC => AES128CBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_AES_192_CBC => AES192CBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_AES_256_CBC => AES256CBCAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_HMAC_WITH_SHA1 => HMACWithSHA1AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_HMAC_WITH_SHA224 => HMACWithSHA224AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_HMAC_WITH_SHA256 => HMACWithSHA256AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_HMAC_WITH_SHA384 => HMACWithSHA384AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_HMAC_WITH_SHA512 => HMACWithSHA512AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_MD5 => MD5AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA1 => SHA1AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA224 => SHA224AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA256 => SHA256AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA384 => SHA384AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA512 => SHA512AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_MD2_WITH_RSA_ENCRYPTION => MD2WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_MD4_WITH_RSA_ENCRYPTION => MD4WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_MD5_WITH_RSA_ENCRYPTION => MD5WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA1_WITH_RSA_ENCRYPTION => SHA1WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA224_WITH_RSA_ENCRYPTION => SHA224WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA256_WITH_RSA_ENCRYPTION => SHA256WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA384_WITH_RSA_ENCRYPTION => SHA384WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_SHA512_WITH_RSA_ENCRYPTION => SHA512WithRSAEncryptionAlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA1 => ECDSAWithSHA1AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA224 => ECDSAWithSHA224AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA256 => ECDSAWithSHA256AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA384 => ECDSAWithSHA384AlgorithmIdentifier::class, + AlgorithmIdentifier::OID_ECDSA_WITH_SHA512 => ECDSAWithSHA512AlgorithmIdentifier::class, + ]; + + /** + * Additional algorithm identifier providers. + * + * @var AlgorithmIdentifierProvider[] + */ + private readonly array $_additionalProviders; + + /** + * @param AlgorithmIdentifierProvider ...$providers Additional providers + */ + private function __construct(AlgorithmIdentifierProvider ...$providers) + { + $this->_additionalProviders = $providers; + } + + public static function create(AlgorithmIdentifierProvider ...$providers): self + { + return new self(...$providers); + } + + /** + * Get the name of a class that implements algorithm identifier for given OID. + * + * @param string $oid Object identifier in dotted format + * + * @return null|string Fully qualified class name or null if not supported + */ + public function getClass(string $oid): ?string + { + // if OID is provided by this factory + if (array_key_exists($oid, self::MAP_OID_TO_CLASS)) { + return self::MAP_OID_TO_CLASS[$oid]; + } + // try additional providers + foreach ($this->_additionalProviders as $provider) { + if ($provider->supportsOID($oid)) { + return $provider->getClassByOID($oid); + } + } + return null; + } + + /** + * Parse AlgorithmIdentifier from an ASN.1 sequence. + */ + public function parse(Sequence $seq): AlgorithmIdentifier + { + $oid = $seq->at(0) + ->asObjectIdentifier() + ->oid(); + $params = $seq->has(1) ? $seq->at(1) : null; + $cls = $this->getClass($oid); + if ($cls !== null) { + return $cls::fromASN1Params($params); + } + + return GenericAlgorithmIdentifier::create($oid, $params); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierProvider.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierProvider.php new file mode 100644 index 000000000..846f0d9df --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/AlgorithmIdentifierProvider.php @@ -0,0 +1,31 @@ + + */ + final public const MAP_CURVE_TO_SIZE = [ + self::CURVE_PRIME192V1 => 192, + self::CURVE_PRIME192V2 => 192, + self::CURVE_PRIME192V3 => 192, + self::CURVE_PRIME239V1 => 239, + self::CURVE_PRIME239V2 => 239, + self::CURVE_PRIME239V3 => 239, + self::CURVE_PRIME256V1 => 256, + self::CURVE_SECP112R1 => 112, + self::CURVE_SECP112R2 => 112, + self::CURVE_SECP128R1 => 128, + self::CURVE_SECP128R2 => 128, + self::CURVE_SECP160K1 => 160, + self::CURVE_SECP160R1 => 160, + self::CURVE_SECP160R2 => 160, + self::CURVE_SECP192K1 => 192, + self::CURVE_SECP224K1 => 224, + self::CURVE_SECP224R1 => 224, + self::CURVE_SECP256K1 => 256, + self::CURVE_SECP384R1 => 384, + self::CURVE_SECP521R1 => 521, + ]; + + /** + * @param string $namedCurve Curve identifier + */ + private function __construct( + private readonly string $namedCurve + ) { + parent::__construct(self::OID_EC_PUBLIC_KEY); + } + + public static function create(string $namedCurve): self + { + return new self($namedCurve); + } + + public function name(): string + { + return 'ecPublicKey'; + } + + /** + * @return self + */ + public static function fromASN1Params(?UnspecifiedType $params = null): SpecificAlgorithmIdentifier + { + if (! isset($params)) { + throw new UnexpectedValueException('No parameters.'); + } + $named_curve = $params->asObjectIdentifier() + ->oid(); + return self::create($named_curve); + } + + /** + * Get OID of the named curve. + */ + public function namedCurve(): string + { + return $this->namedCurve; + } + + /** + * @return ObjectIdentifier + */ + protected function paramsASN1(): ?Element + { + return ObjectIdentifier::create($this->namedCurve); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed25519AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed25519AlgorithmIdentifier.php new file mode 100644 index 000000000..1ac5f8075 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed25519AlgorithmIdentifier.php @@ -0,0 +1,52 @@ +oid() === self::OID_ED25519; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed448AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed448AlgorithmIdentifier.php new file mode 100644 index 000000000..327fefbe6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/Ed448AlgorithmIdentifier.php @@ -0,0 +1,52 @@ +oid() === self::OID_ED448; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RFC8410EdAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RFC8410EdAlgorithmIdentifier.php new file mode 100644 index 000000000..3821feab5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RFC8410EdAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +asNull(); + return self::create(); + } + + /** + * @return NullType + */ + protected function paramsASN1(): ?Element + { + return NullType::create(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RSAPSSSSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RSAPSSSSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..f1507a2f3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/RSAPSSSSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,62 @@ +asNull(); + return self::create(); + } + + /** + * @return NullType + */ + protected function paramsASN1(): ?Element + { + return NullType::create(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/X25519AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/X25519AlgorithmIdentifier.php new file mode 100644 index 000000000..7f362d7a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Asymmetric/X25519AlgorithmIdentifier.php @@ -0,0 +1,43 @@ +asOctetString() + ->string(); + return self::create($iv); + } + + public function name(): string + { + return 'aes128-CBC'; + } + + public function keySize(): int + { + return 16; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES192CBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES192CBCAlgorithmIdentifier.php new file mode 100644 index 000000000..27780936d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES192CBCAlgorithmIdentifier.php @@ -0,0 +1,55 @@ +asOctetString() + ->string(); + return self::create($iv); + } + + public function name(): string + { + return 'aes192-CBC'; + } + + public function keySize(): int + { + return 24; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES256CBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES256CBCAlgorithmIdentifier.php new file mode 100644 index 000000000..73e4e19f0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AES256CBCAlgorithmIdentifier.php @@ -0,0 +1,55 @@ +asOctetString() + ->string(); + return new static($iv); + } + + public function name(): string + { + return 'aes256-CBC'; + } + + public function keySize(): int + { + return 32; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AESCBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AESCBCAlgorithmIdentifier.php new file mode 100644 index 000000000..b14322d14 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/AESCBCAlgorithmIdentifier.php @@ -0,0 +1,40 @@ +initializationVector)) { + throw new LogicException('IV not set.'); + } + return OctetString::create($this->initializationVector); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/BlockCipherAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/BlockCipherAlgorithmIdentifier.php new file mode 100644 index 000000000..08be2a312 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/BlockCipherAlgorithmIdentifier.php @@ -0,0 +1,16 @@ +_checkIVSize($initializationVector); + parent::__construct($oid); + } + + /** + * Get key size in bytes. + */ + abstract public function keySize(): int; + + /** + * Get the initialization vector size in bytes. + */ + abstract public function ivSize(): int; + + /** + * Get initialization vector. + */ + public function initializationVector(): string + { + return $this->initializationVector; + } + + /** + * Get copy of the object with given initialization vector. + * + * @param string $iv Initialization vector or null to remove + */ + public function withInitializationVector(string $iv): self + { + $this->_checkIVSize($iv); + $obj = clone $this; + $obj->initializationVector = $iv; + return $obj; + } + + /** + * Check that initialization vector size is valid for the cipher. + */ + protected function _checkIVSize(string $iv): void + { + if (mb_strlen($iv, '8bit') !== $this->ivSize()) { + throw new UnexpectedValueException('Invalid IV size.'); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESCBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESCBCAlgorithmIdentifier.php new file mode 100644 index 000000000..0e7c5edcd --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESCBCAlgorithmIdentifier.php @@ -0,0 +1,85 @@ +_checkIVSize($iv); + parent::__construct(self::OID_DES_CBC, $iv); + } + + public static function create(?string $iv = null): self + { + return new self($iv); + } + + public function name(): string + { + return 'desCBC'; + } + + /** + * @return self + */ + public static function fromASN1Params(?UnspecifiedType $params = null): SpecificAlgorithmIdentifier + { + if (! isset($params)) { + throw new UnexpectedValueException('No parameters.'); + } + $iv = $params->asOctetString() + ->string(); + return self::create($iv); + } + + public function blockSize(): int + { + return 8; + } + + public function keySize(): int + { + return 8; + } + + public function ivSize(): int + { + return 8; + } + + /** + * @return OctetString + */ + protected function paramsASN1(): ?Element + { + if (! isset($this->initializationVector)) { + throw new LogicException('IV not set.'); + } + return OctetString::create($this->initializationVector); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESEDE3CBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESEDE3CBCAlgorithmIdentifier.php new file mode 100644 index 000000000..a404f19e6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/DESEDE3CBCAlgorithmIdentifier.php @@ -0,0 +1,86 @@ +_checkIVSize($iv); + } + + public static function create(?string $iv = null): self + { + return new self($iv); + } + + public function name(): string + { + return 'des-EDE3-CBC'; + } + + /** + * @return self + */ + public static function fromASN1Params(?UnspecifiedType $params = null): SpecificAlgorithmIdentifier + { + if (! isset($params)) { + throw new UnexpectedValueException('No parameters.'); + } + $iv = $params->asOctetString() + ->string(); + return self::create($iv); + } + + public function blockSize(): int + { + return 8; + } + + public function keySize(): int + { + return 24; + } + + public function ivSize(): int + { + return 8; + } + + /** + * @return OctetString + */ + protected function paramsASN1(): ?Element + { + if (! isset($this->initializationVector)) { + throw new LogicException('IV not set.'); + } + return OctetString::create($this->initializationVector); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/RC2CBCAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/RC2CBCAlgorithmIdentifier.php new file mode 100644 index 000000000..33d0a0b21 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Cipher/RC2CBCAlgorithmIdentifier.php @@ -0,0 +1,197 @@ + ekb => version + */ + private const EKB_TABLE = [ + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, + 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, + 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, + 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, + 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, + 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, + 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, + 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, + 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, + 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, + 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, + 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, + 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, + 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, + 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, + 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, + 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab, + ]; + + /** + * @param int $effectiveKeyBits Number of effective key bits + * @param null|string $iv Initialization vector + */ + private function __construct( + private readonly int $effectiveKeyBits, + ?string $iv + ) { + parent::__construct(self::OID_RC2_CBC, $iv); + $this->_checkIVSize($iv); + } + + public static function create(int $_effectiveKeyBits = 64, ?string $iv = null): self + { + return new self($_effectiveKeyBits, $iv); + } + + public function name(): string + { + return 'rc2-cbc'; + } + + /** + * @return self + */ + public static function fromASN1Params(?UnspecifiedType $params = null): SpecificAlgorithmIdentifier + { + if (! isset($params)) { + throw new UnexpectedValueException('No parameters.'); + } + $key_bits = 32; + // rfc2268 a choice containing only IV + if ($params->isType(Element::TYPE_OCTET_STRING)) { + $iv = $params->asOctetString() + ->string(); + } else { + $seq = $params->asSequence(); + $idx = 0; + // version is optional in rfc2898 + if ($seq->has($idx, Element::TYPE_INTEGER)) { + $version = $seq->at($idx++) + ->asInteger() + ->intNumber(); + $key_bits = self::_versionToEKB($version); + } + // IV is present in all variants + $iv = $seq->at($idx) + ->asOctetString() + ->string(); + } + return self::create($key_bits, $iv); + } + + /** + * Get number of effective key bits. + */ + public function effectiveKeyBits(): int + { + return $this->effectiveKeyBits; + } + + public function blockSize(): int + { + return 8; + } + + public function keySize(): int + { + return (int) round($this->effectiveKeyBits / 8); + } + + public function ivSize(): int + { + return 8; + } + + /** + * @return Sequence + */ + protected function paramsASN1(): ?Element + { + if ($this->effectiveKeyBits >= 256) { + $version = $this->effectiveKeyBits; + } else { + $version = self::EKB_TABLE[$this->effectiveKeyBits]; + } + if (! isset($this->initializationVector)) { + throw new LogicException('IV not set.'); + } + return Sequence::create(Integer::create($version), OctetString::create($this->initializationVector)); + } + + /** + * Translate version number to number of effective key bits. + */ + private static function _versionToEKB(int $version): int + { + static $lut; + if ($version > 255) { + return $version; + } + if (! isset($lut)) { + $lut = array_flip(self::EKB_TABLE); + } + return $lut[$version]; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Feature/AlgorithmIdentifierType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Feature/AlgorithmIdentifierType.php new file mode 100644 index 000000000..6a84b05c4 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Feature/AlgorithmIdentifierType.php @@ -0,0 +1,30 @@ +oid; + } + + public function parameters(): ?UnspecifiedType + { + return $this->params; + } + + protected function paramsASN1(): ?Element + { + return $this->params?->asElement(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA1AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA1AlgorithmIdentifier.php new file mode 100644 index 000000000..74a28a022 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA1AlgorithmIdentifier.php @@ -0,0 +1,59 @@ +asNull()); + } + + public function name(): string + { + return 'hmacWithSHA224'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA256AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA256AlgorithmIdentifier.php new file mode 100644 index 000000000..bd794d433 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA256AlgorithmIdentifier.php @@ -0,0 +1,40 @@ +asNull()); + } + + public function name(): string + { + return 'hmacWithSHA256'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA384AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA384AlgorithmIdentifier.php new file mode 100644 index 000000000..7fe1dacb2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA384AlgorithmIdentifier.php @@ -0,0 +1,40 @@ +asNull()); + } + + public function name(): string + { + return 'hmacWithSHA384'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA512AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA512AlgorithmIdentifier.php new file mode 100644 index 000000000..5d5ecdd60 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/HMACWithSHA512AlgorithmIdentifier.php @@ -0,0 +1,40 @@ +asNull()); + } + + public function name(): string + { + return 'hmacWithSHA512'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/MD5AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/MD5AlgorithmIdentifier.php new file mode 100644 index 000000000..4fae45dd7 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/MD5AlgorithmIdentifier.php @@ -0,0 +1,71 @@ +params = NullType::create(); + } + + public static function create(): self + { + return new self(); + } + + public function name(): string + { + return 'md5'; + } + + public static function fromASN1Params(?UnspecifiedType $params = null): static + { + $obj = static::create(); + // if parameters field is present, it must be null type + if (isset($params)) { + $obj->params = $params->asNull(); + } + return $obj; + } + + /** + * @return null|NullType + */ + protected function paramsASN1(): ?Element + { + return $this->params; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/RFC4231HMACAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/RFC4231HMACAlgorithmIdentifier.php new file mode 100644 index 000000000..b341c6ea3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/RFC4231HMACAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +params; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA1AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA1AlgorithmIdentifier.php new file mode 100644 index 000000000..a079f34a2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA1AlgorithmIdentifier.php @@ -0,0 +1,69 @@ +params = null; + } + + public static function create(): self + { + return new self(); + } + + public function name(): string + { + return 'sha1'; + } + + public static function fromASN1Params(?UnspecifiedType $params = null): static + { + $obj = static::create(); + // if parameters field is present, it must be null type + if (isset($params)) { + $obj->params = $params->asNull(); + } + return $obj; + } + + /** + * @return null|NullType + */ + protected function paramsASN1(): ?Element + { + return $this->params; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA224AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA224AlgorithmIdentifier.php new file mode 100644 index 000000000..ba547c1df --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA224AlgorithmIdentifier.php @@ -0,0 +1,47 @@ +_params = $params->asNull(); + } + return $obj; + } + + public function name(): string + { + return 'sha224'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA256AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA256AlgorithmIdentifier.php new file mode 100644 index 000000000..638f45a9a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA256AlgorithmIdentifier.php @@ -0,0 +1,46 @@ +_params = $params->asNull(); + } + return $obj; + } + + public function name(): string + { + return 'sha256'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA2AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA2AlgorithmIdentifier.php new file mode 100644 index 000000000..679cefb74 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA2AlgorithmIdentifier.php @@ -0,0 +1,38 @@ +_params; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA384AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA384AlgorithmIdentifier.php new file mode 100644 index 000000000..f9fbdbffe --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA384AlgorithmIdentifier.php @@ -0,0 +1,46 @@ +_params = $params->asNull(); + } + return $obj; + } + + public function name(): string + { + return 'sha384'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA512AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA512AlgorithmIdentifier.php new file mode 100644 index 000000000..0294aa354 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Hash/SHA512AlgorithmIdentifier.php @@ -0,0 +1,46 @@ +_params = $params->asNull(); + } + return $obj; + } + + public function name(): string + { + return 'sha512'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/ECDSAWithSHA1AlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/ECDSAWithSHA1AlgorithmIdentifier.php new file mode 100644 index 000000000..fe462024d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/ECDSAWithSHA1AlgorithmIdentifier.php @@ -0,0 +1,39 @@ +oid() === self::OID_EC_PUBLIC_KEY; + } + + protected function paramsASN1(): ?Element + { + return null; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/MD2WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/MD2WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..c9f216ec9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/MD2WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,39 @@ +params; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/RSASignatureAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/RSASignatureAlgorithmIdentifier.php new file mode 100644 index 000000000..65f7600dc --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/RSASignatureAlgorithmIdentifier.php @@ -0,0 +1,20 @@ +oid() === self::OID_RSA_ENCRYPTION; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA1WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA1WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..22a7b6316 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA1WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,40 @@ +asNull(); + return self::create(); + } + + public function name(): string + { + return 'sha1-with-rsa-signature'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA224WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA224WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..15fa65072 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA224WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +asElement()); + } + + public function name(): string + { + return 'sha224WithRSAEncryption'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA256WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA256WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..be749d4cf --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA256WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +asElement()); + } + + public function name(): string + { + return 'sha256WithRSAEncryption'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA384WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA384WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..764078744 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA384WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +asElement()); + } + + public function name(): string + { + return 'sha384WithRSAEncryption'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA512WithRSAEncryptionAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA512WithRSAEncryptionAlgorithmIdentifier.php new file mode 100644 index 000000000..58a7f3fb5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/Signature/SHA512WithRSAEncryptionAlgorithmIdentifier.php @@ -0,0 +1,37 @@ +asElement()); + } + + public function name(): string + { + return 'sha512WithRSAEncryption'; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/SpecificAlgorithmIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/SpecificAlgorithmIdentifier.php new file mode 100644 index 000000000..18da7542f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/AlgorithmIdentifier/SpecificAlgorithmIdentifier.php @@ -0,0 +1,20 @@ + $value->toAttribute(), $values)); + } + + // Nothing yet. Extended from base class for future extensions. +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECConversion.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECConversion.php new file mode 100644 index 000000000..05cd130b1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECConversion.php @@ -0,0 +1,109 @@ +string(); + if ($bs->unusedBits() !== 0) { + // @todo pad string + throw new RuntimeException('Unaligned bitstrings to supported'); + } + return OctetString::create($str); + } + + /** + * Perform Octet-String-to-Bit-String Conversion. + * + * Defined in SEC 1 section 2.3.2. + */ + public static function octetStringToBitString(OctetString $os): BitString + { + return BitString::create($os->string()); + } + + /** + * Perform Integer-to-Octet-String Conversion. + * + * Defined in SEC 1 section 2.3.7. + * + * @param null|int $mlen Optional desired output length + */ + public static function integerToOctetString(Integer $num, ?int $mlen = null): OctetString + { + $bigInteger = BigInteger::of($num->getValue()); + $str = $bigInteger->toBytes(false); + if ($mlen !== null) { + $len = mb_strlen($str, '8bit'); + if ($len > $mlen) { + throw new RangeException('Number is too large.'); + } + // pad with zeroes + if ($len < $mlen) { + $str = str_repeat("\0", $mlen - $len) . $str; + } + } + return OctetString::create($str); + } + + /** + * Perform Octet-String-to-Integer Conversion. + * + * Defined in SEC 1 section 2.3.8. + */ + public static function octetStringToInteger(OctetString $os): Integer + { + $num = BigInteger::fromBytes($os->string(), false); + + return Integer::create($num); + } + + /** + * Convert a base-10 number to octets. + * + * This is a convenicence method for integer <-> octet string conversion without the need for external ASN.1 + * dependencies. + * + * @param int|string $num Number in base-10 + * @param null|int $mlen Optional desired output length + */ + public static function numberToOctets(int|string $num, ?int $mlen = null): string + { + return self::integerToOctetString(Integer::create($num), $mlen)->string(); + } + + /** + * Convert octets to a base-10 number. + * + * This is a convenicence method for integer <-> octet string conversion without the need for external ASN.1 + * dependencies. + * + * @return string Number in base-10 + */ + public static function octetsToNumber(string $str): string + { + return self::octetStringToInteger(OctetString::create($str))->number(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPrivateKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPrivateKey.php new file mode 100644 index 000000000..cb9a8f02d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPrivateKey.php @@ -0,0 +1,190 @@ +at(0) + ->asInteger() + ->intNumber(); + if ($version !== 1) { + throw new UnexpectedValueException('Version must be 1.'); + } + $private_key = $seq->at(1) + ->asOctetString() + ->string(); + $named_curve = null; + if ($seq->hasTagged(0)) { + $params = $seq->getTagged(0) + ->asExplicit(); + $named_curve = $params->asObjectIdentifier() + ->oid(); + } + $public_key = null; + if ($seq->hasTagged(1)) { + $public_key = $seq->getTagged(1) + ->asExplicit() + ->asBitString() + ->string(); + } + return self::create($private_key, $named_curve, $public_key); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * @see PrivateKey::fromPEM() + */ + public static function fromPEM(PEM $pem): self + { + $pk = parent::fromPEM($pem); + if (! ($pk instanceof self)) { + throw new UnexpectedValueException('Not an EC private key.'); + } + return $pk; + } + + /** + * Get the EC private key value. + * + * @return string Octets of the private key + */ + public function privateKeyOctets(): string + { + return $this->privateKey; + } + + /** + * Whether named curve is present. + */ + public function hasNamedCurve(): bool + { + return isset($this->namedCurve); + } + + /** + * Get named curve OID. + */ + public function namedCurve(): string + { + if (! $this->hasNamedCurve()) { + throw new LogicException('namedCurve not set.'); + } + return $this->namedCurve; + } + + /** + * Get self with named curve. + * + * @param null|string $named_curve Named curve OID + */ + public function withNamedCurve(?string $named_curve): self + { + $obj = clone $this; + $obj->namedCurve = $named_curve; + return $obj; + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return ECPublicKeyAlgorithmIdentifier::create($this->namedCurve()); + } + + /** + * Whether public key is present. + */ + public function hasPublicKey(): bool + { + return isset($this->publicKey); + } + + /** + * @return ECPublicKey + */ + public function publicKey(): PublicKey + { + if (! $this->hasPublicKey()) { + throw new LogicException('publicKey not set.'); + } + return ECPublicKey::create($this->publicKey, $this->namedCurve()); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [Integer::create(1), OctetString::create($this->privateKey)]; + if (isset($this->namedCurve)) { + $elements[] = ExplicitlyTaggedType::create(0, ObjectIdentifier::create($this->namedCurve)); + } + if (isset($this->publicKey)) { + $elements[] = ExplicitlyTaggedType::create(1, BitString::create($this->publicKey)); + } + return Sequence::create(...$elements); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_EC_PRIVATE_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPublicKey.php new file mode 100644 index 000000000..5ff88773b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/EC/ECPublicKey.php @@ -0,0 +1,209 @@ +ecPoint = $ecPoint; + } + + public static function create(string $ecPoint, ?string $namedCurve = null): self + { + return new self($ecPoint, $namedCurve); + } + + /** + * Initialize from curve point coordinates. + * + * @param int|string $x X coordinate as a base10 number + * @param int|string $y Y coordinate as a base10 number + * @param null|string $named_curve Named curve OID + * @param null|int $bits Size of *p* in bits + */ + public static function fromCoordinates( + int|string $x, + int|string $y, + ?string $named_curve = null, + ?int $bits = null + ): self { + // if bitsize is not explicitly set, check from supported curves + if (! isset($bits) && isset($named_curve)) { + $bits = self::_curveSize($named_curve); + } + $mlen = null; + if (isset($bits)) { + $mlen = (int) ceil($bits / 8); + } + $x_os = ECConversion::integerToOctetString(Integer::create($x), $mlen)->string(); + $y_os = ECConversion::integerToOctetString(Integer::create($y), $mlen)->string(); + $ec_point = "\x4{$x_os}{$y_os}"; + return self::create($ec_point, $named_curve); + } + + /** + * @see PublicKey::fromPEM() + */ + public static function fromPEM(PEM $pem): self + { + if ($pem->type() !== PEM::TYPE_PUBLIC_KEY) { + throw new UnexpectedValueException('Not a public key.'); + } + $pki = PublicKeyInfo::fromDER($pem->data()); + $algo = $pki->algorithmIdentifier(); + if ($algo->oid() !== AlgorithmIdentifier::OID_EC_PUBLIC_KEY + || ! ($algo instanceof ECPublicKeyAlgorithmIdentifier)) { + throw new UnexpectedValueException('Not an elliptic curve key.'); + } + // ECPoint is directly mapped into public key data + return self::create($pki->publicKeyData()->string(), $algo->namedCurve()); + } + + /** + * Get ECPoint value. + */ + public function ECPoint(): string + { + return $this->ecPoint; + } + + /** + * Get curve point coordinates. + * + * @return string[] Tuple of X and Y coordinates as base-10 numbers + */ + public function curvePoint(): array + { + return array_map(static fn ($str) => ECConversion::octetsToNumber($str), $this->curvePointOctets()); + } + + /** + * Get curve point coordinates in octet string representation. + * + * @return string[] tuple of X and Y field elements as a string + */ + public function curvePointOctets(): array + { + if ($this->isCompressed()) { + throw new RuntimeException('EC point compression not supported.'); + } + $str = mb_substr($this->ecPoint, 1, null, '8bit'); + $length = (int) floor(mb_strlen($str, '8bit') / 2); + if ($length < 1) { + throw new RuntimeException('Invalid EC point.'); + } + [$x, $y] = mb_str_split($str, $length, '8bit'); + return [$x, $y]; + } + + /** + * Whether ECPoint is in compressed form. + */ + public function isCompressed(): bool + { + $c = ord($this->ecPoint[0]); + return $c !== 4; + } + + /** + * Whether named curve is present. + */ + public function hasNamedCurve(): bool + { + return isset($this->namedCurve); + } + + /** + * Get named curve OID. + */ + public function namedCurve(): string + { + if (! $this->hasNamedCurve()) { + throw new LogicException('namedCurve not set.'); + } + return $this->namedCurve; + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return ECPublicKeyAlgorithmIdentifier::create($this->namedCurve()); + } + + /** + * Generate ASN.1 element. + */ + public function toASN1(): OctetString + { + return OctetString::create($this->ecPoint); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * @see https://tools.ietf.org/html/rfc5480#section-2.2 + */ + public function subjectPublicKey(): BitString + { + // ECPoint is directly mapped to subjectPublicKey + return BitString::create($this->ecPoint); + } + + /** + * Get the curve size *p* in bits. + * + * @param string $oid Curve OID + */ + private static function _curveSize(string $oid): ?int + { + if (! array_key_exists($oid, ECPublicKeyAlgorithmIdentifier::MAP_CURVE_TO_SIZE)) { + return null; + } + return ECPublicKeyAlgorithmIdentifier::MAP_CURVE_TO_SIZE[$oid]; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/OneAsymmetricKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/OneAsymmetricKey.php new file mode 100644 index 000000000..f7f29bf00 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/OneAsymmetricKey.php @@ -0,0 +1,322 @@ +version = $version ?? self::VERSION_2; + } + + public static function create( + AlgorithmIdentifierType $algo, + string $privateKeyData, + ?OneAsymmetricKeyAttributes $attributes = null, + ?BitString $publicKeyData = null + ): self { + return new self($algo, $privateKeyData, $attributes, $publicKeyData); + } + + /** + * Get self with version number. + */ + public function withVersion(int $version): self + { + $obj = clone $this; + $obj->version = $version; + return $obj; + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): static + { + $version = $seq->at(0) + ->asInteger() + ->intNumber(); + if (! in_array($version, [self::VERSION_1, self::VERSION_2], true)) { + throw new UnexpectedValueException("Version {$version} not supported."); + } + $algo = AlgorithmIdentifier::fromASN1($seq->at(1)->asSequence()); + $key = $seq->at(2) + ->asOctetString() + ->string(); + $attribs = null; + if ($seq->hasTagged(0)) { + $attribs = OneAsymmetricKeyAttributes::fromASN1($seq->getTagged(0) + ->asImplicit(Element::TYPE_SET)->asSet()); + } + $pubkey = null; + if ($seq->hasTagged(1)) { + $pubkey = $seq->getTagged(1) + ->asImplicit(Element::TYPE_BIT_STRING)->asBitString(); + } + return static::create($algo, $key, $attribs, $pubkey)->withVersion($version); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): static + { + return static::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Initialize from a `PrivateKey`. + * + * Note that `OneAsymmetricKey` <-> `PrivateKey` conversions may not be bidirectional with all key types, since + * `OneAsymmetricKey` may include attributes as well the public key that are not conveyed in a specific `PrivateKey` + * object. + */ + public static function fromPrivateKey(PrivateKey $private_key): static + { + return static::create($private_key->algorithmIdentifier(), $private_key->privateKeyData()); + } + + /** + * Initialize from PEM. + */ + public static function fromPEM(PEM $pem): self + { + return match ($pem->type()) { + PEM::TYPE_PRIVATE_KEY => self::fromDER($pem->data()), + PEM::TYPE_RSA_PRIVATE_KEY => self::fromPrivateKey(RSAPrivateKey::fromDER($pem->data())), + PEM::TYPE_EC_PRIVATE_KEY => self::fromPrivateKey(ECPrivateKey::fromDER($pem->data())), + default => throw new UnexpectedValueException('Invalid PEM type.'), + }; + } + + /** + * Get version number. + */ + public function version(): int + { + return $this->version; + } + + /** + * Get algorithm identifier. + */ + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return $this->algo; + } + + /** + * Get private key data. + */ + public function privateKeyData(): string + { + return $this->privateKeyData; + } + + /** + * Get private key. + */ + public function privateKey(): PrivateKey + { + $algo = $this->algorithmIdentifier(); + switch ($algo->oid()) { + // RSA + case AlgorithmIdentifier::OID_RSA_ENCRYPTION: + return RSAPrivateKey::fromDER($this->privateKeyData); + // RSASSA-PSS + case AlgorithmIdentifier::OID_RSASSA_PSS_ENCRYPTION: + return RSASSAPSSPrivateKey::fromDER($this->privateKeyData); + // elliptic curve + case AlgorithmIdentifier::OID_EC_PUBLIC_KEY: + $pk = ECPrivateKey::fromDER($this->privateKeyData); + // NOTE: OpenSSL strips named curve from ECPrivateKey structure + // when serializing into PrivateKeyInfo. However, RFC 5915 dictates + // that parameters (NamedCurve) must always be included. + // If private key doesn't encode named curve, assign from parameters. + if (! $pk->hasNamedCurve()) { + if (! $algo instanceof ECPublicKeyAlgorithmIdentifier) { + throw new UnexpectedValueException('Not an EC algorithm.'); + } + $pk = $pk->withNamedCurve($algo->namedCurve()); + } + return $pk; + // Ed25519 + case AlgorithmIdentifier::OID_ED25519: + $pubkey = $this->publicKeyData?->string(); + // RFC 8410 defines `CurvePrivateKey ::= OCTET STRING` that + // is encoded into private key data. So Ed25519 private key + // is doubly wrapped into octet string encodings. + return Ed25519PrivateKey::fromOctetString(OctetString::fromDER($this->privateKeyData), $pubkey) + ->withVersion($this->version) + ->withAttributes($this->attributes); + // X25519 + case AlgorithmIdentifier::OID_X25519: + $pubkey = $this->publicKeyData?->string(); + return X25519PrivateKey::fromOctetString(OctetString::fromDER($this->privateKeyData), $pubkey) + ->withVersion($this->version) + ->withAttributes($this->attributes); + // Ed448 + case AlgorithmIdentifier::OID_ED448: + $pubkey = $this->publicKeyData?->string(); + return Ed448PrivateKey::fromOctetString(OctetString::fromDER($this->privateKeyData), $pubkey) + ->withVersion($this->version) + ->withAttributes($this->attributes); + // X448 + case AlgorithmIdentifier::OID_X448: + $pubkey = $this->publicKeyData?->string(); + return X448PrivateKey::fromOctetString(OctetString::fromDER($this->privateKeyData), $pubkey) + ->withVersion($this->version) + ->withAttributes($this->attributes); + default: + throw new RuntimeException('Private key ' . $algo->name() . ' not supported.'); + } + } + + /** + * Get public key info corresponding to the private key. + */ + public function publicKeyInfo(): PublicKeyInfo + { + // if public key is explicitly defined + if ($this->hasPublicKeyData()) { + return PublicKeyInfo::create($this->algo, $this->publicKeyData); + } + // else derive from private key + return $this->privateKey() + ->publicKey() + ->publicKeyInfo(); + } + + /** + * Whether attributes are present. + */ + public function hasAttributes(): bool + { + return isset($this->attributes); + } + + public function attributes(): OneAsymmetricKeyAttributes + { + if (! $this->hasAttributes()) { + throw new LogicException('Attributes not set.'); + } + return $this->attributes; + } + + /** + * Whether explicit public key data is present. + */ + public function hasPublicKeyData(): bool + { + return isset($this->publicKeyData); + } + + /** + * Get the explicit public key data. + */ + public function publicKeyData(): BitString + { + if (! $this->hasPublicKeyData()) { + throw new LogicException('No explicit public key.'); + } + return $this->publicKeyData; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [ + Integer::create($this->version), + $this->algo->toASN1(), + OctetString::create($this->privateKeyData), + ]; + if ($this->attributes !== null) { + $elements[] = ImplicitlyTaggedType::create(0, $this->attributes->toASN1()); + } + if ($this->publicKeyData !== null) { + $elements[] = ImplicitlyTaggedType::create(1, $this->publicKeyData); + } + return Sequence::create(...$elements); + } + + /** + * Generate DER encoding. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Generate PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_PRIVATE_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKey.php new file mode 100644 index 000000000..4208286ad --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKey.php @@ -0,0 +1,71 @@ +toDER(); + } + + /** + * Get the private key as a PrivateKeyInfo type. + */ + public function privateKeyInfo(): PrivateKeyInfo + { + return PrivateKeyInfo::fromPrivateKey($this); + } + + /** + * Initialize private key from PEM. + * + * @return PrivateKey + */ + public static function fromPEM(PEM $pem) + { + return match ($pem->type()) { + PEM::TYPE_RSA_PRIVATE_KEY => RSAPrivateKey::fromDER($pem->data()), + PEM::TYPE_EC_PRIVATE_KEY => ECPrivateKey::fromDER($pem->data()), + PEM::TYPE_PRIVATE_KEY => PrivateKeyInfo::fromDER($pem->data())->privateKey(), + default => throw new UnexpectedValueException('PEM type ' . $pem->type() . ' is not a valid private key.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKeyInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKeyInfo.php new file mode 100644 index 000000000..9ed65b147 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PrivateKeyInfo.php @@ -0,0 +1,31 @@ +toDER()); + } + + /** + * Get the public key as a PublicKeyInfo type. + */ + public function publicKeyInfo(): PublicKeyInfo + { + return PublicKeyInfo::fromPublicKey($this); + } + + /** + * Initialize public key from PEM. + * + * @return PublicKey + */ + public static function fromPEM(PEM $pem) + { + return match ($pem->type()) { + PEM::TYPE_RSA_PUBLIC_KEY => RSAPublicKey::fromDER($pem->data()), + PEM::TYPE_PUBLIC_KEY => PublicKeyInfo::fromPEM($pem)->publicKey(), + default => throw new UnexpectedValueException('PEM type ' . $pem->type() . ' is not a valid public key.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PublicKeyInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PublicKeyInfo.php new file mode 100644 index 000000000..ce92b2ed2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/PublicKeyInfo.php @@ -0,0 +1,186 @@ +at(0)->asSequence()); + $key = $seq->at(1) + ->asBitString(); + return self::create($algo, $key); + } + + /** + * Initialize from a PublicKey. + */ + public static function fromPublicKey(PublicKey $key): self + { + return self::create($key->algorithmIdentifier(), $key->subjectPublicKey()); + } + + /** + * Initialize from PEM. + */ + public static function fromPEM(PEM $pem): self + { + return match ($pem->type()) { + PEM::TYPE_PUBLIC_KEY => self::fromDER($pem->data()), + PEM::TYPE_RSA_PUBLIC_KEY => RSAPublicKey::fromDER($pem->data())->publicKeyInfo(), + default => throw new UnexpectedValueException('Invalid PEM type.'), + }; + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Get algorithm identifier. + */ + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return $this->algo; + } + + /** + * Get public key data. + */ + public function publicKeyData(): BitString + { + return $this->publicKey; + } + + /** + * Get public key. + */ + public function publicKey(): PublicKey + { + $algo = $this->algorithmIdentifier(); + switch ($algo->oid()) { + // RSA + case AlgorithmIdentifier::OID_RSA_ENCRYPTION: + return RSAPublicKey::fromDER($this->publicKey->string()); + // Elliptic Curve + case AlgorithmIdentifier::OID_EC_PUBLIC_KEY: + if (! $algo instanceof ECPublicKeyAlgorithmIdentifier) { + throw new UnexpectedValueException('Not an EC algorithm.'); + } + // ECPoint is directly mapped into public key data + return ECPublicKey::create($this->publicKey->string(), $algo->namedCurve()); + // Ed25519 + case AlgorithmIdentifier::OID_ED25519: + return Ed25519PublicKey::create($this->publicKey->string()); + // X25519 + case AlgorithmIdentifier::OID_X25519: + return X25519PublicKey::create($this->publicKey->string()); + // Ed448 + case AlgorithmIdentifier::OID_ED448: + return Ed448PublicKey::create($this->publicKey->string()); + // X448 + case AlgorithmIdentifier::OID_X448: + return X448PublicKey::create($this->publicKey->string()); + } + throw new RuntimeException('Public key ' . $algo->name() . ' not supported.'); + } + + /** + * Get key identifier using method 1 as described by RFC 5280. + * + * @see https://tools.ietf.org/html/rfc5280#section-4.2.1.2 + * + * @return string 20 bytes (160 bits) long identifier + */ + public function keyIdentifier(): string + { + return sha1($this->publicKey->string(), true); + } + + /** + * Get key identifier using method 2 as described by RFC 5280. + * + * @see https://tools.ietf.org/html/rfc5280#section-4.2.1.2 + * + * @return string 8 bytes (64 bits) long identifier + */ + public function keyIdentifier64(): string + { + $id = mb_substr($this->keyIdentifier(), -8, null, '8bit'); + $c = (ord($id[0]) & 0x0f) | 0x40; + $id[0] = chr($c); + return $id; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create($this->algo->toASN1(), $this->publicKey); + } + + /** + * Generate DER encoding. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Generate PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_PUBLIC_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Curve25519PrivateKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Curve25519PrivateKey.php new file mode 100644 index 000000000..606f61209 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Curve25519PrivateKey.php @@ -0,0 +1,32 @@ +string(), $public_key); + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return Ed25519AlgorithmIdentifier::create(); + } + + public function publicKey(): PublicKey + { + if (! $this->hasPublicKey()) { + throw new LogicException('Public key not set.'); + } + return Ed25519PublicKey::create($this->_publicKeyData); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Ed25519PublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Ed25519PublicKey.php new file mode 100644 index 000000000..41eb7685d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/Ed25519PublicKey.php @@ -0,0 +1,26 @@ +string(), $public_key); + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return X25519AlgorithmIdentifier::create(); + } + + public function publicKey(): PublicKey + { + if (! $this->hasPublicKey()) { + throw new LogicException('Public key not set.'); + } + return X25519PublicKey::create($this->_publicKeyData); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/X25519PublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/X25519PublicKey.php new file mode 100644 index 000000000..95cad2a25 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve25519/X25519PublicKey.php @@ -0,0 +1,26 @@ +string(), $public_key); + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return Ed448AlgorithmIdentifier::create(); + } + + public function publicKey(): PublicKey + { + if (! $this->hasPublicKey()) { + throw new LogicException('Public key not set.'); + } + return Ed448PublicKey::create($this->_publicKeyData); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/Ed448PublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/Ed448PublicKey.php new file mode 100644 index 000000000..d106c4f29 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/Ed448PublicKey.php @@ -0,0 +1,40 @@ +string(), $public_key); + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return X448AlgorithmIdentifier::create(); + } + + public function publicKey(): PublicKey + { + if (! $this->hasPublicKey()) { + throw new LogicException('Public key not set.'); + } + return X448PublicKey::create($this->_publicKeyData); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/X448PublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/X448PublicKey.php new file mode 100644 index 000000000..6d668075b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/Curve448/X448PublicKey.php @@ -0,0 +1,40 @@ +_version = OneAsymmetricKey::VERSION_2; + $this->_attributes = null; + } + + /** + * Get self with version number. + */ + public function withVersion(int $version): self + { + $obj = clone $this; + $obj->_version = $version; + return $obj; + } + + /** + * Get self with attributes. + */ + public function withAttributes(?OneAsymmetricKeyAttributes $attribs): self + { + $obj = clone $this; + $obj->_attributes = $attribs; + return $obj; + } + + public function privateKeyData(): string + { + return $this->_privateKeyData; + } + + /** + * Whether public key is set. + */ + public function hasPublicKey(): bool + { + return isset($this->_publicKeyData); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): OctetString + { + return OctetString::create($this->_privateKeyData); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + public function toPEM(): PEM + { + $pub = $this->_publicKeyData === null ? null : + BitString::create($this->_publicKeyData); + + return OneAsymmetricKey::create($this->algorithmIdentifier(), $this->toDER(), $this->_attributes, $pub) + ->withVersion($this->_version) + ->toPEM(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/RFC8410PublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/RFC8410PublicKey.php new file mode 100644 index 000000000..ceec70b36 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RFC8410/RFC8410PublicKey.php @@ -0,0 +1,37 @@ +publicKey); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPrivateKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPrivateKey.php new file mode 100644 index 000000000..cd98166a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPrivateKey.php @@ -0,0 +1,226 @@ +at(0) + ->asInteger() + ->intNumber(); + if ($version !== 0) { + throw new UnexpectedValueException('Version must be 0.'); + } + // helper function get integer from given index + $get_int = static fn ($idx) => $seq->at($idx) + ->asInteger() + ->number(); + $n = $get_int(1); + $e = $get_int(2); + $d = $get_int(3); + $p = $get_int(4); + $q = $get_int(5); + $dp = $get_int(6); + $dq = $get_int(7); + $qi = $get_int(8); + return self::create($n, $e, $d, $p, $q, $dp, $dq, $qi); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * @see PrivateKey::fromPEM() + */ + public static function fromPEM(PEM $pem): self + { + $pk = parent::fromPEM($pem); + if (! ($pk instanceof self)) { + throw new UnexpectedValueException('Not an RSA private key.'); + } + return $pk; + } + + /** + * Get modulus. + * + * @return string Base 10 integer + */ + public function modulus(): string + { + return $this->modulus; + } + + /** + * Get public exponent. + * + * @return string Base 10 integer + */ + public function publicExponent(): string + { + return $this->publicExponent; + } + + /** + * Get private exponent. + * + * @return string Base 10 integer + */ + public function privateExponent(): string + { + return $this->privateExponent; + } + + /** + * Get first prime factor. + * + * @return string Base 10 integer + */ + public function prime1(): string + { + return $this->prime1; + } + + /** + * Get second prime factor. + * + * @return string Base 10 integer + */ + public function prime2(): string + { + return $this->prime2; + } + + /** + * Get first factor exponent. + * + * @return string Base 10 integer + */ + public function exponent1(): string + { + return $this->exponent1; + } + + /** + * Get second factor exponent. + * + * @return string Base 10 integer + */ + public function exponent2(): string + { + return $this->exponent2; + } + + /** + * Get CRT coefficient of the second factor. + * + * @return string Base 10 integer + */ + public function coefficient(): string + { + return $this->coefficient; + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return RSAEncryptionAlgorithmIdentifier::create(); + } + + /** + * @return RSAPublicKey + */ + public function publicKey(): PublicKey + { + return RSAPublicKey::create($this->modulus, $this->publicExponent); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + Integer::create(0), + Integer::create($this->modulus), + Integer::create($this->publicExponent), + Integer::create($this->privateExponent), + Integer::create($this->prime1), + Integer::create($this->prime2), + Integer::create($this->exponent1), + Integer::create($this->exponent2), + Integer::create($this->coefficient) + ); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_RSA_PRIVATE_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPublicKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPublicKey.php new file mode 100644 index 000000000..86f0c1ac0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSAPublicKey.php @@ -0,0 +1,124 @@ +at(0) + ->asInteger() + ->number(); + $e = $seq->at(1) + ->asInteger() + ->number(); + return self::create($n, $e); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * @see PublicKey::fromPEM() + */ + public static function fromPEM(PEM $pem): self + { + switch ($pem->type()) { + case PEM::TYPE_RSA_PUBLIC_KEY: + return self::fromDER($pem->data()); + case PEM::TYPE_PUBLIC_KEY: + $pki = PublicKeyInfo::fromDER($pem->data()); + if ($pki->algorithmIdentifier() + ->oid() !== + AlgorithmIdentifier::OID_RSA_ENCRYPTION) { + throw new UnexpectedValueException('Not an RSA public key.'); + } + return self::fromDER($pki->publicKeyData()->string()); + } + throw new UnexpectedValueException('Invalid PEM type ' . $pem->type()); + } + + /** + * Get modulus. + * + * @return string Base 10 integer + */ + public function modulus(): string + { + return $this->modulus; + } + + /** + * Get public exponent. + * + * @return string Base 10 integer + */ + public function publicExponent(): string + { + return $this->publicExponent; + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return RSAEncryptionAlgorithmIdentifier::create(); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create(Integer::create($this->modulus), Integer::create($this->publicExponent)); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Generate PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_RSA_PUBLIC_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSASSAPSSPrivateKey.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSASSAPSSPrivateKey.php new file mode 100644 index 000000000..89703e85b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Asymmetric/RSA/RSASSAPSSPrivateKey.php @@ -0,0 +1,226 @@ +at(0) + ->asInteger() + ->intNumber(); + if ($version !== 0) { + throw new UnexpectedValueException('Version must be 0.'); + } + // helper function get integer from given index + $get_int = static fn ($idx) => $seq->at($idx) + ->asInteger() + ->number(); + $n = $get_int(1); + $e = $get_int(2); + $d = $get_int(3); + $p = $get_int(4); + $q = $get_int(5); + $dp = $get_int(6); + $dq = $get_int(7); + $qi = $get_int(8); + return self::create($n, $e, $d, $p, $q, $dp, $dq, $qi); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * @see PrivateKey::fromPEM() + */ + public static function fromPEM(PEM $pem): self + { + $pk = parent::fromPEM($pem); + if (! ($pk instanceof self)) { + throw new UnexpectedValueException('Not an RSA private key.'); + } + return $pk; + } + + /** + * Get modulus. + * + * @return string Base 10 integer + */ + public function modulus(): string + { + return $this->modulus; + } + + /** + * Get public exponent. + * + * @return string Base 10 integer + */ + public function publicExponent(): string + { + return $this->publicExponent; + } + + /** + * Get private exponent. + * + * @return string Base 10 integer + */ + public function privateExponent(): string + { + return $this->privateExponent; + } + + /** + * Get first prime factor. + * + * @return string Base 10 integer + */ + public function prime1(): string + { + return $this->prime1; + } + + /** + * Get second prime factor. + * + * @return string Base 10 integer + */ + public function prime2(): string + { + return $this->prime2; + } + + /** + * Get first factor exponent. + * + * @return string Base 10 integer + */ + public function exponent1(): string + { + return $this->exponent1; + } + + /** + * Get second factor exponent. + * + * @return string Base 10 integer + */ + public function exponent2(): string + { + return $this->exponent2; + } + + /** + * Get CRT coefficient of the second factor. + * + * @return string Base 10 integer + */ + public function coefficient(): string + { + return $this->coefficient; + } + + public function algorithmIdentifier(): AlgorithmIdentifierType + { + return RSAPSSSSAEncryptionAlgorithmIdentifier::create(); + } + + /** + * @return RSAPublicKey + */ + public function publicKey(): PublicKey + { + return RSAPublicKey::create($this->modulus, $this->publicExponent); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + Integer::create(0), + Integer::create($this->modulus), + Integer::create($this->publicExponent), + Integer::create($this->privateExponent), + Integer::create($this->prime1), + Integer::create($this->prime2), + Integer::create($this->exponent1), + Integer::create($this->exponent2), + Integer::create($this->coefficient) + ); + } + + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_PRIVATE_KEY, $this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/ECSignature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/ECSignature.php new file mode 100644 index 000000000..d9b4d0dd6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/ECSignature.php @@ -0,0 +1,95 @@ +at(0) + ->asInteger() + ->number(); + $s = $seq->at(1) + ->asInteger() + ->number(); + return self::create($r, $s); + } + + /** + * Initialize from DER. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Get the r-value. + * + * @return string Base 10 integer string + */ + public function r(): string + { + return $this->r; + } + + /** + * Get the s-value. + * + * @return string Base 10 integer string + */ + public function s(): string + { + return $this->s; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create(Integer::create($this->r), Integer::create($this->s)); + } + + /** + * Get DER encoding of the signature. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + public function bitString(): BitString + { + return BitString::create($this->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed25519Signature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed25519Signature.php new file mode 100644 index 000000000..3a4776680 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed25519Signature.php @@ -0,0 +1,42 @@ +signature = $signature; + } + + public static function create(string $signature): self + { + return new self($signature); + } + + public function bitString(): BitString + { + return BitString::create($this->signature); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed448Signature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed448Signature.php new file mode 100644 index 000000000..263249109 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Ed448Signature.php @@ -0,0 +1,42 @@ +signature = $signature; + } + + public static function create(string $signature): self + { + return new self($signature); + } + + public function bitString(): BitString + { + return BitString::create($this->signature); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/GenericSignature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/GenericSignature.php new file mode 100644 index 000000000..9487f6f11 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/GenericSignature.php @@ -0,0 +1,42 @@ +signatureAlgorithm; + } + + public function bitString(): BitString + { + return $this->signature; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/RSASignature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/RSASignature.php new file mode 100644 index 000000000..61c08c596 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/RSASignature.php @@ -0,0 +1,50 @@ +_signature = strval($signature); + return $obj; + } + + public function bitString(): BitString + { + return BitString::create($this->_signature); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Signature.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Signature.php new file mode 100644 index 000000000..c164b8cc6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/CryptoTypes/Signature/Signature.php @@ -0,0 +1,46 @@ +oid() !== $type->oid()) { + throw new LogicException('Attribute OID mismatch.'); + } + } + $this->type = $type; + $this->values = $values; + } + + public static function create(AttributeType $type, AttributeValue ...$values): self + { + return new self($type, ...$values); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $type = AttributeType::fromASN1($seq->at(0)->asObjectIdentifier()); + $values = array_map( + static fn (UnspecifiedType $el) => AttributeValue::fromASN1ByOID($type->oid(), $el), + $seq->at(1) + ->asSet() + ->elements() + ); + return self::create($type, ...$values); + } + + /** + * Convenience method to initialize from attribute values. + * + * @param AttributeValue ...$values One or more values + */ + public static function fromAttributeValues(AttributeValue ...$values): self + { + // we need at least one value to determine OID + if (count($values) === 0) { + throw new LogicException('No values.'); + } + $oid = reset($values) + ->oid(); + return self::create(AttributeType::create($oid), ...$values); + } + + /** + * Get first value of the attribute. + */ + public function first(): AttributeValue + { + if (count($this->values) === 0) { + throw new LogicException('Attribute contains no values.'); + } + return $this->values[0]; + } + + /** + * Get all values. + * + * @return AttributeValue[] + */ + public function values(): array + { + return $this->values; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $values = array_map(static fn (AttributeValue $value) => $value->toASN1(), $this->values); + $valueset = Set::create(...$values); + return Sequence::create($this->type->toASN1(), $valueset->sortedSetOf()); + } + + /** + * Cast attribute values to another AttributeValue class. + * + * This method is generally used to cast UnknownAttributeValue values to specific objects when class is declared + * outside this package. + * + * The new class must be derived from AttributeValue and have the same OID as current attribute values. + * + * @param string $cls AttributeValue class name + */ + public function castValues(string $cls): self + { + // check that target class derives from AttributeValue + if (! is_subclass_of($cls, AttributeValue::class)) { + throw new LogicException(sprintf('%s must be derived from %s.', $cls, AttributeValue::class)); + } + $values = array_map( + function (AttributeValue $value) use ($cls) { + /** @var AttributeValue $cls Class name as a string */ + $value = $cls::fromSelf($value); + if ($value->oid() !== $this->oid()) { + throw new LogicException('Attribute OID mismatch.'); + } + return $value; + }, + $this->values + ); + return self::fromAttributeValues(...$values); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->values); + } + + /** + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->values); + } + + /** + * Get attribute type. + */ + public function type(): AttributeType + { + return $this->type; + } + + /** + * Get OID of the attribute. + */ + public function oid(): string + { + return $this->type->oid(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeType.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeType.php new file mode 100644 index 000000000..adde42782 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeType.php @@ -0,0 +1,525 @@ + + */ + private const MAP_ATTR_TO_STR_TYPE = [ + self::OID_DN_QUALIFIER => Element::TYPE_PRINTABLE_STRING, + self::OID_COUNTRY_NAME => Element::TYPE_PRINTABLE_STRING, + self::OID_SERIAL_NUMBER => Element::TYPE_PRINTABLE_STRING, + ]; + + /** + * OID to attribute names mapping. + * + * First name is the primary name. If there's more than one name, others may be used as an alias. + * + * Generated using ldap-attribs.py. + * + * @internal + * + * @var array> + */ + private const MAP_OID_TO_NAME = [ + '0.9.2342.19200300.100.1.1' => ['uid', 'userid'], + '0.9.2342.19200300.100.1.2' => ['textEncodedORAddress'], + '0.9.2342.19200300.100.1.3' => ['mail', 'rfc822Mailbox'], + '0.9.2342.19200300.100.1.4' => ['info'], + '0.9.2342.19200300.100.1.5' => ['drink', 'favouriteDrink'], + '0.9.2342.19200300.100.1.6' => ['roomNumber'], + '0.9.2342.19200300.100.1.7' => ['photo'], + '0.9.2342.19200300.100.1.8' => ['userClass'], + '0.9.2342.19200300.100.1.9' => ['host'], + '0.9.2342.19200300.100.1.10' => ['manager'], + '0.9.2342.19200300.100.1.11' => ['documentIdentifier'], + '0.9.2342.19200300.100.1.12' => ['documentTitle'], + '0.9.2342.19200300.100.1.13' => ['documentVersion'], + '0.9.2342.19200300.100.1.14' => ['documentAuthor'], + '0.9.2342.19200300.100.1.15' => ['documentLocation'], + '0.9.2342.19200300.100.1.20' => ['homePhone', 'homeTelephoneNumber'], + '0.9.2342.19200300.100.1.21' => ['secretary'], + '0.9.2342.19200300.100.1.22' => ['otherMailbox'], + '0.9.2342.19200300.100.1.25' => ['dc', 'domainComponent'], + '0.9.2342.19200300.100.1.26' => ['aRecord'], + '0.9.2342.19200300.100.1.27' => ['mDRecord'], + '0.9.2342.19200300.100.1.28' => ['mXRecord'], + '0.9.2342.19200300.100.1.29' => ['nSRecord'], + '0.9.2342.19200300.100.1.30' => ['sOARecord'], + '0.9.2342.19200300.100.1.31' => ['cNAMERecord'], + '0.9.2342.19200300.100.1.37' => ['associatedDomain'], + '0.9.2342.19200300.100.1.38' => ['associatedName'], + '0.9.2342.19200300.100.1.39' => ['homePostalAddress'], + '0.9.2342.19200300.100.1.40' => ['personalTitle'], + '0.9.2342.19200300.100.1.41' => ['mobile', 'mobileTelephoneNumber'], + '0.9.2342.19200300.100.1.42' => ['pager', 'pagerTelephoneNumber'], + '0.9.2342.19200300.100.1.43' => ['co', 'friendlyCountryName'], + '0.9.2342.19200300.100.1.44' => ['uniqueIdentifier'], + '0.9.2342.19200300.100.1.45' => ['organizationalStatus'], + '0.9.2342.19200300.100.1.46' => ['janetMailbox'], + '0.9.2342.19200300.100.1.47' => ['mailPreferenceOption'], + '0.9.2342.19200300.100.1.48' => ['buildingName'], + '0.9.2342.19200300.100.1.49' => ['dSAQuality'], + '0.9.2342.19200300.100.1.50' => ['singleLevelQuality'], + '0.9.2342.19200300.100.1.51' => ['subtreeMinimumQuality'], + '0.9.2342.19200300.100.1.52' => ['subtreeMaximumQuality'], + '0.9.2342.19200300.100.1.53' => ['personalSignature'], + '0.9.2342.19200300.100.1.54' => ['dITRedirect'], + '0.9.2342.19200300.100.1.55' => ['audio'], + '0.9.2342.19200300.100.1.56' => ['documentPublisher'], + '0.9.2342.19200300.100.1.60' => ['jpegPhoto'], + '1.2.840.113549.1.9.1' => ['email', 'emailAddress', 'pkcs9email'], + '1.2.840.113556.1.2.102' => ['memberOf'], + '1.3.6.1.1.1.1.0' => ['uidNumber'], + '1.3.6.1.1.1.1.1' => ['gidNumber'], + '1.3.6.1.1.1.1.2' => ['gecos'], + '1.3.6.1.1.1.1.3' => ['homeDirectory'], + '1.3.6.1.1.1.1.4' => ['loginShell'], + '1.3.6.1.1.1.1.5' => ['shadowLastChange'], + '1.3.6.1.1.1.1.6' => ['shadowMin'], + '1.3.6.1.1.1.1.7' => ['shadowMax'], + '1.3.6.1.1.1.1.8' => ['shadowWarning'], + '1.3.6.1.1.1.1.9' => ['shadowInactive'], + '1.3.6.1.1.1.1.10' => ['shadowExpire'], + '1.3.6.1.1.1.1.11' => ['shadowFlag'], + '1.3.6.1.1.1.1.12' => ['memberUid'], + '1.3.6.1.1.1.1.13' => ['memberNisNetgroup'], + '1.3.6.1.1.1.1.14' => ['nisNetgroupTriple'], + '1.3.6.1.1.1.1.15' => ['ipServicePort'], + '1.3.6.1.1.1.1.16' => ['ipServiceProtocol'], + '1.3.6.1.1.1.1.17' => ['ipProtocolNumber'], + '1.3.6.1.1.1.1.18' => ['oncRpcNumber'], + '1.3.6.1.1.1.1.19' => ['ipHostNumber'], + '1.3.6.1.1.1.1.20' => ['ipNetworkNumber'], + '1.3.6.1.1.1.1.21' => ['ipNetmaskNumber'], + '1.3.6.1.1.1.1.22' => ['macAddress'], + '1.3.6.1.1.1.1.23' => ['bootParameter'], + '1.3.6.1.1.1.1.24' => ['bootFile'], + '1.3.6.1.1.1.1.26' => ['nisMapName'], + '1.3.6.1.1.1.1.27' => ['nisMapEntry'], + '1.3.6.1.1.4' => ['vendorName'], + '1.3.6.1.1.5' => ['vendorVersion'], + '1.3.6.1.1.16.4' => ['entryUUID'], + '1.3.6.1.1.20' => ['entryDN'], + '2.5.4.0' => ['objectClass'], + '2.5.4.1' => ['aliasedObjectName', 'aliasedEntryName'], + '2.5.4.2' => ['knowledgeInformation'], + '2.5.4.3' => ['cn', 'commonName'], + '2.5.4.4' => ['sn', 'surname'], + '2.5.4.5' => ['serialNumber'], + '2.5.4.6' => ['c', 'countryName'], + '2.5.4.7' => ['l', 'localityName'], + '2.5.4.8' => ['st', 'stateOrProvinceName'], + '2.5.4.9' => ['street', 'streetAddress'], + '2.5.4.10' => ['o', 'organizationName'], + '2.5.4.11' => ['ou', 'organizationalUnitName'], + '2.5.4.12' => ['title'], + '2.5.4.13' => ['description'], + '2.5.4.14' => ['searchGuide'], + '2.5.4.15' => ['businessCategory'], + '2.5.4.16' => ['postalAddress'], + '2.5.4.17' => ['postalCode'], + '2.5.4.18' => ['postOfficeBox'], + '2.5.4.19' => ['physicalDeliveryOfficeName'], + '2.5.4.20' => ['telephoneNumber'], + '2.5.4.21' => ['telexNumber'], + '2.5.4.22' => ['teletexTerminalIdentifier'], + '2.5.4.23' => ['facsimileTelephoneNumber', 'fax'], + '2.5.4.24' => ['x121Address'], + '2.5.4.25' => ['internationaliSDNNumber'], + '2.5.4.26' => ['registeredAddress'], + '2.5.4.27' => ['destinationIndicator'], + '2.5.4.28' => ['preferredDeliveryMethod'], + '2.5.4.29' => ['presentationAddress'], + '2.5.4.30' => ['supportedApplicationContext'], + '2.5.4.31' => ['member'], + '2.5.4.32' => ['owner'], + '2.5.4.33' => ['roleOccupant'], + '2.5.4.34' => ['seeAlso'], + '2.5.4.35' => ['userPassword'], + '2.5.4.36' => ['userCertificate'], + '2.5.4.37' => ['cACertificate'], + '2.5.4.38' => ['authorityRevocationList'], + '2.5.4.39' => ['certificateRevocationList'], + '2.5.4.40' => ['crossCertificatePair'], + '2.5.4.41' => ['name'], + '2.5.4.42' => ['givenName', 'gn'], + '2.5.4.43' => ['initials'], + '2.5.4.44' => ['generationQualifier'], + '2.5.4.45' => ['x500UniqueIdentifier'], + '2.5.4.46' => ['dnQualifier'], + '2.5.4.47' => ['enhancedSearchGuide'], + '2.5.4.48' => ['protocolInformation'], + '2.5.4.49' => ['distinguishedName'], + '2.5.4.50' => ['uniqueMember'], + '2.5.4.51' => ['houseIdentifier'], + '2.5.4.52' => ['supportedAlgorithms'], + '2.5.4.53' => ['deltaRevocationList'], + '2.5.4.54' => ['dmdName'], + '2.5.4.65' => ['pseudonym'], + '2.5.18.1' => ['createTimestamp'], + '2.5.18.2' => ['modifyTimestamp'], + '2.5.18.3' => ['creatorsName'], + '2.5.18.4' => ['modifiersName'], + '2.5.18.5' => ['administrativeRole'], + '2.5.18.6' => ['subtreeSpecification'], + '2.5.18.9' => ['hasSubordinates'], + '2.5.18.10' => ['subschemaSubentry'], + '2.5.21.1' => ['dITStructureRules'], + '2.5.21.2' => ['dITContentRules'], + '2.5.21.4' => ['matchingRules'], + '2.5.21.5' => ['attributeTypes'], + '2.5.21.6' => ['objectClasses'], + '2.5.21.7' => ['nameForms'], + '2.5.21.8' => ['matchingRuleUse'], + '2.5.21.9' => ['structuralObjectClass'], + '2.16.840.1.113730.3.1.1' => ['carLicense'], + '2.16.840.1.113730.3.1.2' => ['departmentNumber'], + '2.16.840.1.113730.3.1.3' => ['employeeNumber'], + '2.16.840.1.113730.3.1.4' => ['employeeType'], + '2.16.840.1.113730.3.1.34' => ['ref'], + '2.16.840.1.113730.3.1.39' => ['preferredLanguage'], + '2.16.840.1.113730.3.1.40' => ['userSMIMECertificate'], + '2.16.840.1.113730.3.1.216' => ['userPKCS12'], + '2.16.840.1.113730.3.1.241' => ['displayName'], + ]; + + /** + * @param string $_oid OID in dotted format + */ + private function __construct( + protected string $_oid + ) { + } + + public static function create(string $oid): self + { + return new self($oid); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(ObjectIdentifier $oi): self + { + return self::create($oi->oid()); + } + + /** + * Initialize from attribute name. + */ + public static function fromName(string $name): self + { + $oid = self::attrNameToOID($name); + return self::create($oid); + } + + /** + * Get OID of the attribute. + * + * @return string OID in dotted format + */ + public function oid(): string + { + return $this->_oid; + } + + /** + * Get name of the attribute. + */ + public function typeName(): string + { + if (array_key_exists($this->_oid, self::MAP_OID_TO_NAME)) { + return self::MAP_OID_TO_NAME[$this->_oid][0]; + } + return $this->_oid; + } + + /** + * Generate ASN.1 element. + */ + public function toASN1(): ObjectIdentifier + { + return ObjectIdentifier::create($this->_oid); + } + + /** + * Convert attribute name to OID. + * + * @param string $name Primary attribute name or an alias + * + * @return string OID in dotted format + */ + public static function attrNameToOID(string $name): string + { + // if already in OID form + if (preg_match('/^[0-9]+(?:\.[0-9]+)*$/', $name) === 1) { + return $name; + } + $map = self::_oidReverseMap(); + $k = mb_strtolower($name, '8bit'); + if (! isset($map[$k])) { + throw new OutOfBoundsException("No OID for {$name}."); + } + return $map[$k]; + } + + /** + * Get ASN.1 string for given attribute type. + * + * @param string $oid Attribute OID + * @param string $str String + */ + public static function asn1StringForType(string $oid, string $str): StringType + { + if (! array_key_exists($oid, self::MAP_ATTR_TO_STR_TYPE)) { + return UTF8String::create($str); + } + return PrintableString::create($str); + } + + /** + * Get name to OID lookup map. + * + * @return array + */ + private static function _oidReverseMap(): array + { + static $map; + if (! isset($map)) { + $map = []; + // for each attribute type + foreach (self::MAP_OID_TO_NAME as $oid => $names) { + // for primary name and aliases + foreach ($names as $name) { + $map[mb_strtolower($name, '8bit')] = $oid; + } + } + } + return $map; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeTypeAndValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeTypeAndValue.php new file mode 100644 index 000000000..6bde15bac --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeTypeAndValue.php @@ -0,0 +1,115 @@ +toString(); + } + + public static function create(AttributeType $type, AttributeValue $value): self + { + return new self($type, $value); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $type = AttributeType::fromASN1($seq->at(0)->asObjectIdentifier()); + $value = AttributeValue::fromASN1ByOID($type->oid(), $seq->at(1)); + return self::create($type, $value); + } + + /** + * Convenience method to initialize from attribute value. + * + * @param AttributeValue $value Attribute value + */ + public static function fromAttributeValue(AttributeValue $value): self + { + return self::create(AttributeType::create($value->oid()), $value); + } + + /** + * Get attribute value. + */ + public function value(): AttributeValue + { + return $this->value; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create($this->type->toASN1(), $this->value->toASN1()); + } + + /** + * Get attributeTypeAndValue string conforming to RFC 2253. + * + * @see https://tools.ietf.org/html/rfc2253#section-2.3 + */ + public function toString(): string + { + return $this->type->typeName() . '=' . $this->value->rfc2253String(); + } + + /** + * Check whether attribute is semantically equal to other. + * + * @param AttributeTypeAndValue $other Object to compare to + */ + public function equals(self $other): bool + { + // check that attribute types match + if ($this->oid() !== $other->oid()) { + return false; + } + $matcher = $this->value->equalityMatchingRule(); + + return $matcher->compare($this->value->stringValue(), $other->value->stringValue()) === true; + } + + /** + * Get attribute type. + */ + public function type(): AttributeType + { + return $this->type; + } + + /** + * Get OID of the attribute. + */ + public function oid(): string + { + return $this->type->oid(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/AttributeValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/AttributeValue.php new file mode 100644 index 000000000..9032fae88 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/AttributeValue.php @@ -0,0 +1,146 @@ + + */ + private const MAP_OID_TO_CLASS = [ + AttributeType::OID_COMMON_NAME => CommonNameValue::class, + AttributeType::OID_SURNAME => SurnameValue::class, + AttributeType::OID_SERIAL_NUMBER => SerialNumberValue::class, + AttributeType::OID_COUNTRY_NAME => CountryNameValue::class, + AttributeType::OID_LOCALITY_NAME => LocalityNameValue::class, + AttributeType::OID_STATE_OR_PROVINCE_NAME => StateOrProvinceNameValue::class, + AttributeType::OID_ORGANIZATION_NAME => OrganizationNameValue::class, + AttributeType::OID_ORGANIZATIONAL_UNIT_NAME => OrganizationalUnitNameValue::class, + AttributeType::OID_TITLE => TitleValue::class, + AttributeType::OID_DESCRIPTION => DescriptionValue::class, + AttributeType::OID_NAME => NameValue::class, + AttributeType::OID_GIVEN_NAME => GivenNameValue::class, + AttributeType::OID_PSEUDONYM => PseudonymValue::class, + ]; + + /** + * @param string $oid OID of the attribute type. + */ + protected function __construct( + protected string $oid + ) { + } + + /** + * Get attribute value as an UTF-8 encoded string. + */ + public function __toString(): string + { + return $this->_transcodedString(); + } + + /** + * Generate ASN.1 element. + */ + abstract public function toASN1(): Element; + + /** + * Get attribute value as a string. + */ + abstract public function stringValue(): string; + + /** + * Get matching rule for equality comparison. + */ + abstract public function equalityMatchingRule(): MatchingRule; + + /** + * Get attribute value as a string conforming to RFC 2253. + * + * @see https://tools.ietf.org/html/rfc2253#section-2.4 + */ + abstract public function rfc2253String(): string; + + /** + * Initialize from ASN.1. + */ + abstract public static function fromASN1(UnspecifiedType $el): self; + + /** + * Initialize from ASN.1 with given OID hint. + * + * @param string $oid Attribute's OID + */ + public static function fromASN1ByOID(string $oid, UnspecifiedType $el): self + { + if (! array_key_exists($oid, self::MAP_OID_TO_CLASS)) { + return new UnknownAttributeValue($oid, $el->asElement()); + } + $cls = self::MAP_OID_TO_CLASS[$oid]; + return $cls::fromASN1($el); + } + + /** + * Initialize from another AttributeValue. + * + * This method is generally used to cast UnknownAttributeValue to specific object when class is declared outside + * this package. + * + * @param self $obj Instance of AttributeValue + */ + public static function fromSelf(self $obj): self + { + return static::fromASN1($obj->toASN1()->asUnspecified()); + } + + /** + * Get attribute type's OID. + */ + public function oid(): string + { + return $this->oid; + } + + /** + * Get Attribute object with this as a single value. + */ + public function toAttribute(): Attribute + { + return Attribute::fromAttributeValues($this); + } + + /** + * Get AttributeTypeAndValue object with this as a value. + */ + public function toAttributeTypeAndValue(): AttributeTypeAndValue + { + return AttributeTypeAndValue::fromAttributeValue($this); + } + + /** + * Get attribute value as an UTF-8 string conforming to RFC 4518. + * + * @see https://tools.ietf.org/html/rfc4518#section-2.1 + */ + abstract protected function _transcodedString(): string; +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/CommonNameValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/CommonNameValue.php new file mode 100644 index 000000000..735ddf249 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/CommonNameValue.php @@ -0,0 +1,21 @@ +asPrintableString()->string()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/DescriptionValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/DescriptionValue.php new file mode 100644 index 000000000..b4ca4d675 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/DescriptionValue.php @@ -0,0 +1,21 @@ + + */ + private const MAP_TAG_TO_CLASS = [ + self::TELETEX => T61String::class, + self::PRINTABLE => PrintableString::class, + self::UNIVERSAL => UniversalString::class, + self::UTF8 => UTF8String::class, + self::BMP => BMPString::class, + ]; + + /** + * @param string $_string String value + * @param int $_stringTag Syntax choice + */ + final protected function __construct( + string $oid, + protected string $_string, + protected int $_stringTag + ) { + parent::__construct($oid); + } + + abstract public static function create(string $value, int $string_tag = self::UTF8): static; + + /** + * @return self + */ + public static function fromASN1(UnspecifiedType $el): AttributeValue + { + $tag = $el->tag(); + // validate tag + self::_tagToASN1Class($tag); + return static::create($el->asString()->string(), $tag); + } + + public function toASN1(): Element + { + $cls = self::_tagToASN1Class($this->_stringTag); + return $cls::create($this->_string); + } + + public function stringValue(): string + { + return $this->_string; + } + + public function equalityMatchingRule(): MatchingRule + { + return CaseIgnoreMatch::create($this->_stringTag); + } + + public function rfc2253String(): string + { + // TeletexString is encoded as binary + if ($this->_stringTag === self::TELETEX) { + return $this->_transcodedString(); + } + return DNParser::escapeString($this->_transcodedString()); + } + + protected function _transcodedString(): string + { + return TranscodeStep::create($this->_stringTag) + ->apply($this->_string) + ; + } + + /** + * Get ASN.1 class name for given DirectoryString type tag. + */ + private static function _tagToASN1Class(int $tag): string + { + if (! array_key_exists($tag, self::MAP_TAG_TO_CLASS)) { + throw new UnexpectedValueException( + sprintf('Type %s is not valid DirectoryString.', Element::tagToName($tag)) + ); + } + return self::MAP_TAG_TO_CLASS[$tag]; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/Feature/PrintableStringValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/Feature/PrintableStringValue.php new file mode 100644 index 000000000..c8b31fe25 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/Feature/PrintableStringValue.php @@ -0,0 +1,55 @@ +_string); + } + + public function stringValue(): string + { + return $this->_string; + } + + public function equalityMatchingRule(): MatchingRule + { + // default to caseIgnoreMatch + return CaseIgnoreMatch::create(Element::TYPE_PRINTABLE_STRING); + } + + public function rfc2253String(): string + { + return DNParser::escapeString($this->_transcodedString()); + } + + protected function _transcodedString(): string + { + // PrintableString maps directly to UTF-8 + return $this->_string; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/GivenNameValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/GivenNameValue.php new file mode 100644 index 000000000..a76410865 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/GivenNameValue.php @@ -0,0 +1,21 @@ +asPrintableString()->string()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/StateOrProvinceNameValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/StateOrProvinceNameValue.php new file mode 100644 index 000000000..41188cf2f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/AttributeValue/StateOrProvinceNameValue.php @@ -0,0 +1,21 @@ +oid = $oid; + } + + public static function create(string $oid, Element $_element): self + { + return new self($oid, $_element); + } + + public function toASN1(): Element + { + return $this->_element; + } + + public function stringValue(): string + { + // if value is encoded as a string type + if ($this->_element->isType(Element::TYPE_STRING)) { + return $this->_element->asUnspecified() + ->asString() + ->string(); + } + // return DER encoding as a hexstring (see RFC2253 section 2.4) + return '#' . bin2hex($this->_element->toDER()); + } + + public function equalityMatchingRule(): MatchingRule + { + return new BinaryMatch(); + } + + public function rfc2253String(): string + { + $str = $this->_transcodedString(); + // if value has a string representation + if ($this->_element->isType(Element::TYPE_STRING)) { + $str = DNParser::escapeString($str); + } + return $str; + } + + public static function fromASN1(UnspecifiedType $el): AttributeValue + { + throw new BadMethodCallException('ASN.1 parsing must be implemented in a concrete class.'); + } + + protected function _transcodedString(): string + { + // if transcoding is defined for the value type + if (TranscodeStep::isTypeSupported($this->_element->tag())) { + $step = TranscodeStep::create($this->_element->tag()); + return $step->apply($this->stringValue()); + } + return $this->stringValue(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/AttributeCollection.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/AttributeCollection.php new file mode 100644 index 000000000..998767bb0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/AttributeCollection.php @@ -0,0 +1,187 @@ +_attributes = $attribs; + } + + public static function create(Attribute ...$attribs): static + { + return new static(...$attribs); + } + + /** + * Check whether attribute is present. + * + * @param string $name OID or attribute name + */ + public function has(string $name): bool + { + return $this->_findFirst($name) !== null; + } + + /** + * Get first attribute by OID or attribute name. + * + * @param string $name OID or attribute name + */ + public function firstOf(string $name): Attribute + { + $attr = $this->_findFirst($name); + if ($attr === null) { + throw new UnexpectedValueException("No {$name} attribute."); + } + return $attr; + } + + /** + * Get all attributes of given name. + * + * @param string $name OID or attribute name + * + * @return Attribute[] + */ + public function allOf(string $name): array + { + $oid = AttributeType::attrNameToOID($name); + return array_values(array_filter($this->_attributes, fn (Attribute $attr) => $attr->oid() === $oid)); + } + + /** + * Get all attributes. + * + * @return Attribute[] + */ + public function all(): array + { + return $this->_attributes; + } + + /** + * Get self with additional attributes added. + * + * @param Attribute ...$attribs List of attributes to add + */ + public function withAdditional(Attribute ...$attribs): self + { + $obj = clone $this; + foreach ($attribs as $attr) { + $obj->_attributes[] = $attr; + } + return $obj; + } + + /** + * Get self with single unique attribute added. + * + * All previous attributes of the same type are removed. + * + * @param Attribute $attr Attribute to add + */ + public function withUnique(Attribute $attr): static + { + $attribs = array_values(array_filter($this->_attributes, fn (Attribute $a) => $a->oid() !== $attr->oid())); + $attribs[] = $attr; + $obj = clone $this; + $obj->_attributes = $attribs; + return $obj; + } + + /** + * Get number of attributes. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->_attributes); + } + + /** + * Get iterator for attributes. + * + * @return ArrayIterator|Attribute[] + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->_attributes); + } + + /** + * Find first attribute of given name or OID. + * + * @param string $name OID or attribute name + */ + protected function _findFirst(string $name): ?Attribute + { + $oid = AttributeType::attrNameToOID($name); + foreach ($this->_attributes as $attr) { + if ($attr->oid() === $oid) { + return $attr; + } + } + return null; + } + + /** + * Initialize from ASN.1 constructed element. + * + * @param Structure $struct ASN.1 structure + */ + protected static function _fromASN1Structure(Structure $struct): static + { + return static::create(...array_map( + static fn (UnspecifiedType $el) => static::_castAttributeValues( + Attribute::fromASN1($el->asSequence()) + ), + $struct->elements() + )); + } + + /** + * Cast Attribute's AttributeValues to implementation specific objects. + * + * Overridden in derived classes. + * + * @param Attribute $attribute Attribute to cast + */ + protected static function _castAttributeValues(Attribute $attribute): Attribute + { + // pass through by default + return $attribute; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SequenceOfAttributes.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SequenceOfAttributes.php new file mode 100644 index 000000000..708e4cacb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SequenceOfAttributes.php @@ -0,0 +1,46 @@ + $value->toAttribute(), $values)); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create(...array_map(static fn (Attribute $attr) => $attr->toASN1(), $this->_attributes)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SetOfAttributes.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SetOfAttributes.php new file mode 100644 index 000000000..501956cbb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Collection/SetOfAttributes.php @@ -0,0 +1,47 @@ + $value->toAttribute(), $values)); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Set + { + $set = Set::create(...array_map(static fn (Attribute $attr) => $attr->toASN1(), $this->_attributes)); + return $set->sortedSetOf(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Name.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Name.php new file mode 100644 index 000000000..b9163bfa3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/Name.php @@ -0,0 +1,193 @@ +rdns = $rdns; + } + + public function __toString(): string + { + return $this->toString(); + } + + public static function create(RDN ...$rdns): self + { + return new self(...$rdns); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $rdns = array_map(static fn (UnspecifiedType $el) => RDN::fromASN1($el->asSet()), $seq->elements()); + return self::create(...$rdns); + } + + /** + * Initialize from distinguished name string. + * + * @see https://tools.ietf.org/html/rfc1779 + */ + public static function fromString(string $str): self + { + $rdns = []; + foreach (DNParser::parseString($str) as $nameComponent) { + $attribs = []; + foreach ($nameComponent as [$name, $val]) { + $type = AttributeType::fromName($name); + // hexstrings are parsed to ASN.1 elements + if ($val instanceof Element) { + $el = $val; + } else { + $el = AttributeType::asn1StringForType($type->oid(), $val); + } + $value = AttributeValue::fromASN1ByOID($type->oid(), $el->asUnspecified()); + $attribs[] = AttributeTypeAndValue::create($type, $value); + } + $rdns[] = RDN::create(...$attribs); + } + return self::create(...$rdns); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = array_map(static fn (RDN $rdn) => $rdn->toASN1(), $this->rdns); + return Sequence::create(...$elements); + } + + /** + * Get distinguised name string conforming to RFC 2253. + * + * @see https://tools.ietf.org/html/rfc2253#section-2.1 + */ + public function toString(): string + { + $parts = array_map(static fn (RDN $rdn) => $rdn->toString(), array_reverse($this->rdns)); + return implode(',', $parts); + } + + /** + * Whether name is semantically equal to other. + * + * Comparison conforms to RFC 4518 string preparation algorithm. + * + * @see https://tools.ietf.org/html/rfc4518 + * + * @param Name $other Object to compare to + */ + public function equals(self $other): bool + { + // if RDN count doesn't match + if (count($this) !== count($other)) { + return false; + } + for ($i = count($this) - 1; $i >= 0; --$i) { + $rdn1 = $this->rdns[$i]; + $rdn2 = $other->rdns[$i]; + if (! $rdn1->equals($rdn2)) { + return false; + } + } + return true; + } + + /** + * Get all RDN objects. + * + * @return RDN[] + */ + public function all(): array + { + return $this->rdns; + } + + /** + * Get the first AttributeValue of given type. + * + * Relative name components shall be traversed in encoding order, which is reversed in regards to the string + * representation. Multi-valued RDN with multiple attributes of the requested type is ambiguous and shall throw an + * exception. + * + * @param string $name Attribute OID or name + */ + public function firstValueOf(string $name): AttributeValue + { + $oid = AttributeType::attrNameToOID($name); + foreach ($this->rdns as $rdn) { + $tvs = $rdn->allOf($oid); + if (count($tvs) > 1) { + throw new RangeException("RDN with multiple {$name} attributes."); + } + if (count($tvs) === 1) { + return $tvs[0]->value(); + } + } + throw new RangeException("Attribute {$name} not found."); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->rdns); + } + + /** + * Get the number of attributes of given type. + * + * @param string $name Attribute OID or name + */ + public function countOfType(string $name): int + { + $oid = AttributeType::attrNameToOID($name); + return array_sum(array_map(static fn (RDN $rdn): int => count($rdn->allOf($oid)), $this->rdns)); + } + + /** + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->rdns); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/RDN.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/RDN.php new file mode 100644 index 000000000..51ea33039 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/ASN1/RDN.php @@ -0,0 +1,167 @@ +_attribs = $attribs; + } + + public function __toString(): string + { + return $this->toString(); + } + + public static function create(AttributeTypeAndValue ...$attribs): self + { + return new self(...$attribs); + } + + /** + * Convenience method to initialize RDN from AttributeValue objects. + * + * @param AttributeValue ...$values One or more attributes + */ + public static function fromAttributeValues(AttributeValue ...$values): self + { + $attribs = array_map( + static fn (AttributeValue $value) => AttributeTypeAndValue::create(AttributeType::create( + $value->oid() + ), $value), + $values + ); + return self::create(...$attribs); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Set $set): self + { + $attribs = array_map( + static fn (UnspecifiedType $el) => AttributeTypeAndValue::fromASN1($el->asSequence()), + $set->elements() + ); + return self::create(...$attribs); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Set + { + $elements = array_map(static fn (AttributeTypeAndValue $tv) => $tv->toASN1(), $this->_attribs); + return Set::create(...$elements)->sortedSetOf(); + } + + /** + * Get name-component string conforming to RFC 2253. + * + * @see https://tools.ietf.org/html/rfc2253#section-2.2 + */ + public function toString(): string + { + $parts = array_map(static fn (AttributeTypeAndValue $tv) => $tv->toString(), $this->_attribs); + return implode('+', $parts); + } + + /** + * Check whether RDN is semantically equal to other. + * + * @param RDN $other Object to compare to + */ + public function equals(self $other): bool + { + // if attribute count doesn't match + if (count($this) !== count($other)) { + return false; + } + $attribs1 = $this->_attribs; + $attribs2 = $other->_attribs; + // if there's multiple attributes, sort using SET OF rules + if (count($attribs1) > 1) { + $attribs1 = self::fromASN1($this->toASN1())->_attribs; + $attribs2 = self::fromASN1($other->toASN1())->_attribs; + } + for ($i = count($attribs1) - 1; $i >= 0; --$i) { + $tv1 = $attribs1[$i]; + $tv2 = $attribs2[$i]; + if (! $tv1->equals($tv2)) { + return false; + } + } + return true; + } + + /** + * Get all AttributeTypeAndValue objects. + * + * @return AttributeTypeAndValue[] + */ + public function all(): array + { + return $this->_attribs; + } + + /** + * Get all AttributeTypeAndValue objects of the given attribute type. + * + * @param string $name Attribute OID or name + * + * @return AttributeTypeAndValue[] + */ + public function allOf(string $name): array + { + $oid = AttributeType::attrNameToOID($name); + $attribs = array_filter($this->_attribs, static fn (AttributeTypeAndValue $tv) => $tv->oid() === $oid); + return array_values($attribs); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->_attribs); + } + + /** + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->_attribs); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/DN/DNParser.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/DN/DNParser.php new file mode 100644 index 000000000..d57f4528e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/DN/DNParser.php @@ -0,0 +1,364 @@ +#;'; + + /** + * DN string length. + */ + private readonly int $_len; + + /** + * @param string $_dn Distinguised name + */ + private function __construct( + private readonly string $_dn + ) { + $this->_len = mb_strlen($_dn, '8bit'); + } + + /** + * Parse distinguished name string to name-components. + * + * @return array> + */ + public static function parseString(string $dn): array + { + $parser = new self($dn); + return $parser->parse(); + } + + /** + * Escape a AttributeValue string conforming to RFC 2253. + * + * @see https://tools.ietf.org/html/rfc2253#section-2.4 + */ + public static function escapeString(string $str): string + { + // one of the characters ",", "+", """, "\", "<", ">" or ";" + $str = preg_replace('/([,\+"\\\<\>;])/u', '\\\\$1', $str); + // a space character occurring at the end of the string + $str = preg_replace('/( )$/u', '\\\\$1', (string) $str); + // a space or "#" character occurring at the beginning of the string + $str = preg_replace('/^([ #])/u', '\\\\$1', (string) $str); + // implementation specific special characters + $str = preg_replace_callback( + '/([\pC])/u', + function ($m) { + $octets = mb_str_split(bin2hex($m[1]), 2, '8bit'); + return implode('', array_map(static fn ($octet) => '\\' . mb_strtoupper($octet, '8bit'), $octets)); + }, + (string) $str + ); + return $str; + } + + /** + * Parse DN to name-components. + * + * @return array> + */ + private function parse(): array + { + $offset = 0; + $name = $this->_parseName($offset); + if ($offset < $this->_len) { + $remains = mb_substr($this->_dn, $offset, null, '8bit'); + throw new UnexpectedValueException(sprintf( + 'Parser finished before the end of string, remaining: %s', + $remains + )); + } + return $name; + } + + /** + * Parse 'name'. + * + * name-component *("," name-component) + * + * @return array> Array of name-components + */ + private function _parseName(int &$offset): array + { + $idx = $offset; + $names = []; + while ($idx < $this->_len) { + $names[] = $this->_parseNameComponent($idx); + if ($idx >= $this->_len) { + break; + } + $this->_skipWs($idx); + if ($this->_dn[$idx] !== ',' && $this->_dn[$idx] !== ';') { + break; + } + ++$idx; + $this->_skipWs($idx); + } + $offset = $idx; + return array_reverse($names); + } + + /** + * Parse 'name-component'. + * + * attributeTypeAndValue *("+" attributeTypeAndValue) + * + * @return array> Array of [type, value] tuples + */ + private function _parseNameComponent(int &$offset): array + { + $idx = $offset; + $tvpairs = []; + while ($idx < $this->_len) { + $tvpairs[] = $this->_parseAttrTypeAndValue($idx); + $this->_skipWs($idx); + if ($idx >= $this->_len || $this->_dn[$idx] !== '+') { + break; + } + ++$idx; + $this->_skipWs($idx); + } + $offset = $idx; + return $tvpairs; + } + + /** + * Parse 'attributeTypeAndValue'. + * + * attributeType "=" attributeValue + * + * @return array A tuple of [type, value]. Value may be either a string or + * an Element, if it's encoded as hexstring. + */ + private function _parseAttrTypeAndValue(int &$offset): array + { + $idx = $offset; + $type = $this->_parseAttrType($idx); + $this->_skipWs($idx); + if ($idx >= $this->_len || $this->_dn[$idx++] !== '=') { + throw new UnexpectedValueException('Invalid type and value pair.'); + } + $this->_skipWs($idx); + // hexstring + if ($idx < $this->_len && $this->_dn[$idx] === '#') { + ++$idx; + $data = $this->_parseAttrHexValue($idx); + try { + $value = Element::fromDER($data); + } catch (DecodeException $e) { + throw new UnexpectedValueException('Invalid DER encoding from hexstring.', 0, $e); + } + } else { + $value = $this->_parseAttrStringValue($idx); + } + $offset = $idx; + return [$type, $value]; + } + + /** + * Parse 'attributeType'. + * + * (ALPHA 1*keychar) / oid + */ + private function _parseAttrType(int &$offset): string + { + $idx = $offset; + // dotted OID + $type = $this->_regexMatch('/^(?:oid\.)?([0-9]+(?:\.[0-9]+)*)/i', $idx); + if ($type === null) { + // name + $type = $this->_regexMatch('/^[a-z][a-z0-9\-]*/i', $idx); + if ($type === null) { + throw new UnexpectedValueException('Invalid attribute type.'); + } + } + $offset = $idx; + return $type; + } + + /** + * Parse 'attributeValue' of string type. + */ + private function _parseAttrStringValue(int &$offset): string + { + $idx = $offset; + if ($idx >= $this->_len) { + return ''; + } + if ($this->_dn[$idx] === '"') { // quoted string + $val = $this->_parseQuotedAttrString($idx); + } else { // string + $val = $this->_parseAttrString($idx); + } + $offset = $idx; + return $val; + } + + /** + * Parse plain 'attributeValue' string. + */ + private function _parseAttrString(int &$offset): string + { + $idx = $offset; + $val = ''; + $wsidx = null; + while ($idx < $this->_len) { + $c = $this->_dn[$idx]; + // pair (escape sequence) + if ($c === '\\') { + ++$idx; + $val .= $this->_parsePairAfterSlash($idx); + $wsidx = null; + continue; + } + if ($c === '"') { + throw new UnexpectedValueException('Unexpected quotation.'); + } + if (mb_strpos(self::SPECIAL_CHARS, $c, 0, '8bit') !== false) { + break; + } + // keep track of the first consecutive whitespace + if ($c === ' ') { + if ($wsidx === null) { + $wsidx = $idx; + } + } else { + $wsidx = null; + } + // stringchar + $val .= $c; + ++$idx; + } + // if there was non-escaped whitespace in the end of the value + if ($wsidx !== null) { + $val = mb_substr($val, 0, -($idx - $wsidx), '8bit'); + } + $offset = $idx; + return $val; + } + + /** + * Parse quoted 'attributeValue' string. + * + * @param int $offset Offset to starting quote + */ + private function _parseQuotedAttrString(int &$offset): string + { + $idx = $offset + 1; + $val = ''; + while ($idx < $this->_len) { + $c = $this->_dn[$idx]; + if ($c === '\\') { // pair + ++$idx; + $val .= $this->_parsePairAfterSlash($idx); + continue; + } + if ($c === '"') { + ++$idx; + break; + } + $val .= $c; + ++$idx; + } + $offset = $idx; + return $val; + } + + /** + * Parse 'attributeValue' of binary type. + */ + private function _parseAttrHexValue(int &$offset): string + { + $idx = $offset; + $hexstr = $this->_regexMatch('/^(?:[0-9a-f]{2})+/i', $idx); + if ($hexstr === null) { + throw new UnexpectedValueException('Invalid hexstring.'); + } + $data = hex2bin($hexstr); + $offset = $idx; + return $data; + } + + /** + * Parse 'pair' after leading slash. + */ + private function _parsePairAfterSlash(int &$offset): string + { + $idx = $offset; + if ($idx >= $this->_len) { + throw new UnexpectedValueException('Unexpected end of escape sequence.'); + } + $c = $this->_dn[$idx++]; + // special | \ | " | SPACE + if (mb_strpos(self::SPECIAL_CHARS . '\\" ', $c, 0, '8bit') !== false) { + $val = $c; + } else { // hexpair + if ($idx >= $this->_len) { + throw new UnexpectedValueException('Unexpected end of hexpair.'); + } + $val = @hex2bin($c . $this->_dn[$idx++]); + if ($val === false) { + throw new UnexpectedValueException('Invalid hexpair.'); + } + } + $offset = $idx; + return $val; + } + + /** + * Match DN to pattern and extract the last capture group. + * + * Updates offset to fully matched pattern. + * + * @return null|string Null if pattern doesn't match + */ + private function _regexMatch(string $pattern, int &$offset): ?string + { + $idx = $offset; + if (preg_match($pattern, mb_substr($this->_dn, $idx, null, '8bit'), $match) !== 1) { + return null; + } + $idx += mb_strlen($match[0], '8bit'); + $offset = $idx; + return end($match); + } + + /** + * Skip consecutive spaces. + */ + private function _skipWs(int &$offset): void + { + $idx = $offset; + while ($idx < $this->_len) { + if ($this->_dn[$idx] !== ' ') { + break; + } + ++$idx; + } + $offset = $idx; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/BinaryMatch.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/BinaryMatch.php new file mode 100644 index 000000000..0bb6ab31d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/BinaryMatch.php @@ -0,0 +1,18 @@ +withCaseFolding(true) + ); + } + + public static function create(int $stringType): self + { + return new self($stringType); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/MatchingRule.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/MatchingRule.php new file mode 100644 index 000000000..7bc5a0c21 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/MatchingRule/MatchingRule.php @@ -0,0 +1,24 @@ +preparer->prepare($assertion); + $value = $this->preparer->prepare($value); + return strcmp($assertion, $value) === 0; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/CheckBidiStep.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/CheckBidiStep.php new file mode 100644 index 000000000..e6aa502b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/CheckBidiStep.php @@ -0,0 +1,22 @@ +fold) { + $string = mb_convert_case($string, MB_CASE_LOWER, 'UTF-8'); + } + return $string; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/NormalizeStep.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/NormalizeStep.php new file mode 100644 index 000000000..f6413916e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/NormalizeStep.php @@ -0,0 +1,23 @@ + TranscodeStep::create($string_type), + self::STEP_MAP => MapStep::create(), + self::STEP_NORMALIZE => new NormalizeStep(), + self::STEP_PROHIBIT => new ProhibitStep(), + self::STEP_CHECK_BIDI => new CheckBidiStep(), + // @todo Vary by string type + self::STEP_INSIGNIFICANT_CHARS => new InsignificantNonSubstringSpaceStep(), + ]; + return new self($steps); + } + + /** + * Get self with case folding set. + * + * @param bool $fold True to apply case folding + */ + public function withCaseFolding(bool $fold): self + { + $obj = clone $this; + $obj->_steps[self::STEP_MAP] = MapStep::create($fold); + return $obj; + } + + /** + * Prepare string. + */ + public function prepare(string $string): string + { + foreach ($this->_steps as $step) { + $string = $step->apply($string); + } + return $string; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/TranscodeStep.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/TranscodeStep.php new file mode 100644 index 000000000..0a744641a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X501/StringPrep/TranscodeStep.php @@ -0,0 +1,83 @@ + + */ + private const SUPPORTED_TYPES = [ + Element::TYPE_UTF8_STRING, + Element::TYPE_PRINTABLE_STRING, + Element::TYPE_BMP_STRING, + Element::TYPE_UNIVERSAL_STRING, + Element::TYPE_T61_STRING, + ]; + + /** + * @param int $_type ASN.1 type tag of the string + */ + private function __construct( + private readonly int $_type + ) { + } + + public static function create(int $_type): self + { + return new self($_type); + } + + /** + * Check whether transcoding from given ASN.1 type tag is supported. + * + * @param int $type ASN.1 type tag + */ + public static function isTypeSupported(int $type): bool + { + return in_array($type, self::SUPPORTED_TYPES, true); + } + + /** + * @param string $string String to prepare + * + * @return string UTF-8 encoded string + */ + public function apply(string $string): string + { + switch ($this->_type) { + // UTF-8 string as is + case Element::TYPE_UTF8_STRING: + // PrintableString maps directly to UTF-8 + case Element::TYPE_PRINTABLE_STRING: + return $string; + // UCS-2 to UTF-8 + case Element::TYPE_BMP_STRING: + return mb_convert_encoding($string, 'UTF-8', 'UCS-2BE'); + // UCS-4 to UTF-8 + case Element::TYPE_UNIVERSAL_STRING: + return mb_convert_encoding($string, 'UTF-8', 'UCS-4BE'); + // TeletexString mapping is a local matter. + // We take a shortcut here and encode it as a hexstring. + case Element::TYPE_T61_STRING: + $el = T61String::create($string); + return '#' . bin2hex($el->toDER()); + } + throw new LogicException(sprintf('Unsupported string type %s.', Element::tagToName($this->_type))); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertIssuer.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertIssuer.php new file mode 100644 index 000000000..8dce6afc5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertIssuer.php @@ -0,0 +1,69 @@ +tbsCertificate()->subject()); + } + + /** + * Initialize from ASN.1. + * + * @param UnspecifiedType $el CHOICE + */ + public static function fromASN1(UnspecifiedType $el): self + { + if (! $el->isTagged()) { + throw new UnexpectedValueException('v1Form issuer not supported.'); + } + $tagged = $el->asTagged(); + return match ($tagged->tag()) { + 0 => V2Form::fromV2ASN1($tagged->asImplicit(Element::TYPE_SEQUENCE)->asSequence()), + default => throw new UnexpectedValueException('Unsupported issuer type.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertValidityPeriod.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertValidityPeriod.php new file mode 100644 index 000000000..88119bf87 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttCertValidityPeriod.php @@ -0,0 +1,86 @@ +at(0) + ->asGeneralizedTime() + ->dateTime(); + $na = $seq->at(1) + ->asGeneralizedTime() + ->dateTime(); + return self::create($nb, $na); + } + + /** + * Initialize from date strings. + * + * @param null|string $nb_date Not before date + * @param null|string $na_date Not after date + * @param null|string $tz Timezone string + */ + public static function fromStrings(?string $nb_date, ?string $na_date, ?string $tz = null): self + { + $nb = self::createDateTime($nb_date, $tz); + $na = self::createDateTime($na_date, $tz); + return self::create($nb, $na); + } + + /** + * Get not before time. + */ + public function notBeforeTime(): DateTimeImmutable + { + return $this->notBeforeTime; + } + + /** + * Get not after time. + */ + public function notAfterTime(): DateTimeImmutable + { + return $this->notAfterTime; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + GeneralizedTime::create($this->notBeforeTime), + GeneralizedTime::create($this->notAfterTime) + ); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AccessIdentityAttributeValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AccessIdentityAttributeValue.php new file mode 100644 index 000000000..e40e62ef4 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AccessIdentityAttributeValue.php @@ -0,0 +1,43 @@ +asSequence(); + $service = GeneralName::fromASN1($seq->at(0)->asTagged()); + $ident = GeneralName::fromASN1($seq->at(1)->asTagged()); + $auth_info = null; + if ($seq->has(2, Element::TYPE_OCTET_STRING)) { + $auth_info = $seq->at(2) + ->asString() + ->string(); + } + return static::create($service, $ident, $auth_info); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AuthenticationInfoAttributeValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AuthenticationInfoAttributeValue.php new file mode 100644 index 000000000..7baa8a207 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/AuthenticationInfoAttributeValue.php @@ -0,0 +1,43 @@ +asSequence(); + $service = GeneralName::fromASN1($seq->at(0)->asTagged()); + $ident = GeneralName::fromASN1($seq->at(1)->asTagged()); + $auth_info = null; + if ($seq->has(2, Element::TYPE_OCTET_STRING)) { + $auth_info = $seq->at(2) + ->asString() + ->string(); + } + return static::create($service, $ident, $auth_info); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/ChargingIdentityAttributeValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/ChargingIdentityAttributeValue.php new file mode 100644 index 000000000..fe828f3d9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/ChargingIdentityAttributeValue.php @@ -0,0 +1,20 @@ +_policyAuthority = null; + $this->_values = $values; + } + + abstract public static function create(IetfAttrValue ...$values): self; + + /** + * @return self + */ + public static function fromASN1(UnspecifiedType $el): AttributeValue + { + $seq = $el->asSequence(); + $authority = null; + $idx = 0; + if ($seq->hasTagged(0)) { + $authority = GeneralNames::fromASN1( + $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + ++$idx; + } + $values = array_map( + static fn (UnspecifiedType $el) => IetfAttrValue::fromASN1($el), + $seq->at($idx) + ->asSequence() + ->elements() + ); + $obj = static::create(...$values); + $obj->_policyAuthority = $authority; + return $obj; + } + + /** + * Get self with policy authority. + */ + public function withPolicyAuthority(GeneralNames $names): self + { + $obj = clone $this; + $obj->_policyAuthority = $names; + return $obj; + } + + /** + * Check whether policy authority is present. + */ + public function hasPolicyAuthority(): bool + { + return isset($this->_policyAuthority); + } + + /** + * Get policy authority. + */ + public function policyAuthority(): GeneralNames + { + if (! $this->hasPolicyAuthority()) { + throw new LogicException('policyAuthority not set.'); + } + return $this->_policyAuthority; + } + + /** + * Get values. + * + * @return IetfAttrValue[] + */ + public function values(): array + { + return $this->_values; + } + + /** + * Get first value. + */ + public function first(): IetfAttrValue + { + if (count($this->_values) === 0) { + throw new LogicException('No values.'); + } + return $this->_values[0]; + } + + public function toASN1(): Element + { + $elements = []; + if (isset($this->_policyAuthority)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->_policyAuthority->toASN1()); + } + $values = array_map(static fn (IetfAttrValue $val) => $val->toASN1(), $this->_values); + $elements[] = Sequence::create(...$values); + return Sequence::create(...$elements); + } + + public function stringValue(): string + { + return '#' . bin2hex($this->toASN1()->toDER()); + } + + public function equalityMatchingRule(): MatchingRule + { + return new BinaryMatch(); + } + + public function rfc2253String(): string + { + return $this->stringValue(); + } + + /** + * Get number of values. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->_values); + } + + /** + * Get iterator for values. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->_values); + } + + protected function _transcodedString(): string + { + return $this->stringValue(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/IetfAttrValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/IetfAttrValue.php new file mode 100644 index 000000000..7b7c1e1c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/IetfAttrValue.php @@ -0,0 +1,128 @@ +value; + } + + public static function create(string $value, int $type): self + { + return new self($value, $type); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(UnspecifiedType $el): self + { + return match ($el->tag()) { + Element::TYPE_OCTET_STRING, Element::TYPE_UTF8_STRING => self::create( + $el->asString() + ->string(), + $el->tag() + ), + Element::TYPE_OBJECT_IDENTIFIER => self::create($el->asObjectIdentifier()->oid(), $el->tag()), + default => throw new UnexpectedValueException('Type ' . Element::tagToName($el->tag()) . ' not supported.'), + }; + } + + /** + * Initialize from octet string. + */ + public static function fromOctets(string $octets): self + { + return self::create($octets, Element::TYPE_OCTET_STRING); + } + + /** + * Initialize from UTF-8 string. + */ + public static function fromString(string $str): self + { + return self::create($str, Element::TYPE_UTF8_STRING); + } + + /** + * Initialize from OID. + */ + public static function fromOID(string $oid): self + { + return self::create($oid, Element::TYPE_OBJECT_IDENTIFIER); + } + + /** + * Get type tag. + */ + public function type(): int + { + return $this->type; + } + + /** + * Whether value type is octets. + */ + public function isOctets(): bool + { + return $this->type === Element::TYPE_OCTET_STRING; + } + + /** + * Whether value type is OID. + */ + public function isOID(): bool + { + return $this->type === Element::TYPE_OBJECT_IDENTIFIER; + } + + /** + * Whether value type is string. + */ + public function isString(): bool + { + return $this->type === Element::TYPE_UTF8_STRING; + } + + public function value(): string + { + return $this->value; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Element + { + return match ($this->type) { + Element::TYPE_OCTET_STRING => OctetString::create($this->value), + Element::TYPE_UTF8_STRING => UTF8String::create($this->value), + Element::TYPE_OBJECT_IDENTIFIER => ObjectIdentifier::create($this->value), + default => throw new LogicException('Type ' . Element::tagToName($this->type) . ' not supported.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/RoleAttributeValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/RoleAttributeValue.php new file mode 100644 index 000000000..6471fb080 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/RoleAttributeValue.php @@ -0,0 +1,129 @@ +asSequence(); + $authority = null; + if ($seq->hasTagged(0)) { + $authority = GeneralNames::fromASN1( + $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + $name = GeneralName::fromASN1($seq->getTagged(1)->asExplicit()->asTagged()); + return self::create($name, $authority); + } + + /** + * Check whether issuing authority is present. + */ + public function hasRoleAuthority(): bool + { + return isset($this->roleAuthority); + } + + /** + * Get issuing authority. + */ + public function roleAuthority(): GeneralNames + { + if (! $this->hasRoleAuthority()) { + throw new LogicException('roleAuthority not set.'); + } + return $this->roleAuthority; + } + + /** + * Get role name. + */ + public function roleName(): GeneralName + { + return $this->roleName; + } + + public function toASN1(): Element + { + $elements = []; + if (isset($this->roleAuthority)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->roleAuthority->toASN1()); + } + $elements[] = ExplicitlyTaggedType::create(1, $this->roleName->toASN1()); + return Sequence::create(...$elements); + } + + public function stringValue(): string + { + return '#' . bin2hex($this->toASN1()->toDER()); + } + + public function equalityMatchingRule(): MatchingRule + { + return new BinaryMatch(); + } + + public function rfc2253String(): string + { + return $this->stringValue(); + } + + protected function _transcodedString(): string + { + return $this->stringValue(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/SvceAuthInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/SvceAuthInfo.php new file mode 100644 index 000000000..4e4d93cc2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attribute/SvceAuthInfo.php @@ -0,0 +1,95 @@ +service; + } + + public function ident(): GeneralName + { + return $this->ident; + } + + /** + * Check whether authentication info is present. + */ + public function hasAuthInfo(): bool + { + return isset($this->authInfo); + } + + /** + * Get authentication info. + */ + public function authInfo(): string + { + if (! $this->hasAuthInfo()) { + throw new LogicException('authInfo not set.'); + } + return $this->authInfo; + } + + public function toASN1(): Element + { + $elements = [$this->service->toASN1(), $this->ident->toASN1()]; + if (isset($this->authInfo)) { + $elements[] = OctetString::create($this->authInfo); + } + return Sequence::create(...$elements); + } + + public function stringValue(): string + { + return '#' . bin2hex($this->toASN1()->toDER()); + } + + public function equalityMatchingRule(): MatchingRule + { + return new BinaryMatch(); + } + + public function rfc2253String(): string + { + return $this->stringValue(); + } + + protected function _transcodedString(): string + { + return $this->stringValue(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificate.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificate.php new file mode 100644 index 000000000..80e70f2af --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificate.php @@ -0,0 +1,175 @@ +toPEM() + ->string(); + } + + public static function create( + AttributeCertificateInfo $acInfo, + SignatureAlgorithmIdentifier $signatureAlgorithm, + Signature $signatureValue + ): self { + return new self($acInfo, $signatureAlgorithm, $signatureValue); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $acinfo = AttributeCertificateInfo::fromASN1($seq->at(0)->asSequence()); + $algo = AlgorithmIdentifier::fromASN1($seq->at(1)->asSequence()); + if (! $algo instanceof SignatureAlgorithmIdentifier) { + throw new UnexpectedValueException('Unsupported signature algorithm ' . $algo->oid() . '.'); + } + $signature = Signature::fromSignatureData($seq->at(2)->asBitString()->string(), $algo); + return self::create($acinfo, $algo, $signature); + } + + /** + * Initialize from DER data. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Initialize from PEM. + */ + public static function fromPEM(PEM $pem): self + { + if ($pem->type() !== PEM::TYPE_ATTRIBUTE_CERTIFICATE) { + throw new UnexpectedValueException('Invalid PEM type.'); + } + return self::fromDER($pem->data()); + } + + /** + * Get attribute certificate info. + */ + public function acinfo(): AttributeCertificateInfo + { + return $this->acInfo; + } + + /** + * Get signature algorithm identifier. + */ + public function signatureAlgorithm(): SignatureAlgorithmIdentifier + { + return $this->signatureAlgorithm; + } + + /** + * Get signature value. + */ + public function signatureValue(): Signature + { + return $this->signatureValue; + } + + /** + * Get ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + $this->acInfo->toASN1(), + $this->signatureAlgorithm->toASN1(), + $this->signatureValue->bitString() + ); + } + + /** + * Get attribute certificate as a DER. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Get attribute certificate as a PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_ATTRIBUTE_CERTIFICATE, $this->toDER()); + } + + /** + * Check whether attribute certificate is issued to the subject identified by given public key certificate. + * + * @param Certificate $cert Certificate + */ + public function isHeldBy(Certificate $cert): bool + { + if (! $this->acInfo->holder()->identifiesPKC($cert)) { + return false; + } + return true; + } + + /** + * Check whether attribute certificate is issued by given public key certificate. + * + * @param Certificate $cert Certificate + */ + public function isIssuedBy(Certificate $cert): bool + { + if (! $this->acInfo->issuer()->identifiesPKC($cert)) { + return false; + } + return true; + } + + /** + * Verify signature. + * + * @param PublicKeyInfo $pubkey_info Signer's public key + * @param null|Crypto $crypto Crypto engine, use default if not set + */ + public function verify(PublicKeyInfo $pubkey_info, ?Crypto $crypto = null): bool + { + $crypto ??= Crypto::getDefault(); + $data = $this->acInfo->toASN1() + ->toDER(); + return $crypto->verify($data, $this->signatureValue, $pubkey_info, $this->signatureAlgorithm); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificateInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificateInfo.php new file mode 100644 index 000000000..d17f1980d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/AttributeCertificateInfo.php @@ -0,0 +1,366 @@ +version = self::VERSION_2; + $this->extensions = Extensions::create(); + } + + public static function create( + Holder $holder, + AttCertIssuer $issuer, + AttCertValidityPeriod $attrCertValidityPeriod, + Attributes $attributes + ): self { + return new self($holder, $issuer, $attrCertValidityPeriod, $attributes); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $idx = 0; + $version = $seq->at($idx++) + ->asInteger() + ->intNumber(); + if ($version !== self::VERSION_2) { + throw new UnexpectedValueException('Version must be 2.'); + } + $holder = Holder::fromASN1($seq->at($idx++)->asSequence()); + $issuer = AttCertIssuer::fromASN1($seq->at($idx++)); + $signature = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence()); + if (! $signature instanceof SignatureAlgorithmIdentifier) { + throw new UnexpectedValueException('Unsupported signature algorithm ' . $signature->oid() . '.'); + } + $serial = $seq->at($idx++) + ->asInteger() + ->number(); + $validity = AttCertValidityPeriod::fromASN1($seq->at($idx++)->asSequence()); + $attribs = Attributes::fromASN1($seq->at($idx++)->asSequence()); + $obj = self::create($holder, $issuer, $validity, $attribs); + $obj->signature = $signature; + $obj->serialNumber = $serial; + if ($seq->has($idx, Element::TYPE_BIT_STRING)) { + $obj->issuerUniqueID = UniqueIdentifier::fromASN1($seq->at($idx++)->asBitString()); + } + if ($seq->has($idx, Element::TYPE_SEQUENCE)) { + $obj->extensions = Extensions::fromASN1($seq->at($idx++)->asSequence()); + } + return $obj; + } + + /** + * Get self with holder. + */ + public function withHolder(Holder $holder): self + { + $obj = clone $this; + $obj->holder = $holder; + return $obj; + } + + /** + * Get self with issuer. + */ + public function withIssuer(AttCertIssuer $issuer): self + { + $obj = clone $this; + $obj->issuer = $issuer; + return $obj; + } + + /** + * Get self with signature algorithm identifier. + */ + public function withSignature(SignatureAlgorithmIdentifier $algo): self + { + $obj = clone $this; + $obj->signature = $algo; + return $obj; + } + + /** + * Get self with serial number. + * + * @param int|string $serial Base 10 serial number + */ + public function withSerialNumber(int|string $serial): self + { + $obj = clone $this; + $obj->serialNumber = strval($serial); + return $obj; + } + + /** + * Get self with random positive serial number. + * + * @param int $size Number of random bytes + */ + public function withRandomSerialNumber(int $size): self + { + // ensure that first byte is always non-zero and having first bit unset + $num = BigInteger::of(random_int(1, 0x7f)); + for ($i = 1; $i < $size; ++$i) { + $num = $num->shiftedLeft(8); + $num = $num->plus(random_int(0, 0xff)); + } + return $this->withSerialNumber($num->toBase(10)); + } + + /** + * Get self with validity period. + */ + public function withValidity(AttCertValidityPeriod $validity): self + { + $obj = clone $this; + $obj->attrCertValidityPeriod = $validity; + return $obj; + } + + /** + * Get self with attributes. + */ + public function withAttributes(Attributes $attribs): self + { + $obj = clone $this; + $obj->attributes = $attribs; + return $obj; + } + + /** + * Get self with issuer unique identifier. + */ + public function withIssuerUniqueID(UniqueIdentifier $uid): self + { + $obj = clone $this; + $obj->issuerUniqueID = $uid; + return $obj; + } + + /** + * Get self with extensions. + */ + public function withExtensions(Extensions $extensions): self + { + $obj = clone $this; + $obj->extensions = $extensions; + return $obj; + } + + /** + * Get self with extensions added. + * + * @param Extension ...$exts One or more Extension objects + */ + public function withAdditionalExtensions(Extension ...$exts): self + { + $obj = clone $this; + $obj->extensions = $obj->extensions->withExtensions(...$exts); + return $obj; + } + + public function version(): int + { + return $this->version; + } + + /** + * Get AC holder. + */ + public function holder(): Holder + { + return $this->holder; + } + + /** + * Get AC issuer. + */ + public function issuer(): AttCertIssuer + { + return $this->issuer; + } + + /** + * Check whether signature is set. + */ + public function hasSignature(): bool + { + return $this->signature !== null; + } + + /** + * Get signature algorithm identifier. + */ + public function signature(): SignatureAlgorithmIdentifier + { + if (! $this->hasSignature()) { + throw new LogicException('signature not set.'); + } + return $this->signature; + } + + /** + * Check whether serial number is present. + */ + public function hasSerialNumber(): bool + { + return isset($this->serialNumber); + } + + /** + * Get AC serial number as a base 10 integer. + */ + public function serialNumber(): string + { + if (! $this->hasSerialNumber()) { + throw new LogicException('serialNumber not set.'); + } + return $this->serialNumber; + } + + /** + * Get validity period. + */ + public function validityPeriod(): AttCertValidityPeriod + { + return $this->attrCertValidityPeriod; + } + + public function attributes(): Attributes + { + return $this->attributes; + } + + /** + * Check whether issuer unique identifier is present. + */ + public function hasIssuerUniqueID(): bool + { + return isset($this->issuerUniqueID); + } + + /** + * Get issuer unique identifier. + */ + public function issuerUniqueID(): UniqueIdentifier + { + if (! $this->hasIssuerUniqueID()) { + throw new LogicException('issuerUniqueID not set.'); + } + return $this->issuerUniqueID; + } + + public function extensions(): Extensions + { + return $this->extensions; + } + + /** + * Get ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [Integer::create($this->version), $this->holder->toASN1(), + $this->issuer->toASN1(), $this->signature() + ->toASN1(), + Integer::create($this->serialNumber()), + $this->attrCertValidityPeriod->toASN1(), + $this->attributes->toASN1(), ]; + if (isset($this->issuerUniqueID)) { + $elements[] = $this->issuerUniqueID->toASN1(); + } + if (count($this->extensions) !== 0) { + $elements[] = $this->extensions->toASN1(); + } + return Sequence::create(...$elements); + } + + /** + * Create signed attribute certificate. + * + * @param SignatureAlgorithmIdentifier $algo Signature algorithm + * @param PrivateKeyInfo $privkey_info Private key + * @param null|Crypto $crypto Crypto engine, use default if not set + */ + public function sign( + SignatureAlgorithmIdentifier $algo, + PrivateKeyInfo $privkey_info, + ?Crypto $crypto = null + ): AttributeCertificate { + $crypto ??= Crypto::getDefault(); + $aci = clone $this; + if (! isset($aci->serialNumber)) { + $aci->serialNumber = '0'; + } + $aci->signature = $algo; + $data = $aci->toASN1() + ->toDER(); + $signature = $crypto->sign($data, $privkey_info, $algo); + return AttributeCertificate::create($aci, $algo, $signature); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attributes.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attributes.php new file mode 100644 index 000000000..2696a4624 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Attributes.php @@ -0,0 +1,151 @@ + + */ + private const MAP_OID_TO_CLASS = [ + AccessIdentityAttributeValue::OID => AccessIdentityAttributeValue::class, + AuthenticationInfoAttributeValue::OID => AuthenticationInfoAttributeValue::class, + ChargingIdentityAttributeValue::OID => ChargingIdentityAttributeValue::class, + GroupAttributeValue::OID => GroupAttributeValue::class, + AttributeType::OID_ROLE => RoleAttributeValue::class, + ]; + + /** + * Initialize from attribute values. + * + * @param AttributeValue ...$values List of attribute values + */ + public static function fromAttributeValues(AttributeValue ...$values): static + { + return static::create(...array_map(static fn (AttributeValue $value) => $value->toAttribute(), $values)); + } + + /** + * Check whether 'Access Identity' attribute is present. + */ + public function hasAccessIdentity(): bool + { + return $this->has(AccessIdentityAttributeValue::OID); + } + + /** + * Get the first 'Access Identity' attribute value. + */ + public function accessIdentity(): AccessIdentityAttributeValue + { + return $this->firstOf(AccessIdentityAttributeValue::OID)->first(); + } + + /** + * Check whether 'Service Authentication Information' attribute is present. + */ + public function hasAuthenticationInformation(): bool + { + return $this->has(AuthenticationInfoAttributeValue::OID); + } + + /** + * Get the first 'Service Authentication Information' attribute value. + */ + public function authenticationInformation(): AuthenticationInfoAttributeValue + { + return $this->firstOf(AuthenticationInfoAttributeValue::OID)->first(); + } + + /** + * Check whether 'Charging Identity' attribute is present. + */ + public function hasChargingIdentity(): bool + { + return $this->has(ChargingIdentityAttributeValue::OID); + } + + /** + * Get the first 'Charging Identity' attribute value. + */ + public function chargingIdentity(): ChargingIdentityAttributeValue + { + return $this->firstOf(ChargingIdentityAttributeValue::OID)->first(); + } + + /** + * Check whether 'Group' attribute is present. + */ + public function hasGroup(): bool + { + return $this->has(GroupAttributeValue::OID); + } + + /** + * Get the first 'Group' attribute value. + */ + public function group(): GroupAttributeValue + { + return $this->firstOf(GroupAttributeValue::OID)->first(); + } + + /** + * Check whether 'Role' attribute is present. + */ + public function hasRole(): bool + { + return $this->has(AttributeType::OID_ROLE); + } + + /** + * Get the first 'Role' attribute value. + */ + public function role(): RoleAttributeValue + { + return $this->firstOf(AttributeType::OID_ROLE)->first(); + } + + /** + * Get all 'Role' attribute values. + * + * @return RoleAttributeValue[] + */ + public function roles(): array + { + return array_merge( + [], + ...array_map(static fn (Attribute $attr) => $attr->values(), $this->allOf(AttributeType::OID_ROLE)) + ); + } + + protected static function _castAttributeValues(Attribute $attribute): Attribute + { + $oid = $attribute->oid(); + if (isset(self::MAP_OID_TO_CLASS[$oid])) { + return $attribute->castValues(self::MAP_OID_TO_CLASS[$oid]); + } + return $attribute; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Holder.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Holder.php new file mode 100644 index 000000000..d647f9adf --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Holder.php @@ -0,0 +1,242 @@ +hasTagged(0)) { + $cert_id = IssuerSerial::fromASN1( + $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + if ($seq->hasTagged(1)) { + $entity_name = GeneralNames::fromASN1( + $seq->getTagged(1) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + if ($seq->hasTagged(2)) { + $digest_info = ObjectDigestInfo::fromASN1( + $seq->getTagged(2) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + return self::create($cert_id, $entity_name) + ->withObjectDigestInfo($digest_info); + } + + /** + * Get self with base certificate ID. + */ + public function withBaseCertificateID(IssuerSerial $issuer): self + { + $obj = clone $this; + $obj->baseCertificateID = $issuer; + return $obj; + } + + /** + * Get self with entity name. + */ + public function withEntityName(GeneralNames $names): self + { + $obj = clone $this; + $obj->entityName = $names; + return $obj; + } + + /** + * Get self with object digest info. + */ + public function withObjectDigestInfo(?ObjectDigestInfo $odi): self + { + $obj = clone $this; + $obj->objectDigestInfo = $odi; + return $obj; + } + + /** + * Check whether base certificate ID is present. + */ + public function hasBaseCertificateID(): bool + { + return isset($this->baseCertificateID); + } + + /** + * Get base certificate ID. + */ + public function baseCertificateID(): IssuerSerial + { + if (! $this->hasBaseCertificateID()) { + throw new LogicException('baseCertificateID not set.'); + } + return $this->baseCertificateID; + } + + /** + * Check whether entity name is present. + */ + public function hasEntityName(): bool + { + return isset($this->entityName); + } + + /** + * Get entity name. + */ + public function entityName(): GeneralNames + { + if (! $this->hasEntityName()) { + throw new LogicException('entityName not set.'); + } + return $this->entityName; + } + + /** + * Check whether object digest info is present. + */ + public function hasObjectDigestInfo(): bool + { + return isset($this->objectDigestInfo); + } + + /** + * Get object digest info. + */ + public function objectDigestInfo(): ObjectDigestInfo + { + if (! $this->hasObjectDigestInfo()) { + throw new LogicException('objectDigestInfo not set.'); + } + return $this->objectDigestInfo; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = []; + if (isset($this->baseCertificateID)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->baseCertificateID->toASN1()); + } + if (isset($this->entityName)) { + $elements[] = ImplicitlyTaggedType::create(1, $this->entityName->toASN1()); + } + if (isset($this->objectDigestInfo)) { + $elements[] = ImplicitlyTaggedType::create(2, $this->objectDigestInfo->toASN1()); + } + return Sequence::create(...$elements); + } + + /** + * Check whether Holder identifies given certificate. + */ + public function identifiesPKC(Certificate $cert): bool + { + // if neither baseCertificateID nor entityName are present + if ($this->baseCertificateID === null && $this->entityName === null) { + return false; + } + // if baseCertificateID is present, but doesn't match + if ($this->baseCertificateID !== null && ! $this->baseCertificateID->identifiesPKC($cert)) { + return false; + } + // if entityName is present, but doesn't match + if ($this->entityName !== null && ! $this->_checkEntityName($cert)) { + return false; + } + return true; + } + + /** + * Check whether entityName matches the given certificate. + */ + private function _checkEntityName(Certificate $cert): bool + { + $name = $this->entityName?->firstDN(); + if ($name !== null && $cert->tbsCertificate()->subject()->equals($name)) { + return true; + } + $exts = $cert->tbsCertificate() + ->extensions(); + if ($exts->hasSubjectAlternativeName()) { + $ext = $exts->subjectAlternativeName(); + if ($this->_checkEntityAlternativeNames($ext->names())) { + return true; + } + } + return false; + } + + /** + * Check whether any of the subject alternative names match entityName. + */ + private function _checkEntityAlternativeNames(GeneralNames $san): bool + { + // only directory names supported for now + $name = $this->entityName?->firstDN(); + if ($name === null) { + return false; + } + foreach ($san->allOf(GeneralName::TAG_DIRECTORY_NAME) as $dn) { + if ($dn instanceof DirectoryName && $dn->dn()->equals($name)) { + return true; + } + } + return false; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/IssuerSerial.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/IssuerSerial.php new file mode 100644 index 000000000..d8c4af5d8 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/IssuerSerial.php @@ -0,0 +1,141 @@ +at(0)->asSequence()); + $serial = $seq->at(1) + ->asInteger() + ->number(); + $uid = null; + if ($seq->has(2, Element::TYPE_BIT_STRING)) { + $uid = UniqueIdentifier::fromASN1($seq->at(2)->asBitString()); + } + return self::create($issuer, $serial, $uid); + } + + /** + * Initialize from a public key certificate. + */ + public static function fromPKC(Certificate $cert): self + { + $tbsCert = $cert->tbsCertificate(); + $issuer = GeneralNames::create(DirectoryName::create($tbsCert->issuer())); + $serial = $tbsCert->serialNumber(); + $uid = $tbsCert->hasIssuerUniqueID() ? $tbsCert->issuerUniqueID() : null; + return self::create($issuer, $serial, $uid); + } + + /** + * Get issuer name. + */ + public function issuer(): GeneralNames + { + return $this->issuer; + } + + /** + * Get serial number. + */ + public function serial(): string + { + return $this->serial; + } + + /** + * Check whether issuer unique identifier is present. + */ + public function hasIssuerUID(): bool + { + return isset($this->issuerUID); + } + + /** + * Get issuer unique identifier. + */ + public function issuerUID(): UniqueIdentifier + { + if (! $this->hasIssuerUID()) { + throw new LogicException('issuerUID not set.'); + } + return $this->issuerUID; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [$this->issuer->toASN1(), Integer::create($this->serial)]; + if (isset($this->issuerUID)) { + $elements[] = $this->issuerUID->toASN1(); + } + return Sequence::create(...$elements); + } + + /** + * Check whether this IssuerSerial identifies given certificate. + */ + public function identifiesPKC(Certificate $cert): bool + { + $tbs = $cert->tbsCertificate(); + if (! $tbs->issuer()->equals($this->issuer->firstDN())) { + return false; + } + if ($tbs->serialNumber() !== $this->serial) { + return false; + } + if ($this->issuerUID !== null && ! $this->_checkUniqueID($cert)) { + return false; + } + return true; + } + + /** + * Check whether issuerUID matches given certificate. + */ + private function _checkUniqueID(Certificate $cert): bool + { + if (! $cert->tbsCertificate()->hasIssuerUniqueID()) { + return false; + } + $uid = $cert->tbsCertificate() + ->issuerUniqueID() + ->string(); + return $this->issuerUID?->string() === $uid; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/ObjectDigestInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/ObjectDigestInfo.php new file mode 100644 index 000000000..78a52656a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/ObjectDigestInfo.php @@ -0,0 +1,80 @@ +at($idx++) + ->asEnumerated() + ->intNumber(); + if ($seq->has($idx, Element::TYPE_OBJECT_IDENTIFIER)) { + $oid = $seq->at($idx++) + ->asObjectIdentifier() + ->oid(); + } + $algo = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence()); + $digest = $seq->at($idx) + ->asBitString(); + return self::create($type, $algo, $digest, $oid); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [Enumerated::create($this->digestedObjectType)]; + if (isset($this->otherObjectTypeID)) { + $elements[] = ObjectIdentifier::create($this->otherObjectTypeID); + } + $elements[] = $this->digestAlgorithm->toASN1(); + $elements[] = $this->objectDigest; + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/V2Form.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/V2Form.php new file mode 100644 index 000000000..ee5813f86 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/V2Form.php @@ -0,0 +1,116 @@ +has(0, Element::TYPE_SEQUENCE)) { + $issuer = GeneralNames::fromASN1($seq->at(0)->asSequence()); + } + if ($seq->hasTagged(0)) { + $cert_id = IssuerSerial::fromASN1( + $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + if ($seq->hasTagged(1)) { + $digest_info = ObjectDigestInfo::fromASN1( + $seq->getTagged(1) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + return self::create($issuer, $cert_id, $digest_info); + } + + /** + * Check whether issuer name is set. + */ + public function hasIssuerName(): bool + { + return isset($this->issuerName); + } + + /** + * Get issuer name. + */ + public function issuerName(): GeneralNames + { + if (! $this->hasIssuerName()) { + throw new LogicException('issuerName not set.'); + } + return $this->issuerName; + } + + /** + * Get DN of the issuer. + * + * This is a convenience method conforming to RFC 5755, which states that Issuer must contain only one non-empty + * distinguished name. + */ + public function name(): Name + { + return $this->issuerName() + ->firstDN(); + } + + public function toASN1(): Element + { + $elements = []; + if (isset($this->issuerName)) { + $elements[] = $this->issuerName->toASN1(); + } + if (isset($this->baseCertificateID)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->baseCertificateID->toASN1()); + } + if (isset($this->objectDigestInfo)) { + $elements[] = ImplicitlyTaggedType::create(1, $this->objectDigestInfo->toASN1()); + } + return ImplicitlyTaggedType::create(0, Sequence::create(...$elements)); + } + + public function identifiesPKC(Certificate $cert): bool + { + $name = $this->issuerName?->firstDN(); + return ! ($name === null || ! $cert->tbsCertificate()->subject()->equals($name)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidationConfig.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidationConfig.php new file mode 100644 index 000000000..4f994698b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidationConfig.php @@ -0,0 +1,98 @@ +evalTime = new DateTimeImmutable(); + $this->targets = []; + } + + public static function create(CertificationPath $holderPath, CertificationPath $issuerPath): self + { + return new self($holderPath, $issuerPath); + } + + /** + * Get certification path of the AC's holder. + */ + public function holderPath(): CertificationPath + { + return $this->holderPath; + } + + /** + * Get certification path of the AC's issuer. + */ + public function issuerPath(): CertificationPath + { + return $this->issuerPath; + } + + /** + * Get self with given evaluation reference time. + */ + public function withEvaluationTime(DateTimeImmutable $dt): self + { + $obj = clone $this; + $obj->evalTime = $dt; + return $obj; + } + + /** + * Get the evaluation reference time. + */ + public function evaluationTime(): DateTimeImmutable + { + return $this->evalTime; + } + + /** + * Get self with permitted targets. + */ + public function withTargets(Target ...$targets): self + { + $obj = clone $this; + $obj->targets = $targets; + return $obj; + } + + /** + * Get array of permitted targets. + * + * @return Target[] + */ + public function targets(): array + { + return $this->targets; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidator.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidator.php new file mode 100644 index 000000000..934427ce1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/ACValidator.php @@ -0,0 +1,185 @@ +crypto = $crypto ?? Crypto::getDefault(); + } + + public static function create( + AttributeCertificate $ac, + ACValidationConfig $config, + ?Crypto $crypto = null + ): self { + return new self($ac, $config, $crypto); + } + + /** + * Validate attribute certificate. + * + * @return AttributeCertificate Validated AC + */ + public function validate(): AttributeCertificate + { + $this->validateHolder(); + $issuer = $this->verifyIssuer(); + $this->validateIssuerProfile($issuer); + $this->validateTime(); + $this->validateTargeting(); + return $this->ac; + } + + /** + * Validate AC holder's certification. + * + * @return Certificate Certificate of the AC's holder + */ + private function validateHolder(): Certificate + { + $path = $this->config->holderPath(); + $config = PathValidationConfig::defaultConfig() + ->withMaxLength(count($path)) + ->withDateTime($this->config->evaluationTime()); + try { + $holder = $path->validate($config, $this->crypto) + ->certificate(); + } catch (PathValidationException $e) { + throw new ACValidationException("Failed to validate holder PKC's certification path.", 0, $e); + } + if (! $this->ac->isHeldBy($holder)) { + throw new ACValidationException("Name mismatch of AC's holder PKC."); + } + return $holder; + } + + /** + * Verify AC's signature and issuer's certification. + * + * @return Certificate Certificate of the AC's issuer + */ + private function verifyIssuer(): Certificate + { + $path = $this->config->issuerPath(); + $config = PathValidationConfig::defaultConfig() + ->withMaxLength(count($path)) + ->withDateTime($this->config->evaluationTime()); + try { + $issuer = $path->validate($config, $this->crypto) + ->certificate(); + } catch (PathValidationException $e) { + throw new ACValidationException("Failed to validate issuer PKC's certification path.", 0, $e); + } + if (! $this->ac->isIssuedBy($issuer)) { + throw new ACValidationException("Name mismatch of AC's issuer PKC."); + } + $pubkey_info = $issuer->tbsCertificate() + ->subjectPublicKeyInfo(); + if (! $this->ac->verify($pubkey_info, $this->crypto)) { + throw new ACValidationException('Failed to verify signature.'); + } + return $issuer; + } + + /** + * Validate AC issuer's profile. + * + * @see https://tools.ietf.org/html/rfc5755#section-4.5 + */ + private function validateIssuerProfile(Certificate $cert): void + { + $exts = $cert->tbsCertificate() + ->extensions(); + if ($exts->hasKeyUsage() && ! $exts->keyUsage()->isDigitalSignature()) { + throw new ACValidationException( + "Issuer PKC's Key Usage extension doesn't permit" . + ' verification of digital signatures.' + ); + } + if ($exts->hasBasicConstraints() && $exts->basicConstraints()->isCA()) { + throw new ACValidationException('Issuer PKC must not be a CA.'); + } + } + + /** + * Validate AC's validity period. + */ + private function validateTime(): void + { + $t = $this->config->evaluationTime(); + $validity = $this->ac->acinfo() + ->validityPeriod(); + if ($validity->notBeforeTime()->diff($t)->invert === 1) { + throw new ACValidationException('Validity period has not started.'); + } + if ($t->diff($validity->notAfterTime())->invert === 1) { + throw new ACValidationException('Attribute certificate has expired.'); + } + } + + /** + * Validate AC's target information. + */ + private function validateTargeting(): void + { + $exts = $this->ac->acinfo() + ->extensions(); + // if target information extension is not present + if (! $exts->has(Extension::OID_TARGET_INFORMATION)) { + return; + } + $ext = $exts->get(Extension::OID_TARGET_INFORMATION); + if ($ext instanceof TargetInformationExtension && + ! $this->_hasMatchingTarget($ext->targets())) { + throw new ACValidationException("Attribute certificate doesn't have a matching target."); + } + } + + /** + * Check whether validation configuration has matching targets. + * + * @param Targets $targets Set of eligible targets + */ + private function _hasMatchingTarget(Targets $targets): bool + { + foreach ($this->config->targets() as $target) { + if ($targets->hasTarget($target)) { + return true; + } + } + return false; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/Exception/ACValidationException.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/Exception/ACValidationException.php new file mode 100644 index 000000000..bd33d0646 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/AttributeCertificate/Validation/Exception/ACValidationException.php @@ -0,0 +1,11 @@ +toPEM() + ->string(); + } + + public static function create( + TBSCertificate $tbsCertificate, + SignatureAlgorithmIdentifier $signatureAlgorithm, + Signature $signatureValue + ): self { + return new self($tbsCertificate, $signatureAlgorithm, $signatureValue); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $tbsCert = TBSCertificate::fromASN1($seq->at(0)->asSequence()); + $algo = AlgorithmIdentifier::fromASN1($seq->at(1)->asSequence()); + if (! $algo instanceof SignatureAlgorithmIdentifier) { + throw new UnexpectedValueException('Unsupported signature algorithm ' . $algo->oid() . '.'); + } + $signature = Signature::fromSignatureData($seq->at(2)->asBitString()->string(), $algo); + return self::create($tbsCert, $algo, $signature); + } + + /** + * Initialize from DER. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Initialize from PEM. + */ + public static function fromPEM(PEM $pem): self + { + if ($pem->type() !== PEM::TYPE_CERTIFICATE) { + throw new UnexpectedValueException('Invalid PEM type.'); + } + return self::fromDER($pem->data()); + } + + /** + * Get certificate information. + */ + public function tbsCertificate(): TBSCertificate + { + return $this->tbsCertificate; + } + + /** + * Get signature algorithm. + */ + public function signatureAlgorithm(): SignatureAlgorithmIdentifier + { + return $this->signatureAlgorithm; + } + + /** + * Get signature value. + */ + public function signatureValue(): Signature + { + return $this->signatureValue; + } + + /** + * Check whether certificate is self-issued. + */ + public function isSelfIssued(): bool + { + return $this->tbsCertificate->subject() + ->equals($this->tbsCertificate->issuer()); + } + + /** + * Check whether certificate is semantically equal to another. + * + * @param Certificate $cert Certificate to compare to + */ + public function equals(self $cert): bool + { + return $this->_hasEqualSerialNumber($cert) && + $this->_hasEqualPublicKey($cert) && $this->_hasEqualSubject($cert); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + $this->tbsCertificate->toASN1(), + $this->signatureAlgorithm->toASN1(), + $this->signatureValue->bitString() + ); + } + + /** + * Get certificate as a DER. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Get certificate as a PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_CERTIFICATE, $this->toDER()); + } + + /** + * Verify certificate signature. + * + * @param PublicKeyInfo $pubkey_info Issuer's public key + * @param null|Crypto $crypto Crypto engine, use default if not set + * + * @return bool True if certificate signature is valid + */ + public function verify(PublicKeyInfo $pubkey_info, ?Crypto $crypto = null): bool + { + $crypto ??= Crypto::getDefault(); + $data = $this->tbsCertificate->toASN1() + ->toDER(); + return $crypto->verify($data, $this->signatureValue, $pubkey_info, $this->signatureAlgorithm); + } + + /** + * Check whether certificate has serial number equal to another. + */ + private function _hasEqualSerialNumber(self $cert): bool + { + $sn1 = $this->tbsCertificate->serialNumber(); + $sn2 = $cert->tbsCertificate->serialNumber(); + return $sn1 === $sn2; + } + + /** + * Check whether certificate has public key equal to another. + */ + private function _hasEqualPublicKey(self $cert): bool + { + $kid1 = $this->tbsCertificate->subjectPublicKeyInfo() + ->keyIdentifier(); + $kid2 = $cert->tbsCertificate->subjectPublicKeyInfo() + ->keyIdentifier(); + return $kid1 === $kid2; + } + + /** + * Check whether certificate has subject equal to another. + */ + private function _hasEqualSubject(self $cert): bool + { + $dn1 = $this->tbsCertificate->subject(); + $dn2 = $cert->tbsCertificate->subject(); + return $dn1->equals($dn2); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateBundle.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateBundle.php new file mode 100644 index 000000000..9429cdc59 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateBundle.php @@ -0,0 +1,202 @@ +certs = $certs; + } + + /** + * Reset internal cached variables on clone. + */ + public function __clone() + { + $this->keyIdMap = null; + } + + public static function create(Certificate ...$certs): self + { + return new self(...$certs); + } + + /** + * Initialize from PEMs. + * + * @param PEM ...$pems PEM objects + */ + public static function fromPEMs(PEM ...$pems): self + { + $certs = array_map(static fn ($pem) => Certificate::fromPEM($pem), $pems); + return self::create(...$certs); + } + + /** + * Initialize from PEM bundle. + */ + public static function fromPEMBundle(PEMBundle $pem_bundle): self + { + return self::fromPEMs(...$pem_bundle->all()); + } + + /** + * Get self with certificates added. + */ + public function withCertificates(Certificate ...$cert): self + { + $obj = clone $this; + $obj->certs = array_merge($obj->certs, $cert); + return $obj; + } + + /** + * Get self with certificates from PEMBundle added. + */ + public function withPEMBundle(PEMBundle $pem_bundle): self + { + $certs = $this->certs; + foreach ($pem_bundle as $pem) { + $certs[] = Certificate::fromPEM($pem); + } + return self::create(...$certs); + } + + /** + * Get self with single certificate from PEM added. + */ + public function withPEM(PEM $pem): self + { + $certs = $this->certs; + $certs[] = Certificate::fromPEM($pem); + return self::create(...$certs); + } + + /** + * Check whether bundle contains a given certificate. + */ + public function contains(Certificate $cert): bool + { + $id = self::_getCertKeyId($cert); + $map = $this->_getKeyIdMap(); + if (! isset($map[$id])) { + return false; + } + foreach ($map[$id] as $c) { + /** @var Certificate $c */ + if ($cert->equals($c)) { + return true; + } + } + return false; + } + + /** + * Get all certificates that have given subject key identifier. + * + * @return Certificate[] + */ + public function allBySubjectKeyIdentifier(string $id): array + { + $map = $this->_getKeyIdMap(); + if (! isset($map[$id])) { + return []; + } + return $map[$id]; + } + + /** + * Get all certificates in a bundle. + * + * @return Certificate[] + */ + public function all(): array + { + return $this->certs; + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->certs); + } + + /** + * Get iterator for certificates. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->certs); + } + + /** + * Get certificate mapping by public key id. + * + * @return (Certificate[])[] + */ + private function _getKeyIdMap(): array + { + // lazily build mapping + if (! isset($this->keyIdMap)) { + $this->keyIdMap = []; + foreach ($this->certs as $cert) { + $id = self::_getCertKeyId($cert); + if (! isset($this->keyIdMap[$id])) { + $this->keyIdMap[$id] = []; + } + array_push($this->keyIdMap[$id], $cert); + } + } + return $this->keyIdMap; + } + + /** + * Get public key id for the certificate. + */ + private static function _getCertKeyId(Certificate $cert): string + { + $exts = $cert->tbsCertificate() + ->extensions(); + if ($exts->hasSubjectKeyIdentifier()) { + return $exts->subjectKeyIdentifier() + ->keyIdentifier(); + } + return $cert->tbsCertificate() + ->subjectPublicKeyInfo() + ->keyIdentifier(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateChain.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateChain.php new file mode 100644 index 000000000..d4ef84cef --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/CertificateChain.php @@ -0,0 +1,124 @@ +certs = $certs; + } + + public static function create(Certificate ...$certs): self + { + return new self(...$certs); + } + + /** + * Initialize from a list of PEMs. + */ + public static function fromPEMs(PEM ...$pems): self + { + $certs = array_map(static fn (PEM $pem) => Certificate::fromPEM($pem), $pems); + return self::create(...$certs); + } + + /** + * Initialize from a string containing multiple PEM blocks. + */ + public static function fromPEMString(string $str): self + { + $pems = PEMBundle::fromString($str)->all(); + return self::fromPEMs(...$pems); + } + + /** + * Get all certificates in a chain ordered from the end-entity certificate to the trust anchor. + * + * @return Certificate[] + */ + public function certificates(): array + { + return $this->certs; + } + + /** + * Get the end-entity certificate. + */ + public function endEntityCertificate(): Certificate + { + if (count($this->certs) === 0) { + throw new LogicException('No certificates.'); + } + return $this->certs[0]; + } + + /** + * Get the trust anchor certificate. + */ + public function trustAnchorCertificate(): Certificate + { + if (count($this->certs) === 0) { + throw new LogicException('No certificates.'); + } + return $this->certs[count($this->certs) - 1]; + } + + /** + * Convert certificate chain to certification path. + */ + public function certificationPath(): CertificationPath + { + return CertificationPath::fromCertificateChain($this); + } + + /** + * Convert certificate chain to string of PEM blocks. + */ + public function toPEMString(): string + { + return implode("\n", array_map(static fn (Certificate $cert) => $cert->toPEM()->string(), $this->certs)); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->certs); + } + + /** + * Get iterator for certificates. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->certs); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AAControlsExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AAControlsExtension.php new file mode 100644 index 000000000..d576e4ec5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AAControlsExtension.php @@ -0,0 +1,184 @@ +pathLenConstraint); + } + + /** + * Get path length constraint. + */ + public function pathLen(): int + { + if (! $this->hasPathLen()) { + throw new LogicException('pathLen not set.'); + } + return $this->pathLenConstraint; + } + + /** + * Check whether permitted attributes are present. + */ + public function hasPermittedAttrs(): bool + { + return isset($this->permittedAttrs); + } + + /** + * Get OID's of permitted attributes. + * + * @return string[] + */ + public function permittedAttrs(): array + { + if (! $this->hasPermittedAttrs()) { + throw new LogicException('permittedAttrs not set.'); + } + return $this->permittedAttrs; + } + + /** + * Check whether excluded attributes are present. + */ + public function hasExcludedAttrs(): bool + { + return isset($this->excludedAttrs); + } + + /** + * Get OID's of excluded attributes. + * + * @return string[] + */ + public function excludedAttrs(): array + { + if (! $this->hasExcludedAttrs()) { + throw new LogicException('excludedAttrs not set.'); + } + return $this->excludedAttrs; + } + + /** + * Whether to permit attributes that are not explicitly specified in neither permitted nor excluded list. + */ + public function permitUnspecified(): bool + { + return $this->permitUnSpecified; + } + + protected static function fromDER(string $data, bool $critical): static + { + $seq = UnspecifiedType::fromDER($data)->asSequence(); + $path_len = null; + $permitted = null; + $excluded = null; + $permit_unspecified = true; + $idx = 0; + if ($seq->has($idx, Element::TYPE_INTEGER)) { + $path_len = $seq->at($idx++) + ->asInteger() + ->intNumber(); + } + if ($seq->hasTagged(0)) { + $attr_seq = $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence(); + $permitted = array_map( + static fn (UnspecifiedType $el) => $el->asObjectIdentifier() + ->oid(), + $attr_seq->elements() + ); + ++$idx; + } + if ($seq->hasTagged(1)) { + $attr_seq = $seq->getTagged(1) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence(); + $excluded = array_map( + static fn (UnspecifiedType $el) => $el->asObjectIdentifier() + ->oid(), + $attr_seq->elements() + ); + ++$idx; + } + if ($seq->has($idx, Element::TYPE_BOOLEAN)) { + $permit_unspecified = $seq->at($idx++) + ->asBoolean() + ->value(); + } + return self::create($critical, $path_len, $permitted, $excluded, $permit_unspecified); + } + + protected function valueASN1(): Element + { + $elements = []; + if (isset($this->pathLenConstraint)) { + $elements[] = Integer::create($this->pathLenConstraint); + } + if (isset($this->permittedAttrs)) { + $oids = array_map(static fn ($oid) => ObjectIdentifier::create($oid), $this->permittedAttrs); + $elements[] = ImplicitlyTaggedType::create(0, Sequence::create(...$oids)); + } + if (isset($this->excludedAttrs)) { + $oids = array_map(static fn ($oid) => ObjectIdentifier::create($oid), $this->excludedAttrs); + $elements[] = ImplicitlyTaggedType::create(1, Sequence::create(...$oids)); + } + if ($this->permitUnSpecified !== true) { + $elements[] = Boolean::create(false); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AccessDescription.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AccessDescription.php new file mode 100644 index 000000000..99c019603 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AccessDescription.php @@ -0,0 +1,57 @@ +accessMethod; + } + + /** + * Get the access location. + */ + public function accessLocation(): GeneralName + { + return $this->accessLocation; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create(ObjectIdentifier::create($this->accessMethod), $this->accessLocation->toASN1()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AuthorityAccessDescription.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AuthorityAccessDescription.php new file mode 100644 index 000000000..ac1fa1570 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/AuthorityAccessDescription.php @@ -0,0 +1,52 @@ +at(0)->asObjectIdentifier()->oid(), GeneralName::fromASN1($seq->at(1)->asTagged())); + } + + /** + * Check whether access method is OSCP. + */ + public function isOSCPMethod(): bool + { + return $this->accessMethod === self::OID_METHOD_OSCP; + } + + /** + * Check whether access method is CA issuers. + */ + public function isCAIssuersMethod(): bool + { + return $this->accessMethod === self::OID_METHOD_CA_ISSUERS; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/SubjectAccessDescription.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/SubjectAccessDescription.php new file mode 100644 index 000000000..43e3767db --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AccessDescription/SubjectAccessDescription.php @@ -0,0 +1,52 @@ +at(0)->asObjectIdentifier()->oid(), GeneralName::fromASN1($seq->at(1)->asTagged())); + } + + /** + * Check whether access method is time stamping. + */ + public function isTimeStampingMethod(): bool + { + return $this->accessMethod === self::OID_METHOD_TIME_STAMPING; + } + + /** + * Check whether access method is CA repository. + */ + public function isCARepositoryMethod(): bool + { + return $this->accessMethod === self::OID_METHOD_CA_REPOSITORY; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityInformationAccessExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityInformationAccessExtension.php new file mode 100644 index 000000000..3fbcd8868 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityInformationAccessExtension.php @@ -0,0 +1,87 @@ +accessDescriptions = $access; + } + + public static function create(bool $critical, AuthorityAccessDescription ...$access): self + { + return new self($critical, ...$access); + } + + /** + * Get the access descriptions. + * + * @return AuthorityAccessDescription[] + */ + public function accessDescriptions(): array + { + return $this->accessDescriptions; + } + + /** + * Get the number of access descriptions. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->accessDescriptions); + } + + /** + * Get iterator for access descriptions. + * + * @return ArrayIterator List of AuthorityAccessDescription objects + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->accessDescriptions); + } + + protected static function fromDER(string $data, bool $critical): static + { + $access = array_map( + static fn (UnspecifiedType $el) => AuthorityAccessDescription::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + return self::create($critical, ...$access); + } + + protected function valueASN1(): Element + { + $elements = array_map(static fn (AccessDescription $access) => $access->toASN1(), $this->accessDescriptions); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityKeyIdentifierExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityKeyIdentifierExtension.php new file mode 100644 index 000000000..9fa6dd6d1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/AuthorityKeyIdentifierExtension.php @@ -0,0 +1,163 @@ +keyIdentifier()); + } + + /** + * Whether key identifier is present. + */ + public function hasKeyIdentifier(): bool + { + return isset($this->keyIdentifier); + } + + /** + * Get key identifier. + */ + public function keyIdentifier(): string + { + if (! $this->hasKeyIdentifier()) { + throw new LogicException('keyIdentifier not set.'); + } + return $this->keyIdentifier; + } + + /** + * Whether issuer is present. + */ + public function hasIssuer(): bool + { + return isset($this->authorityCertIssuer); + } + + public function issuer(): GeneralNames + { + if (! $this->hasIssuer()) { + throw new LogicException('authorityCertIssuer not set.'); + } + return $this->authorityCertIssuer; + } + + /** + * Whether serial is present. + */ + public function hasSerial(): bool + { + return isset($this->authorityCertSerialNumber); + } + + /** + * Get serial number. + * + * @return string Base 10 integer string + */ + public function serial(): string + { + if (! $this->hasSerial()) { + throw new LogicException('authorityCertSerialNumber not set.'); + } + return $this->authorityCertSerialNumber; + } + + protected static function fromDER(string $data, bool $critical): static + { + $seq = UnspecifiedType::fromDER($data)->asSequence(); + $keyIdentifier = null; + $issuer = null; + $serial = null; + if ($seq->hasTagged(0)) { + $keyIdentifier = $seq->getTagged(0) + ->asImplicit(Element::TYPE_OCTET_STRING) + ->asOctetString() + ->string(); + } + if ($seq->hasTagged(1) || $seq->hasTagged(2)) { + if (! $seq->hasTagged(1) || ! $seq->hasTagged(2)) { + throw new UnexpectedValueException( + 'AuthorityKeyIdentifier must have both' . + ' authorityCertIssuer and authorityCertSerialNumber' . + ' present or both absent.' + ); + } + $issuer = GeneralNames::fromASN1($seq->getTagged(1)->asImplicit(Element::TYPE_SEQUENCE)->asSequence()); + $serial = $seq->getTagged(2) + ->asImplicit(Element::TYPE_INTEGER) + ->asInteger() + ->number(); + } + return self::create($critical, $keyIdentifier, $issuer, $serial); + } + + protected function valueASN1(): Element + { + $elements = []; + if (isset($this->keyIdentifier)) { + $elements[] = ImplicitlyTaggedType::create(0, OctetString::create($this->keyIdentifier)); + } + // if either issuer or serial is set, both must be set + if (isset($this->authorityCertIssuer) || + isset($this->authorityCertSerialNumber)) { + if (! isset($this->authorityCertIssuer, + $this->authorityCertSerialNumber)) { + throw new LogicException( + 'AuthorityKeyIdentifier must have both' . + ' authorityCertIssuer and authorityCertSerialNumber' . + ' present or both absent.' + ); + } + $elements[] = ImplicitlyTaggedType::create(1, $this->authorityCertIssuer->toASN1()); + $elements[] = ImplicitlyTaggedType::create(2, Integer::create($this->authorityCertSerialNumber)); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/BasicConstraintsExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/BasicConstraintsExtension.php new file mode 100644 index 000000000..1253c466b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/BasicConstraintsExtension.php @@ -0,0 +1,95 @@ +ca; + } + + /** + * Whether path length is present. + */ + public function hasPathLen(): bool + { + return isset($this->pathLen); + } + + /** + * Get path length. + */ + public function pathLen(): int + { + if (! $this->hasPathLen()) { + throw new LogicException('pathLenConstraint not set.'); + } + return $this->pathLen; + } + + protected static function fromDER(string $data, bool $critical): static + { + $seq = UnspecifiedType::fromDER($data)->asSequence(); + $ca = false; + $path_len = null; + $idx = 0; + if ($seq->has($idx, Element::TYPE_BOOLEAN)) { + $ca = $seq->at($idx++) + ->asBoolean() + ->value(); + } + if ($seq->has($idx, Element::TYPE_INTEGER)) { + $path_len = $seq->at($idx) + ->asInteger() + ->intNumber(); + } + return self::create($critical, $ca, $path_len); + } + + protected function valueASN1(): Element + { + $elements = []; + if ($this->ca) { + $elements[] = Boolean::create(true); + } + if (isset($this->pathLen)) { + $elements[] = Integer::create($this->pathLen); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CRLDistributionPointsExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CRLDistributionPointsExtension.php new file mode 100644 index 000000000..77aee6dda --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CRLDistributionPointsExtension.php @@ -0,0 +1,94 @@ +distributionPoints = $distributionPoints; + } + + public static function create(bool $critical, DistributionPoint ...$distribution_points): self + { + return new self(self::OID_CRL_DISTRIBUTION_POINTS, $critical, ...$distribution_points); + } + + /** + * Get distribution points. + * + * @return DistributionPoint[] + */ + public function distributionPoints(): array + { + return $this->distributionPoints; + } + + /** + * Get the number of distribution points. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->distributionPoints); + } + + /** + * Get iterator for distribution points. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->distributionPoints); + } + + protected static function fromDER(string $data, bool $critical): static + { + $dps = array_map( + static fn (UnspecifiedType $el) => DistributionPoint::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + if (count($dps) === 0) { + throw new UnexpectedValueException('CRLDistributionPoints must have at least one DistributionPoint.'); + } + // late static bound, extended by Freshest CRL extension + return static::create($critical, ...$dps); + } + + protected function valueASN1(): Element + { + if (count($this->distributionPoints) === 0) { + throw new LogicException('No distribution points.'); + } + $elements = array_map(static fn (DistributionPoint $dp) => $dp->toASN1(), $this->distributionPoints); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePoliciesExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePoliciesExtension.php new file mode 100644 index 000000000..9112bc8e4 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePoliciesExtension.php @@ -0,0 +1,124 @@ +_policies = []; + foreach ($policies as $policy) { + $this->_policies[$policy->oid()] = $policy; + } + } + + public static function create(bool $critical, PolicyInformation ...$policies): self + { + return new self($critical, ...$policies); + } + + /** + * Check whether policy information by OID is present. + */ + public function has(string $oid): bool + { + return isset($this->_policies[$oid]); + } + + /** + * Get policy information by OID. + */ + public function get(string $oid): PolicyInformation + { + if (! $this->has($oid)) { + throw new LogicException("Not certificate policy by OID {$oid}."); + } + return $this->_policies[$oid]; + } + + /** + * Check whether anyPolicy is present. + */ + public function hasAnyPolicy(): bool + { + return $this->has(PolicyInformation::OID_ANY_POLICY); + } + + /** + * Get anyPolicy information. + */ + public function anyPolicy(): PolicyInformation + { + if (! $this->hasAnyPolicy()) { + throw new LogicException('No anyPolicy.'); + } + return $this->get(PolicyInformation::OID_ANY_POLICY); + } + + /** + * Get the number of policies. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->_policies); + } + + /** + * Get iterator for policy information terms. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->_policies); + } + + protected static function fromDER(string $data, bool $critical): static + { + $policies = array_map( + static fn (UnspecifiedType $el) => PolicyInformation::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + if (count($policies) === 0) { + throw new UnexpectedValueException('certificatePolicies must contain at least one PolicyInformation.'); + } + return self::create($critical, ...$policies); + } + + protected function valueASN1(): Element + { + if (count($this->_policies) === 0) { + throw new LogicException('No policies.'); + } + $elements = array_map(static fn (PolicyInformation $pi) => $pi->toASN1(), array_values($this->_policies)); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/CPSQualifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/CPSQualifier.php new file mode 100644 index 000000000..3cd94dd6c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/CPSQualifier.php @@ -0,0 +1,46 @@ +asString()->string()); + } + + public function uri(): string + { + return $this->uri; + } + + protected function qualifierASN1(): Element + { + return IA5String::create($this->uri); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/DisplayText.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/DisplayText.php new file mode 100644 index 000000000..911a477fb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/DisplayText.php @@ -0,0 +1,78 @@ +string(); + } + + public static function create(string $text, int $tag): self + { + return new self($text, $tag); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(StringType $el): self + { + return self::create($el->string(), $el->tag()); + } + + /** + * Initialize from a UTF-8 string. + */ + public static function fromString(string $str): self + { + return self::create($str, Element::TYPE_UTF8_STRING); + } + + /** + * Get the text. + */ + public function string(): string + { + return $this->text; + } + + /** + * Generate ASN.1 element. + */ + public function toASN1(): StringType + { + return match ($this->tag) { + Element::TYPE_IA5_STRING => IA5String::create($this->text), + Element::TYPE_VISIBLE_STRING => VisibleString::create($this->text), + Element::TYPE_BMP_STRING => BMPString::create($this->text), + Element::TYPE_UTF8_STRING => UTF8String::create($this->text), + default => throw new UnexpectedValueException('Type ' . Element::tagToName( + $this->tag + ) . ' not supported.'), + }; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/NoticeReference.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/NoticeReference.php new file mode 100644 index 000000000..1a58962c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/NoticeReference.php @@ -0,0 +1,80 @@ +numbers = $numbers; + } + + public static function create(DisplayText $organization, int ...$numbers): self + { + return new self($organization, ...$numbers); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $org = DisplayText::fromASN1($seq->at(0)->asString()); + $numbers = array_map( + static fn (UnspecifiedType $el) => $el->asInteger() + ->intNumber(), + $seq->at(1) + ->asSequence() + ->elements() + ); + return self::create($org, ...$numbers); + } + + /** + * Get reference organization. + */ + public function organization(): DisplayText + { + return $this->organization; + } + + /** + * Get reference numbers. + * + * @return int[] + */ + public function numbers(): array + { + return $this->numbers; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $org = $this->organization->toASN1(); + $nums = array_map(static fn ($number) => Integer::create($number), $this->numbers); + return Sequence::create($org, Sequence::create(...$nums)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyInformation.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyInformation.php new file mode 100644 index 000000000..0ca3d55ad --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyInformation.php @@ -0,0 +1,190 @@ +qualifiers = []; + foreach ($qualifiers as $qualifier) { + $this->qualifiers[$qualifier->oid()] = $qualifier; + } + } + + public static function create(string $oid, PolicyQualifierInfo ...$qualifiers): self + { + return new self($oid, ...$qualifiers); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $oid = $seq->at(0) + ->asObjectIdentifier() + ->oid(); + $qualifiers = []; + if (count($seq) > 1) { + $qualifiers = array_map( + static fn (UnspecifiedType $el) => PolicyQualifierInfo::fromASN1($el->asSequence()), + $seq->at(1) + ->asSequence() + ->elements() + ); + } + return self::create($oid, ...$qualifiers); + } + + /** + * Get policy identifier. + */ + public function oid(): string + { + return $this->oid; + } + + /** + * Check whether this policy is anyPolicy. + */ + public function isAnyPolicy(): bool + { + return $this->oid === self::OID_ANY_POLICY; + } + + /** + * Get policy qualifiers. + * + * @return PolicyQualifierInfo[] + */ + public function qualifiers(): array + { + return array_values($this->qualifiers); + } + + /** + * Check whether qualifier is present. + */ + public function has(string $oid): bool + { + return isset($this->qualifiers[$oid]); + } + + /** + * Get qualifier by OID. + */ + public function get(string $oid): PolicyQualifierInfo + { + if (! $this->has($oid)) { + throw new LogicException("No {$oid} qualifier."); + } + return $this->qualifiers[$oid]; + } + + /** + * Check whether CPS qualifier is present. + */ + public function hasCPSQualifier(): bool + { + return $this->has(PolicyQualifierInfo::OID_CPS); + } + + /** + * Get CPS qualifier. + */ + public function CPSQualifier(): CPSQualifier + { + if (! $this->hasCPSQualifier()) { + throw new LogicException('CPS qualifier not set.'); + } + return $this->get(PolicyQualifierInfo::OID_CPS); + } + + /** + * Check whether user notice qualifier is present. + */ + public function hasUserNoticeQualifier(): bool + { + return $this->has(PolicyQualifierInfo::OID_UNOTICE); + } + + /** + * Get user notice qualifier. + */ + public function userNoticeQualifier(): UserNoticeQualifier + { + if (! $this->hasUserNoticeQualifier()) { + throw new LogicException('User notice qualifier not set.'); + } + return $this->get(PolicyQualifierInfo::OID_UNOTICE); + } + + /** + * Get ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [ObjectIdentifier::create($this->oid)]; + if (count($this->qualifiers) !== 0) { + $qualifiers = array_map( + static fn (PolicyQualifierInfo $pqi) => $pqi->toASN1(), + array_values($this->qualifiers) + ); + $elements[] = Sequence::create(...$qualifiers); + } + return Sequence::create(...$elements); + } + + /** + * Get number of qualifiers. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->qualifiers); + } + + /** + * Get iterator for qualifiers. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->qualifiers); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyQualifierInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyQualifierInfo.php new file mode 100644 index 000000000..240ad9dbb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/PolicyQualifierInfo.php @@ -0,0 +1,79 @@ +at(0) + ->asObjectIdentifier() + ->oid(); + return match ($oid) { + self::OID_CPS => CPSQualifier::fromQualifierASN1($seq->at(1)), + self::OID_UNOTICE => UserNoticeQualifier::fromQualifierASN1($seq->at(1)), + default => throw new UnexpectedValueException("Qualifier {$oid} not supported."), + }; + } + + /** + * Get qualifier identifier. + */ + public function oid(): string + { + return $this->oid; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create(ObjectIdentifier::create($this->oid), $this->qualifierASN1()); + } + + /** + * Generate ASN.1 for the 'qualifier' field. + */ + abstract protected function qualifierASN1(): Element; +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/UserNoticeQualifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/UserNoticeQualifier.php new file mode 100644 index 000000000..312402068 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/CertificatePolicy/UserNoticeQualifier.php @@ -0,0 +1,98 @@ +asSequence(); + $ref = null; + $text = null; + $idx = 0; + if ($seq->has($idx, Element::TYPE_SEQUENCE)) { + $ref = NoticeReference::fromASN1($seq->at($idx++)->asSequence()); + } + if ($seq->has($idx, Element::TYPE_STRING)) { + $text = DisplayText::fromASN1($seq->at($idx)->asString()); + } + return self::create($text, $ref); + } + + /** + * Whether explicit text is present. + */ + public function hasExplicitText(): bool + { + return isset($this->text); + } + + /** + * Get explicit text. + */ + public function explicitText(): DisplayText + { + if (! $this->hasExplicitText()) { + throw new LogicException('explicitText not set.'); + } + return $this->text; + } + + /** + * Whether notice reference is present. + */ + public function hasNoticeRef(): bool + { + return isset($this->ref); + } + + /** + * Get notice reference. + */ + public function noticeRef(): NoticeReference + { + if (! $this->hasNoticeRef()) { + throw new LogicException('noticeRef not set.'); + } + return $this->ref; + } + + protected function qualifierASN1(): Element + { + $elements = []; + if (isset($this->ref)) { + $elements[] = $this->ref->toASN1(); + } + if (isset($this->text)) { + $elements[] = $this->text->toASN1(); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPoint.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPoint.php new file mode 100644 index 000000000..d9475f98a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPoint.php @@ -0,0 +1,181 @@ +hasTagged(0)) { + // promoted to explicit tagging because underlying type is CHOICE + $name = DistributionPointName::fromTaggedType($seq->getTagged(0)->asExplicit()->asTagged()); + } + if ($seq->hasTagged(1)) { + $reasons = ReasonFlags::fromASN1( + $seq->getTagged(1) + ->asImplicit(Element::TYPE_BIT_STRING) + ->asBitString() + ); + } + if ($seq->hasTagged(2)) { + $issuer = GeneralNames::fromASN1( + $seq->getTagged(2) + ->asImplicit(Element::TYPE_SEQUENCE) + ->asSequence() + ); + } + return self::create($name, $reasons, $issuer); + } + + /** + * Check whether distribution point name is set. + */ + public function hasDistributionPointName(): bool + { + return isset($this->distributionPoint); + } + + /** + * Get distribution point name. + */ + public function distributionPointName(): DistributionPointName + { + if (! $this->hasDistributionPointName()) { + throw new LogicException('distributionPoint not set.'); + } + return $this->distributionPoint; + } + + /** + * Check whether distribution point name is set, and it's a full name. + */ + public function hasFullName(): bool + { + return $this->distributionPointName() + ->tag() === + DistributionPointName::TAG_FULL_NAME; + } + + /** + * Get full distribution point name. + */ + public function fullName(): FullName + { + if (! $this->distributionPoint instanceof FullName || ! $this->hasFullName()) { + throw new LogicException('fullName not set.'); + } + return $this->distributionPoint; + } + + /** + * Check whether distribution point name is set and it's a relative name. + */ + public function hasRelativeName(): bool + { + return $this->distributionPointName() + ->tag() === + DistributionPointName::TAG_RDN; + } + + /** + * Get relative distribution point name. + */ + public function relativeName(): RelativeName + { + if (! $this->distributionPoint instanceof RelativeName || ! $this->hasRelativeName()) { + throw new LogicException('nameRelativeToCRLIssuer not set.'); + } + return $this->distributionPoint; + } + + /** + * Check whether reasons flags is set. + */ + public function hasReasons(): bool + { + return isset($this->reasons); + } + + /** + * Get revocation reason flags. + */ + public function reasons(): ReasonFlags + { + if (! $this->hasReasons()) { + throw new LogicException('reasons not set.'); + } + return $this->reasons; + } + + /** + * Check whether cRLIssuer is set. + */ + public function hasCRLIssuer(): bool + { + return isset($this->issuer); + } + + /** + * Get CRL issuer. + */ + public function crlIssuer(): GeneralNames + { + if (! $this->hasCRLIssuer()) { + throw new LogicException('crlIssuer not set.'); + } + return $this->issuer; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = []; + if (isset($this->distributionPoint)) { + $elements[] = ExplicitlyTaggedType::create(0, $this->distributionPoint->toASN1()); + } + if (isset($this->reasons)) { + $elements[] = ImplicitlyTaggedType::create(1, $this->reasons->toASN1()); + } + if (isset($this->issuer)) { + $elements[] = ImplicitlyTaggedType::create(2, $this->issuer->toASN1()); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPointName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPointName.php new file mode 100644 index 000000000..633333a98 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/DistributionPointName.php @@ -0,0 +1,66 @@ +tag()) { + self::TAG_FULL_NAME => FullName::create(GeneralNames::fromASN1( + $el->asImplicit(Element::TYPE_SEQUENCE)->asSequence() + )), + self::TAG_RDN => RelativeName::create(RDN::fromASN1($el->asImplicit(Element::TYPE_SET)->asSet())), + default => throw new UnexpectedValueException( + 'DistributionPointName tag ' . $el->tag() . ' not supported.' + ), + }; + } + + /** + * Get type tag. + */ + public function tag(): int + { + return $this->tag; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): ImplicitlyTaggedType + { + return ImplicitlyTaggedType::create($this->tag, $this->_valueASN1()); + } + + /** + * Generate ASN.1 element. + */ + abstract protected function _valueASN1(): Element; +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/FullName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/FullName.php new file mode 100644 index 000000000..a315737c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/FullName.php @@ -0,0 +1,47 @@ +names; + } + + protected function _valueASN1(): Element + { + return $this->names->toASN1(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/ReasonFlags.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/ReasonFlags.php new file mode 100644 index 000000000..970b61c64 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/ReasonFlags.php @@ -0,0 +1,133 @@ +intNumber()); + } + + /** + * Check whether keyCompromise flag is set. + */ + public function isKeyCompromise(): bool + { + return $this->flagSet(self::KEY_COMPROMISE); + } + + /** + * Check whether cACompromise flag is set. + */ + public function isCACompromise(): bool + { + return $this->flagSet(self::CA_COMPROMISE); + } + + /** + * Check whether affiliationChanged flag is set. + */ + public function isAffiliationChanged(): bool + { + return $this->flagSet(self::AFFILIATION_CHANGED); + } + + /** + * Check whether superseded flag is set. + */ + public function isSuperseded(): bool + { + return $this->flagSet(self::SUPERSEDED); + } + + /** + * Check whether cessationOfOperation flag is set. + */ + public function isCessationOfOperation(): bool + { + return $this->flagSet(self::CESSATION_OF_OPERATION); + } + + /** + * Check whether certificateHold flag is set. + */ + public function isCertificateHold(): bool + { + return $this->flagSet(self::CERTIFICATE_HOLD); + } + + /** + * Check whether privilegeWithdrawn flag is set. + */ + public function isPrivilegeWithdrawn(): bool + { + return $this->flagSet(self::PRIVILEGE_WITHDRAWN); + } + + /** + * Check whether aACompromise flag is set. + */ + public function isAACompromise(): bool + { + return $this->flagSet(self::AA_COMPROMISE); + } + + /** + * Generate ASN.1 element. + */ + public function toASN1(): BitString + { + $flags = Flags::create($this->flags, 9); + return $flags->bitString() + ->withoutTrailingZeroes(); + } + + /** + * Check whether given flag is set. + */ + private function flagSet(int $flag): bool + { + return (bool) ($this->flags & $flag); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/RelativeName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/RelativeName.php new file mode 100644 index 000000000..5f0abe678 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/DistributionPoint/RelativeName.php @@ -0,0 +1,38 @@ +rdn; + } + + protected function _valueASN1(): Element + { + return $this->rdn->toASN1(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/ExtendedKeyUsageExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/ExtendedKeyUsageExtension.php new file mode 100644 index 000000000..f77cd0695 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/ExtendedKeyUsageExtension.php @@ -0,0 +1,160 @@ +purposes = $purposes; + } + + public static function create(bool $critical, string ...$purposes): self + { + return new self($critical, ...$purposes); + } + + /** + * Whether purposes are present. + * + * If multiple purposes are checked, all must be present. + */ + public function has(string ...$oids): bool + { + foreach ($oids as $oid) { + if (! in_array($oid, $this->purposes, true)) { + return false; + } + } + return true; + } + + /** + * Get key usage purpose OID's. + * + * @return string[] + */ + public function purposes(): array + { + return $this->purposes; + } + + /** + * Get the number of purposes. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->purposes); + } + + /** + * Get iterator for usage purposes. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->purposes); + } + + protected static function fromDER(string $data, bool $critical): static + { + $purposes = array_map( + static fn (UnspecifiedType $el) => $el->asObjectIdentifier() + ->oid(), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + return self::create($critical, ...$purposes); + } + + protected function valueASN1(): Element + { + $elements = array_map(static fn ($oid) => ObjectIdentifier::create($oid), $this->purposes); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Extension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Extension.php new file mode 100644 index 000000000..da4a80c08 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Extension.php @@ -0,0 +1,327 @@ + + */ + private const MAP_OID_TO_CLASS = [ + self::OID_AUTHORITY_KEY_IDENTIFIER => AuthorityKeyIdentifierExtension::class, + self::OID_SUBJECT_KEY_IDENTIFIER => SubjectKeyIdentifierExtension::class, + self::OID_KEY_USAGE => KeyUsageExtension::class, + self::OID_CERTIFICATE_POLICIES => CertificatePoliciesExtension::class, + self::OID_POLICY_MAPPINGS => PolicyMappingsExtension::class, + self::OID_SUBJECT_ALT_NAME => SubjectAlternativeNameExtension::class, + self::OID_ISSUER_ALT_NAME => IssuerAlternativeNameExtension::class, + self::OID_SUBJECT_DIRECTORY_ATTRIBUTES => SubjectDirectoryAttributesExtension::class, + self::OID_BASIC_CONSTRAINTS => BasicConstraintsExtension::class, + self::OID_NAME_CONSTRAINTS => NameConstraintsExtension::class, + self::OID_POLICY_CONSTRAINTS => PolicyConstraintsExtension::class, + self::OID_EXT_KEY_USAGE => ExtendedKeyUsageExtension::class, + self::OID_CRL_DISTRIBUTION_POINTS => CRLDistributionPointsExtension::class, + self::OID_INHIBIT_ANY_POLICY => InhibitAnyPolicyExtension::class, + self::OID_FRESHEST_CRL => FreshestCRLExtension::class, + self::OID_NO_REV_AVAIL => NoRevocationAvailableExtension::class, + self::OID_TARGET_INFORMATION => TargetInformationExtension::class, + self::OID_AUTHORITY_INFORMATION_ACCESS => AuthorityInformationAccessExtension::class, + self::OID_AA_CONTROLS => AAControlsExtension::class, + self::OID_SUBJECT_INFORMATION_ACCESS => SubjectInformationAccessExtension::class, + ]; + + /** + * Mapping from extensions ID to short name. + * + * @internal + * + * @var array + */ + private const MAP_OID_TO_NAME = [ + self::OID_AUTHORITY_KEY_IDENTIFIER => 'authorityKeyIdentifier', + self::OID_SUBJECT_KEY_IDENTIFIER => 'subjectKeyIdentifier', + self::OID_KEY_USAGE => 'keyUsage', + self::OID_PRIVATE_KEY_USAGE_PERIOD => 'privateKeyUsagePeriod', + self::OID_CERTIFICATE_POLICIES => 'certificatePolicies', + self::OID_POLICY_MAPPINGS => 'policyMappings', + self::OID_SUBJECT_ALT_NAME => 'subjectAltName', + self::OID_ISSUER_ALT_NAME => 'issuerAltName', + self::OID_SUBJECT_DIRECTORY_ATTRIBUTES => 'subjectDirectoryAttributes', + self::OID_BASIC_CONSTRAINTS => 'basicConstraints', + self::OID_NAME_CONSTRAINTS => 'nameConstraints', + self::OID_POLICY_CONSTRAINTS => 'policyConstraints', + self::OID_EXT_KEY_USAGE => 'extKeyUsage', + self::OID_CRL_DISTRIBUTION_POINTS => 'cRLDistributionPoints', + self::OID_INHIBIT_ANY_POLICY => 'inhibitAnyPolicy', + self::OID_FRESHEST_CRL => 'freshestCRL', + self::OID_NO_REV_AVAIL => 'noRevAvail', + self::OID_TARGET_INFORMATION => 'targetInformation', + self::OID_AUTHORITY_INFORMATION_ACCESS => 'authorityInfoAccess', + self::OID_AA_CONTROLS => 'aaControls', + self::OID_SUBJECT_INFORMATION_ACCESS => 'subjectInfoAccess', + self::OID_LOGOTYPE => 'logotype', + ]; + + /** + * @param string $oid Extension OID + * @param bool $critical Whether extension is critical + */ + protected function __construct( + private readonly string $oid, + private readonly bool $critical + ) { + } + + public function __toString(): string + { + return $this->extensionName(); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $idx = 0; + $extnID = $seq->at($idx++) + ->asObjectIdentifier() + ->oid(); + $critical = false; + if ($seq->has($idx, Element::TYPE_BOOLEAN)) { + $critical = $seq->at($idx++) + ->asBoolean() + ->value(); + } + $data = $seq->at($idx) + ->asOctetString() + ->string(); + if (array_key_exists($extnID, self::MAP_OID_TO_CLASS)) { + $cls = self::MAP_OID_TO_CLASS[$extnID]; + return $cls::fromDER($data, $critical); + } + return UnknownExtension::fromRawString($extnID, $critical, $data); + } + + /** + * Get extension OID. + */ + public function oid(): string + { + return $this->oid; + } + + /** + * Check whether extension is critical. + */ + public function isCritical(): bool + { + return $this->critical; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [ObjectIdentifier::create($this->oid)]; + if ($this->critical) { + $elements[] = Boolean::create(true); + } + $elements[] = $this->extnValue(); + return Sequence::create(...$elements); + } + + /** + * Get short name of the extension. + */ + public function extensionName(): string + { + if (array_key_exists($this->oid, self::MAP_OID_TO_NAME)) { + return self::MAP_OID_TO_NAME[$this->oid]; + } + return $this->oid(); + } + + /** + * Get ASN.1 structure of the extension value. + */ + abstract protected function valueASN1(): Element; + + /** + * Parse extension value from DER. + * + * @param string $data DER data + * @param bool $critical Whether extension is critical + */ + abstract protected static function fromDER(string $data, bool $critical): static; + + /** + * Get the extnValue element. + */ + protected function extnValue(): OctetString + { + return OctetString::create($this->valueASN1()->toDER()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/FreshestCRLExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/FreshestCRLExtension.php new file mode 100644 index 000000000..82ed6ec55 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/FreshestCRLExtension.php @@ -0,0 +1,20 @@ +skipCerts; + } + + protected static function fromDER(string $data, bool $critical): static + { + return self::create($critical, UnspecifiedType::fromDER($data)->asInteger()->intNumber()); + } + + protected function valueASN1(): Element + { + return Integer::create($this->skipCerts); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/IssuerAlternativeNameExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/IssuerAlternativeNameExtension.php new file mode 100644 index 000000000..574784038 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/IssuerAlternativeNameExtension.php @@ -0,0 +1,44 @@ +names; + } + + protected static function fromDER(string $data, bool $critical): static + { + return self::create($critical, GeneralNames::fromASN1(UnspecifiedType::fromDER($data)->asSequence())); + } + + protected function valueASN1(): Element + { + return $this->names->toASN1(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/KeyUsageExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/KeyUsageExtension.php new file mode 100644 index 000000000..d6b0356b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/KeyUsageExtension.php @@ -0,0 +1,142 @@ +_flagSet(self::DIGITAL_SIGNATURE); + } + + /** + * Check whether nonRepudiation/contentCommitment flag is set. + */ + public function isNonRepudiation(): bool + { + return $this->_flagSet(self::NON_REPUDIATION); + } + + /** + * Check whether keyEncipherment flag is set. + */ + public function isKeyEncipherment(): bool + { + return $this->_flagSet(self::KEY_ENCIPHERMENT); + } + + /** + * Check whether dataEncipherment flag is set. + */ + public function isDataEncipherment(): bool + { + return $this->_flagSet(self::DATA_ENCIPHERMENT); + } + + /** + * Check whether keyAgreement flag is set. + */ + public function isKeyAgreement(): bool + { + return $this->_flagSet(self::KEY_AGREEMENT); + } + + /** + * Check whether keyCertSign flag is set. + */ + public function isKeyCertSign(): bool + { + return $this->_flagSet(self::KEY_CERT_SIGN); + } + + /** + * Check whether cRLSign flag is set. + */ + public function isCRLSign(): bool + { + return $this->_flagSet(self::CRL_SIGN); + } + + /** + * Check whether encipherOnly flag is set. + */ + public function isEncipherOnly(): bool + { + return $this->_flagSet(self::ENCIPHER_ONLY); + } + + /** + * Check whether decipherOnly flag is set. + */ + public function isDecipherOnly(): bool + { + return $this->_flagSet(self::DECIPHER_ONLY); + } + + /** + * Check whether given flag is set. + */ + protected function _flagSet(int $flag): bool + { + return (bool) ($this->keyUsage & $flag); + } + + protected static function fromDER(string $data, bool $critical): static + { + return self::create( + $critical, + Flags::fromBitString(UnspecifiedType::fromDER($data)->asBitString(), 9)->intNumber() + ); + } + + protected function valueASN1(): Element + { + $flags = Flags::create($this->keyUsage, 9); + return $flags->bitString() + ->withoutTrailingZeroes(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php new file mode 100644 index 000000000..1cd1ba1d6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtree.php @@ -0,0 +1,99 @@ +base; + } + + public function getMin(): int + { + return $this->min; + } + + public function getMax(): ?int + { + return $this->max; + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $base = GeneralName::fromASN1($seq->at(0)->asTagged()); + $min = 0; + $max = null; + // GeneralName is a CHOICE, which may be tagged as otherName [0] + // or rfc822Name [1]. As minimum and maximum are also implicitly tagged, + // we have to iterate the remaining elements instead of just checking + // for tagged types. + $count = count($seq); + for ($i = 1; $i < $count; ++$i) { + $el = $seq->at($i) + ->expectTagged(); + switch ($el->tag()) { + case 0: + $min = $el->asImplicit(Element::TYPE_INTEGER) + ->asInteger() + ->intNumber(); + break; + case 1: + $max = $el->asImplicit(Element::TYPE_INTEGER) + ->asInteger() + ->intNumber(); + break; + } + } + return self::create($base, $min, $max); + } + + public function base(): GeneralName + { + return $this->base; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [$this->base->toASN1()]; + if ($this->min !== 0) { + $elements[] = ImplicitlyTaggedType::create(0, Integer::create($this->min)); + } + if (isset($this->max)) { + $elements[] = ImplicitlyTaggedType::create(1, Integer::create($this->max)); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtrees.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtrees.php new file mode 100644 index 000000000..a26908b40 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraints/GeneralSubtrees.php @@ -0,0 +1,94 @@ +subtrees = $subtrees; + } + + public static function create(GeneralSubtree ...$subtrees): self + { + return new self(...$subtrees); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $subtrees = array_map( + static fn (UnspecifiedType $el) => GeneralSubtree::fromASN1($el->asSequence()), + $seq->elements() + ); + if (count($subtrees) === 0) { + throw new UnexpectedValueException('GeneralSubtrees must contain at least one GeneralSubtree.'); + } + return self::create(...$subtrees); + } + + /** + * Get all subtrees. + * + * @return GeneralSubtree[] + */ + public function all(): array + { + return $this->subtrees; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + if (count($this->subtrees) === 0) { + throw new LogicException('No subtrees.'); + } + $elements = array_map(static fn (GeneralSubtree $gs) => $gs->toASN1(), $this->subtrees); + return Sequence::create(...$elements); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->subtrees); + } + + /** + * Get iterator for subtrees. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->subtrees); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraintsExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraintsExtension.php new file mode 100644 index 000000000..279a4012b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NameConstraintsExtension.php @@ -0,0 +1,106 @@ +permitted); + } + + /** + * Get permitted subtrees. + */ + public function permittedSubtrees(): GeneralSubtrees + { + if (! $this->hasPermittedSubtrees()) { + throw new LogicException('No permitted subtrees.'); + } + return $this->permitted; + } + + /** + * Whether excluded subtrees are present. + */ + public function hasExcludedSubtrees(): bool + { + return isset($this->excluded); + } + + /** + * Get excluded subtrees. + */ + public function excludedSubtrees(): GeneralSubtrees + { + if (! $this->hasExcludedSubtrees()) { + throw new LogicException('No excluded subtrees.'); + } + return $this->excluded; + } + + protected static function fromDER(string $data, bool $critical): static + { + $seq = UnspecifiedType::fromDER($data)->asSequence(); + $permitted = null; + $excluded = null; + if ($seq->hasTagged(0)) { + $permitted = GeneralSubtrees::fromASN1( + $seq->getTagged(0) + ->asImplicit(Element::TYPE_SEQUENCE)->asSequence() + ); + } + if ($seq->hasTagged(1)) { + $excluded = GeneralSubtrees::fromASN1( + $seq->getTagged(1) + ->asImplicit(Element::TYPE_SEQUENCE)->asSequence() + ); + } + return self::create($critical, $permitted, $excluded); + } + + protected function valueASN1(): Element + { + $elements = []; + if (isset($this->permitted)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->permitted->toASN1()); + } + if (isset($this->excluded)) { + $elements[] = ImplicitlyTaggedType::create(1, $this->excluded->toASN1()); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NoRevocationAvailableExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NoRevocationAvailableExtension.php new file mode 100644 index 000000000..aa3d0ad52 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/NoRevocationAvailableExtension.php @@ -0,0 +1,37 @@ +requireExplicitPolicy); + } + + public function requireExplicitPolicy(): int + { + if (! $this->hasRequireExplicitPolicy()) { + throw new LogicException('requireExplicitPolicy not set.'); + } + return $this->requireExplicitPolicy; + } + + /** + * Whether inhibitPolicyMapping is present. + */ + public function hasInhibitPolicyMapping(): bool + { + return isset($this->inhibitPolicyMapping); + } + + public function inhibitPolicyMapping(): int + { + if (! $this->hasInhibitPolicyMapping()) { + throw new LogicException('inhibitPolicyMapping not set.'); + } + return $this->inhibitPolicyMapping; + } + + protected static function fromDER(string $data, bool $critical): static + { + $seq = UnspecifiedType::fromDER($data)->asSequence(); + $require_explicit_policy = null; + $inhibit_policy_mapping = null; + if ($seq->hasTagged(0)) { + $require_explicit_policy = $seq->getTagged(0) + ->asImplicit(Element::TYPE_INTEGER)->asInteger()->intNumber(); + } + if ($seq->hasTagged(1)) { + $inhibit_policy_mapping = $seq->getTagged(1) + ->asImplicit(Element::TYPE_INTEGER)->asInteger()->intNumber(); + } + return self::create($critical, $require_explicit_policy, $inhibit_policy_mapping); + } + + protected function valueASN1(): Element + { + $elements = []; + if (isset($this->requireExplicitPolicy)) { + $elements[] = ImplicitlyTaggedType::create(0, Integer::create($this->requireExplicitPolicy)); + } + if (isset($this->inhibitPolicyMapping)) { + $elements[] = ImplicitlyTaggedType::create(1, Integer::create($this->inhibitPolicyMapping)); + } + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappings/PolicyMapping.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappings/PolicyMapping.php new file mode 100644 index 000000000..717503991 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappings/PolicyMapping.php @@ -0,0 +1,76 @@ +at(0) + ->asObjectIdentifier() + ->oid(); + $subject_policy = $seq->at(1) + ->asObjectIdentifier() + ->oid(); + return self::create($issuer_policy, $subject_policy); + } + + /** + * Get issuer domain policy. + * + * @return string OID in dotted format + */ + public function issuerDomainPolicy(): string + { + return $this->issuerDomainPolicy; + } + + /** + * Get subject domain policy. + * + * @return string OID in dotted format + */ + public function subjectDomainPolicy(): string + { + return $this->subjectDomainPolicy; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + ObjectIdentifier::create($this->issuerDomainPolicy), + ObjectIdentifier::create($this->subjectDomainPolicy) + ); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappingsExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappingsExtension.php new file mode 100644 index 000000000..ec142aa9c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/PolicyMappingsExtension.php @@ -0,0 +1,165 @@ +mappings = $mappings; + } + + public static function create(bool $critical, PolicyMapping ...$mappings): self + { + return new self($critical, ...$mappings); + } + + /** + * Get all mappings. + * + * @return PolicyMapping[] + */ + public function mappings(): array + { + return $this->mappings; + } + + /** + * Get mappings flattened into a single array of arrays of subject domains keyed by issuer domain. + * + * Eg. if policy mappings contains multiple mappings with the same issuer domain policy, their corresponding subject + * domain policies are placed under the same key. + * + * @return (string[])[] + */ + public function flattenedMappings(): array + { + $mappings = []; + foreach ($this->mappings as $mapping) { + $idp = $mapping->issuerDomainPolicy(); + if (! isset($mappings[$idp])) { + $mappings[$idp] = []; + } + array_push($mappings[$idp], $mapping->subjectDomainPolicy()); + } + return $mappings; + } + + /** + * Get all subject domain policy OIDs that are mapped to given issuer domain policy OID. + * + * @param string $oid Issuer domain policy + * + * @return string[] List of OIDs in dotted format + */ + public function issuerMappings(string $oid): array + { + $oids = []; + foreach ($this->mappings as $mapping) { + if ($mapping->issuerDomainPolicy() === $oid) { + $oids[] = $mapping->subjectDomainPolicy(); + } + } + return $oids; + } + + /** + * Get all mapped issuer domain policy OIDs. + * + * @return string[] + */ + public function issuerDomainPolicies(): array + { + $idps = array_map(static fn (PolicyMapping $mapping) => $mapping->issuerDomainPolicy(), $this->mappings); + return array_values(array_unique($idps)); + } + + /** + * Check whether policy mappings have anyPolicy mapped. + * + * RFC 5280 section 4.2.1.5 states that "Policies MUST NOT be mapped either to or from the special value anyPolicy". + */ + public function hasAnyPolicyMapping(): bool + { + foreach ($this->mappings as $mapping) { + if ($mapping->issuerDomainPolicy() === PolicyInformation::OID_ANY_POLICY) { + return true; + } + if ($mapping->subjectDomainPolicy() === PolicyInformation::OID_ANY_POLICY) { + return true; + } + } + return false; + } + + /** + * Get the number of mappings. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->mappings); + } + + /** + * Get iterator for policy mappings. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->mappings); + } + + protected static function fromDER(string $data, bool $critical): static + { + $mappings = array_map( + static fn (UnspecifiedType $el) => PolicyMapping::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + if (count($mappings) === 0) { + throw new UnexpectedValueException('PolicyMappings must have at least one mapping.'); + } + return self::create($critical, ...$mappings); + } + + protected function valueASN1(): Element + { + if (count($this->mappings) === 0) { + throw new LogicException('No mappings.'); + } + $elements = array_map(static fn (PolicyMapping $mapping) => $mapping->toASN1(), $this->mappings); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectAlternativeNameExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectAlternativeNameExtension.php new file mode 100644 index 000000000..7b4114041 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectAlternativeNameExtension.php @@ -0,0 +1,44 @@ +names; + } + + protected static function fromDER(string $data, bool $critical): static + { + return self::create($critical, GeneralNames::fromASN1(UnspecifiedType::fromDER($data)->asSequence())); + } + + protected function valueASN1(): Element + { + return $this->names->toASN1(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectDirectoryAttributesExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectDirectoryAttributesExtension.php new file mode 100644 index 000000000..51f8f405f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectDirectoryAttributesExtension.php @@ -0,0 +1,120 @@ +attributes = SequenceOfAttributes::create(...$attribs); + } + + public static function create(bool $critical, Attribute ...$attribs): self + { + return new self($critical, ...$attribs); + } + + /** + * Check whether attribute is present. + * + * @param string $name OID or attribute name + */ + public function has(string $name): bool + { + return $this->attributes->has($name); + } + + /** + * Get first attribute by OID or attribute name. + * + * @param string $name OID or attribute name + */ + public function firstOf(string $name): Attribute + { + return $this->attributes->firstOf($name); + } + + /** + * Get all attributes of given name. + * + * @param string $name OID or attribute name + * + * @return Attribute[] + */ + public function allOf(string $name): array + { + return $this->attributes->allOf($name); + } + + /** + * Get all attributes. + * + * @return Attribute[] + */ + public function all(): array + { + return $this->attributes->all(); + } + + /** + * Get number of attributes. + */ + public function count(): int + { + return count($this->attributes); + } + + /** + * Get iterator for attributes. + * + * @return ArrayIterator|Attribute[] + */ + public function getIterator(): ArrayIterator + { + return $this->attributes->getIterator(); + } + + protected static function fromDER(string $data, bool $critical): static + { + $attribs = SequenceOfAttributes::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + if (count($attribs) === 0) { + throw new UnexpectedValueException('SubjectDirectoryAttributes must have at least one Attribute.'); + } + return self::create($critical, ...$attribs->all()); + } + + protected function valueASN1(): Element + { + if (count($this->attributes) === 0) { + throw new LogicException('No attributes'); + } + return $this->attributes->toASN1(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectInformationAccessExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectInformationAccessExtension.php new file mode 100644 index 000000000..a000bef3f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectInformationAccessExtension.php @@ -0,0 +1,87 @@ +accessDescriptions = $accessDescriptions; + } + + public static function create(bool $critical, SubjectAccessDescription ...$accessDescriptions): self + { + return new self($critical, ...$accessDescriptions); + } + + /** + * Get the access descriptions. + * + * @return SubjectAccessDescription[] + */ + public function accessDescriptions(): array + { + return $this->accessDescriptions; + } + + /** + * Get the number of access descriptions. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->accessDescriptions); + } + + /** + * Get iterator for access descriptions. + * + * @return ArrayIterator List of SubjectAccessDescription objects + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->accessDescriptions); + } + + protected static function fromDER(string $data, bool $critical): static + { + $access = array_map( + static fn (UnspecifiedType $el) => SubjectAccessDescription::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + return self::create($critical, ...$access); + } + + protected function valueASN1(): Element + { + $elements = array_map(static fn (AccessDescription $access) => $access->toASN1(), $this->accessDescriptions); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectKeyIdentifierExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectKeyIdentifierExtension.php new file mode 100644 index 000000000..602352343 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/SubjectKeyIdentifierExtension.php @@ -0,0 +1,47 @@ +keyIdentifier; + } + + protected static function fromDER(string $data, bool $critical): static + { + return self::create($critical, UnspecifiedType::fromDER($data)->asOctetString()->string()); + } + + protected function valueASN1(): Element + { + return OctetString::create($this->keyIdentifier); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Target.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Target.php new file mode 100644 index 000000000..eb3f6af46 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Target.php @@ -0,0 +1,79 @@ +tag()) { + self::TYPE_NAME => TargetName::fromChosenASN1($el->asExplicit()->asTagged()), + self::TYPE_GROUP => TargetGroup::fromChosenASN1($el->asExplicit()->asTagged()), + self::TYPE_CERT => throw new RuntimeException('targetCert not supported.'), + default => throw new UnexpectedValueException('Target type ' . $el->tag() . ' not supported.'), + }; + } + + /** + * Get type tag. + */ + public function type(): int + { + return $this->type; + } + + /** + * Check whether target is equal to another. + */ + public function equals(self $other): bool + { + if ($this->type !== $other->type) { + return false; + } + if ($this->toASN1()->toDER() !== $other->toASN1()->toDER()) { + return false; + } + return true; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetGroup.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetGroup.php new file mode 100644 index 000000000..870203e1c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetGroup.php @@ -0,0 +1,55 @@ +name->string(); + } + + /** + * Get group name. + */ + public function name(): GeneralName + { + return $this->name; + } + + public function toASN1(): Element + { + return ExplicitlyTaggedType::create($this->type, $this->name->toASN1()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetName.php new file mode 100644 index 000000000..ef9bfe4de --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/TargetName.php @@ -0,0 +1,52 @@ +name->string(); + } + + public function name(): GeneralName + { + return $this->name; + } + + public function toASN1(): Element + { + return ExplicitlyTaggedType::create($this->type, $this->name->toASN1()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Targets.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Targets.php new file mode 100644 index 000000000..4961bb0b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/Target/Targets.php @@ -0,0 +1,126 @@ +targets = $targets; + } + + public static function create(Target ...$targets): self + { + return new self(...$targets); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $targets = array_map(static fn (UnspecifiedType $el) => Target::fromASN1($el->asTagged()), $seq->elements()); + return self::create(...$targets); + } + + /** + * Get all targets. + * + * @return Target[] + */ + public function all(): array + { + return $this->targets; + } + + /** + * Get all name targets. + * + * @return Target[] + */ + public function nameTargets(): array + { + return $this->allOfType(Target::TYPE_NAME); + } + + /** + * Get all group targets. + * + * @return Target[] + */ + public function groupTargets(): array + { + return $this->allOfType(Target::TYPE_GROUP); + } + + /** + * Check whether given target is present. + */ + public function hasTarget(Target $target): bool + { + foreach ($this->allOfType($target->type()) as $t) { + if ($target->equals($t)) { + return true; + } + } + return false; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = array_map(static fn (Target $target) => $target->toASN1(), $this->targets); + return Sequence::create(...$elements); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->targets); + } + + /** + * Get iterator for targets. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->targets); + } + + /** + * Get all targets of given type. + * + * @return Target[] + */ + private function allOfType(int $type): array + { + return array_values(array_filter($this->targets, static fn (Target $target) => $target->type() === $type)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/TargetInformationExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/TargetInformationExtension.php new file mode 100644 index 000000000..41f72be0b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/TargetInformationExtension.php @@ -0,0 +1,137 @@ +targets = $targets; + } + + /** + * Reset internal state on clone. + */ + public function __clone() + { + $this->merged = null; + } + + public static function create(bool $critical, Targets ...$targets): self + { + return new self($critical, ...$targets); + } + + /** + * Initialize from one or more Target objects. + * + * Extension criticality shall be set to true as specified by RFC 5755. + */ + public static function fromTargets(Target ...$target): self + { + return self::create(true, Targets::create(...$target)); + } + + /** + * Get all targets. + */ + public function targets(): Targets + { + if ($this->merged === null) { + $a = []; + foreach ($this->targets as $targets) { + $a = array_merge($a, $targets->all()); + } + $this->merged = Targets::create(...$a); + } + return $this->merged; + } + + /** + * Get all name targets. + * + * @return Target[] + */ + public function names(): array + { + return $this->targets() + ->nameTargets(); + } + + /** + * Get all group targets. + * + * @return Target[] + */ + public function groups(): array + { + return $this->targets() + ->groupTargets(); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->targets()); + } + + /** + * Get iterator for targets. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->targets()->all()); + } + + protected static function fromDER(string $data, bool $critical): static + { + $targets = array_map( + static fn (UnspecifiedType $el) => Targets::fromASN1($el->asSequence()), + UnspecifiedType::fromDER($data)->asSequence()->elements() + ); + return self::create($critical, ...$targets); + } + + protected function valueASN1(): Element + { + $elements = array_map(static fn (Targets $targets) => $targets->toASN1(), $this->targets); + return Sequence::create(...$elements); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/UnknownExtension.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/UnknownExtension.php new file mode 100644 index 000000000..64fea5716 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extension/UnknownExtension.php @@ -0,0 +1,61 @@ +toDER()); + } + + /** + * Create instance from a raw encoded extension value. + */ + public static function fromRawString(string $oid, bool $critical, string $data): self + { + return new self($oid, $critical, NullType::create(), $data); + } + + /** + * Get the encoded extension value. + */ + public function extensionValue(): string + { + return $this->data; + } + + protected function extnValue(): OctetString + { + return OctetString::create($this->data); + } + + protected function valueASN1(): Element + { + return $this->element; + } + + protected static function fromDER(string $data, bool $critical): static + { + throw new BadMethodCallException(__FUNCTION__ . ' must be implemented in derived class.'); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extensions.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extensions.php new file mode 100644 index 000000000..692380aef --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Extensions.php @@ -0,0 +1,344 @@ +extensions = []; + foreach ($extensions as $ext) { + $this->extensions[$ext->oid()] = $ext; + } + } + + public static function create(Extension ...$extensions): self + { + return new self(...$extensions); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $extensions = array_map( + static fn (UnspecifiedType $el) => Extension::fromASN1($el->asSequence()), + $seq->elements() + ); + return self::create(...$extensions); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = array_values(array_map(static fn ($ext) => $ext->toASN1(), $this->extensions)); + return Sequence::create(...$elements); + } + + /** + * Get self with extensions added. + * + * @param Extension ...$exts One or more extensions to add + */ + public function withExtensions(Extension ...$exts): self + { + $obj = clone $this; + foreach ($exts as $ext) { + $obj->extensions[$ext->oid()] = $ext; + } + return $obj; + } + + /** + * Check whether extension is present. + * + * @param string $oid Extensions OID + */ + public function has(string $oid): bool + { + return isset($this->extensions[$oid]); + } + + /** + * Get extension by OID. + */ + public function get(string $oid): Extension + { + if (! $this->has($oid)) { + throw new LogicException("No extension by OID {$oid}."); + } + return $this->extensions[$oid]; + } + + /** + * Check whether 'Authority Key Identifier' extension is present. + */ + public function hasAuthorityKeyIdentifier(): bool + { + return $this->has(Extension::OID_AUTHORITY_KEY_IDENTIFIER); + } + + /** + * Get 'Authority Key Identifier' extension. + */ + public function authorityKeyIdentifier(): AuthorityKeyIdentifierExtension + { + return $this->get(Extension::OID_AUTHORITY_KEY_IDENTIFIER); + } + + /** + * Check whether 'Subject Key Identifier' extension is present. + */ + public function hasSubjectKeyIdentifier(): bool + { + return $this->has(Extension::OID_SUBJECT_KEY_IDENTIFIER); + } + + /** + * Get 'Subject Key Identifier' extension. + */ + public function subjectKeyIdentifier(): SubjectKeyIdentifierExtension + { + return $this->get(Extension::OID_SUBJECT_KEY_IDENTIFIER); + } + + /** + * Check whether 'Key Usage' extension is present. + */ + public function hasKeyUsage(): bool + { + return $this->has(Extension::OID_KEY_USAGE); + } + + /** + * Get 'Key Usage' extension. + */ + public function keyUsage(): KeyUsageExtension + { + return $this->get(Extension::OID_KEY_USAGE); + } + + /** + * Check whether 'Certificate Policies' extension is present. + */ + public function hasCertificatePolicies(): bool + { + return $this->has(Extension::OID_CERTIFICATE_POLICIES); + } + + /** + * Get 'Certificate Policies' extension. + */ + public function certificatePolicies(): CertificatePoliciesExtension + { + return $this->get(Extension::OID_CERTIFICATE_POLICIES); + } + + /** + * Check whether 'Policy Mappings' extension is present. + */ + public function hasPolicyMappings(): bool + { + return $this->has(Extension::OID_POLICY_MAPPINGS); + } + + /** + * Get 'Policy Mappings' extension. + */ + public function policyMappings(): PolicyMappingsExtension + { + return $this->get(Extension::OID_POLICY_MAPPINGS); + } + + /** + * Check whether 'Subject Alternative Name' extension is present. + */ + public function hasSubjectAlternativeName(): bool + { + return $this->has(Extension::OID_SUBJECT_ALT_NAME); + } + + /** + * Get 'Subject Alternative Name' extension. + */ + public function subjectAlternativeName(): SubjectAlternativeNameExtension + { + return $this->get(Extension::OID_SUBJECT_ALT_NAME); + } + + /** + * Check whether 'Issuer Alternative Name' extension is present. + */ + public function hasIssuerAlternativeName(): bool + { + return $this->has(Extension::OID_ISSUER_ALT_NAME); + } + + /** + * Get 'Issuer Alternative Name' extension. + */ + public function issuerAlternativeName(): IssuerAlternativeNameExtension + { + return $this->get(Extension::OID_ISSUER_ALT_NAME); + } + + /** + * Check whether 'Basic Constraints' extension is present. + */ + public function hasBasicConstraints(): bool + { + return $this->has(Extension::OID_BASIC_CONSTRAINTS); + } + + /** + * Get 'Basic Constraints' extension. + */ + public function basicConstraints(): BasicConstraintsExtension + { + return $this->get(Extension::OID_BASIC_CONSTRAINTS); + } + + /** + * Check whether 'Name Constraints' extension is present. + */ + public function hasNameConstraints(): bool + { + return $this->has(Extension::OID_NAME_CONSTRAINTS); + } + + /** + * Get 'Name Constraints' extension. + */ + public function nameConstraints(): NameConstraintsExtension + { + return $this->get(Extension::OID_NAME_CONSTRAINTS); + } + + /** + * Check whether 'Policy Constraints' extension is present. + */ + public function hasPolicyConstraints(): bool + { + return $this->has(Extension::OID_POLICY_CONSTRAINTS); + } + + /** + * Get 'Policy Constraints' extension. + */ + public function policyConstraints(): PolicyConstraintsExtension + { + return $this->get(Extension::OID_POLICY_CONSTRAINTS); + } + + /** + * Check whether 'Extended Key Usage' extension is present. + */ + public function hasExtendedKeyUsage(): bool + { + return $this->has(Extension::OID_EXT_KEY_USAGE); + } + + /** + * Get 'Extended Key Usage' extension. + */ + public function extendedKeyUsage(): ExtendedKeyUsageExtension + { + return $this->get(Extension::OID_EXT_KEY_USAGE); + } + + /** + * Check whether 'CRL Distribution Points' extension is present. + */ + public function hasCRLDistributionPoints(): bool + { + return $this->has(Extension::OID_CRL_DISTRIBUTION_POINTS); + } + + /** + * Get 'CRL Distribution Points' extension. + */ + public function crlDistributionPoints(): CRLDistributionPointsExtension + { + return $this->get(Extension::OID_CRL_DISTRIBUTION_POINTS); + } + + /** + * Check whether 'Inhibit anyPolicy' extension is present. + */ + public function hasInhibitAnyPolicy(): bool + { + return $this->has(Extension::OID_INHIBIT_ANY_POLICY); + } + + /** + * Get 'Inhibit anyPolicy' extension. + */ + public function inhibitAnyPolicy(): InhibitAnyPolicyExtension + { + return $this->get(Extension::OID_INHIBIT_ANY_POLICY); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->extensions); + } + + /** + * Get iterator for extensions. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): Traversable + { + return new ArrayIterator($this->extensions); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/TBSCertificate.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/TBSCertificate.php new file mode 100644 index 000000000..c917e3692 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/TBSCertificate.php @@ -0,0 +1,527 @@ +extensions = Extensions::create(); + } + + public static function create( + Name $subject, + PublicKeyInfo $subjectPublicKeyInfo, + Name $issuer, + Validity $validity + ): self { + return new self($subject, $subjectPublicKeyInfo, $issuer, $validity); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $idx = 0; + if ($seq->hasTagged(0)) { + ++$idx; + $version = $seq->getTagged(0) + ->asExplicit() + ->asInteger() + ->intNumber(); + } else { + $version = self::VERSION_1; + } + $serial = $seq->at($idx++) + ->asInteger() + ->number(); + $algo = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence()); + if (! $algo instanceof SignatureAlgorithmIdentifier) { + throw new UnexpectedValueException('Unsupported signature algorithm ' . $algo->name() . '.'); + } + $issuer = Name::fromASN1($seq->at($idx++)->asSequence()); + $validity = Validity::fromASN1($seq->at($idx++)->asSequence()); + $subject = Name::fromASN1($seq->at($idx++)->asSequence()); + $pki = PublicKeyInfo::fromASN1($seq->at($idx++)->asSequence()); + $tbs_cert = self::create($subject, $pki, $issuer, $validity) + ->withVersion($version) + ->withSerialNumber($serial) + ->withSignature($algo) + ; + if ($seq->hasTagged(1)) { + $tbs_cert = $tbs_cert->withIssuerUniqueID(UniqueIdentifier::fromASN1( + $seq->getTagged(1) + ->asImplicit(Element::TYPE_BIT_STRING) + ->asBitString() + )); + } + if ($seq->hasTagged(2)) { + $tbs_cert = $tbs_cert->withSubjectUniqueID(UniqueIdentifier::fromASN1( + $seq->getTagged(2) + ->asImplicit(Element::TYPE_BIT_STRING) + ->asBitString() + )); + } + if ($seq->hasTagged(3)) { + $tbs_cert = $tbs_cert->withExtensions(Extensions::fromASN1($seq->getTagged(3)->asExplicit()->asSequence())); + } + return $tbs_cert; + } + + /** + * Initialize from certification request. + * + * Note that signature is not verified and must be done by the caller. + */ + public static function fromCSR(CertificationRequest $cr): self + { + $cri = $cr->certificationRequestInfo(); + $tbs_cert = self::create( + $cri->subject(), + $cri->subjectPKInfo(), + Name::create(), + Validity::fromStrings(null, null) + ); + // if CSR has Extension Request attribute + if ($cri->hasAttributes()) { + $attribs = $cri->attributes(); + if ($attribs->hasExtensionRequest()) { + $tbs_cert = $tbs_cert->withExtensions($attribs->extensionRequest()->extensions()); + } + } + // add Subject Key Identifier extension + return $tbs_cert->withAdditionalExtensions( + SubjectKeyIdentifierExtension::create(false, $cri->subjectPKInfo()->keyIdentifier()) + ); + } + + /** + * Get self with fields set from the issuer's certificate. + * + * Issuer shall be set to issuing certificate's subject. Authority key identifier extensions shall be added with a + * key identifier set to issuing certificate's public key identifier. + * + * @param Certificate $cert Issuing party's certificate + */ + public function withIssuerCertificate(Certificate $cert): self + { + $obj = clone $this; + // set issuer DN from cert's subject + $obj->issuer = $cert->tbsCertificate() + ->subject(); + // add authority key identifier extension + $key_id = $cert->tbsCertificate() + ->subjectPublicKeyInfo() + ->keyIdentifier(); + $obj->extensions = $obj->extensions->withExtensions(AuthorityKeyIdentifierExtension::create(false, $key_id)); + return $obj; + } + + /** + * Get self with given version. + * + * If version is not set, appropriate version is automatically determined during signing. + */ + public function withVersion(int $version): self + { + $obj = clone $this; + $obj->version = $version; + return $obj; + } + + /** + * Get self with given serial number. + * + * @param int|string $serial Base 10 number + */ + public function withSerialNumber(int|string $serial): self + { + $obj = clone $this; + $obj->serialNumber = strval($serial); + return $obj; + } + + /** + * Get self with random positive serial number. + * + * @param int $size Number of random bytes + */ + public function withRandomSerialNumber(int $size): self + { + // ensure that first byte is always non-zero and having first bit unset + $num = BigInteger::of(random_int(1, 0x7f)); + for ($i = 1; $i < $size; ++$i) { + $num = $num->shiftedLeft(8); + $num = $num->plus(random_int(0, 0xff)); + } + return $this->withSerialNumber($num->toBase(10)); + } + + /** + * Get self with given signature algorithm. + */ + public function withSignature(SignatureAlgorithmIdentifier $algo): self + { + $obj = clone $this; + $obj->signature = $algo; + return $obj; + } + + /** + * Get self with given issuer. + */ + public function withIssuer(Name $issuer): self + { + $obj = clone $this; + $obj->issuer = $issuer; + return $obj; + } + + /** + * Get self with given validity. + */ + public function withValidity(Validity $validity): self + { + $obj = clone $this; + $obj->validity = $validity; + return $obj; + } + + /** + * Get self with given subject. + */ + public function withSubject(Name $subject): self + { + $obj = clone $this; + $obj->subject = $subject; + return $obj; + } + + /** + * Get self with given subject public key info. + */ + public function withSubjectPublicKeyInfo(PublicKeyInfo $pub_key_info): self + { + $obj = clone $this; + $obj->subjectPublicKeyInfo = $pub_key_info; + return $obj; + } + + /** + * Get self with issuer unique ID. + */ + public function withIssuerUniqueID(UniqueIdentifier $id): self + { + $obj = clone $this; + $obj->issuerUniqueID = $id; + return $obj; + } + + /** + * Get self with subject unique ID. + */ + public function withSubjectUniqueID(UniqueIdentifier $id): self + { + $obj = clone $this; + $obj->subjectUniqueID = $id; + return $obj; + } + + /** + * Get self with given extensions. + */ + public function withExtensions(Extensions $extensions): self + { + $obj = clone $this; + $obj->extensions = $extensions; + return $obj; + } + + /** + * Get self with extensions added. + * + * @param Extension ...$exts One or more Extension objects + */ + public function withAdditionalExtensions(Extension ...$exts): self + { + $obj = clone $this; + $obj->extensions = $obj->extensions->withExtensions(...$exts); + return $obj; + } + + /** + * Check whether version is set. + */ + public function hasVersion(): bool + { + return isset($this->version); + } + + /** + * Get certificate version. + */ + public function version(): int + { + if (! $this->hasVersion()) { + throw new LogicException('version not set.'); + } + return $this->version; + } + + /** + * Check whether serial number is set. + */ + public function hasSerialNumber(): bool + { + return isset($this->serialNumber); + } + + /** + * Get serial number. + * + * @return string Base 10 integer + */ + public function serialNumber(): string + { + if (! $this->hasSerialNumber()) { + throw new LogicException('serialNumber not set.'); + } + return $this->serialNumber; + } + + /** + * Check whether signature algorithm is set. + */ + public function hasSignature(): bool + { + return isset($this->signature); + } + + /** + * Get signature algorithm. + */ + public function signature(): SignatureAlgorithmIdentifier + { + if (! $this->hasSignature()) { + throw new LogicException('signature not set.'); + } + return $this->signature; + } + + public function issuer(): Name + { + return $this->issuer; + } + + /** + * Get validity period. + */ + public function validity(): Validity + { + return $this->validity; + } + + public function subject(): Name + { + return $this->subject; + } + + /** + * Get subject public key. + */ + public function subjectPublicKeyInfo(): PublicKeyInfo + { + return $this->subjectPublicKeyInfo; + } + + /** + * Whether issuer unique identifier is present. + */ + public function hasIssuerUniqueID(): bool + { + return isset($this->issuerUniqueID); + } + + public function issuerUniqueID(): UniqueIdentifier + { + if (! $this->hasIssuerUniqueID()) { + throw new LogicException('issuerUniqueID not set.'); + } + return $this->issuerUniqueID; + } + + /** + * Whether subject unique identifier is present. + */ + public function hasSubjectUniqueID(): bool + { + return isset($this->subjectUniqueID); + } + + public function subjectUniqueID(): UniqueIdentifier + { + if (! $this->hasSubjectUniqueID()) { + throw new LogicException('subjectUniqueID not set.'); + } + return $this->subjectUniqueID; + } + + public function extensions(): Extensions + { + return $this->extensions; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = []; + $version = $this->version(); + // if version is not default + if ($version !== self::VERSION_1) { + $elements[] = ExplicitlyTaggedType::create(0, Integer::create($version)); + } + $serial = $this->serialNumber(); + $signature = $this->signature(); + // add required elements + array_push( + $elements, + Integer::create($serial), + $signature->toASN1(), + $this->issuer->toASN1(), + $this->validity->toASN1(), + $this->subject->toASN1(), + $this->subjectPublicKeyInfo->toASN1() + ); + if (isset($this->issuerUniqueID)) { + $elements[] = ImplicitlyTaggedType::create(1, $this->issuerUniqueID->toASN1()); + } + if (isset($this->subjectUniqueID)) { + $elements[] = ImplicitlyTaggedType::create(2, $this->subjectUniqueID->toASN1()); + } + if (count($this->extensions) !== 0) { + $elements[] = ExplicitlyTaggedType::create(3, $this->extensions->toASN1()); + } + return Sequence::create(...$elements); + } + + /** + * Create signed certificate. + * + * @param SignatureAlgorithmIdentifier $algo Algorithm used for signing + * @param PrivateKeyInfo $privkey_info Private key used for signing + * @param null|Crypto $crypto Crypto engine, use default if not set + */ + public function sign( + SignatureAlgorithmIdentifier $algo, + PrivateKeyInfo $privkey_info, + ?Crypto $crypto = null + ): Certificate { + $crypto ??= Crypto::getDefault(); + $tbs_cert = clone $this; + if (! isset($tbs_cert->version)) { + $tbs_cert->version = $tbs_cert->_determineVersion(); + } + if (! isset($tbs_cert->serialNumber)) { + $tbs_cert->serialNumber = '0'; + } + $tbs_cert->signature = $algo; + $data = $tbs_cert->toASN1() + ->toDER(); + $signature = $crypto->sign($data, $privkey_info, $algo); + return Certificate::create($tbs_cert, $algo, $signature); + } + + /** + * Determine minimum version for the certificate. + */ + private function _determineVersion(): int + { + // if extensions are present + if (count($this->extensions) !== 0) { + return self::VERSION_3; + } + // if UniqueIdentifier is present + if (isset($this->issuerUniqueID) || isset($this->subjectUniqueID)) { + return self::VERSION_2; + } + return self::VERSION_1; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Time.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Time.php new file mode 100644 index 000000000..8e2ec909c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Time.php @@ -0,0 +1,103 @@ +type = $type ?? self::determineType($dt); + } + + public static function create(DateTimeImmutable $dt, ?int $time = null): self + { + return new self($dt, $time); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(TimeType $el): self + { + // Pass the type of the original ASN.1 primitive + if ($el instanceof UTCTime) { + return self::create($el->dateTime(), Element::TYPE_UTC_TIME); + } + if ($el instanceof GeneralizedTime) { + return self::create($el->dateTime(), Element::TYPE_GENERALIZED_TIME); + } + + return self::create($el->dateTime()); // TODO: should never happen? + } + + /** + * Initialize from date string. + */ + public static function fromString(?string $time, ?string $tz = null): self + { + return self::create(self::createDateTime($time, $tz)); + } + + public function dateTime(): DateTimeImmutable + { + return $this->dt; + } + + /** + * Generate ASN.1. + */ + public function toASN1(): TimeType + { + $dt = $this->dt; + switch ($this->type) { + case Element::TYPE_UTC_TIME: + return UTCTime::create($dt); + case Element::TYPE_GENERALIZED_TIME: + // GeneralizedTime must not contain fractional seconds + // (rfc5280 4.1.2.5.2) + if ((int) $dt->format('u') !== 0) { + // remove fractional seconds (round down) + $dt = self::roundDownFractionalSeconds($dt); + } + return GeneralizedTime::create($dt); + } + throw new UnexpectedValueException('Time type ' . Element::tagToName($this->type) . ' not supported.'); + } + + /** + * Determine whether to use UTCTime or GeneralizedTime ASN.1 type. + * + * @return int Type tag + */ + protected static function determineType(DateTimeImmutable $dt): int + { + if ($dt->format('Y') >= 2050) { + return Element::TYPE_GENERALIZED_TIME; + } + return Element::TYPE_UTC_TIME; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/UniqueIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/UniqueIdentifier.php new file mode 100644 index 000000000..da6a7f8b7 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/UniqueIdentifier.php @@ -0,0 +1,65 @@ +uid->string(); + } + + /** + * Get unique identifier as a bit string. + */ + public function bitString(): BitString + { + return $this->uid; + } + + /** + * Get ASN.1 element. + */ + public function toASN1(): BitString + { + return $this->uid; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Validity.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Validity.php new file mode 100644 index 000000000..c58c39b9f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Certificate/Validity.php @@ -0,0 +1,72 @@ +at(0)->asTime()); + $na = Time::fromASN1($seq->at(1)->asTime()); + return self::create($nb, $na); + } + + /** + * Initialize from date strings. + * + * @param null|string $nb_date Not before date + * @param null|string $na_date Not after date + * @param null|string $tz Timezone string + */ + public static function fromStrings(?string $nb_date, ?string $na_date, ?string $tz = null): self + { + return self::create(Time::fromString($nb_date, $tz), Time::fromString($na_date, $tz)); + } + + /** + * Get not before time. + */ + public function notBefore(): Time + { + return $this->notBefore; + } + + /** + * Get not after time. + */ + public function notAfter(): Time + { + return $this->notAfter; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create($this->notBefore->toASN1(), $this->notAfter->toASN1()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/CertificationPath.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/CertificationPath.php new file mode 100644 index 000000000..098af86bb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/CertificationPath.php @@ -0,0 +1,178 @@ +certificates = $certificates; + } + + public static function create(Certificate ...$certificates): self + { + return new self(...$certificates); + } + + /** + * Initialize from a certificate chain. + */ + public static function fromCertificateChain(CertificateChain $chain): self + { + return self::create(...array_reverse($chain->certificates(), false)); + } + + /** + * Build certification path to given target. + * + * @param Certificate $target Target end-entity certificate + * @param CertificateBundle $trust_anchors List of trust anchors + * @param null|CertificateBundle $intermediate Optional intermediate certificates + */ + public static function toTarget( + Certificate $target, + CertificateBundle $trust_anchors, + ?CertificateBundle $intermediate = null + ): self { + return CertificationPathBuilder::create($trust_anchors)->shortestPathToTarget($target, $intermediate); + } + + /** + * Build certification path from given trust anchor to target certificate, using intermediate certificates from + * given bundle. + * + * @param Certificate $trust_anchor Trust anchor certificate + * @param Certificate $target Target end-entity certificate + * @param null|CertificateBundle $intermediate Optional intermediate certificates + */ + public static function fromTrustAnchorToTarget( + Certificate $trust_anchor, + Certificate $target, + ?CertificateBundle $intermediate = null + ): self { + return self::toTarget($target, CertificateBundle::create($trust_anchor), $intermediate); + } + + /** + * Get certificates. + * + * @return Certificate[] + */ + public function certificates(): array + { + return $this->certificates; + } + + /** + * Get the trust anchor certificate from the path. + */ + public function trustAnchorCertificate(): Certificate + { + if (count($this->certificates) === 0) { + throw new LogicException('No certificates.'); + } + return $this->certificates[0]; + } + + /** + * Get the end-entity certificate from the path. + */ + public function endEntityCertificate(): Certificate + { + if (count($this->certificates) === 0) { + throw new LogicException('No certificates.'); + } + return $this->certificates[count($this->certificates) - 1]; + } + + /** + * Get certification path as a certificate chain. + */ + public function certificateChain(): CertificateChain + { + return CertificateChain::create(...array_reverse($this->certificates, false)); + } + + /** + * Check whether certification path starts with one ore more given certificates in parameter order. + * + * @param Certificate ...$certs Certificates + */ + public function startsWith(Certificate ...$certs): bool + { + $n = count($certs); + if ($n > count($this->certificates)) { + return false; + } + for ($i = 0; $i < $n; ++$i) { + if (! $certs[$i]->equals($this->certificates[$i])) { + return false; + } + } + return true; + } + + /** + * Validate certification path. + * + * @param null|Crypto $crypto Crypto engine, use default if not set + */ + public function validate(PathValidationConfig $config, ?Crypto $crypto = null): PathValidationResult + { + $crypto ??= Crypto::getDefault(); + return PathValidator::create($crypto, $config, ...$this->certificates)->validate(); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->certificates); + } + + /** + * Get iterator for certificates. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->certificates); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Exception/PathBuildingException.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Exception/PathBuildingException.php new file mode 100644 index 000000000..a55536e6a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Exception/PathBuildingException.php @@ -0,0 +1,14 @@ +resolvePathsToTarget($target, $intermediate); + // map paths to CertificationPath objects + return array_map(static fn ($certs) => CertificationPath::create(...$certs), $paths); + } + + /** + * Get the shortest path to given target certificate from any trust anchor. + * + * @param Certificate $target Target certificate + * @param null|CertificateBundle $intermediate Optional intermediate certificates + */ + public function shortestPathToTarget( + Certificate $target, + ?CertificateBundle $intermediate = null + ): CertificationPath { + $paths = $this->allPathsToTarget($target, $intermediate); + if (count($paths) === 0) { + throw new PathBuildingException('No certification paths.'); + } + usort($paths, fn ($a, $b) => count($a) < count($b) ? -1 : 1); + return reset($paths); + } + + /** + * Find all issuers of the target certificate from a given bundle. + * + * @param Certificate $target Target certificate + * @param CertificateBundle $bundle Certificates to search + * + * @return Certificate[] + */ + private function findIssuers(Certificate $target, CertificateBundle $bundle): array + { + $issuers = []; + $issuer_name = $target->tbsCertificate() + ->issuer(); + $extensions = $target->tbsCertificate() + ->extensions(); + // find by authority key identifier + if ($extensions->hasAuthorityKeyIdentifier()) { + $ext = $extensions->authorityKeyIdentifier(); + if ($ext->hasKeyIdentifier()) { + foreach ($bundle->allBySubjectKeyIdentifier($ext->keyIdentifier()) as $issuer) { + // check that issuer name matches + if ($issuer->tbsCertificate()->subject()->equals($issuer_name)) { + $issuers[] = $issuer; + } + } + } + } + return $issuers; + } + + /** + * Resolve all possible certification paths from any trust anchor to the target certificate, using optional + * intermediate certificates. + * + * Helper method for allPathsToTarget to be called recursively. + * + * @return array> Array of arrays containing path certificates + * @todo Implement loop detection + */ + private function resolvePathsToTarget(Certificate $target, ?CertificateBundle $intermediate = null): array + { + // array of possible paths + $paths = []; + // signed by certificate in the trust list + foreach ($this->findIssuers($target, $this->trustList) as $issuer) { + // if target is self-signed, path consists of only + // the target certificate + if ($target->equals($issuer)) { + $paths[] = [$target]; + } else { + $paths[] = [$issuer, $target]; + } + } + if (isset($intermediate)) { + // signed by intermediate certificate + foreach ($this->findIssuers($target, $intermediate) as $issuer) { + // intermediate certificate must not be self-signed + if ($issuer->isSelfIssued()) { + continue; + } + // resolve paths to issuer + $subpaths = $this->resolvePathsToTarget($issuer, $intermediate); + foreach ($subpaths as $path) { + $paths[] = array_merge($path, [$target]); + } + } + } + + return $paths; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationConfig.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationConfig.php new file mode 100644 index 000000000..3fbf04f6b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationConfig.php @@ -0,0 +1,210 @@ +policySet = [PolicyInformation::OID_ANY_POLICY]; + $this->policyMappingInhibit = false; + $this->explicitPolicy = false; + $this->anyPolicyInhibit = false; + } + + public static function create(DateTimeImmutable $dateTime, int $maxLength): self + { + return new self($dateTime, $maxLength); + } + + /** + * Get default configuration. + */ + public static function defaultConfig(): self + { + return self::create(new DateTimeImmutable(), 3); + } + + /** + * Get self with maximum path length. + */ + public function withMaxLength(int $length): self + { + $obj = clone $this; + $obj->maxLength = $length; + return $obj; + } + + /** + * Get self with reference date and time. + */ + public function withDateTime(DateTimeImmutable $dt): self + { + $obj = clone $this; + $obj->dateTime = $dt; + return $obj; + } + + /** + * Get self with trust anchor certificate. + */ + public function withTrustAnchor(Certificate $ca): self + { + $obj = clone $this; + $obj->trustAnchor = $ca; + return $obj; + } + + /** + * Get self with initial-policy-mapping-inhibit set. + */ + public function withPolicyMappingInhibit(bool $flag): self + { + $obj = clone $this; + $obj->policyMappingInhibit = $flag; + return $obj; + } + + /** + * Get self with initial-explicit-policy set. + */ + public function withExplicitPolicy(bool $flag): self + { + $obj = clone $this; + $obj->explicitPolicy = $flag; + return $obj; + } + + /** + * Get self with initial-any-policy-inhibit set. + */ + public function withAnyPolicyInhibit(bool $flag): self + { + $obj = clone $this; + $obj->anyPolicyInhibit = $flag; + return $obj; + } + + /** + * Get self with user-initial-policy-set set to policy OIDs. + * + * @param string ...$policies List of policy OIDs + */ + public function withPolicySet(string ...$policies): self + { + $obj = clone $this; + $obj->policySet = $policies; + return $obj; + } + + /** + * Get maximum certification path length. + */ + public function maxLength(): int + { + return $this->maxLength; + } + + /** + * Get reference date and time. + */ + public function dateTime(): DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Get user-initial-policy-set. + * + * @return string[] Array of OID's + */ + public function policySet(): array + { + return $this->policySet; + } + + /** + * Check whether trust anchor certificate is set. + */ + public function hasTrustAnchor(): bool + { + return isset($this->trustAnchor); + } + + /** + * Get trust anchor certificate. + */ + public function trustAnchor(): Certificate + { + if (! $this->hasTrustAnchor()) { + throw new LogicException('No trust anchor.'); + } + return $this->trustAnchor; + } + + public function policyMappingInhibit(): bool + { + return $this->policyMappingInhibit; + } + + public function explicitPolicy(): bool + { + return $this->explicitPolicy; + } + + public function anyPolicyInhibit(): bool + { + return $this->anyPolicyInhibit; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationResult.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationResult.php new file mode 100644 index 000000000..b80e89f57 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidationResult.php @@ -0,0 +1,99 @@ +certificates = array_values($certificates); + } + + /** + * @param Certificate[] $certificates Certificates in a certification path + * @param null|PolicyTree $policyTree Valid policy tree + * @param PublicKeyInfo $publicKeyInfo Public key of the end-entity certificate + * @param AlgorithmIdentifierType $publicKeyAlgo Public key algorithm of the end-entity certificate + * @param null|Element $publicKeyParameters Algorithm parameters + */ + public static function create( + array $certificates, + ?PolicyTree $policyTree, + PublicKeyInfo $publicKeyInfo, + AlgorithmIdentifierType $publicKeyAlgo, + ?Element $publicKeyParameters = null + ): self { + return new self($certificates, $policyTree, $publicKeyInfo, $publicKeyAlgo, $publicKeyParameters); + } + + public function getPolicyTree(): ?PolicyTree + { + return $this->policyTree; + } + + public function getPublicKeyInfo(): PublicKeyInfo + { + return $this->publicKeyInfo; + } + + public function getPublicKeyAlgo(): AlgorithmIdentifierType + { + return $this->publicKeyAlgo; + } + + public function getPublicKeyParameters(): ?Element + { + return $this->publicKeyParameters; + } + + /** + * Get end-entity certificate. + */ + public function certificate(): Certificate + { + return $this->certificates[count($this->certificates) - 1]; + } + + /** + * Get certificate policies of the end-entity certificate. + * + * @return PolicyInformation[] + */ + public function policies(): array + { + if ($this->policyTree === null) { + return []; + } + return $this->policyTree->policiesAtDepth(count($this->certificates)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidator.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidator.php new file mode 100644 index 000000000..8a64596c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/PathValidator.php @@ -0,0 +1,484 @@ +certificates = $certificates; + // if trust anchor is explicitly given in configuration + if ($config->hasTrustAnchor()) { + $this->trustAnchor = $config->trustAnchor(); + } else { + $this->trustAnchor = $certificates[0]; + } + } + + public static function create( + Crypto $crypto, + PathValidationConfig $config, + Certificate ...$certificates + ): self { + return new self($crypto, $config, ...$certificates); + } + + /** + * Validate certification path. + */ + public function validate(): PathValidationResult + { + $n = count($this->certificates); + $state = ValidatorState::initialize($this->config, $this->trustAnchor, $n); + foreach ($this->certificates as $i => $iValue) { + $state = $state->withIndex($i + 1); + $cert = $iValue; + // process certificate (section 6.1.3.) + $state = $this->processCertificate($state, $cert); + if (! $state->isFinal()) { + // prepare next certificate (section 6.1.4.) + $state = $this->prepareNext($state, $cert); + } + } + if (! isset($cert)) { + throw new LogicException('No certificates.'); + } + // wrap-up (section 6.1.5.) + $state = $this->wrapUp($state, $cert); + // return outputs + return $state->getResult($this->certificates); + } + + /** + * Apply basic certificate processing according to RFC 5280 section 6.1.3. + * + * @see https://tools.ietf.org/html/rfc5280#section-6.1.3 + */ + private function processCertificate(ValidatorState $state, Certificate $cert): ValidatorState + { + // (a.1) verify signature + $this->verifySignature($state, $cert); + // (a.2) check validity period + $this->checkValidity($cert); + // (a.3) check that certificate is not revoked + $this->checkRevocation(); + // (a.4) check issuer + $this->checkIssuer($state, $cert); + // (b)(c) if certificate is self-issued and it is not + // the final certificate in the path, skip this step + if (! ($cert->isSelfIssued() && ! $state->isFinal())) { + // (b) check permitted subtrees + $this->checkPermittedSubtrees($state); + // (c) check excluded subtrees + $this->checkExcludedSubtrees($state); + } + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasCertificatePolicies()) { + // (d) process policy information + if ($state->hasValidPolicyTree()) { + $state = $state->validPolicyTree() + ->processPolicies($state, $cert); + } + } else { + // (e) certificate policies extension not present, + // set the valid_policy_tree to NULL + $state = $state->withoutValidPolicyTree(); + } + // (f) check that explicit_policy > 0 or valid_policy_tree is set + if (! ($state->explicitPolicy() > 0 || $state->hasValidPolicyTree())) { + throw new PathValidationException('No valid policies.'); + } + return $state; + } + + /** + * Apply preparation for the certificate i+1 according to rfc5280 section 6.1.4. + * + * @see https://tools.ietf.org/html/rfc5280#section-6.1.4 + */ + private function prepareNext(ValidatorState $state, Certificate $cert): ValidatorState + { + // (a)(b) if policy mappings extension is present + $state = $this->preparePolicyMappings($state, $cert); + // (c) assign working_issuer_name + $state = $state->withWorkingIssuerName($cert->tbsCertificate()->subject()); + // (d)(e)(f) + $state = $this->setPublicKeyState($state, $cert); + // (g) if name constraints extension is present + $state = $this->prepareNameConstraints($state, $cert); + // (h) if certificate is not self-issued + if (! $cert->isSelfIssued()) { + $state = $this->prepareNonSelfIssued($state); + } + // (i) if policy constraints extension is present + $state = $this->preparePolicyConstraints($state, $cert); + // (j) if inhibit any policy extension is present + $state = $this->prepareInhibitAnyPolicy($state, $cert); + // (k) check basic constraints + $this->processBasicContraints($cert); + // (l) verify max_path_length + $state = $this->verifyMaxPathLength($state, $cert); + // (m) check pathLenContraint + $state = $this->processPathLengthContraint($state, $cert); + // (n) check key usage + $this->checkKeyUsage($cert); + // (o) process relevant extensions + return $this->processExtensions($state); + } + + /** + * Apply wrap-up procedure according to RFC 5280 section 6.1.5. + * + * @see https://tools.ietf.org/html/rfc5280#section-6.1.5 + */ + private function wrapUp(ValidatorState $state, Certificate $cert): ValidatorState + { + $tbs_cert = $cert->tbsCertificate(); + $extensions = $tbs_cert->extensions(); + // (a) + if ($state->explicitPolicy() > 0) { + $state = $state->withExplicitPolicy($state->explicitPolicy() - 1); + } + // (b) + if ($extensions->hasPolicyConstraints()) { + $ext = $extensions->policyConstraints(); + if ($ext->hasRequireExplicitPolicy() && + $ext->requireExplicitPolicy() === 0) { + $state = $state->withExplicitPolicy(0); + } + } + // (c)(d)(e) + $state = $this->setPublicKeyState($state, $cert); + // (f) process relevant extensions + $state = $this->processExtensions($state); + // (g) intersection of valid_policy_tree and the initial-policy-set + $state = $this->calculatePolicyIntersection($state); + // check that explicit_policy > 0 or valid_policy_tree is set + if (! ($state->explicitPolicy() > 0 || $state->hasValidPolicyTree())) { + throw new PathValidationException('No valid policies.'); + } + // path validation succeeded + return $state; + } + + /** + * Update working_public_key, working_public_key_parameters and working_public_key_algorithm state variables from + * certificate. + */ + private function setPublicKeyState(ValidatorState $state, Certificate $cert): ValidatorState + { + $pk_info = $cert->tbsCertificate() + ->subjectPublicKeyInfo(); + // assign working_public_key + $state = $state->withWorkingPublicKey($pk_info); + // assign working_public_key_parameters + $params = ValidatorState::getAlgorithmParameters($pk_info->algorithmIdentifier()); + if ($params !== null) { + $state = $state->withWorkingPublicKeyParameters($params); + } else { + // if algorithms differ, set parameters to null + if ($pk_info->algorithmIdentifier()->oid() !== + $state->workingPublicKeyAlgorithm() + ->oid()) { + $state = $state->withWorkingPublicKeyParameters(null); + } + } + // assign working_public_key_algorithm + return $state->withWorkingPublicKeyAlgorithm($pk_info->algorithmIdentifier()); + } + + /** + * Verify certificate signature. + */ + private function verifySignature(ValidatorState $state, Certificate $cert): void + { + try { + $valid = $cert->verify($state->workingPublicKey(), $this->crypto); + } catch (RuntimeException $e) { + throw new PathValidationException('Failed to verify signature: ' . $e->getMessage(), 0, $e); + } + if (! $valid) { + throw new PathValidationException("Certificate signature doesn't match."); + } + } + + /** + * Check certificate validity. + */ + private function checkValidity(Certificate $cert): void + { + $refdt = $this->config->dateTime(); + $validity = $cert->tbsCertificate() + ->validity(); + if ($validity->notBefore()->dateTime()->diff($refdt)->invert !== 0) { + throw new PathValidationException('Certificate validity period has not started.'); + } + if ($refdt->diff($validity->notAfter()->dateTime())->invert !== 0) { + throw new PathValidationException('Certificate has expired.'); + } + } + + /** + * Check certificate revocation. + */ + private function checkRevocation(): void + { + // @todo Implement CRL handling + } + + /** + * Check certificate issuer. + */ + private function checkIssuer(ValidatorState $state, Certificate $cert): void + { + if (! $cert->tbsCertificate()->issuer()->equals($state->workingIssuerName())) { + throw new PathValidationException('Certification issuer mismatch.'); + } + } + + private function checkPermittedSubtrees(ValidatorState $state): void + { + // @todo Implement + $state->permittedSubtrees(); + } + + private function checkExcludedSubtrees(ValidatorState $state): void + { + // @todo Implement + $state->excludedSubtrees(); + } + + /** + * Apply policy mappings handling for the preparation step. + */ + private function preparePolicyMappings(ValidatorState $state, Certificate $cert): ValidatorState + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasPolicyMappings()) { + // (a) verify that anyPolicy mapping is not used + if ($extensions->policyMappings()->hasAnyPolicyMapping()) { + throw new PathValidationException('anyPolicy mapping found.'); + } + // (b) process policy mappings + if ($state->hasValidPolicyTree()) { + $state = $state->validPolicyTree() + ->processMappings($state, $cert); + } + } + return $state; + } + + /** + * Apply name constraints handling for the preparation step. + */ + private function prepareNameConstraints(ValidatorState $state, Certificate $cert): ValidatorState + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasNameConstraints()) { + $state = $this->processNameConstraints($state); + } + return $state; + } + + /** + * Apply preparation for a non-self-signed certificate. + */ + private function prepareNonSelfIssued(ValidatorState $state): ValidatorState + { + // (h.1) + if ($state->explicitPolicy() > 0) { + $state = $state->withExplicitPolicy($state->explicitPolicy() - 1); + } + // (h.2) + if ($state->policyMapping() > 0) { + $state = $state->withPolicyMapping($state->policyMapping() - 1); + } + // (h.3) + if ($state->inhibitAnyPolicy() > 0) { + $state = $state->withInhibitAnyPolicy($state->inhibitAnyPolicy() - 1); + } + return $state; + } + + /** + * Apply policy constraints handling for the preparation step. + */ + private function preparePolicyConstraints(ValidatorState $state, Certificate $cert): ValidatorState + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if (! $extensions->hasPolicyConstraints()) { + return $state; + } + $ext = $extensions->policyConstraints(); + // (i.1) + if ($ext->hasRequireExplicitPolicy() && + $ext->requireExplicitPolicy() < $state->explicitPolicy()) { + $state = $state->withExplicitPolicy($ext->requireExplicitPolicy()); + } + // (i.2) + if ($ext->hasInhibitPolicyMapping() && + $ext->inhibitPolicyMapping() < $state->policyMapping()) { + $state = $state->withPolicyMapping($ext->inhibitPolicyMapping()); + } + return $state; + } + + /** + * Apply inhibit any-policy handling for the preparation step. + */ + private function prepareInhibitAnyPolicy(ValidatorState $state, Certificate $cert): ValidatorState + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasInhibitAnyPolicy()) { + $ext = $extensions->inhibitAnyPolicy(); + if ($ext->skipCerts() < $state->inhibitAnyPolicy()) { + $state = $state->withInhibitAnyPolicy($ext->skipCerts()); + } + } + return $state; + } + + /** + * Verify maximum certification path length for the preparation step. + */ + private function verifyMaxPathLength(ValidatorState $state, Certificate $cert): ValidatorState + { + if (! $cert->isSelfIssued()) { + if ($state->maxPathLength() <= 0) { + throw new PathValidationException('Certification path length exceeded.'); + } + $state = $state->withMaxPathLength($state->maxPathLength() - 1); + } + return $state; + } + + /** + * Check key usage extension for the preparation step. + */ + private function checkKeyUsage(Certificate $cert): void + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasKeyUsage()) { + $ext = $extensions->keyUsage(); + if (! $ext->isKeyCertSign()) { + throw new PathValidationException('keyCertSign usage not set.'); + } + } + } + + private function processNameConstraints(ValidatorState $state): ValidatorState + { + // @todo Implement + return $state; + } + + /** + * Process basic constraints extension. + */ + private function processBasicContraints(Certificate $cert): void + { + if ($cert->tbsCertificate()->version() === TBSCertificate::VERSION_3) { + $extensions = $cert->tbsCertificate() + ->extensions(); + if (! $extensions->hasBasicConstraints()) { + throw new PathValidationException('v3 certificate must have basicConstraints extension.'); + } + // verify that cA is set to TRUE + if (! $extensions->basicConstraints()->isCA()) { + throw new PathValidationException('Certificate is not a CA certificate.'); + } + } + } + + /** + * Process pathLenConstraint. + */ + private function processPathLengthContraint(ValidatorState $state, Certificate $cert): ValidatorState + { + $extensions = $cert->tbsCertificate() + ->extensions(); + if ($extensions->hasBasicConstraints()) { + $ext = $extensions->basicConstraints(); + if ($ext->hasPathLen()) { + if ($ext->pathLen() < $state->maxPathLength()) { + $state = $state->withMaxPathLength($ext->pathLen()); + } + } + } + return $state; + } + + private function processExtensions(ValidatorState $state): ValidatorState + { + // @todo Implement + return $state; + } + + private function calculatePolicyIntersection(ValidatorState $state): ValidatorState + { + // (i) If the valid_policy_tree is NULL, the intersection is NULL + if (! $state->hasValidPolicyTree()) { + return $state; + } + // (ii) If the valid_policy_tree is not NULL and + // the user-initial-policy-set is any-policy, the intersection + // is the entire valid_policy_tree + $initial_policies = $this->config->policySet(); + if (in_array(PolicyInformation::OID_ANY_POLICY, $initial_policies, true)) { + return $state; + } + // (iii) If the valid_policy_tree is not NULL and the + // user-initial-policy-set is not any-policy, calculate + // the intersection of the valid_policy_tree and the + // user-initial-policy-set as follows + return $state->validPolicyTree() + ->calculateIntersection($state, $initial_policies); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/ValidatorState.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/ValidatorState.php new file mode 100644 index 000000000..7f83b1d7f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/PathValidation/ValidatorState.php @@ -0,0 +1,379 @@ +_pathLength = $n; + $state->_index = 1; + $state->_validPolicyTree = PolicyTree::create(PolicyNode::anyPolicyNode()); + $state->_permittedSubtrees = null; + $state->_excludedSubtrees = null; + $state->_explicitPolicy = $config->explicitPolicy() ? 0 : $n + 1; + $state->_inhibitAnyPolicy = $config->anyPolicyInhibit() ? 0 : $n + 1; + $state->_policyMapping = $config->policyMappingInhibit() ? 0 : $n + 1; + $state->_workingPublicKeyAlgorithm = $trust_anchor->signatureAlgorithm(); + $tbsCert = $trust_anchor->tbsCertificate(); + $state->_workingPublicKey = $tbsCert->subjectPublicKeyInfo(); + $state->_workingPublicKeyParameters = self::getAlgorithmParameters( + $state->_workingPublicKey->algorithmIdentifier() + ); + $state->_workingIssuerName = $tbsCert->issuer(); + $state->_maxPathLength = $config->maxLength(); + return $state; + } + + /** + * Get self with current certification path index set. + */ + public function withIndex(int $index): self + { + $state = clone $this; + $state->_index = $index; + return $state; + } + + /** + * Get self with valid_policy_tree. + */ + public function withValidPolicyTree(PolicyTree $policy_tree): self + { + $state = clone $this; + $state->_validPolicyTree = $policy_tree; + return $state; + } + + /** + * Get self with valid_policy_tree set to null. + */ + public function withoutValidPolicyTree(): self + { + $state = clone $this; + $state->_validPolicyTree = null; + return $state; + } + + /** + * Get self with explicit_policy. + */ + public function withExplicitPolicy(int $num): self + { + $state = clone $this; + $state->_explicitPolicy = $num; + return $state; + } + + /** + * Get self with inhibit_anyPolicy. + */ + public function withInhibitAnyPolicy(int $num): self + { + $state = clone $this; + $state->_inhibitAnyPolicy = $num; + return $state; + } + + /** + * Get self with policy_mapping. + */ + public function withPolicyMapping(int $num): self + { + $state = clone $this; + $state->_policyMapping = $num; + return $state; + } + + /** + * Get self with working_public_key_algorithm. + */ + public function withWorkingPublicKeyAlgorithm(AlgorithmIdentifierType $algo): self + { + $state = clone $this; + $state->_workingPublicKeyAlgorithm = $algo; + return $state; + } + + /** + * Get self with working_public_key. + */ + public function withWorkingPublicKey(PublicKeyInfo $pubkey_info): self + { + $state = clone $this; + $state->_workingPublicKey = $pubkey_info; + return $state; + } + + /** + * Get self with working_public_key_parameters. + */ + public function withWorkingPublicKeyParameters(?Element $params = null): self + { + $state = clone $this; + $state->_workingPublicKeyParameters = $params; + return $state; + } + + /** + * Get self with working_issuer_name. + */ + public function withWorkingIssuerName(Name $issuer): self + { + $state = clone $this; + $state->_workingIssuerName = $issuer; + return $state; + } + + /** + * Get self with max_path_length. + */ + public function withMaxPathLength(int $length): self + { + $state = clone $this; + $state->_maxPathLength = $length; + return $state; + } + + /** + * Get the certification path length (n). + */ + public function pathLength(): int + { + return $this->_pathLength; + } + + /** + * Get the current index in certification path in the range of 1..n. + */ + public function index(): int + { + return $this->_index; + } + + /** + * Check whether valid_policy_tree is present. + */ + public function hasValidPolicyTree(): bool + { + return isset($this->_validPolicyTree); + } + + public function validPolicyTree(): PolicyTree + { + if (! $this->hasValidPolicyTree()) { + throw new LogicException('valid_policy_tree not set.'); + } + return $this->_validPolicyTree; + } + + public function permittedSubtrees(): mixed + { + return $this->_permittedSubtrees; + } + + public function excludedSubtrees(): mixed + { + return $this->_excludedSubtrees; + } + + public function explicitPolicy(): int + { + return $this->_explicitPolicy; + } + + public function inhibitAnyPolicy(): int + { + return $this->_inhibitAnyPolicy; + } + + public function policyMapping(): int + { + return $this->_policyMapping; + } + + public function workingPublicKeyAlgorithm(): AlgorithmIdentifierType + { + return $this->_workingPublicKeyAlgorithm; + } + + public function workingPublicKey(): PublicKeyInfo + { + return $this->_workingPublicKey; + } + + public function workingPublicKeyParameters(): ?Element + { + return $this->_workingPublicKeyParameters; + } + + public function workingIssuerName(): Name + { + return $this->_workingIssuerName; + } + + /** + * Get maximum certification path length. + */ + public function maxPathLength(): int + { + return $this->_maxPathLength; + } + + /** + * Check whether processing the final certificate of the certification path. + */ + public function isFinal(): bool + { + return $this->_index === $this->_pathLength; + } + + /** + * Get the path validation result. + * + * @param Certificate[] $certificates Certificates in a certification path + */ + public function getResult(array $certificates): PathValidationResult + { + return PathValidationResult::create( + $certificates, + $this->_validPolicyTree, + $this->_workingPublicKey, + $this->_workingPublicKeyAlgorithm, + $this->_workingPublicKeyParameters + ); + } + + /** + * Get ASN.1 parameters from algorithm identifier. + * + * @return null|Element ASN.1 element or null if parameters are omitted + */ + public static function getAlgorithmParameters(AlgorithmIdentifierType $algo): ?Element + { + $seq = $algo->toASN1(); + return $seq->has(1) ? $seq->at(1) + ->asElement() : null; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyNode.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyNode.php new file mode 100644 index 000000000..f355276be --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyNode.php @@ -0,0 +1,242 @@ +children = []; + } + + /** + * @param PolicyQualifierInfo[] $qualifiers + * @param string[] $expectedPolicies + */ + public static function create(string $validPolicy, array $qualifiers, array $expectedPolicies): self + { + return new self($validPolicy, $qualifiers, $expectedPolicies); + } + + /** + * Create initial node for the policy tree. + */ + public static function anyPolicyNode(): self + { + return self::create(PolicyInformation::OID_ANY_POLICY, [], [PolicyInformation::OID_ANY_POLICY]); + } + + /** + * Get the valid policy OID. + */ + public function validPolicy(): string + { + return $this->validPolicy; + } + + /** + * Check whether node has anyPolicy as a valid policy. + */ + public function isAnyPolicy(): bool + { + return $this->validPolicy === PolicyInformation::OID_ANY_POLICY; + } + + /** + * Get the qualifier set. + * + * @return PolicyQualifierInfo[] + */ + public function qualifiers(): array + { + return $this->qualifiers; + } + + /** + * Check whether node has OID as an expected policy. + */ + public function hasExpectedPolicy(string $oid): bool + { + return in_array($oid, $this->expectedPolicies, true); + } + + /** + * Get the expected policy set. + * + * @return string[] + */ + public function expectedPolicies(): array + { + return $this->expectedPolicies; + } + + /** + * Set expected policies. + * + * @param string ...$oids Policy OIDs + */ + public function setExpectedPolicies(string ...$oids): void + { + $this->expectedPolicies = $oids; + } + + /** + * Check whether node has a child node with given valid policy OID. + */ + public function hasChildWithValidPolicy(string $oid): bool + { + foreach ($this->children as $node) { + if ($node->validPolicy() === $oid) { + return true; + } + } + return false; + } + + /** + * Add child node. + */ + public function addChild(self $node): self + { + $id = spl_object_hash($node); + $node->parent = $this; + $this->children[$id] = $node; + return $this; + } + + /** + * Get the child nodes. + * + * @return PolicyNode[] + */ + public function children(): array + { + return array_values($this->children); + } + + /** + * Remove this node from the tree. + * + * @return self The removed node + */ + public function remove(): self + { + if ($this->parent !== null) { + $id = spl_object_hash($this); + unset($this->parent->children[$id], $this->parent); + } + return $this; + } + + /** + * Check whether node has a parent. + */ + public function hasParent(): bool + { + return isset($this->parent); + } + + /** + * Get the parent node. + */ + public function parent(): ?self + { + return $this->parent; + } + + /** + * Get chain of parent nodes from this node's parent to the root node. + * + * @return PolicyNode[] + */ + public function parents(): array + { + if ($this->parent === null) { + return []; + } + $nodes = $this->parent->parents(); + $nodes[] = $this->parent; + return array_reverse($nodes); + } + + /** + * Walk tree from this node, applying a callback for each node. + * + * Nodes are traversed depth-first and callback shall be applied post-order. + */ + public function walkNodes(callable $fn): void + { + foreach ($this->children as $node) { + $node->walkNodes($fn); + } + $fn($this); + } + + /** + * Get the total number of nodes in a tree. + */ + public function nodeCount(): int + { + $c = 1; + foreach ($this->children as $child) { + $c += $child->nodeCount(); + } + return $c; + } + + /** + * Get the number of child nodes. + * + * @see \Countable::count() + */ + public function count(): int + { + return count($this->children); + } + + /** + * Get iterator for the child nodes. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->children); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyTree.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyTree.php new file mode 100644 index 000000000..56ee3550b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationPath/Policy/PolicyTree.php @@ -0,0 +1,389 @@ +tbsCertificate() + ->extensions() + ->certificatePolicies(); + $tree = clone $this; + // (d.1) for each policy P not equal to anyPolicy + foreach ($policies as $policy) { + /** @var PolicyInformation $policy */ + if ($policy->isAnyPolicy()) { + $tree->processAnyPolicy($policy, $cert, $state); + } else { + $tree->processPolicy($policy, $state); + } + } + // if whole tree is pruned + if ($tree->pruneTree($state->index() - 1) === 0) { + return $state->withoutValidPolicyTree(); + } + return $state->withValidPolicyTree($tree); + } + + /** + * Process policy mappings from the certificate. + */ + public function processMappings(ValidatorState $state, Certificate $cert): ValidatorState + { + $tree = clone $this; + if ($state->policyMapping() > 0) { + $tree->_applyMappings($cert, $state); + } elseif ($state->policyMapping() === 0) { + $tree->_deleteMappings($cert, $state); + } + // if whole tree is pruned + if ($tree->root === null) { + return $state->withoutValidPolicyTree(); + } + return $state->withValidPolicyTree($tree); + } + + /** + * Calculate policy intersection as specified in Wrap-Up Procedure 6.1.5.g. + * + * @param array $policies + */ + public function calculateIntersection(ValidatorState $state, array $policies): ValidatorState + { + $tree = clone $this; + $valid_policy_node_set = $tree->validPolicyNodeSet(); + // 2. If the valid_policy of any node in the valid_policy_node_set + // is not in the user-initial-policy-set and is not anyPolicy, + // delete this node and all its children. + $valid_policy_node_set = array_filter( + $valid_policy_node_set, + function (PolicyNode $node) use ($policies) { + if ($node->isAnyPolicy()) { + return true; + } + if (in_array($node->validPolicy(), $policies, true)) { + return true; + } + $node->remove(); + return false; + } + ); + // array of valid policy OIDs + $valid_policy_set = array_map(static fn (PolicyNode $node) => $node->validPolicy(), $valid_policy_node_set); + // 3. If the valid_policy_tree includes a node of depth n with + // the valid_policy anyPolicy and the user-initial-policy-set + // is not any-policy + foreach ($tree->nodesAtDepth($state->index()) as $node) { + if ($node->hasParent() && $node->isAnyPolicy()) { + // a. Set P-Q to the qualifier_set in the node of depth n + // with valid_policy anyPolicy. + $pq = $node->qualifiers(); + // b. For each P-OID in the user-initial-policy-set that is not + // the valid_policy of a node in the valid_policy_node_set, + // create a child node whose parent is the node of depth n-1 + // with the valid_policy anyPolicy. + $poids = array_diff($policies, $valid_policy_set); + foreach ($tree->nodesAtDepth($state->index() - 1) as $parent) { + if ($parent->isAnyPolicy()) { + // Set the values in the child node as follows: + // set the valid_policy to P-OID, set the qualifier_set + // to P-Q, and set the expected_policy_set to {P-OID}. + foreach ($poids as $poid) { + $parent->addChild(PolicyNode::create($poid, $pq, [$poid])); + } + break; + } + } + // c. Delete the node of depth n with the + // valid_policy anyPolicy. + $node->remove(); + } + } + // 4. If there is a node in the valid_policy_tree of depth n-1 or less + // without any child nodes, delete that node. Repeat this step until + // there are no nodes of depth n-1 or less without children. + if ($tree->pruneTree($state->index() - 1) === 0) { + return $state->withoutValidPolicyTree(); + } + return $state->withValidPolicyTree($tree); + } + + /** + * Get policies at given policy tree depth. + * + * @param int $i Depth in range 1..n + * + * @return PolicyInformation[] + */ + public function policiesAtDepth(int $i): array + { + $policies = []; + foreach ($this->nodesAtDepth($i) as $node) { + $policies[] = PolicyInformation::create($node->validPolicy(), ...$node->qualifiers()); + } + return $policies; + } + + /** + * Process single policy information. + */ + private function processPolicy(PolicyInformation $policy, ValidatorState $state): void + { + $p_oid = $policy->oid(); + $i = $state->index(); + $match_count = 0; + // (d.1.i) for each node of depth i-1 in the valid_policy_tree... + foreach ($this->nodesAtDepth($i - 1) as $node) { + // ...where P-OID is in the expected_policy_set + if ($node->hasExpectedPolicy($p_oid)) { + $node->addChild(PolicyNode::create($p_oid, $policy->qualifiers(), [$p_oid])); + ++$match_count; + } + } + // (d.1.ii) if there was no match in step (i)... + if ($match_count === 0) { + // ...and the valid_policy_tree includes a node of depth i-1 with + // the valid_policy anyPolicy + foreach ($this->nodesAtDepth($i - 1) as $node) { + if ($node->isAnyPolicy()) { + $node->addChild(PolicyNode::create($p_oid, $policy->qualifiers(), [$p_oid])); + } + } + } + } + + /** + * Process anyPolicy policy information. + */ + private function processAnyPolicy(PolicyInformation $policy, Certificate $cert, ValidatorState $state): void + { + $i = $state->index(); + // if (a) inhibit_anyPolicy is greater than 0 or + // (b) iinhibitAnyPolicy() > 0 || + ($i < $state->pathLength() && $cert->isSelfIssued()))) { + return; + } + // for each node in the valid_policy_tree of depth i-1 + foreach ($this->nodesAtDepth($i - 1) as $node) { + // for each value in the expected_policy_set + foreach ($node->expectedPolicies() as $p_oid) { + // that does not appear in a child node + if (! $node->hasChildWithValidPolicy($p_oid)) { + $node->addChild(PolicyNode::create($p_oid, $policy->qualifiers(), [$p_oid])); + } + } + } + } + + /** + * Apply policy mappings to the policy tree. + */ + private function _applyMappings(Certificate $cert, ValidatorState $state): void + { + $policy_mappings = $cert->tbsCertificate() + ->extensions() + ->policyMappings(); + // (6.1.4. b.1.) for each node in the valid_policy_tree of depth i... + foreach ($policy_mappings->flattenedMappings() as $idp => $sdps) { + $match_count = 0; + foreach ($this->nodesAtDepth($state->index()) as $node) { + // ...where ID-P is the valid_policy + if ($node->validPolicy() === $idp) { + // set expected_policy_set to the set of subjectDomainPolicy + // values that are specified as equivalent to ID-P by + // the policy mappings extension + $node->setExpectedPolicies(...$sdps); + ++$match_count; + } + } + // if no node of depth i in the valid_policy_tree has + // a valid_policy of ID-P... + if ($match_count === 0) { + $this->_applyAnyPolicyMapping($cert, $state, $idp, $sdps); + } + } + } + + /** + * Apply anyPolicy mapping to the policy tree as specified in 6.1.4 (b)(1). + * + * @param string $idp OID of the issuer domain policy + * @param array $sdps Array of subject domain policy OIDs + */ + private function _applyAnyPolicyMapping( + Certificate $cert, + ValidatorState $state, + string $idp, + array $sdps + ): void { + // (6.1.4. b.1.) ...but there is a node of depth i with + // a valid_policy of anyPolicy + foreach ($this->nodesAtDepth($state->index()) as $node) { + if ($node->isAnyPolicy()) { + // then generate a child node of the node of depth i-1 + // that has a valid_policy of anyPolicy as follows... + foreach ($this->nodesAtDepth($state->index() - 1) as $subnode) { + if ($subnode->isAnyPolicy()) { + // try to fetch qualifiers of anyPolicy certificate policy + try { + $qualifiers = $cert->tbsCertificate() + ->extensions() + ->certificatePolicies() + ->anyPolicy() + ->qualifiers(); + } catch (LogicException) { + // if there's no policies or no qualifiers + $qualifiers = []; + } + $subnode->addChild(PolicyNode::create($idp, $qualifiers, $sdps)); + // bail after first anyPolicy has been processed + break; + } + } + // bail after first anyPolicy has been processed + break; + } + } + } + + /** + * Delete nodes as specified in 6.1.4 (b)(2). + */ + private function _deleteMappings(Certificate $cert, ValidatorState $state): void + { + $idps = $cert->tbsCertificate() + ->extensions() + ->policyMappings() + ->issuerDomainPolicies(); + // delete each node of depth i in the valid_policy_tree + // where ID-P is the valid_policy + foreach ($this->nodesAtDepth($state->index()) as $node) { + if (in_array($node->validPolicy(), $idps, true)) { + $node->remove(); + } + } + $this->pruneTree($state->index() - 1); + } + + /** + * Prune tree starting from given depth. + * + * @return int The number of nodes left in a tree + */ + private function pruneTree(int $depth): int + { + if ($this->root === null) { + return 0; + } + for ($i = $depth; $i > 0; --$i) { + foreach ($this->nodesAtDepth($i) as $node) { + if (count($node) === 0) { + $node->remove(); + } + } + } + // if root has no children left + if (count($this->root) === 0) { + $this->root = null; + return 0; + } + return $this->root->nodeCount(); + } + + /** + * Get all nodes at given depth. + * + * @return PolicyNode[] + */ + private function nodesAtDepth(int $i): array + { + if ($this->root === null) { + return []; + } + $depth = 0; + $nodes = [$this->root]; + while ($depth < $i) { + $nodes = self::gatherChildren(...$nodes); + if (count($nodes) === 0) { + break; + } + ++$depth; + } + return $nodes; + } + + /** + * Get the valid policy node set as specified in spec 6.1.5.(g)(iii)1. + * + * @return PolicyNode[] + */ + private function validPolicyNodeSet(): array + { + // 1. Determine the set of policy nodes whose parent nodes have + // a valid_policy of anyPolicy. This is the valid_policy_node_set. + $set = []; + if ($this->root === null) { + return $set; + } + // for each node in a tree + $this->root->walkNodes( + function (PolicyNode $node) use (&$set) { + $parents = $node->parents(); + // node has parents + if (count($parents) !== 0) { + // check that each ancestor is an anyPolicy node + foreach ($parents as $ancestor) { + if (! $ancestor->isAnyPolicy()) { + return; + } + } + $set[] = $node; + } + } + ); + return $set; + } + + /** + * Gather all children of given nodes to a flattened array. + * + * @return PolicyNode[] + */ + private static function gatherChildren(PolicyNode ...$nodes): array + { + $children = []; + foreach ($nodes as $node) { + $children = array_merge($children, $node->children()); + } + return $children; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attribute/ExtensionRequestValue.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attribute/ExtensionRequestValue.php new file mode 100644 index 000000000..1b9e6868c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attribute/ExtensionRequestValue.php @@ -0,0 +1,77 @@ +asSequence())); + } + + /** + * Get requested extensions. + */ + public function extensions(): Extensions + { + return $this->extensions; + } + + public function toASN1(): Element + { + return $this->extensions->toASN1(); + } + + public function stringValue(): string + { + return '#' . bin2hex($this->toASN1()->toDER()); + } + + public function equalityMatchingRule(): MatchingRule + { + return new BinaryMatch(); + } + + public function rfc2253String(): string + { + return $this->stringValue(); + } + + protected function _transcodedString(): string + { + return $this->stringValue(); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attributes.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attributes.php new file mode 100644 index 000000000..9df717440 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/Attributes.php @@ -0,0 +1,68 @@ + + */ + private const MAP_OID_TO_CLASS = [ + ExtensionRequestValue::OID => ExtensionRequestValue::class, + ]; + + /** + * Initialize from attribute values. + * + * @param AttributeValue ...$values List of attribute values + */ + public static function fromAttributeValues(AttributeValue ...$values): static + { + return static::create(...array_map(static fn (AttributeValue $value) => $value->toAttribute(), $values)); + } + + /** + * Check whether extension request attribute is present. + */ + public function hasExtensionRequest(): bool + { + return $this->has(ExtensionRequestValue::OID); + } + + /** + * Get extension request attribute value. + */ + public function extensionRequest(): ExtensionRequestValue + { + if (! $this->hasExtensionRequest()) { + throw new LogicException('No extension request attribute.'); + } + return $this->firstOf(ExtensionRequestValue::OID)->first(); + } + + protected static function _castAttributeValues(Attribute $attribute): Attribute + { + $oid = $attribute->oid(); + if (isset(self::MAP_OID_TO_CLASS[$oid])) { + return $attribute->castValues(self::MAP_OID_TO_CLASS[$oid]); + } + return $attribute; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequest.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequest.php new file mode 100644 index 000000000..300385e8d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequest.php @@ -0,0 +1,146 @@ +toPEM() + ->string(); + } + + public static function create( + CertificationRequestInfo $_certificationRequestInfo, + SignatureAlgorithmIdentifier $_signatureAlgorithm, + Signature $_signature + ): self { + return new self($_certificationRequestInfo, $_signatureAlgorithm, $_signature); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $info = CertificationRequestInfo::fromASN1($seq->at(0)->asSequence()); + $algo = AlgorithmIdentifier::fromASN1($seq->at(1)->asSequence()); + if (! $algo instanceof SignatureAlgorithmIdentifier) { + throw new UnexpectedValueException('Unsupported signature algorithm ' . $algo->oid() . '.'); + } + $signature = Signature::fromSignatureData($seq->at(2)->asBitString()->string(), $algo); + return self::create($info, $algo, $signature); + } + + /** + * Initialize from DER. + */ + public static function fromDER(string $data): self + { + return self::fromASN1(UnspecifiedType::fromDER($data)->asSequence()); + } + + /** + * Initialize from PEM. + */ + public static function fromPEM(PEM $pem): self + { + if ($pem->type() !== PEM::TYPE_CERTIFICATE_REQUEST) { + throw new UnexpectedValueException('Invalid PEM type.'); + } + return self::fromDER($pem->data()); + } + + /** + * Get certification request info. + */ + public function certificationRequestInfo(): CertificationRequestInfo + { + return $this->certificationRequestInfo; + } + + /** + * Get signature algorithm. + */ + public function signatureAlgorithm(): SignatureAlgorithmIdentifier + { + return $this->signatureAlgorithm; + } + + public function signature(): Signature + { + return $this->signature; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + return Sequence::create( + $this->certificationRequestInfo->toASN1(), + $this->signatureAlgorithm->toASN1(), + $this->signature->bitString() + ); + } + + /** + * Get certification request as a DER. + */ + public function toDER(): string + { + return $this->toASN1() + ->toDER(); + } + + /** + * Get certification request as a PEM. + */ + public function toPEM(): PEM + { + return PEM::create(PEM::TYPE_CERTIFICATE_REQUEST, $this->toDER()); + } + + /** + * Verify certification request signature. + * + * @param null|Crypto $crypto Crypto engine, use default if not set + * + * @return bool True if signature matches + */ + public function verify(?Crypto $crypto = null): bool + { + $crypto ??= Crypto::getDefault(); + $data = $this->certificationRequestInfo->toASN1() + ->toDER(); + $pk_info = $this->certificationRequestInfo->subjectPKInfo(); + return $crypto->verify($data, $this->signature, $pk_info, $this->signatureAlgorithm); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequestInfo.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequestInfo.php new file mode 100644 index 000000000..b93584e2a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/CertificationRequest/CertificationRequestInfo.php @@ -0,0 +1,181 @@ +version = self::VERSION_1; + } + + public static function create(Name $subject, PublicKeyInfo $subjectPKInfo): self + { + return new self($subject, $subjectPKInfo); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + $version = $seq->at(0) + ->asInteger() + ->intNumber(); + if ($version !== self::VERSION_1) { + throw new UnexpectedValueException("Version {$version} not supported."); + } + $subject = Name::fromASN1($seq->at(1)->asSequence()); + $pkinfo = PublicKeyInfo::fromASN1($seq->at(2)->asSequence()); + $obj = self::create($subject, $pkinfo); + if ($seq->hasTagged(0)) { + $obj = $obj->withAttributes( + Attributes::fromASN1($seq->getTagged(0)->asImplicit(Element::TYPE_SET)->asSet()) + ); + } + + return $obj; + } + + public function version(): int + { + return $this->version; + } + + /** + * Get self with subject. + */ + public function withSubject(Name $subject): self + { + $obj = clone $this; + $obj->subject = $subject; + return $obj; + } + + public function subject(): Name + { + return $this->subject; + } + + /** + * Get subject public key info. + */ + public function subjectPKInfo(): PublicKeyInfo + { + return $this->subjectPKInfo; + } + + /** + * Whether certification request info has attributes. + */ + public function hasAttributes(): bool + { + return isset($this->attributes); + } + + public function attributes(): Attributes + { + if (! $this->hasAttributes()) { + throw new LogicException('No attributes.'); + } + return $this->attributes; + } + + /** + * Get instance of self with attributes. + */ + public function withAttributes(Attributes $attribs): self + { + $obj = clone $this; + $obj->attributes = $attribs; + return $obj; + } + + /** + * Get self with extension request attribute. + * + * @param Extensions $extensions Extensions to request + */ + public function withExtensionRequest(Extensions $extensions): self + { + $obj = clone $this; + if (! isset($obj->attributes)) { + $obj->attributes = Attributes::create(); + } + $obj->attributes = $obj->attributes->withUnique( + Attribute::fromAttributeValues(ExtensionRequestValue::create($extensions)) + ); + return $obj; + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + $elements = [Integer::create($this->version), $this->subject->toASN1(), $this->subjectPKInfo->toASN1()]; + if (isset($this->attributes)) { + $elements[] = ImplicitlyTaggedType::create(0, $this->attributes->toASN1()); + } + return Sequence::create(...$elements); + } + + /** + * Create signed CertificationRequest. + * + * @param SignatureAlgorithmIdentifier $algo Algorithm used for signing + * @param PrivateKeyInfo $privkey_info Private key used for signing + * @param null|Crypto $crypto Crypto engine, use default if not set + */ + public function sign( + SignatureAlgorithmIdentifier $algo, + PrivateKeyInfo $privkey_info, + ?Crypto $crypto = null + ): CertificationRequest { + $crypto ??= Crypto::getDefault(); + $data = $this->toASN1() + ->toDER(); + $signature = $crypto->sign($data, $privkey_info, $algo); + return CertificationRequest::create($this, $algo, $signature); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Exception/X509ValidationException.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Exception/X509ValidationException.php new file mode 100644 index 000000000..83d49d88d --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/Exception/X509ValidationException.php @@ -0,0 +1,11 @@ +format('Y-m-d H:i:s'), $dt->getTimezone()); + } + + /** + * Create DateTimeZone object from string. + */ + private static function createTimeZone(string $tz): DateTimeZone + { + try { + return new DateTimeZone($tz); + } catch (Exception $e) { + throw new UnexpectedValueException('Invalid timezone.', 0, $e); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DNSName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DNSName.php new file mode 100644 index 000000000..a71db11a7 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DNSName.php @@ -0,0 +1,58 @@ +asIA5String()->string()); + } + + public function string(): string + { + return $this->name; + } + + /** + * Get DNS name. + */ + public function name(): string + { + return $this->name; + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, IA5String::create($this->name)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DirectoryName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DirectoryName.php new file mode 100644 index 000000000..cb1a4854e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/DirectoryName.php @@ -0,0 +1,65 @@ +asSequence())); + } + + /** + * Initialize from distinguished name string. + */ + public static function fromDNString(string $str): self + { + return self::create(Name::fromString($str)); + } + + public function string(): string + { + return $this->directoryName->toString(); + } + + /** + * Get directory name. + */ + public function dn(): Name + { + return $this->directoryName; + } + + protected function choiceASN1(): TaggedType + { + // Name type is itself a CHOICE, so explicit tagging must be + // employed to avoid ambiguities + return ExplicitlyTaggedType::create($this->tag, $this->directoryName->toASN1()); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/EDIPartyName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/EDIPartyName.php new file mode 100644 index 000000000..231c4d59e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/EDIPartyName.php @@ -0,0 +1,51 @@ +asSequence()); + } + + public function string(): string + { + return bin2hex($this->element->toDER()); + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, $this->element); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralName.php new file mode 100644 index 000000000..485f5957e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralName.php @@ -0,0 +1,119 @@ +string(); + } + + /** + * Get string value of the type. + */ + abstract public function string(): string; + + /** + * Initialize concrete object from the chosen ASN.1 element. + */ + abstract public static function fromChosenASN1(UnspecifiedType $el): self; + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(TaggedType $el): self + { + return match ($el->tag()) { + self::TAG_OTHER_NAME => OtherName::fromChosenASN1($el->asImplicit(Element::TYPE_SEQUENCE)), + self::TAG_RFC822_NAME => RFC822Name::fromChosenASN1($el->asImplicit(Element::TYPE_IA5_STRING)), + self::TAG_DNS_NAME => DNSName::fromChosenASN1($el->asImplicit(Element::TYPE_IA5_STRING)), + self::TAG_X400_ADDRESS => X400Address::fromChosenASN1($el->asImplicit(Element::TYPE_SEQUENCE)), + self::TAG_DIRECTORY_NAME => DirectoryName::fromChosenASN1($el->asExplicit()), + self::TAG_EDI_PARTY_NAME => EDIPartyName::fromChosenASN1($el->asImplicit(Element::TYPE_SEQUENCE)), + self::TAG_URI => UniformResourceIdentifier::fromChosenASN1($el->asImplicit(Element::TYPE_IA5_STRING)), + self::TAG_IP_ADDRESS => IPAddress::fromChosenASN1($el->asImplicit(Element::TYPE_OCTET_STRING)), + self::TAG_REGISTERED_ID => RegisteredID::fromChosenASN1($el->asImplicit(Element::TYPE_OBJECT_IDENTIFIER)), + default => throw new UnexpectedValueException('GeneralName type ' . $el->tag() . ' not supported.'), + }; + } + + /** + * Get type tag. + */ + public function tag(): int + { + return $this->tag; + } + + /** + * Generate ASN.1 element. + */ + public function toASN1(): Element + { + return $this->choiceASN1(); + } + + /** + * Check whether GeneralName is equal to others. + * + * @param GeneralName $other GeneralName to compare to + * + * @return bool True if names are equal + */ + public function equals(self $other): bool + { + if ($this->tag !== $other->tag) { + return false; + } + if ($this->choiceASN1()->toDER() !== $other->choiceASN1()->toDER()) { + return false; + } + return true; + } + + /** + * Get ASN.1 value in GeneralName CHOICE context. + */ + abstract protected function choiceASN1(): TaggedType; +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralNames.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralNames.php new file mode 100644 index 000000000..1854f3d77 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/GeneralNames.php @@ -0,0 +1,174 @@ +_names = $names; + } + + public static function create(GeneralName ...$names): self + { + return new self(...$names); + } + + /** + * Initialize from ASN.1. + */ + public static function fromASN1(Sequence $seq): self + { + if (count($seq) === 0) { + throw new UnexpectedValueException('GeneralNames must have at least one GeneralName.'); + } + $names = array_map(static fn (UnspecifiedType $el) => GeneralName::fromASN1($el->asTagged()), $seq->elements()); + return self::create(...$names); + } + + /** + * Check whether GeneralNames contains a GeneralName of given type. + * + * @param int $tag One of `GeneralName::TAG_*` enumerations + */ + public function has(int $tag): bool + { + return $this->findFirst($tag) !== null; + } + + /** + * Get first GeneralName of given type. + * + * @param int $tag One of `GeneralName::TAG_*` enumerations + */ + public function firstOf(int $tag): GeneralName + { + $name = $this->findFirst($tag); + if ($name === null) { + throw new UnexpectedValueException("No GeneralName by tag {$tag}."); + } + return $name; + } + + /** + * Get all GeneralName objects of given type. + * + * @param int $tag One of `GeneralName::TAG_*` enumerations + * + * @return GeneralName[] + */ + public function allOf(int $tag): array + { + $names = array_filter($this->_names, fn (GeneralName $name) => $name->tag() === $tag); + return array_values($names); + } + + /** + * Get value of the first 'dNSName' type. + */ + public function firstDNS(): string + { + $gn = $this->firstOf(GeneralName::TAG_DNS_NAME); + if (! $gn instanceof DNSName) { + throw new RuntimeException(DNSName::class . ' expected, got ' . $gn::class); + } + return $gn->name(); + } + + /** + * Get value of the first 'directoryName' type. + */ + public function firstDN(): Name + { + $gn = $this->firstOf(GeneralName::TAG_DIRECTORY_NAME); + if (! $gn instanceof DirectoryName) { + throw new RuntimeException(DirectoryName::class . ' expected, got ' . $gn::class); + } + return $gn->dn(); + } + + /** + * Get value of the first 'uniformResourceIdentifier' type. + */ + public function firstURI(): string + { + $gn = $this->firstOf(GeneralName::TAG_URI); + if (! $gn instanceof UniformResourceIdentifier) { + throw new RuntimeException(UniformResourceIdentifier::class . ' expected, got ' . $gn::class); + } + return $gn->uri(); + } + + /** + * Generate ASN.1 structure. + */ + public function toASN1(): Sequence + { + if (count($this->_names) === 0) { + throw new LogicException('GeneralNames must have at least one GeneralName.'); + } + $elements = array_map(static fn (GeneralName $name) => $name->toASN1(), $this->_names); + return Sequence::create(...$elements); + } + + /** + * @see \Countable::count() + */ + public function count(): int + { + return count($this->_names); + } + + /** + * Get iterator for GeneralName objects. + * + * @see \IteratorAggregate::getIterator() + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->_names); + } + + /** + * Find first GeneralName by given tag. + */ + private function findFirst(int $tag): ?GeneralName + { + foreach ($this->_names as $name) { + if ($name->tag() === $tag) { + return $name; + } + } + return null; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPAddress.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPAddress.php new file mode 100644 index 000000000..38d44b5f5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPAddress.php @@ -0,0 +1,86 @@ +asOctetString() + ->string(); + return match (mb_strlen($octets, '8bit')) { + 4, 8 => IPv4Address::fromOctets($octets), + 16, 32 => IPv6Address::fromOctets($octets), + default => throw new UnexpectedValueException('Invalid octet length for IP address.'), + }; + } + + public function string(): string + { + return $this->ip . (isset($this->mask) ? '/' . $this->mask : ''); + } + + /** + * Get IP address as a string. + */ + public function address(): string + { + return $this->ip; + } + + /** + * Check whether mask is present. + */ + public function hasMask(): bool + { + return isset($this->mask); + } + + /** + * Get subnet mask as a string. + */ + public function mask(): string + { + if (! $this->hasMask()) { + throw new LogicException('mask is not set.'); + } + return $this->mask; + } + + /** + * Get octet representation of the IP address. + */ + abstract protected function octets(): string; + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, OctetString::create($this->octets())); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv4Address.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv4Address.php new file mode 100644 index 000000000..a5563b8ed --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv4Address.php @@ -0,0 +1,48 @@ +ip)); + if (isset($this->mask)) { + $bytes = array_merge($bytes, array_map('intval', explode('.', $this->mask))); + } + return pack('C*', ...$bytes); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv6Address.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv6Address.php new file mode 100644 index 000000000..74194e22e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/IPv6Address.php @@ -0,0 +1,60 @@ + sprintf('%04x', $word), $words); + return implode(':', $groups); + } + + protected function octets(): string + { + $words = array_map('hexdec', explode(':', $this->ip)); + if (isset($this->mask)) { + $words = array_merge($words, array_map('hexdec', explode(':', $this->mask))); + } + return pack('n*', ...$words); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/OtherName.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/OtherName.php new file mode 100644 index 000000000..03f601ea0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/OtherName.php @@ -0,0 +1,80 @@ +asSequence(); + $type_id = $seq->at(0) + ->asObjectIdentifier() + ->oid(); + $value = $seq->getTagged(0) + ->asExplicit() + ->asElement(); + return self::create($type_id, $value); + } + + public function string(): string + { + return $this->type . '/#' . bin2hex($this->element->toDER()); + } + + /** + * Get type OID. + */ + public function type(): string + { + return $this->type; + } + + /** + * Get value element. + */ + public function value(): Element + { + return $this->element; + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create( + $this->tag, + Sequence::create(ObjectIdentifier::create($this->type), ExplicitlyTaggedType::create(0, $this->element)) + ); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RFC822Name.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RFC822Name.php new file mode 100644 index 000000000..294d27b70 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RFC822Name.php @@ -0,0 +1,52 @@ +asIA5String()->string()); + } + + public function string(): string + { + return $this->email; + } + + public function email(): string + { + return $this->email; + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, IA5String::create($this->email)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RegisteredID.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RegisteredID.php new file mode 100644 index 000000000..a30e02a73 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/RegisteredID.php @@ -0,0 +1,60 @@ +asObjectIdentifier()->oid()); + } + + public function string(): string + { + return $this->oid; + } + + /** + * Get object identifier in dotted format. + * + * @return string OID + */ + public function oid(): string + { + return $this->oid; + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, ObjectIdentifier::create($this->oid)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/UniformResourceIdentifier.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/UniformResourceIdentifier.php new file mode 100644 index 000000000..3b107a81f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/UniformResourceIdentifier.php @@ -0,0 +1,52 @@ +asIA5String()->string()); + } + + public function string(): string + { + return $this->uri; + } + + public function uri(): string + { + return $this->uri; + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, IA5String::create($this->uri)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/X400Address.php b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/X400Address.php new file mode 100644 index 000000000..8b0476c22 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/pki-framework/src/X509/GeneralName/X400Address.php @@ -0,0 +1,48 @@ +asSequence()); + } + + public function string(): string + { + return bin2hex($this->element->toDER()); + } + + protected function choiceASN1(): TaggedType + { + return ImplicitlyTaggedType::create($this->tag, $this->element); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/CHANGELOG.md b/lam/lib/3rdParty/composer/symfony/clock/CHANGELOG.md new file mode 100644 index 000000000..3b1315739 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/CHANGELOG.md @@ -0,0 +1,20 @@ +CHANGELOG +========= + +6.4 +--- + + * Add `DatePoint`: an immutable DateTime implementation with stricter error handling and return types + * Throw `DateMalformedStringException`/`DateInvalidTimeZoneException` when appropriate + * Add `$modifier` argument to the `now()` helper + +6.3 +--- + + * Add `ClockAwareTrait` to help write time-sensitive classes + * Add `Clock` class and `now()` function + +6.2 +--- + + * Add the component diff --git a/lam/lib/3rdParty/composer/symfony/clock/Clock.php b/lam/lib/3rdParty/composer/symfony/clock/Clock.php new file mode 100644 index 000000000..311e8fc07 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/Clock.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +use Psr\Clock\ClockInterface as PsrClockInterface; + +/** + * A global clock. + * + * @author Nicolas Grekas + */ +final class Clock implements ClockInterface +{ + private static ClockInterface $globalClock; + + public function __construct( + private readonly ?PsrClockInterface $clock = null, + private ?\DateTimeZone $timezone = null, + ) { + } + + /** + * Returns the current global clock. + * + * Note that you should prefer injecting a ClockInterface or using + * ClockAwareTrait when possible instead of using this method. + */ + public static function get(): ClockInterface + { + return self::$globalClock ??= new NativeClock(); + } + + public static function set(PsrClockInterface $clock): void + { + self::$globalClock = $clock instanceof ClockInterface ? $clock : new self($clock); + } + + public function now(): DatePoint + { + $now = ($this->clock ?? self::get())->now(); + + if (!$now instanceof DatePoint) { + $now = DatePoint::createFromInterface($now); + } + + return isset($this->timezone) ? $now->setTimezone($this->timezone) : $now; + } + + public function sleep(float|int $seconds): void + { + $clock = $this->clock ?? self::get(); + + if ($clock instanceof ClockInterface) { + $clock->sleep($seconds); + } else { + (new NativeClock())->sleep($seconds); + } + } + + /** + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function withTimeZone(\DateTimeZone|string $timezone): static + { + if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (\is_string($timezone)) { + try { + $timezone = new \DateTimeZone($timezone); + } catch (\Exception $e) { + throw new \DateInvalidTimeZoneException($e->getMessage(), $e->getCode(), $e); + } + } + + $clone = clone $this; + $clone->timezone = $timezone; + + return $clone; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/ClockAwareTrait.php b/lam/lib/3rdParty/composer/symfony/clock/ClockAwareTrait.php new file mode 100644 index 000000000..44ce04464 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/ClockAwareTrait.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +use Psr\Clock\ClockInterface; +use Symfony\Contracts\Service\Attribute\Required; + +/** + * A trait to help write time-sensitive classes. + * + * @author Nicolas Grekas + */ +trait ClockAwareTrait +{ + private readonly ClockInterface $clock; + + #[Required] + public function setClock(ClockInterface $clock): void + { + $this->clock = $clock; + } + + /** + * @return DatePoint + */ + protected function now(): \DateTimeImmutable + { + $now = ($this->clock ??= new Clock())->now(); + + return $now instanceof DatePoint ? $now : DatePoint::createFromInterface($now); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/ClockInterface.php b/lam/lib/3rdParty/composer/symfony/clock/ClockInterface.php new file mode 100644 index 000000000..435775a8f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/ClockInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +use Psr\Clock\ClockInterface as PsrClockInterface; + +/** + * @author Nicolas Grekas + */ +interface ClockInterface extends PsrClockInterface +{ + public function sleep(float|int $seconds): void; + + public function withTimeZone(\DateTimeZone|string $timezone): static; +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/DatePoint.php b/lam/lib/3rdParty/composer/symfony/clock/DatePoint.php new file mode 100644 index 000000000..1ced5fcef --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/DatePoint.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +/** + * An immmutable DateTime with stricter error handling and return types than the native one. + * + * @author Nicolas Grekas + */ +final class DatePoint extends \DateTimeImmutable +{ + /** + * @throws \DateMalformedStringException When $datetime is invalid + */ + public function __construct(string $datetime = 'now', ?\DateTimeZone $timezone = null, ?parent $reference = null) + { + $now = $reference ?? Clock::get()->now(); + + if ('now' !== $datetime) { + if (!$now instanceof static) { + $now = static::createFromInterface($now); + } + + if (\PHP_VERSION_ID < 80300) { + try { + $builtInDate = new parent($datetime, $timezone ?? $now->getTimezone()); + $timezone = $builtInDate->getTimezone(); + } catch (\Exception $e) { + throw new \DateMalformedStringException($e->getMessage(), $e->getCode(), $e); + } + } else { + $builtInDate = new parent($datetime, $timezone ?? $now->getTimezone()); + $timezone = $builtInDate->getTimezone(); + } + + $now = $now->setTimezone($timezone)->modify($datetime); + + if ('00:00:00.000000' === $builtInDate->format('H:i:s.u')) { + $now = $now->setTime(0, 0); + } + } elseif (null !== $timezone) { + $now = $now->setTimezone($timezone); + } + + if (\PHP_VERSION_ID < 80200) { + $now = (array) $now; + $this->date = $now['date']; + $this->timezone_type = $now['timezone_type']; + $this->timezone = $now['timezone']; + $this->__wakeup(); + + return; + } + + $this->__unserialize((array) $now); + } + + /** + * @throws \DateMalformedStringException When $format or $datetime are invalid + */ + public static function createFromFormat(string $format, string $datetime, ?\DateTimeZone $timezone = null): static + { + return parent::createFromFormat($format, $datetime, $timezone) ?: throw new \DateMalformedStringException(static::getLastErrors()['errors'][0] ?? 'Invalid date string or format.'); + } + + public static function createFromInterface(\DateTimeInterface $object): static + { + return parent::createFromInterface($object); + } + + public static function createFromMutable(\DateTime $object): static + { + return parent::createFromMutable($object); + } + + public function add(\DateInterval $interval): static + { + return parent::add($interval); + } + + public function sub(\DateInterval $interval): static + { + return parent::sub($interval); + } + + /** + * @throws \DateMalformedStringException When $modifier is invalid + */ + public function modify(string $modifier): static + { + if (\PHP_VERSION_ID < 80300) { + return @parent::modify($modifier) ?: throw new \DateMalformedStringException(error_get_last()['message'] ?? \sprintf('Invalid modifier: "%s".', $modifier)); + } + + return parent::modify($modifier); + } + + public function setTimestamp(int $value): static + { + return parent::setTimestamp($value); + } + + public function setDate(int $year, int $month, int $day): static + { + return parent::setDate($year, $month, $day); + } + + public function setISODate(int $year, int $week, int $day = 1): static + { + return parent::setISODate($year, $week, $day); + } + + public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): static + { + return parent::setTime($hour, $minute, $second, $microsecond); + } + + public function setTimezone(\DateTimeZone $timezone): static + { + return parent::setTimezone($timezone); + } + + public function getTimezone(): \DateTimeZone + { + return parent::getTimezone() ?: throw new \DateInvalidTimeZoneException('The DatePoint object has no timezone.'); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/LICENSE b/lam/lib/3rdParty/composer/symfony/clock/LICENSE new file mode 100644 index 000000000..733c826eb --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2022-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/clock/MockClock.php b/lam/lib/3rdParty/composer/symfony/clock/MockClock.php new file mode 100644 index 000000000..9ba2726bf --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/MockClock.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +/** + * A clock that always returns the same date, suitable for testing time-sensitive logic. + * + * Consider using ClockSensitiveTrait in your test cases instead of using this class directly. + * + * @author Nicolas Grekas + */ +final class MockClock implements ClockInterface +{ + private DatePoint $now; + + /** + * @throws \DateMalformedStringException When $now is invalid + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function __construct(\DateTimeImmutable|string $now = 'now', \DateTimeZone|string|null $timezone = null) + { + if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (\is_string($timezone)) { + try { + $timezone = new \DateTimeZone($timezone); + } catch (\Exception $e) { + throw new \DateInvalidTimeZoneException($e->getMessage(), $e->getCode(), $e); + } + } + + if (\is_string($now)) { + $now = new DatePoint($now, $timezone ?? new \DateTimeZone('UTC')); + } elseif (!$now instanceof DatePoint) { + $now = DatePoint::createFromInterface($now); + } + + $this->now = null !== $timezone ? $now->setTimezone($timezone) : $now; + } + + public function now(): DatePoint + { + return clone $this->now; + } + + public function sleep(float|int $seconds): void + { + $now = (float) $this->now->format('Uu') + $seconds * 1e6; + $now = substr_replace(\sprintf('@%07.0F', $now), '.', -6, 0); + $timezone = $this->now->getTimezone(); + + $this->now = DatePoint::createFromInterface(new \DateTimeImmutable($now, $timezone))->setTimezone($timezone); + } + + /** + * @throws \DateMalformedStringException When $modifier is invalid + */ + public function modify(string $modifier): void + { + if (\PHP_VERSION_ID < 80300) { + $this->now = @$this->now->modify($modifier) ?: throw new \DateMalformedStringException(error_get_last()['message'] ?? \sprintf('Invalid modifier: "%s". Could not modify MockClock.', $modifier)); + + return; + } + + $this->now = $this->now->modify($modifier); + } + + /** + * @throws \DateInvalidTimeZoneException When the timezone name is invalid + */ + public function withTimeZone(\DateTimeZone|string $timezone): static + { + if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (\is_string($timezone)) { + try { + $timezone = new \DateTimeZone($timezone); + } catch (\Exception $e) { + throw new \DateInvalidTimeZoneException($e->getMessage(), $e->getCode(), $e); + } + } + + $clone = clone $this; + $clone->now = $clone->now->setTimezone($timezone); + + return $clone; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/MonotonicClock.php b/lam/lib/3rdParty/composer/symfony/clock/MonotonicClock.php new file mode 100644 index 000000000..d27bf9c31 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/MonotonicClock.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +/** + * A monotonic clock suitable for performance profiling. + * + * @author Nicolas Grekas + */ +final class MonotonicClock implements ClockInterface +{ + private int $sOffset; + private int $usOffset; + private \DateTimeZone $timezone; + + /** + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function __construct(\DateTimeZone|string|null $timezone = null) + { + if (false === $offset = hrtime()) { + throw new \RuntimeException('hrtime() returned false: the runtime environment does not provide access to a monotonic timer.'); + } + + $time = explode(' ', microtime(), 2); + $this->sOffset = $time[1] - $offset[0]; + $this->usOffset = (int) ($time[0] * 1000000) - (int) ($offset[1] / 1000); + + $this->timezone = \is_string($timezone ??= date_default_timezone_get()) ? $this->withTimeZone($timezone)->timezone : $timezone; + } + + public function now(): DatePoint + { + [$s, $us] = hrtime(); + + if (1000000 <= $us = (int) ($us / 1000) + $this->usOffset) { + ++$s; + $us -= 1000000; + } elseif (0 > $us) { + --$s; + $us += 1000000; + } + + if (6 !== \strlen($now = (string) $us)) { + $now = str_pad($now, 6, '0', \STR_PAD_LEFT); + } + + $now = '@'.($s + $this->sOffset).'.'.$now; + + return DatePoint::createFromInterface(new \DateTimeImmutable($now, $this->timezone))->setTimezone($this->timezone); + } + + public function sleep(float|int $seconds): void + { + if (0 < $s = (int) $seconds) { + sleep($s); + } + + if (0 < $us = $seconds - $s) { + usleep((int) ($us * 1E6)); + } + } + + /** + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function withTimeZone(\DateTimeZone|string $timezone): static + { + if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (\is_string($timezone)) { + try { + $timezone = new \DateTimeZone($timezone); + } catch (\Exception $e) { + throw new \DateInvalidTimeZoneException($e->getMessage(), $e->getCode(), $e); + } + } + + $clone = clone $this; + $clone->timezone = $timezone; + + return $clone; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/NativeClock.php b/lam/lib/3rdParty/composer/symfony/clock/NativeClock.php new file mode 100644 index 000000000..b580a886c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/NativeClock.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +/** + * A clock that relies the system time. + * + * @author Nicolas Grekas + */ +final class NativeClock implements ClockInterface +{ + private \DateTimeZone $timezone; + + /** + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function __construct(\DateTimeZone|string|null $timezone = null) + { + $this->timezone = \is_string($timezone ??= date_default_timezone_get()) ? $this->withTimeZone($timezone)->timezone : $timezone; + } + + public function now(): DatePoint + { + return DatePoint::createFromInterface(new \DateTimeImmutable('now', $this->timezone)); + } + + public function sleep(float|int $seconds): void + { + if (0 < $s = (int) $seconds) { + sleep($s); + } + + if (0 < $us = $seconds - $s) { + usleep((int) ($us * 1E6)); + } + } + + /** + * @throws \DateInvalidTimeZoneException When $timezone is invalid + */ + public function withTimeZone(\DateTimeZone|string $timezone): static + { + if (\PHP_VERSION_ID >= 80300 && \is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (\is_string($timezone)) { + try { + $timezone = new \DateTimeZone($timezone); + } catch (\Exception $e) { + throw new \DateInvalidTimeZoneException($e->getMessage(), $e->getCode(), $e); + } + } + + $clone = clone $this; + $clone->timezone = $timezone; + + return $clone; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/README.md b/lam/lib/3rdParty/composer/symfony/clock/README.md new file mode 100644 index 000000000..e860a6474 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/README.md @@ -0,0 +1,47 @@ +Clock Component +=============== + +Symfony Clock decouples applications from the system clock. + +Getting Started +--------------- + +``` +$ composer require symfony/clock +``` + +```php +use Symfony\Component\Clock\NativeClock; +use Symfony\Component\Clock\ClockInterface; + +class MyClockSensitiveClass +{ + public function __construct( + private ClockInterface $clock, + ) { + // Only if you need to force a timezone: + //$this->clock = $clock->withTimeZone('UTC'); + } + + public function doSomething() + { + $now = $this->clock->now(); + // [...] do something with $now, which is a \DateTimeImmutable object + + $this->clock->sleep(2.5); // Pause execution for 2.5 seconds + } +} + +$clock = new NativeClock(); +$service = new MyClockSensitiveClass($clock); +$service->doSomething(); +``` + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/clock.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/lam/lib/3rdParty/composer/symfony/clock/Resources/now.php b/lam/lib/3rdParty/composer/symfony/clock/Resources/now.php new file mode 100644 index 000000000..47d086c67 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/Resources/now.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock; + +if (!\function_exists(now::class)) { + /** + * @throws \DateMalformedStringException When the modifier is invalid + */ + function now(string $modifier = 'now'): DatePoint + { + if ('now' !== $modifier) { + return new DatePoint($modifier); + } + + $now = Clock::get()->now(); + + return $now instanceof DatePoint ? $now : DatePoint::createFromInterface($now); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/Test/ClockSensitiveTrait.php b/lam/lib/3rdParty/composer/symfony/clock/Test/ClockSensitiveTrait.php new file mode 100644 index 000000000..fcc282022 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/Test/ClockSensitiveTrait.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Clock\Test; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use Psr\Clock\ClockInterface; +use Symfony\Component\Clock\Clock; +use Symfony\Component\Clock\MockClock; + +use function Symfony\Component\Clock\now; + +/** + * Helps with mocking the time in your test cases. + * + * This trait provides one self::mockTime() method that freezes the time. + * It restores the global clock after each test case. + * self::mockTime() accepts either a string (eg '+1 days' or '2022-12-22'), + * a DateTimeImmutable, or a boolean (to freeze/restore the global clock). + * + * @author Nicolas Grekas + */ +trait ClockSensitiveTrait +{ + public static function mockTime(string|\DateTimeImmutable|bool $when = true): ClockInterface + { + Clock::set(match (true) { + false === $when => self::saveClockBeforeTest(false), + true === $when => new MockClock(), + $when instanceof \DateTimeImmutable => new MockClock($when), + default => new MockClock(now($when)), + }); + + return Clock::get(); + } + + /** + * @beforeClass + * + * @before + * + * @internal + */ + #[Before] + #[BeforeClass] + public static function saveClockBeforeTest(bool $save = true): ClockInterface + { + static $originalClock; + + if ($save && $originalClock) { + self::restoreClockAfterTest(); + } + + return $save ? $originalClock = Clock::get() : $originalClock; + } + + /** + * @after + * + * @internal + */ + #[After] + protected static function restoreClockAfterTest(): void + { + Clock::set(self::saveClockBeforeTest(false)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/clock/composer.json b/lam/lib/3rdParty/composer/symfony/clock/composer.json new file mode 100644 index 000000000..d9a0f985c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/clock/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/clock", + "type": "library", + "description": "Decouples applications from the system clock", + "keywords": ["clock", "time", "psr20"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "provide": { + "psr/clock-implementation": "1.0" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "autoload": { + "files": [ "Resources/now.php" ], + "psr-4": { "Symfony\\Component\\Clock\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Application.php b/lam/lib/3rdParty/composer/symfony/console/Application.php new file mode 100644 index 000000000..c18d482b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Application.php @@ -0,0 +1,1331 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Command\CompleteCommand; +use Symfony\Component\Console\Command\DumpCompletionCommand; +use Symfony\Component\Console\Command\HelpCommand; +use Symfony\Component\Console\Command\LazyCommand; +use Symfony\Component\Console\Command\ListCommand; +use Symfony\Component\Console\Command\SignalableCommandInterface; +use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Event\ConsoleSignalEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\Console\Exception\CommandNotFoundException; +use Symfony\Component\Console\Exception\ExceptionInterface; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Exception\NamespaceNotFoundException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\DebugFormatterHelper; +use Symfony\Component\Console\Helper\DescriptorHelper; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\ProcessHelper; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputAwareInterface; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\SignalRegistry\SignalRegistry; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\ErrorHandler\ErrorHandler; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->add(new SimpleCommand()); + * $app->run(); + * + * @author Fabien Potencier + */ +class Application implements ResetInterface +{ + private array $commands = []; + private bool $wantHelps = false; + private ?Command $runningCommand = null; + private string $name; + private string $version; + private ?CommandLoaderInterface $commandLoader = null; + private bool $catchExceptions = true; + private bool $catchErrors = false; + private bool $autoExit = true; + private InputDefinition $definition; + private HelperSet $helperSet; + private ?EventDispatcherInterface $dispatcher = null; + private Terminal $terminal; + private string $defaultCommand; + private bool $singleCommand = false; + private bool $initialized = false; + private ?SignalRegistry $signalRegistry = null; + private array $signalsToDispatchEvent = []; + + public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN') + { + $this->name = $name; + $this->version = $version; + $this->terminal = new Terminal(); + $this->defaultCommand = 'list'; + if (\defined('SIGINT') && SignalRegistry::isSupported()) { + $this->signalRegistry = new SignalRegistry(); + $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; + } + } + + /** + * @final + */ + public function setDispatcher(EventDispatcherInterface $dispatcher): void + { + $this->dispatcher = $dispatcher; + } + + /** + * @return void + */ + public function setCommandLoader(CommandLoaderInterface $commandLoader) + { + $this->commandLoader = $commandLoader; + } + + public function getSignalRegistry(): SignalRegistry + { + if (!$this->signalRegistry) { + throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + + return $this->signalRegistry; + } + + /** + * @return void + */ + public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) + { + $this->signalsToDispatchEvent = $signalsToDispatchEvent; + } + + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + * + * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. + */ + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int + { + if (\function_exists('putenv')) { + @putenv('LINES='.$this->terminal->getHeight()); + @putenv('COLUMNS='.$this->terminal->getWidth()); + } + + $input ??= new ArgvInput(); + $output ??= new ConsoleOutput(); + + $renderException = function (\Throwable $e) use ($output) { + if ($output instanceof ConsoleOutputInterface) { + $this->renderThrowable($e, $output->getErrorOutput()); + } else { + $this->renderThrowable($e, $output); + } + }; + if ($phpHandler = set_exception_handler($renderException)) { + restore_exception_handler(); + if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { + $errorHandler = true; + } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) { + $phpHandler[0]->setExceptionHandler($errorHandler); + } + } + + try { + $this->configureIO($input, $output); + + $exitCode = $this->doRun($input, $output); + } catch (\Throwable $e) { + if ($e instanceof \Exception && !$this->catchExceptions) { + throw $e; + } + if (!$e instanceof \Exception && !$this->catchErrors) { + throw $e; + } + + $renderException($e); + + $exitCode = $e->getCode(); + if (is_numeric($exitCode)) { + $exitCode = (int) $exitCode; + if ($exitCode <= 0) { + $exitCode = 1; + } + } else { + $exitCode = 1; + } + } finally { + // if the exception handler changed, keep it + // otherwise, unregister $renderException + if (!$phpHandler) { + if (set_exception_handler($renderException) === $renderException) { + restore_exception_handler(); + } + restore_exception_handler(); + } elseif (!$errorHandler) { + $finalHandler = $phpHandler[0]->setExceptionHandler(null); + if ($finalHandler !== $renderException) { + $phpHandler[0]->setExceptionHandler($finalHandler); + } + } + } + + if ($this->autoExit) { + if ($exitCode > 255) { + $exitCode = 255; + } + + exit($exitCode); + } + + return $exitCode; + } + + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + if (true === $input->hasParameterOption(['--version', '-V'], true)) { + $output->writeln($this->getLongVersion()); + + return 0; + } + + try { + // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. + $input->bind($this->getDefinition()); + } catch (ExceptionInterface) { + // Errors must be ignored, full binding/validation happens later when the command is known. + } + + $name = $this->getCommandName($input); + if (true === $input->hasParameterOption(['--help', '-h'], true)) { + if (!$name) { + $name = 'help'; + $input = new ArrayInput(['command_name' => $this->defaultCommand]); + } else { + $this->wantHelps = true; + } + } + + if (!$name) { + $name = $this->defaultCommand; + $definition = $this->getDefinition(); + $definition->setArguments(array_merge( + $definition->getArguments(), + [ + 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name), + ] + )); + } + + try { + $this->runningCommand = null; + // the command name MUST be the first element of the input + $command = $this->find($name); + } catch (\Throwable $e) { + if (($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) { + $alternative = $alternatives[0]; + + $style = new SymfonyStyle($input, $output); + $output->writeln(''); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true); + $output->writeln($formattedBlock); + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + + return $event->getExitCode(); + } + + return 1; + } + + $command = $this->find($alternative); + } else { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + + if (0 === $event->getExitCode()) { + return 0; + } + + $e = $event->getError(); + } + + try { + if ($e instanceof CommandNotFoundException && $namespace = $this->findNamespace($name)) { + $helper = new DescriptorHelper(); + $helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, [ + 'format' => 'txt', + 'raw_text' => false, + 'namespace' => $namespace, + 'short' => false, + ]); + + return isset($event) ? $event->getExitCode() : 1; + } + + throw $e; + } catch (NamespaceNotFoundException) { + throw $e; + } + } + } + + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + + $this->runningCommand = $command; + $exitCode = $this->doRunCommand($command, $input, $output); + $this->runningCommand = null; + + return $exitCode; + } + + /** + * @return void + */ + public function reset() + { + } + + /** + * @return void + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Get the helper set associated with the command. + */ + public function getHelperSet(): HelperSet + { + return $this->helperSet ??= $this->getDefaultHelperSet(); + } + + /** + * @return void + */ + public function setDefinition(InputDefinition $definition) + { + $this->definition = $definition; + } + + /** + * Gets the InputDefinition related to this Application. + */ + public function getDefinition(): InputDefinition + { + $this->definition ??= $this->getDefaultInputDefinition(); + + if ($this->singleCommand) { + $inputDefinition = $this->definition; + $inputDefinition->setArguments(); + + return $inputDefinition; + } + + return $this->definition; + } + + /** + * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ( + CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() + && 'command' === $input->getCompletionName() + ) { + foreach ($this->all() as $name => $command) { + // skip hidden commands and aliased commands as they already get added below + if ($command->isHidden() || $command->getName() !== $name) { + continue; + } + $suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription())); + foreach ($command->getAliases() as $name) { + $suggestions->suggestValue(new Suggestion($name, $command->getDescription())); + } + } + + return; + } + + if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) { + $suggestions->suggestOptions($this->getDefinition()->getOptions()); + + return; + } + } + + /** + * Gets the help message. + */ + public function getHelp(): string + { + return $this->getLongVersion(); + } + + /** + * Gets whether to catch exceptions or not during commands execution. + */ + public function areExceptionsCaught(): bool + { + return $this->catchExceptions; + } + + /** + * Sets whether to catch exceptions or not during commands execution. + * + * @return void + */ + public function setCatchExceptions(bool $boolean) + { + $this->catchExceptions = $boolean; + } + + /** + * Sets whether to catch errors or not during commands execution. + */ + public function setCatchErrors(bool $catchErrors = true): void + { + $this->catchErrors = $catchErrors; + } + + /** + * Gets whether to automatically exit after a command execution or not. + */ + public function isAutoExitEnabled(): bool + { + return $this->autoExit; + } + + /** + * Sets whether to automatically exit after a command execution or not. + * + * @return void + */ + public function setAutoExit(bool $boolean) + { + $this->autoExit = $boolean; + } + + /** + * Gets the name of the application. + */ + public function getName(): string + { + return $this->name; + } + + /** + * Sets the application name. + * + * @return void + */ + public function setName(string $name) + { + $this->name = $name; + } + + /** + * Gets the application version. + */ + public function getVersion(): string + { + return $this->version; + } + + /** + * Sets the application version. + * + * @return void + */ + public function setVersion(string $version) + { + $this->version = $version; + } + + /** + * Returns the long version of the application. + * + * @return string + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName()) { + if ('UNKNOWN' !== $this->getVersion()) { + return \sprintf('%s %s', $this->getName(), $this->getVersion()); + } + + return $this->getName(); + } + + return 'Console Tool'; + } + + /** + * Registers a new command. + */ + public function register(string $name): Command + { + return $this->add(new Command($name)); + } + + /** + * Adds an array of command objects. + * + * If a Command is not enabled it will not be added. + * + * @param Command[] $commands An array of commands + * + * @return void + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) { + $this->add($command); + } + } + + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * If the command is not enabled it will not be added. + * + * @return Command|null + */ + public function add(Command $command) + { + $this->init(); + + $command->setApplication($this); + + if (!$command->isEnabled()) { + $command->setApplication(null); + + return null; + } + + if (!$command instanceof LazyCommand) { + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + } + + if (!$command->getName()) { + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); + } + + $this->commands[$command->getName()] = $command; + + foreach ($command->getAliases() as $alias) { + $this->commands[$alias] = $command; + } + + return $command; + } + + /** + * Returns a registered command by name or alias. + * + * @return Command + * + * @throws CommandNotFoundException When given command name does not exist + */ + public function get(string $name) + { + $this->init(); + + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + + // When the command has a different name than the one used at the command loader level + if (!isset($this->commands[$name])) { + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + } + + $command = $this->commands[$name]; + + if ($this->wantHelps) { + $this->wantHelps = false; + + $helpCommand = $this->get('help'); + $helpCommand->setCommand($command); + + return $helpCommand; + } + + return $command; + } + + /** + * Returns true if the command exists, false otherwise. + */ + public function has(string $name): bool + { + $this->init(); + + return isset($this->commands[$name]) || ($this->commandLoader?->has($name) && $this->add($this->commandLoader->get($name))); + } + + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not return the global namespace which always exists. + * + * @return string[] + */ + public function getNamespaces(): array + { + $namespaces = []; + foreach ($this->all() as $command) { + if ($command->isHidden()) { + continue; + } + + $namespaces[] = $this->extractAllNamespaces($command->getName()); + + foreach ($command->getAliases() as $alias) { + $namespaces[] = $this->extractAllNamespaces($alias); + } + } + + return array_values(array_unique(array_filter(array_merge([], ...$namespaces)))); + } + + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous + */ + public function findNamespace(string $namespace): string + { + $allNamespaces = $this->getNamespaces(); + $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*'; + $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); + + if (empty($namespaces)) { + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); + + if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + + $message .= implode("\n ", $alternatives); + } + + throw new NamespaceNotFoundException($message, $alternatives); + } + + $exact = \in_array($namespace, $namespaces, true); + if (\count($namespaces) > 1 && !$exact) { + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + } + + return $exact ? $namespace : reset($namespaces); + } + + /** + * Finds a command by name or alias. + * + * Contrary to get, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @return Command + * + * @throws CommandNotFoundException When command name is incorrect or ambiguous + */ + public function find(string $name) + { + $this->init(); + + $aliases = []; + + foreach ($this->commands as $command) { + foreach ($command->getAliases() as $alias) { + if (!$this->has($alias)) { + $this->commands[$alias] = $command; + } + } + } + + if ($this->has($name)) { + return $this->get($name); + } + + $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands); + $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*'; + $commands = preg_grep('{^'.$expr.'}', $allCommands); + + if (empty($commands)) { + $commands = preg_grep('{^'.$expr.'}i', $allCommands); + } + + // if no commands matched or we just matched namespaces + if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) { + if (false !== $pos = strrpos($name, ':')) { + // check if a namespace exists and contains commands + $this->findNamespace(substr($name, 0, $pos)); + } + + $message = \sprintf('Command "%s" is not defined.', $name); + + if ($alternatives = $this->findAlternatives($name, $allCommands)) { + // remove hidden commands + $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden()); + + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= implode("\n ", $alternatives); + } + + throw new CommandNotFoundException($message, array_values($alternatives)); + } + + // filter out aliases for commands which are already on the list + if (\count($commands) > 1) { + $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; + $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) { + if (!$commandList[$nameOrAlias] instanceof Command) { + $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); + } + + $commandName = $commandList[$nameOrAlias]->getName(); + + $aliases[$nameOrAlias] = $commandName; + + return $commandName === $nameOrAlias || !\in_array($commandName, $commands); + })); + } + + if (\count($commands) > 1) { + $usableWidth = $this->terminal->getWidth() - 10; + $abbrevs = array_values($commands); + $maxLen = 0; + foreach ($abbrevs as $abbrev) { + $maxLen = max(Helper::width($abbrev), $maxLen); + } + $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) { + if ($commandList[$cmd]->isHidden()) { + unset($commands[array_search($cmd, $commands)]); + + return false; + } + + $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription(); + + return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev; + }, array_values($commands)); + + if (\count($commands) > 1) { + $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); + + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); + } + } + + $command = $this->get(reset($commands)); + + if ($command->isHidden()) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + + return $command; + } + + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @return Command[] + */ + public function all(?string $namespace = null) + { + $this->init(); + + if (null === $namespace) { + if (!$this->commandLoader) { + return $this->commands; + } + + $commands = $this->commands; + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + + return $commands; + } + + $commands = []; + foreach ($this->commands as $name => $command) { + if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) { + $commands[$name] = $command; + } + } + + if ($this->commandLoader) { + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + } + + return $commands; + } + + /** + * Returns an array of possible abbreviations given a set of names. + * + * @return string[][] + */ + public static function getAbbreviations(array $names): array + { + $abbrevs = []; + foreach ($names as $name) { + for ($len = \strlen($name); $len > 0; --$len) { + $abbrev = substr($name, 0, $len); + $abbrevs[$abbrev][] = $name; + } + } + + return $abbrevs; + } + + public function renderThrowable(\Throwable $e, OutputInterface $output): void + { + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + + $this->doRenderThrowable($e, $output); + + if (null !== $this->runningCommand) { + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } + + protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void + { + do { + $message = trim($e->getMessage()); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $class = get_debug_type($e); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $len = Helper::width($title); + } else { + $len = 0; + } + + if (str_contains($message, "@anonymous\0")) { + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); + } + + $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; + $lines = []; + foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) { + foreach ($this->splitStringByWidth($line, $width - 4) as $line) { + // pre-format lines to get the right string length + $lineLength = Helper::width($line) + 4; + $lines[] = [$line, $lineLength]; + + $len = max($lineLength, $len); + } + } + + $messages = []; + if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + } + $messages[] = $emptyLine = \sprintf('%s', str_repeat(' ', $len)); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); + } + foreach ($lines as $line) { + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); + } + $messages[] = $emptyLine; + $messages[] = ''; + + $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); + + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); + + // exception related properties + $trace = $e->getTrace(); + + array_unshift($trace, [ + 'function' => '', + 'file' => $e->getFile() ?: 'n/a', + 'line' => $e->getLine() ?: 'n/a', + 'args' => [], + ]); + + for ($i = 0, $count = \count($trace); $i < $count; ++$i) { + $class = $trace[$i]['class'] ?? ''; + $type = $trace[$i]['type'] ?? ''; + $function = $trace[$i]['function'] ?? ''; + $file = $trace[$i]['file'] ?? 'n/a'; + $line = $trace[$i]['line'] ?? 'n/a'; + + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + } + + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } while ($e = $e->getPrevious()); + } + + /** + * Configures the input and output instances based on the user arguments and options. + * + * @return void + */ + protected function configureIO(InputInterface $input, OutputInterface $output) + { + if (true === $input->hasParameterOption(['--ansi'], true)) { + $output->setDecorated(true); + } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) { + $output->setDecorated(false); + } + + if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) { + $input->setInteractive(false); + } + + switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) { + case -1: + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + break; + case 1: + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + break; + case 2: + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + break; + case 3: + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + break; + default: + $shellVerbosity = 0; + break; + } + + if (true === $input->hasParameterOption(['--quiet', '-q'], true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + $shellVerbosity = -1; + } else { + if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + $shellVerbosity = 3; + } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + $shellVerbosity = 2; + } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + $shellVerbosity = 1; + } + } + + if (-1 === $shellVerbosity) { + $input->setInteractive(false); + } + + if (\function_exists('putenv')) { + @putenv('SHELL_VERBOSITY='.$shellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; + } + + /** + * Runs the current command. + * + * If an event dispatcher has been attached to the application, + * events are also dispatched during the life-cycle of the command. + * + * @return int 0 if everything went fine, or an error code + */ + protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) + { + foreach ($command->getHelperSet() as $helper) { + if ($helper instanceof InputAwareInterface) { + $helper->setInput($input); + } + } + + $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { + if (!$this->signalRegistry) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + + if (Terminal::hasSttyAvailable()) { + $sttyMode = shell_exec('stty -g'); + + foreach ([\SIGINT, \SIGTERM] as $signal) { + $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); + } + } + + if ($this->dispatcher) { + // We register application signals, so that we can dispatch the event + foreach ($this->signalsToDispatchEvent as $signal) { + $event = new ConsoleSignalEvent($command, $input, $output, $signal); + + $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) { + $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + $exitCode = $event->getExitCode(); + + // If the command is signalable, we call the handleSignal() method + if (\in_array($signal, $commandSignals, true)) { + $exitCode = $command->handleSignal($signal, $exitCode); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; + } + } + + if (false !== $exitCode) { + $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + + exit($event->getExitCode()); + } + }); + } + + // then we register command signals, but not if already handled after the dispatcher + $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent); + } + + foreach ($commandSignals as $signal) { + $this->signalRegistry->register($signal, function (int $signal) use ($command): void { + $exitCode = $command->handleSignal($signal); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; + } + + if (false !== $exitCode) { + exit($exitCode); + } + }); + } + } + + if (null === $this->dispatcher) { + return $command->run($input, $output); + } + + // bind before the console.command event, so the listeners have access to input options/arguments + try { + $command->mergeApplicationDefinition(); + $input->bind($command->getDefinition()); + } catch (ExceptionInterface) { + // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition + } + + $event = new ConsoleCommandEvent($command, $input, $output); + $e = null; + + try { + $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND); + + if ($event->commandShouldRun()) { + $exitCode = $command->run($input, $output); + } else { + $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; + } + } catch (\Throwable $e) { + $event = new ConsoleErrorEvent($input, $output, $e, $command); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + $e = $event->getError(); + + if (0 === $exitCode = $event->getExitCode()) { + $e = null; + } + } + + $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + + if (null !== $e) { + throw $e; + } + + return $event->getExitCode(); + } + + /** + * Gets the name of the command based on input. + */ + protected function getCommandName(InputInterface $input): ?string + { + return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); + } + + /** + * Gets the default input definition. + */ + protected function getDefaultInputDefinition(): InputDefinition + { + return new InputDefinition([ + new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), + new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the '.$this->defaultCommand.' command'), + new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), + new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), + new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), + new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), + new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), + ]); + } + + /** + * Gets the default commands that should always be available. + * + * @return Command[] + */ + protected function getDefaultCommands(): array + { + return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()]; + } + + /** + * Gets the default helper set with the helpers that should always be available. + */ + protected function getDefaultHelperSet(): HelperSet + { + return new HelperSet([ + new FormatterHelper(), + new DebugFormatterHelper(), + new ProcessHelper(), + new QuestionHelper(), + ]); + } + + /** + * Returns abbreviated suggestions in string format. + */ + private function getAbbreviationSuggestions(array $abbrevs): string + { + return ' '.implode("\n ", $abbrevs); + } + + /** + * Returns the namespace part of the command name. + * + * This method is not part of public API and should not be used directly. + */ + public function extractNamespace(string $name, ?int $limit = null): string + { + $parts = explode(':', $name, -1); + + return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit)); + } + + /** + * Finds alternative of $name among $collection, + * if nothing is found in $collection, try in $abbrevs. + * + * @return string[] + */ + private function findAlternatives(string $name, iterable $collection): array + { + $threshold = 1e3; + $alternatives = []; + + $collectionParts = []; + foreach ($collection as $item) { + $collectionParts[$item] = explode(':', $item); + } + + foreach (explode(':', $name) as $i => $subname) { + foreach ($collectionParts as $collectionName => $parts) { + $exists = isset($alternatives[$collectionName]); + if (!isset($parts[$i]) && $exists) { + $alternatives[$collectionName] += $threshold; + continue; + } elseif (!isset($parts[$i])) { + continue; + } + + $lev = levenshtein($subname, $parts[$i]); + if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) { + $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; + } elseif ($exists) { + $alternatives[$collectionName] += $threshold; + } + } + } + + foreach ($collection as $item) { + $lev = levenshtein($name, $item); + if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) { + $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; + } + } + + $alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold); + ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); + + return array_keys($alternatives); + } + + /** + * Sets the default Command name. + * + * @return $this + */ + public function setDefaultCommand(string $commandName, bool $isSingleCommand = false): static + { + $this->defaultCommand = explode('|', ltrim($commandName, '|'))[0]; + + if ($isSingleCommand) { + // Ensure the command exist + $this->find($commandName); + + $this->singleCommand = true; + } + + return $this; + } + + /** + * @internal + */ + public function isSingleCommand(): bool + { + return $this->singleCommand; + } + + private function splitStringByWidth(string $string, int $width): array + { + // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. + // additionally, array_slice() is not enough as some character has doubled width. + // we need a function to split string not by character count but by string width + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return str_split($string, $width); + } + + $utf8String = mb_convert_encoding($string, 'utf8', $encoding); + $lines = []; + $line = ''; + + $offset = 0; + while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) { + $offset += \strlen($m[0]); + + foreach (preg_split('//u', $m[0]) as $char) { + // test if $char could be appended to current line + if (Helper::width($line.$char) <= $width) { + $line .= $char; + continue; + } + // if not, push current line to array and make new line + $lines[] = str_pad($line, $width); + $line = $char; + } + } + + $lines[] = \count($lines) ? str_pad($line, $width) : $line; + + mb_convert_variables($encoding, 'utf8', $lines); + + return $lines; + } + + /** + * Returns all namespaces of the command name. + * + * @return string[] + */ + private function extractAllNamespaces(string $name): array + { + // -1 as third argument is needed to skip the command short name when exploding + $parts = explode(':', $name, -1); + $namespaces = []; + + foreach ($parts as $part) { + if (\count($namespaces)) { + $namespaces[] = end($namespaces).':'.$part; + } else { + $namespaces[] = $part; + } + } + + return $namespaces; + } + + private function init(): void + { + if ($this->initialized) { + return; + } + $this->initialized = true; + + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Attribute/AsCommand.php b/lam/lib/3rdParty/composer/symfony/console/Attribute/AsCommand.php new file mode 100644 index 000000000..b337f548f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Attribute/AsCommand.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Attribute; + +/** + * Service tag to autoconfigure commands. + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class AsCommand +{ + public function __construct( + public string $name, + public ?string $description = null, + array $aliases = [], + bool $hidden = false, + ) { + if (!$hidden && !$aliases) { + return; + } + + $name = explode('|', $name); + $name = array_merge($name, $aliases); + + if ($hidden && '' !== $name[0]) { + array_unshift($name, ''); + } + + $this->name = implode('|', $name); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/CHANGELOG.md b/lam/lib/3rdParty/composer/symfony/console/CHANGELOG.md new file mode 100644 index 000000000..9ccb41d94 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/CHANGELOG.md @@ -0,0 +1,261 @@ +CHANGELOG +========= + +6.4 +--- + + * Add `SignalMap` to map signal value to its name + * Multi-line text in vertical tables is aligned properly + * The application can also catch errors with `Application::setCatchErrors(true)` + * Add `RunCommandMessage` and `RunCommandMessageHandler` + * Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()` + +6.3 +--- + + * Add support for choosing exit code while handling signal, or to not exit at all + * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global. + * Add `ReStructuredTextDescriptor` + +6.2 +--- + + * Improve truecolor terminal detection in some cases + * Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it) + * Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments + * Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)` + * Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)` + +6.1 +--- + + * Add support to display table vertically when calling setVertical() + * Add method `__toString()` to `InputInterface` + * Added `OutputWrapper` to prevent truncated URL in `SymfonyStyle::createBlock`. + * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead + * Add suggested values for arguments and options in input definition, for input completion + * Add `$resumeAt` parameter to `ProgressBar#start()`, so that one can easily 'resume' progress on longer tasks, and still get accurate `getEstimate()` and `getRemaining()` results. + +6.0 +--- + + * `Command::setHidden()` has a default value (`true`) for `$hidden` parameter and is final + * Remove `Helper::strlen()`, use `Helper::width()` instead + * Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead + * `AddConsoleCommandPass` can not be configured anymore + * Remove `HelperSet::setCommand()` and `getCommand()` without replacement + +5.4 +--- + + * Add `TesterTrait::assertCommandIsSuccessful()` to test command + * Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement + +5.3 +--- + + * Add `GithubActionReporter` to render annotations in a Github Action + * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options + * Add the `Command::$defaultDescription` static property and the `description` attribute + on the `console.command` tag to allow the `list` command to instantiate commands lazily + * Add option `--short` to the `list` command + * Add support for bright colors + * Add `#[AsCommand]` attribute for declaring commands on PHP 8 + * Add `Helper::width()` and `Helper::length()` + * The `--ansi` and `--no-ansi` options now default to `null`. + +5.2.0 +----- + + * Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester` + * added support for multiline responses to questions through `Question::setMultiline()` + and `Question::isMultiline()` + * Added `SignalRegistry` class to stack signals handlers + * Added support for signals: + * Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods + * Added `SignalableCommandInterface` interface + * Added `TableCellStyle` class to customize table cell + * Removed `php ` prefix invocation from help messages. + +5.1.0 +----- + + * `Command::setHidden()` is final since Symfony 5.1 + * Add `SingleCommandApplication` + * Add `Cursor` class + +5.0.0 +----- + + * removed support for finding hidden commands using an abbreviation, use the full name instead + * removed `TableStyle::setCrossingChar()` method in favor of `TableStyle::setDefaultCrossingChar()` + * removed `TableStyle::setHorizontalBorderChar()` method in favor of `TableStyle::setDefaultCrossingChars()` + * removed `TableStyle::getHorizontalBorderChar()` method in favor of `TableStyle::getBorderChars()` + * removed `TableStyle::setVerticalBorderChar()` method in favor of `TableStyle::setVerticalBorderChars()` + * removed `TableStyle::getVerticalBorderChar()` method in favor of `TableStyle::getBorderChars()` + * removed support for returning `null` from `Command::execute()`, return `0` instead + * `ProcessHelper::run()` accepts only `array|Symfony\Component\Process\Process` for its `command` argument + * `Application::setDispatcher` accepts only `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` + for its `dispatcher` argument + * renamed `Application::renderException()` and `Application::doRenderException()` + to `renderThrowable()` and `doRenderThrowable()` respectively. + +4.4.0 +----- + + * deprecated finding hidden commands using an abbreviation, use the full name instead + * added `Question::setTrimmable` default to true to allow the answer to be trimmed + * added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar` + * `Application` implements `ResetInterface` + * marked all dispatched event classes as `@final` + * added support for displaying table horizontally + * deprecated returning `null` from `Command::execute()`, return `0` instead + * Deprecated the `Application::renderException()` and `Application::doRenderException()` methods, + use `renderThrowable()` and `doRenderThrowable()` instead. + * added support for the `NO_COLOR` env var (https://no-color.org/) + +4.3.0 +----- + + * added support for hyperlinks + * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating + * added `Question::setAutocompleterCallback()` to provide a callback function + that dynamically generates suggestions as the user types + +4.2.0 +----- + + * allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to + `ProcessHelper::run()` to pass environment variables + * deprecated passing a command as a string to `ProcessHelper::run()`, + pass it the command as an array of its arguments instead + * made the `ProcessHelper` class final + * added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`) + * added `capture_stderr_separately` option to `CommandTester::execute()` + +4.1.0 +----- + + * added option to run suggested command if command is not found and only 1 alternative is available + * added option to modify console output and print multiple modifiable sections + * added support for iterable messages in output `write` and `writeln` methods + +4.0.0 +----- + + * `OutputFormatter` throws an exception when unknown options are used + * removed `QuestionHelper::setInputStream()/getInputStream()` + * removed `Application::getTerminalWidth()/getTerminalHeight()` and + `Application::setTerminalDimensions()/getTerminalDimensions()` + * removed `ConsoleExceptionEvent` + * removed `ConsoleEvents::EXCEPTION` + +3.4.0 +----- + + * added `SHELL_VERBOSITY` env var to control verbosity + * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11 + `ContainerCommandLoader` for commands lazy-loading + * added a case-insensitive command name matching fallback + * added static `Command::$defaultName/getDefaultName()`, allowing for + commands to be registered at compile time in the application command loader. + Setting the `$defaultName` property avoids the need for filling the `command` + attribute on the `console.command` tag when using `AddConsoleCommandPass`. + +3.3.0 +----- + + * added `ExceptionListener` + * added `AddConsoleCommandPass` (originally in FrameworkBundle) + * [BC BREAK] `Input::getOption()` no longer returns the default value for options + with value optional explicitly passed empty + * added console.error event to catch exceptions thrown by other listeners + * deprecated console.exception event in favor of console.error + * added ability to handle `CommandNotFoundException` through the + `console.error` event + * deprecated default validation in `SymfonyQuestionHelper::ask` + +3.2.0 +------ + + * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs + * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface) + * added StreamableInputInterface + * added LockableTrait + +3.1.0 +----- + + * added truncate method to FormatterHelper + * added setColumnWidth(s) method to Table + +2.8.3 +----- + + * remove readline support from the question helper as it caused issues + +2.8.0 +----- + + * use readline for user input in the question helper when available to allow + the use of arrow keys + +2.6.0 +----- + + * added a Process helper + * added a DebugFormatter helper + +2.5.0 +----- + + * deprecated the dialog helper (use the question helper instead) + * deprecated TableHelper in favor of Table + * deprecated ProgressHelper in favor of ProgressBar + * added ConsoleLogger + * added a question helper + * added a way to set the process name of a command + * added a way to set a default command instead of `ListCommand` + +2.4.0 +----- + + * added a way to force terminal dimensions + * added a convenient method to detect verbosity level + * [BC BREAK] made descriptors use output instead of returning a string + +2.3.0 +----- + + * added multiselect support to the select dialog helper + * added Table Helper for tabular data rendering + * added support for events in `Application` + * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()` + * added a way to set the progress bar progress via the `setCurrent` method + * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'` + * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG + +2.2.0 +----- + + * added support for colorization on Windows via ConEmu + * add a method to Dialog Helper to ask for a question and hide the response + * added support for interactive selections in console (DialogHelper::select()) + * added support for autocompletion as you type in Dialog Helper + +2.1.0 +----- + + * added ConsoleOutputInterface + * added the possibility to disable a command (Command::isEnabled()) + * added suggestions when a command does not exist + * added a --raw option to the list command + * added support for STDERR in the console output class (errors are now sent + to STDERR) + * made the defaults (helper set, commands, input definition) in Application + more easily customizable + * added support for the shell even if readline is not available + * added support for process isolation in Symfony shell via + `--process-isolation` switch + * added support for `--`, which disables options parsing after that point + (tokens will be parsed as arguments) diff --git a/lam/lib/3rdParty/composer/symfony/console/CI/GithubActionReporter.php b/lam/lib/3rdParty/composer/symfony/console/CI/GithubActionReporter.php new file mode 100644 index 000000000..28112c2a2 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/CI/GithubActionReporter.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CI; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Utility class for Github actions. + * + * @author Maxime Steinhausser + */ +class GithubActionReporter +{ + private OutputInterface $output; + + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 + */ + private const ESCAPED_DATA = [ + '%' => '%25', + "\r" => '%0D', + "\n" => '%0A', + ]; + + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94 + */ + private const ESCAPED_PROPERTIES = [ + '%' => '%25', + "\r" => '%0D', + "\n" => '%0A', + ':' => '%3A', + ',' => '%2C', + ]; + + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + + public static function isGithubActionEnvironment(): bool + { + return false !== getenv('GITHUB_ACTIONS'); + } + + /** + * Output an error using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + */ + public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void + { + $this->log('error', $message, $file, $line, $col); + } + + /** + * Output a warning using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message + */ + public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void + { + $this->log('warning', $message, $file, $line, $col); + } + + /** + * Output a debug log using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message + */ + public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void + { + $this->log('debug', $message, $file, $line, $col); + } + + private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void + { + // Some values must be encoded. + $message = strtr($message, self::ESCAPED_DATA); + + if (!$file) { + // No file provided, output the message solely: + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); + + return; + } + + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Color.php b/lam/lib/3rdParty/composer/symfony/console/Color.php new file mode 100644 index 000000000..b1914c19a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Color.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * @author Fabien Potencier + */ +final class Color +{ + private const COLORS = [ + 'black' => 0, + 'red' => 1, + 'green' => 2, + 'yellow' => 3, + 'blue' => 4, + 'magenta' => 5, + 'cyan' => 6, + 'white' => 7, + 'default' => 9, + ]; + + private const BRIGHT_COLORS = [ + 'gray' => 0, + 'bright-red' => 1, + 'bright-green' => 2, + 'bright-yellow' => 3, + 'bright-blue' => 4, + 'bright-magenta' => 5, + 'bright-cyan' => 6, + 'bright-white' => 7, + ]; + + private const AVAILABLE_OPTIONS = [ + 'bold' => ['set' => 1, 'unset' => 22], + 'underscore' => ['set' => 4, 'unset' => 24], + 'blink' => ['set' => 5, 'unset' => 25], + 'reverse' => ['set' => 7, 'unset' => 27], + 'conceal' => ['set' => 8, 'unset' => 28], + ]; + + private string $foreground; + private string $background; + private array $options = []; + + public function __construct(string $foreground = '', string $background = '', array $options = []) + { + $this->foreground = $this->parseColor($foreground); + $this->background = $this->parseColor($background, true); + + foreach ($options as $option) { + if (!isset(self::AVAILABLE_OPTIONS[$option])) { + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); + } + + $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; + } + } + + public function apply(string $text): string + { + return $this->set().$text.$this->unset(); + } + + public function set(): string + { + $setCodes = []; + if ('' !== $this->foreground) { + $setCodes[] = $this->foreground; + } + if ('' !== $this->background) { + $setCodes[] = $this->background; + } + foreach ($this->options as $option) { + $setCodes[] = $option['set']; + } + if (0 === \count($setCodes)) { + return ''; + } + + return \sprintf("\033[%sm", implode(';', $setCodes)); + } + + public function unset(): string + { + $unsetCodes = []; + if ('' !== $this->foreground) { + $unsetCodes[] = 39; + } + if ('' !== $this->background) { + $unsetCodes[] = 49; + } + foreach ($this->options as $option) { + $unsetCodes[] = $option['unset']; + } + if (0 === \count($unsetCodes)) { + return ''; + } + + return \sprintf("\033[%sm", implode(';', $unsetCodes)); + } + + private function parseColor(string $color, bool $background = false): string + { + if ('' === $color) { + return ''; + } + + if ('#' === $color[0]) { + return ($background ? '4' : '3').Terminal::getColorMode()->convertFromHexToAnsiColorCode($color); + } + + if (isset(self::COLORS[$color])) { + return ($background ? '4' : '3').self::COLORS[$color]; + } + + if (isset(self::BRIGHT_COLORS[$color])) { + return ($background ? '10' : '9').self::BRIGHT_COLORS[$color]; + } + + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/Command.php b/lam/lib/3rdParty/composer/symfony/console/Command/Command.php new file mode 100644 index 000000000..3ede6ca6b --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/Command.php @@ -0,0 +1,725 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Exception\ExceptionInterface; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Helper\HelperInterface; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Base class for all commands. + * + * @author Fabien Potencier + */ +class Command +{ + // see https://tldp.org/LDP/abs/html/exitcodes.html + public const SUCCESS = 0; + public const FAILURE = 1; + public const INVALID = 2; + + /** + * @var string|null The default command name + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead + */ + protected static $defaultName; + + /** + * @var string|null The default command description + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead + */ + protected static $defaultDescription; + + private ?Application $application = null; + private ?string $name = null; + private ?string $processTitle = null; + private array $aliases = []; + private InputDefinition $definition; + private bool $hidden = false; + private string $help = ''; + private string $description = ''; + private ?InputDefinition $fullDefinition = null; + private bool $ignoreValidationErrors = false; + private ?\Closure $code = null; + private array $synopsis = []; + private array $usages = []; + private ?HelperSet $helperSet = null; + + public static function getDefaultName(): ?string + { + $class = static::class; + + if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { + return $attribute[0]->newInstance()->name; + } + + $r = new \ReflectionProperty($class, 'defaultName'); + + if ($class !== $r->class || null === static::$defaultName) { + return null; + } + + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + + return static::$defaultName; + } + + public static function getDefaultDescription(): ?string + { + $class = static::class; + + if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { + return $attribute[0]->newInstance()->description; + } + + $r = new \ReflectionProperty($class, 'defaultDescription'); + + if ($class !== $r->class || null === static::$defaultDescription) { + return null; + } + + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + + return static::$defaultDescription; + } + + /** + * @param string|null $name The name of the command; passing null means it must be set in configure() + * + * @throws LogicException When the command name is empty + */ + public function __construct(?string $name = null) + { + $this->definition = new InputDefinition(); + + if (null === $name && null !== $name = static::getDefaultName()) { + $aliases = explode('|', $name); + + if ('' === $name = array_shift($aliases)) { + $this->setHidden(true); + $name = array_shift($aliases); + } + + $this->setAliases($aliases); + } + + if (null !== $name) { + $this->setName($name); + } + + if ('' === $this->description) { + $this->setDescription(static::getDefaultDescription() ?? ''); + } + + $this->configure(); + } + + /** + * Ignores validation errors. + * + * This is mainly useful for the help command. + * + * @return void + */ + public function ignoreValidationErrors() + { + $this->ignoreValidationErrors = true; + } + + /** + * @return void + */ + public function setApplication(?Application $application = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->application = $application; + if ($application) { + $this->setHelperSet($application->getHelperSet()); + } else { + $this->helperSet = null; + } + + $this->fullDefinition = null; + } + + /** + * @return void + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set. + */ + public function getHelperSet(): ?HelperSet + { + return $this->helperSet; + } + + /** + * Gets the application instance for this command. + */ + public function getApplication(): ?Application + { + return $this->application; + } + + /** + * Checks whether the command is enabled or not in the current environment. + * + * Override this to check for x or y and return false if the command cannot + * run properly under the current conditions. + * + * @return bool + */ + public function isEnabled() + { + return true; + } + + /** + * Configures the current command. + * + * @return void + */ + protected function configure() + { + } + + /** + * Executes the current command. + * + * This method is not abstract because you can use this class + * as a concrete class. In this case, instead of defining the + * execute() method, you set the code to execute by passing + * a Closure to the setCode() method. + * + * @return int 0 if everything went fine, or an exit code + * + * @throws LogicException When this abstract method is not implemented + * + * @see setCode() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new LogicException('You must override the execute() method in the concrete command class.'); + } + + /** + * Interacts with the user. + * + * This method is executed before the InputDefinition is validated. + * This means that this is the only place where the command can + * interactively ask for values of missing required arguments. + * + * @return void + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + + /** + * Initializes the command after the input has been bound and before the input + * is validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @see InputInterface::bind() + * @see InputInterface::validate() + * + * @return void + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + + /** + * Runs the command. + * + * The code to execute is either defined directly with the + * setCode() method or by overriding the execute() method + * in a sub-class. + * + * @return int The command exit code + * + * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}. + * + * @see setCode() + * @see execute() + */ + public function run(InputInterface $input, OutputInterface $output): int + { + // add the application arguments and options + $this->mergeApplicationDefinition(); + + // bind the input against the command specific arguments/options + try { + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + if (!$this->ignoreValidationErrors) { + throw $e; + } + } + + $this->initialize($input, $output); + + if (null !== $this->processTitle) { + if (\function_exists('cli_set_process_title')) { + if (!@cli_set_process_title($this->processTitle)) { + if ('Darwin' === \PHP_OS) { + $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE); + } else { + cli_set_process_title($this->processTitle); + } + } + } elseif (\function_exists('setproctitle')) { + setproctitle($this->processTitle); + } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Install the proctitle PECL to be able to change the process title.'); + } + } + + if ($input->isInteractive()) { + $this->interact($input, $output); + } + + // The command name argument is often omitted when a command is executed directly with its run() method. + // It would fail the validation if we didn't make sure the command argument is present, + // since it's required by the application. + if ($input->hasArgument('command') && null === $input->getArgument('command')) { + $input->setArgument('command', $this->getName()); + } + + $input->validate(); + + if ($this->code) { + $statusCode = ($this->code)($input, $output); + } else { + $statusCode = $this->execute($input, $output); + + if (!\is_int($statusCode)) { + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); + } + } + + return is_numeric($statusCode) ? (int) $statusCode : 0; + } + + /** + * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $definition = $this->getDefinition(); + if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) { + $definition->getOption($input->getCompletionName())->complete($input, $suggestions); + } elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) { + $definition->getArgument($input->getCompletionName())->complete($input, $suggestions); + } + } + + /** + * Sets the code to execute when running this command. + * + * If this method is used, it overrides the code defined + * in the execute() method. + * + * @param callable $code A callable(InputInterface $input, OutputInterface $output) + * + * @return $this + * + * @throws InvalidArgumentException + * + * @see execute() + */ + public function setCode(callable $code): static + { + if ($code instanceof \Closure) { + $r = new \ReflectionFunction($code); + if (null === $r->getClosureThis()) { + set_error_handler(static function () {}); + try { + if ($c = \Closure::bind($code, $this)) { + $code = $c; + } + } finally { + restore_error_handler(); + } + } + } else { + $code = $code(...); + } + + $this->code = $code; + + return $this; + } + + /** + * Merges the application definition with the command definition. + * + * This method is not part of public API and should not be used directly. + * + * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments + * + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = true): void + { + if (null === $this->application) { + return; + } + + $this->fullDefinition = new InputDefinition(); + $this->fullDefinition->setOptions($this->definition->getOptions()); + $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions()); + + if ($mergeArgs) { + $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments()); + $this->fullDefinition->addArguments($this->definition->getArguments()); + } else { + $this->fullDefinition->setArguments($this->definition->getArguments()); + } + } + + /** + * Sets an array of argument and option instances. + * + * @return $this + */ + public function setDefinition(array|InputDefinition $definition): static + { + if ($definition instanceof InputDefinition) { + $this->definition = $definition; + } else { + $this->definition->setDefinition($definition); + } + + $this->fullDefinition = null; + + return $this; + } + + /** + * Gets the InputDefinition attached to this Command. + */ + public function getDefinition(): InputDefinition + { + return $this->fullDefinition ?? $this->getNativeDefinition(); + } + + /** + * Gets the InputDefinition to be used to create representations of this Command. + * + * Can be overridden to provide the original command representation when it would otherwise + * be changed by merging with the application InputDefinition. + * + * This method is not part of public API and should not be used directly. + */ + public function getNativeDefinition(): InputDefinition + { + return $this->definition ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + } + + /** + * Adds an argument. + * + * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param $default The default value (for InputArgument::OPTIONAL mode only) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @return $this + * + * @throws InvalidArgumentException When argument mode is not valid + */ + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static + { + $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; + if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + } + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); + $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); + + return $this; + } + + /** + * Adds an option. + * + * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param $mode The option mode: One of the InputOption::VALUE_* constants + * @param $default The default value (must be null for InputOption::VALUE_NONE) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @return $this + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + */ + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + { + $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; + if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + } + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); + $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); + + return $this; + } + + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @return $this + * + * @throws InvalidArgumentException When the name is invalid + */ + public function setName(string $name): static + { + $this->validateName($name); + + $this->name = $name; + + return $this; + } + + /** + * Sets the process title of the command. + * + * This feature should be used only when creating a long process command, + * like a daemon. + * + * @return $this + */ + public function setProcessTitle(string $title): static + { + $this->processTitle = $title; + + return $this; + } + + /** + * Returns the command name. + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * @param bool $hidden Whether or not the command should be hidden from the list of commands + * + * @return $this + */ + public function setHidden(bool $hidden = true): static + { + $this->hidden = $hidden; + + return $this; + } + + /** + * @return bool whether the command should be publicly shown or not + */ + public function isHidden(): bool + { + return $this->hidden; + } + + /** + * Sets the description for the command. + * + * @return $this + */ + public function setDescription(string $description): static + { + $this->description = $description; + + return $this; + } + + /** + * Returns the description for the command. + */ + public function getDescription(): string + { + return $this->description; + } + + /** + * Sets the help for the command. + * + * @return $this + */ + public function setHelp(string $help): static + { + $this->help = $help; + + return $this; + } + + /** + * Returns the help for the command. + */ + public function getHelp(): string + { + return $this->help; + } + + /** + * Returns the processed help for the command replacing the %command.name% and + * %command.full_name% patterns with the real values dynamically. + */ + public function getProcessedHelp(): string + { + $name = $this->name; + $isSingleCommand = $this->application?->isSingleCommand(); + + $placeholders = [ + '%command.name%', + '%command.full_name%', + ]; + $replacements = [ + $name, + $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name, + ]; + + return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription()); + } + + /** + * Sets the aliases for the command. + * + * @param string[] $aliases An array of aliases for the command + * + * @return $this + * + * @throws InvalidArgumentException When an alias is invalid + */ + public function setAliases(iterable $aliases): static + { + $list = []; + + foreach ($aliases as $alias) { + $this->validateName($alias); + $list[] = $alias; + } + + $this->aliases = \is_array($aliases) ? $aliases : $list; + + return $this; + } + + /** + * Returns the aliases for the command. + */ + public function getAliases(): array + { + return $this->aliases; + } + + /** + * Returns the synopsis for the command. + * + * @param bool $short Whether to show the short version of the synopsis (with options folded) or not + */ + public function getSynopsis(bool $short = false): string + { + $key = $short ? 'short' : 'long'; + + if (!isset($this->synopsis[$key])) { + $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + } + + return $this->synopsis[$key]; + } + + /** + * Add a command usage example, it'll be prefixed with the command name. + * + * @return $this + */ + public function addUsage(string $usage): static + { + if (!str_starts_with($usage, $this->name)) { + $usage = \sprintf('%s %s', $this->name, $usage); + } + + $this->usages[] = $usage; + + return $this; + } + + /** + * Returns alternative usages of the command. + */ + public function getUsages(): array + { + return $this->usages; + } + + /** + * Gets a helper instance by name. + * + * @return HelperInterface + * + * @throws LogicException if no HelperSet is defined + * @throws InvalidArgumentException if the helper is not defined + */ + public function getHelper(string $name): mixed + { + if (null === $this->helperSet) { + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + } + + return $this->helperSet->get($name); + } + + /** + * Validates a command name. + * + * It must be non-empty and parts can optionally be separated by ":". + * + * @throws InvalidArgumentException When the name is invalid + */ + private function validateName(string $name): void + { + if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/CompleteCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/CompleteCommand.php new file mode 100644 index 000000000..33f7f93c8 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/CompleteCommand.php @@ -0,0 +1,223 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Output\BashCompletionOutput; +use Symfony\Component\Console\Completion\Output\CompletionOutputInterface; +use Symfony\Component\Console\Completion\Output\FishCompletionOutput; +use Symfony\Component\Console\Completion\Output\ZshCompletionOutput; +use Symfony\Component\Console\Exception\CommandNotFoundException; +use Symfony\Component\Console\Exception\ExceptionInterface; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Responsible for providing the values to the shell completion. + * + * @author Wouter de Jong + */ +#[AsCommand(name: '|_complete', description: 'Internal command to provide shell completion suggestions')] +final class CompleteCommand extends Command +{ + public const COMPLETION_API_VERSION = '1'; + + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultName = '|_complete'; + + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; + + private array $completionOutputs; + + private bool $isDebug = false; + + /** + * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value + */ + public function __construct(array $completionOutputs = []) + { + // must be set before the parent constructor, as the property value is used in configure() + $this->completionOutputs = $completionOutputs + [ + 'bash' => BashCompletionOutput::class, + 'fish' => FishCompletionOutput::class, + 'zsh' => ZshCompletionOutput::class, + ]; + + parent::__construct(); + } + + protected function configure(): void + { + $this + ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")') + ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)') + ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)') + ->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script') + ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated') + ; + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + try { + // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 + $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); + if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) { + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); + $this->log($message); + + $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); + + return 126; + } + + $shell = $input->getOption('shell'); + if (!$shell) { + throw new \RuntimeException('The "--shell" option must be set.'); + } + + if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); + } + + $completionInput = $this->createCompletionInput($input); + $suggestions = new CompletionSuggestions(); + + $this->log([ + '', + ''.date('Y-m-d H:i:s').'', + 'Input: ("|" indicates the cursor position)', + ' '.(string) $completionInput, + 'Command:', + ' '.(string) implode(' ', $_SERVER['argv']), + 'Messages:', + ]); + + $command = $this->findCommand($completionInput, $output); + if (null === $command) { + $this->log(' No command found, completing using the Application class.'); + + $this->getApplication()->complete($completionInput, $suggestions); + } elseif ( + $completionInput->mustSuggestArgumentValuesFor('command') + && $command->getName() !== $completionInput->getCompletionValue() + && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true) + ) { + $this->log(' No command found, completing using the Application class.'); + + // expand shortcut names ("cache:cl") into their full name ("cache:clear") + $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases()))); + } else { + $command->mergeApplicationDefinition(); + $completionInput->bind($command->getDefinition()); + + if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { + $this->log(' Completing option names for the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' command.'); + + $suggestions->suggestOptions($command->getDefinition()->getOptions()); + } else { + $this->log([ + ' Completing using the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' class.', + ' Completing '.$completionInput->getCompletionType().' for '.$completionInput->getCompletionName().'', + ]); + if (null !== $compval = $completionInput->getCompletionValue()) { + $this->log(' Current value: '.$compval.''); + } + + $command->complete($completionInput, $suggestions); + } + } + + /** @var CompletionOutputInterface $completionOutput */ + $completionOutput = new $completionOutput(); + + $this->log('Suggestions:'); + if ($options = $suggestions->getOptionSuggestions()) { + $this->log(' --'.implode(' --', array_map(fn ($o) => $o->getName(), $options))); + } elseif ($values = $suggestions->getValueSuggestions()) { + $this->log(' '.implode(' ', $values)); + } else { + $this->log(' No suggestions were provided'); + } + + $completionOutput->write($suggestions, $output); + } catch (\Throwable $e) { + $this->log([ + 'Error!', + (string) $e, + ]); + + if ($output->isDebug()) { + throw $e; + } + + return 2; + } + + return 0; + } + + private function createCompletionInput(InputInterface $input): CompletionInput + { + $currentIndex = $input->getOption('current'); + if (!$currentIndex || !ctype_digit($currentIndex)) { + throw new \RuntimeException('The "--current" option must be set and it must be an integer.'); + } + + $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex); + + try { + $completionInput->bind($this->getApplication()->getDefinition()); + } catch (ExceptionInterface) { + } + + return $completionInput; + } + + private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command + { + try { + $inputName = $completionInput->getFirstArgument(); + if (null === $inputName) { + return null; + } + + return $this->getApplication()->find($inputName); + } catch (CommandNotFoundException) { + } + + return null; + } + + private function log($messages): void + { + if (!$this->isDebug) { + return; + } + + $commandName = basename($_SERVER['argv'][0]); + file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\PHP_EOL, (array) $messages).\PHP_EOL, \FILE_APPEND); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/DumpCompletionCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/DumpCompletionCommand.php new file mode 100644 index 000000000..571425b88 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/DumpCompletionCommand.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Process\Process; + +/** + * Dumps the completion script for the current shell. + * + * @author Wouter de Jong + */ +#[AsCommand(name: 'completion', description: 'Dump the shell completion script')] +final class DumpCompletionCommand extends Command +{ + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultName = 'completion'; + + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultDescription = 'Dump the shell completion script'; + + private array $supportedShells; + + protected function configure(): void + { + $fullCommand = $_SERVER['PHP_SELF']; + $commandName = basename($fullCommand); + $fullCommand = @realpath($fullCommand) ?: $fullCommand; + + $shell = $this->guessShell(); + [$rcFile, $completionFile] = match ($shell) { + 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], + 'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName], + default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"], + }; + + $supportedShells = implode(', ', $this->getSupportedShells()); + + $this + ->setHelp(<<%command.name% command dumps the shell completion script required +to use shell autocompletion (currently, {$supportedShells} completion are supported). + +Static installation +------------------- + +Dump the script to a global completion file and restart your shell: + + %command.full_name% {$shell} | sudo tee {$completionFile} + +Or dump the script to a local file and source it: + + %command.full_name% {$shell} > completion.sh + + # source the file whenever you use the project + source completion.sh + + # or add this line at the end of your "{$rcFile}" file: + source /path/to/completion.sh + +Dynamic installation +-------------------- + +Add this to the end of your shell configuration file (e.g. "{$rcFile}"): + + eval "$({$fullCommand} completion {$shell})" +EOH + ) + ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, $this->getSupportedShells(...)) + ->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $commandName = basename($_SERVER['argv'][0]); + + if ($input->getOption('debug')) { + $this->tailDebugLog($commandName, $output); + + return 0; + } + + $shell = $input->getArgument('shell') ?? self::guessShell(); + $completionFile = __DIR__.'/../Resources/completion.'.$shell; + if (!file_exists($completionFile)) { + $supportedShells = $this->getSupportedShells(); + + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + if ($shell) { + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); + } else { + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); + } + + return 2; + } + + $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], file_get_contents($completionFile))); + + return 0; + } + + private static function guessShell(): string + { + return basename($_SERVER['SHELL'] ?? ''); + } + + private function tailDebugLog(string $commandName, OutputInterface $output): void + { + $debugFile = sys_get_temp_dir().'/sf_'.$commandName.'.log'; + if (!file_exists($debugFile)) { + touch($debugFile); + } + $process = new Process(['tail', '-f', $debugFile], null, null, null, 0); + $process->run(function (string $type, string $line) use ($output): void { + $output->write($line); + }); + } + + /** + * @return string[] + */ + private function getSupportedShells(): array + { + if (isset($this->supportedShells)) { + return $this->supportedShells; + } + + $shells = []; + + foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) { + if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) { + $shells[] = $file->getExtension(); + } + } + sort($shells); + + return $this->supportedShells = $shells; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/HelpCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/HelpCommand.php new file mode 100644 index 000000000..e6447b050 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/HelpCommand.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Descriptor\ApplicationDescription; +use Symfony\Component\Console\Helper\DescriptorHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * HelpCommand displays the help for a given command. + * + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + private Command $command; + + /** + * @return void + */ + protected function configure() + { + $this->ignoreValidationErrors(); + + $this + ->setName('help') + ->setDefinition([ + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), + new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), + ]) + ->setDescription('Display help for a command') + ->setHelp(<<<'EOF' +The %command.name% command displays help for a given command: + + %command.full_name% list + +You can also output the help in other formats by using the --format option: + + %command.full_name% --format=xml list + +To display the list of available commands, please use the list command. +EOF + ) + ; + } + + /** + * @return void + */ + public function setCommand(Command $command) + { + $this->command = $command; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->command ??= $this->getApplication()->find($input->getArgument('command_name')); + + $helper = new DescriptorHelper(); + $helper->describe($output, $this->command, [ + 'format' => $input->getOption('format'), + 'raw_text' => $input->getOption('raw'), + ]); + + unset($this->command); + + return 0; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/LazyCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/LazyCommand.php new file mode 100644 index 000000000..b94da6665 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/LazyCommand.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Helper\HelperInterface; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Nicolas Grekas + */ +final class LazyCommand extends Command +{ + private \Closure|Command $command; + private ?bool $isEnabled; + + public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true) + { + $this->setName($name) + ->setAliases($aliases) + ->setHidden($isHidden) + ->setDescription($description); + + $this->command = $commandFactory; + $this->isEnabled = $isEnabled; + } + + public function ignoreValidationErrors(): void + { + $this->getCommand()->ignoreValidationErrors(); + } + + public function setApplication(?Application $application = null): void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->command instanceof parent) { + $this->command->setApplication($application); + } + + parent::setApplication($application); + } + + public function setHelperSet(HelperSet $helperSet): void + { + if ($this->command instanceof parent) { + $this->command->setHelperSet($helperSet); + } + + parent::setHelperSet($helperSet); + } + + public function isEnabled(): bool + { + return $this->isEnabled ?? $this->getCommand()->isEnabled(); + } + + public function run(InputInterface $input, OutputInterface $output): int + { + return $this->getCommand()->run($input, $output); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $this->getCommand()->complete($input, $suggestions); + } + + public function setCode(callable $code): static + { + $this->getCommand()->setCode($code); + + return $this; + } + + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = true): void + { + $this->getCommand()->mergeApplicationDefinition($mergeArgs); + } + + public function setDefinition(array|InputDefinition $definition): static + { + $this->getCommand()->setDefinition($definition); + + return $this; + } + + public function getDefinition(): InputDefinition + { + return $this->getCommand()->getDefinition(); + } + + public function getNativeDefinition(): InputDefinition + { + return $this->getCommand()->getNativeDefinition(); + } + + /** + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + */ + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + { + $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; + $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); + + return $this; + } + + /** + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + */ + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + { + $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; + $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + + return $this; + } + + public function setProcessTitle(string $title): static + { + $this->getCommand()->setProcessTitle($title); + + return $this; + } + + public function setHelp(string $help): static + { + $this->getCommand()->setHelp($help); + + return $this; + } + + public function getHelp(): string + { + return $this->getCommand()->getHelp(); + } + + public function getProcessedHelp(): string + { + return $this->getCommand()->getProcessedHelp(); + } + + public function getSynopsis(bool $short = false): string + { + return $this->getCommand()->getSynopsis($short); + } + + public function addUsage(string $usage): static + { + $this->getCommand()->addUsage($usage); + + return $this; + } + + public function getUsages(): array + { + return $this->getCommand()->getUsages(); + } + + public function getHelper(string $name): HelperInterface + { + return $this->getCommand()->getHelper($name); + } + + public function getCommand(): parent + { + if (!$this->command instanceof \Closure) { + return $this->command; + } + + $command = $this->command = ($this->command)(); + $command->setApplication($this->getApplication()); + + if (null !== $this->getHelperSet()) { + $command->setHelperSet($this->getHelperSet()); + } + + $command->setName($this->getName()) + ->setAliases($this->getAliases()) + ->setHidden($this->isHidden()) + ->setDescription($this->getDescription()); + + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + + return $command; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/ListCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/ListCommand.php new file mode 100644 index 000000000..5850c3d7b --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/ListCommand.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Descriptor\ApplicationDescription; +use Symfony\Component\Console\Helper\DescriptorHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * ListCommand displays the list of all available commands for the application. + * + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * @return void + */ + protected function configure() + { + $this + ->setName('list') + ->setDefinition([ + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())), + new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), + new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'), + ]) + ->setDescription('List commands') + ->setHelp(<<<'EOF' +The %command.name% command lists all commands: + + %command.full_name% + +You can also display the commands for a specific namespace: + + %command.full_name% test + +You can also output the information in other formats by using the --format option: + + %command.full_name% --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + %command.full_name% --raw +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $helper = new DescriptorHelper(); + $helper->describe($output, $this->getApplication(), [ + 'format' => $input->getOption('format'), + 'raw_text' => $input->getOption('raw'), + 'namespace' => $input->getArgument('namespace'), + 'short' => $input->getOption('short'), + ]); + + return 0; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/LockableTrait.php b/lam/lib/3rdParty/composer/symfony/console/Command/LockableTrait.php new file mode 100644 index 000000000..cd7548f02 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/LockableTrait.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Lock\LockFactory; +use Symfony\Component\Lock\LockInterface; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\SemaphoreStore; + +/** + * Basic lock feature for commands. + * + * @author Geoffrey Brier + */ +trait LockableTrait +{ + private ?LockInterface $lock = null; + + /** + * Locks a command. + */ + private function lock(?string $name = null, bool $blocking = false): bool + { + if (!class_exists(SemaphoreStore::class)) { + throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); + } + + if (null !== $this->lock) { + throw new LogicException('A lock is already in place.'); + } + + if (SemaphoreStore::isSupported()) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(); + } + + $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); + if (!$this->lock->acquire($blocking)) { + $this->lock = null; + + return false; + } + + return true; + } + + /** + * Releases the command lock if there is one. + */ + private function release(): void + { + if ($this->lock) { + $this->lock->release(); + $this->lock = null; + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/SignalableCommandInterface.php b/lam/lib/3rdParty/composer/symfony/console/Command/SignalableCommandInterface.php new file mode 100644 index 000000000..74d59b086 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/SignalableCommandInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +/** + * Interface for command reacting to signal. + * + * @author Grégoire Pineau + */ +interface SignalableCommandInterface +{ + /** + * Returns the list of signals to subscribe. + */ + public function getSubscribedSignals(): array; + + /** + * The method will be called when the application is signaled. + * + * @param int|false $previousExitCode + * + * @return int|false The exit code to return or false to continue the normal execution + */ + public function handleSignal(int $signal/* , int|false $previousExitCode = 0 */); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Command/TraceableCommand.php b/lam/lib/3rdParty/composer/symfony/console/Command/TraceableCommand.php new file mode 100644 index 000000000..9df467b0d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Command/TraceableCommand.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Helper\HelperInterface; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @internal + * + * @author Jules Pietri + */ +final class TraceableCommand extends Command implements SignalableCommandInterface +{ + public readonly Command $command; + public int $exitCode; + public ?int $interruptedBySignal = null; + public bool $ignoreValidation; + public bool $isInteractive = false; + public string $duration = 'n/a'; + public string $maxMemoryUsage = 'n/a'; + public InputInterface $input; + public OutputInterface $output; + /** @var array */ + public array $arguments; + /** @var array */ + public array $options; + /** @var array */ + public array $interactiveInputs = []; + public array $handledSignals = []; + + public function __construct( + Command $command, + private readonly Stopwatch $stopwatch, + ) { + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + + $this->command = $command; + + // prevent call to self::getDefaultDescription() + $this->setDescription($command->getDescription()); + + parent::__construct($command->getName()); + + // init below enables calling {@see parent::run()} + [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () { + return [$this->code, $this->processTitle, $this->ignoreValidationErrors]; + }, $command, Command::class)(); + + if (\is_callable($code)) { + $this->setCode($code); + } + + if ($processTitle) { + parent::setProcessTitle($processTitle); + } + + if ($ignoreValidationErrors) { + parent::ignoreValidationErrors(); + } + + $this->ignoreValidation = $ignoreValidationErrors; + } + + public function __call(string $name, array $arguments): mixed + { + return $this->command->{$name}(...$arguments); + } + + public function getSubscribedSignals(): array + { + return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : []; + } + + public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false + { + if (!$this->command instanceof SignalableCommandInterface) { + return false; + } + + $event = $this->stopwatch->start($this->getName().'.handle_signal'); + + $exit = $this->command->handleSignal($signal, $previousExitCode); + + $event->stop(); + + if (!isset($this->handledSignals[$signal])) { + $this->handledSignals[$signal] = [ + 'handled' => 0, + 'duration' => 0, + 'memory' => 0, + ]; + } + + ++$this->handledSignals[$signal]['handled']; + $this->handledSignals[$signal]['duration'] += $event->getDuration(); + $this->handledSignals[$signal]['memory'] = max( + $this->handledSignals[$signal]['memory'], + $event->getMemory() >> 20 + ); + + return $exit; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function ignoreValidationErrors(): void + { + $this->ignoreValidation = true; + $this->command->ignoreValidationErrors(); + + parent::ignoreValidationErrors(); + } + + public function setApplication(?Application $application = null): void + { + $this->command->setApplication($application); + } + + public function getApplication(): ?Application + { + return $this->command->getApplication(); + } + + public function setHelperSet(HelperSet $helperSet): void + { + $this->command->setHelperSet($helperSet); + } + + public function getHelperSet(): ?HelperSet + { + return $this->command->getHelperSet(); + } + + public function isEnabled(): bool + { + return $this->command->isEnabled(); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $this->command->complete($input, $suggestions); + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setCode(callable $code): static + { + $this->command->setCode($code); + + return parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int { + $event = $this->stopwatch->start($this->getName().'.code'); + + $this->exitCode = $code($input, $output); + + $event->stop(); + + return $this->exitCode; + }); + } + + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = true): void + { + $this->command->mergeApplicationDefinition($mergeArgs); + } + + public function setDefinition(array|InputDefinition $definition): static + { + $this->command->setDefinition($definition); + + return $this; + } + + public function getDefinition(): InputDefinition + { + return $this->command->getDefinition(); + } + + public function getNativeDefinition(): InputDefinition + { + return $this->command->getNativeDefinition(); + } + + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addArgument($name, $mode, $description, $default, $suggestedValues); + + return $this; + } + + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + + return $this; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setProcessTitle(string $title): static + { + $this->command->setProcessTitle($title); + + return parent::setProcessTitle($title); + } + + public function setHelp(string $help): static + { + $this->command->setHelp($help); + + return $this; + } + + public function getHelp(): string + { + return $this->command->getHelp(); + } + + public function getProcessedHelp(): string + { + return $this->command->getProcessedHelp(); + } + + public function getSynopsis(bool $short = false): string + { + return $this->command->getSynopsis($short); + } + + public function addUsage(string $usage): static + { + $this->command->addUsage($usage); + + return $this; + } + + public function getUsages(): array + { + return $this->command->getUsages(); + } + + public function getHelper(string $name): HelperInterface + { + return $this->command->getHelper($name); + } + + public function run(InputInterface $input, OutputInterface $output): int + { + $this->input = $input; + $this->output = $output; + $this->arguments = $input->getArguments(); + $this->options = $input->getOptions(); + $event = $this->stopwatch->start($this->getName(), 'command'); + + try { + $this->exitCode = $this->command->run($input, $output); + } finally { + $event->stop(); + + if ($output instanceof ConsoleOutputInterface && $output->isDebug()) { + $output->getErrorOutput()->writeln((string) $event); + } + + $this->duration = $event->getDuration().' ms'; + $this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB'; + + if ($this->isInteractive) { + $this->extractInteractiveInputs($input->getArguments(), $input->getOptions()); + } + } + + return $this->exitCode; + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + $event = $this->stopwatch->start($this->getName().'.init', 'command'); + + $this->command->initialize($input, $output); + + $event->stop(); + } + + protected function interact(InputInterface $input, OutputInterface $output): void + { + if (!$this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) { + return; + } + + $event = $this->stopwatch->start($this->getName().'.interact', 'command'); + + $this->command->interact($input, $output); + + $event->stop(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $event = $this->stopwatch->start($this->getName().'.execute', 'command'); + + $exitCode = $this->command->execute($input, $output); + + $event->stop(); + + return $exitCode; + } + + private function extractInteractiveInputs(array $arguments, array $options): void + { + foreach ($arguments as $argName => $argValue) { + if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) { + continue; + } + + $this->interactiveInputs[$argName] = $argValue; + } + + foreach ($options as $optName => $optValue) { + if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) { + continue; + } + + $this->interactiveInputs['--'.$optName] = $optValue; + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/CommandLoader/CommandLoaderInterface.php b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/CommandLoaderInterface.php new file mode 100644 index 000000000..b6b637ce6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/CommandLoaderInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CommandLoader; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * @author Robin Chalas + */ +interface CommandLoaderInterface +{ + /** + * Loads a command. + * + * @throws CommandNotFoundException + */ + public function get(string $name): Command; + + /** + * Checks if a command exists. + */ + public function has(string $name): bool; + + /** + * @return string[] + */ + public function getNames(): array; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/CommandLoader/ContainerCommandLoader.php b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/ContainerCommandLoader.php new file mode 100644 index 000000000..1638f2fd0 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CommandLoader; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * Loads commands from a PSR-11 container. + * + * @author Robin Chalas + */ +class ContainerCommandLoader implements CommandLoaderInterface +{ + private ContainerInterface $container; + private array $commandMap; + + /** + * @param array $commandMap An array with command names as keys and service ids as values + */ + public function __construct(ContainerInterface $container, array $commandMap) + { + $this->container = $container; + $this->commandMap = $commandMap; + } + + public function get(string $name): Command + { + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + + return $this->container->get($this->commandMap[$name]); + } + + public function has(string $name): bool + { + return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); + } + + public function getNames(): array + { + return array_keys($this->commandMap); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/CommandLoader/FactoryCommandLoader.php b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/FactoryCommandLoader.php new file mode 100644 index 000000000..ffe1b520c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CommandLoader; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * A simple command loader using factories to instantiate commands lazily. + * + * @author Maxime Steinhausser + */ +class FactoryCommandLoader implements CommandLoaderInterface +{ + private array $factories; + + /** + * @param callable[] $factories Indexed by command names + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + public function has(string $name): bool + { + return isset($this->factories[$name]); + } + + public function get(string $name): Command + { + if (!isset($this->factories[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + + $factory = $this->factories[$name]; + + return $factory(); + } + + public function getNames(): array + { + return array_keys($this->factories); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionInput.php b/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionInput.php new file mode 100644 index 000000000..79c2f659a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionInput.php @@ -0,0 +1,248 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion; + +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * An input specialized for shell completion. + * + * This input allows unfinished option names or values and exposes what kind of + * completion is expected. + * + * @author Wouter de Jong + */ +final class CompletionInput extends ArgvInput +{ + public const TYPE_ARGUMENT_VALUE = 'argument_value'; + public const TYPE_OPTION_VALUE = 'option_value'; + public const TYPE_OPTION_NAME = 'option_name'; + public const TYPE_NONE = 'none'; + + private array $tokens; + private int $currentIndex; + private string $completionType; + private ?string $completionName = null; + private string $completionValue = ''; + + /** + * Converts a terminal string into tokens. + * + * This is required for shell completions without COMP_WORDS support. + */ + public static function fromString(string $inputStr, int $currentIndex): self + { + preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?tokens = $tokens; + $input->currentIndex = $currentIndex; + + return $input; + } + + public function bind(InputDefinition $definition): void + { + parent::bind($definition); + + $relevantToken = $this->getRelevantToken(); + if ('-' === $relevantToken[0]) { + // the current token is an input option: complete either option name or option value + [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', '']; + + $option = $this->getOptionFromToken($optionToken); + if (null === $option && !$this->isCursorFree()) { + $this->completionType = self::TYPE_OPTION_NAME; + $this->completionValue = $relevantToken; + + return; + } + + if ($option?->acceptValue()) { + $this->completionType = self::TYPE_OPTION_VALUE; + $this->completionName = $option->getName(); + $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : ''); + + return; + } + } + + $previousToken = $this->tokens[$this->currentIndex - 1]; + if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) { + // check if previous option accepted a value + $previousOption = $this->getOptionFromToken($previousToken); + if ($previousOption?->acceptValue()) { + $this->completionType = self::TYPE_OPTION_VALUE; + $this->completionName = $previousOption->getName(); + $this->completionValue = $relevantToken; + + return; + } + } + + // complete argument value + $this->completionType = self::TYPE_ARGUMENT_VALUE; + + foreach ($this->definition->getArguments() as $argumentName => $argument) { + if (!isset($this->arguments[$argumentName])) { + break; + } + + $argumentValue = $this->arguments[$argumentName]; + $this->completionName = $argumentName; + if (\is_array($argumentValue)) { + $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null; + } else { + $this->completionValue = $argumentValue; + } + } + + if ($this->currentIndex >= \count($this->tokens)) { + if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { + $this->completionName = $argumentName; + $this->completionValue = ''; + } else { + // we've reached the end + $this->completionType = self::TYPE_NONE; + $this->completionName = null; + $this->completionValue = ''; + } + } + } + + /** + * Returns the type of completion required. + * + * TYPE_ARGUMENT_VALUE when completing the value of an input argument + * TYPE_OPTION_VALUE when completing the value of an input option + * TYPE_OPTION_NAME when completing the name of an input option + * TYPE_NONE when nothing should be completed + * + * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component. + * + * @return self::TYPE_* + */ + public function getCompletionType(): string + { + return $this->completionType; + } + + /** + * The name of the input option or argument when completing a value. + * + * @return string|null returns null when completing an option name + */ + public function getCompletionName(): ?string + { + return $this->completionName; + } + + /** + * The value already typed by the user (or empty string). + */ + public function getCompletionValue(): string + { + return $this->completionValue; + } + + public function mustSuggestOptionValuesFor(string $optionName): bool + { + return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName(); + } + + public function mustSuggestArgumentValuesFor(string $argumentName): bool + { + return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName(); + } + + protected function parseToken(string $token, bool $parseOptions): bool + { + try { + return parent::parseToken($token, $parseOptions); + } catch (RuntimeException) { + // suppress errors, completed input is almost never valid + } + + return $parseOptions; + } + + private function getOptionFromToken(string $optionToken): ?InputOption + { + $optionName = ltrim($optionToken, '-'); + if (!$optionName) { + return null; + } + + if ('-' === ($optionToken[1] ?? ' ')) { + // long option name + return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null; + } + + // short option name + return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null; + } + + /** + * The token of the cursor, or the last token if the cursor is at the end of the input. + */ + private function getRelevantToken(): string + { + return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex]; + } + + /** + * Whether the cursor is "free" (i.e. at the end of the input preceded by a space). + */ + private function isCursorFree(): bool + { + $nrOfTokens = \count($this->tokens); + if ($this->currentIndex > $nrOfTokens) { + throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.'); + } + + return $this->currentIndex >= $nrOfTokens; + } + + public function __toString() + { + $str = ''; + foreach ($this->tokens as $i => $token) { + $str .= $token; + + if ($this->currentIndex === $i) { + $str .= '|'; + } + + $str .= ' '; + } + + if ($this->currentIndex > $i) { + $str .= '|'; + } + + return rtrim($str); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionSuggestions.php b/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionSuggestions.php new file mode 100644 index 000000000..549bbafbd --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/CompletionSuggestions.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion; + +use Symfony\Component\Console\Input\InputOption; + +/** + * Stores all completion suggestions for the current input. + * + * @author Wouter de Jong + */ +final class CompletionSuggestions +{ + private array $valueSuggestions = []; + private array $optionSuggestions = []; + + /** + * Add a suggested value for an input option or argument. + * + * @return $this + */ + public function suggestValue(string|Suggestion $value): static + { + $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value; + + return $this; + } + + /** + * Add multiple suggested values at once for an input option or argument. + * + * @param list $values + * + * @return $this + */ + public function suggestValues(array $values): static + { + foreach ($values as $value) { + $this->suggestValue($value); + } + + return $this; + } + + /** + * Add a suggestion for an input option name. + * + * @return $this + */ + public function suggestOption(InputOption $option): static + { + $this->optionSuggestions[] = $option; + + return $this; + } + + /** + * Add multiple suggestions for input option names at once. + * + * @param InputOption[] $options + * + * @return $this + */ + public function suggestOptions(array $options): static + { + foreach ($options as $option) { + $this->suggestOption($option); + } + + return $this; + } + + /** + * @return InputOption[] + */ + public function getOptionSuggestions(): array + { + return $this->optionSuggestions; + } + + /** + * @return Suggestion[] + */ + public function getValueSuggestions(): array + { + return $this->valueSuggestions; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/Output/BashCompletionOutput.php b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/BashCompletionOutput.php new file mode 100644 index 000000000..c6f76eb8f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/BashCompletionOutput.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion\Output; + +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Wouter de Jong + */ +class BashCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output): void + { + $values = $suggestions->getValueSuggestions(); + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--'.$option->getName(); + if ($option->isNegatable()) { + $values[] = '--no-'.$option->getName(); + } + } + $output->writeln(implode("\n", $values)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/Output/CompletionOutputInterface.php b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/CompletionOutputInterface.php new file mode 100644 index 000000000..659e59655 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/CompletionOutputInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion\Output; + +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion. + * + * @author Wouter de Jong + */ +interface CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output): void; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/Output/FishCompletionOutput.php b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/FishCompletionOutput.php new file mode 100644 index 000000000..d2c414e48 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/FishCompletionOutput.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion\Output; + +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Guillaume Aveline + */ +class FishCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output): void + { + $values = $suggestions->getValueSuggestions(); + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--'.$option->getName(); + if ($option->isNegatable()) { + $values[] = '--no-'.$option->getName(); + } + } + $output->write(implode("\n", $values)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/Output/ZshCompletionOutput.php b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/ZshCompletionOutput.php new file mode 100644 index 000000000..bb4ce70b5 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/Output/ZshCompletionOutput.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion\Output; + +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Jitendra A + */ +class ZshCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output): void + { + $values = []; + foreach ($suggestions->getValueSuggestions() as $value) { + $values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : ''); + } + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); + if ($option->isNegatable()) { + $values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); + } + } + $output->write(implode("\n", $values)."\n"); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Completion/Suggestion.php b/lam/lib/3rdParty/composer/symfony/console/Completion/Suggestion.php new file mode 100644 index 000000000..3251b079f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Completion/Suggestion.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion; + +/** + * Represents a single suggested value. + * + * @author Wouter de Jong + */ +class Suggestion implements \Stringable +{ + public function __construct( + private readonly string $value, + private readonly string $description = '', + ) { + } + + public function getValue(): string + { + return $this->value; + } + + public function getDescription(): string + { + return $this->description; + } + + public function __toString(): string + { + return $this->getValue(); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/ConsoleEvents.php b/lam/lib/3rdParty/composer/symfony/console/ConsoleEvents.php new file mode 100644 index 000000000..6ae8f32b8 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/ConsoleEvents.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Event\ConsoleSignalEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; + +/** + * Contains all events dispatched by an Application. + * + * @author Francesco Levorato + */ +final class ConsoleEvents +{ + /** + * The COMMAND event allows you to attach listeners before any command is + * executed by the console. It also allows you to modify the command, input and output + * before they are handed to the command. + * + * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") + */ + public const COMMAND = 'console.command'; + + /** + * The SIGNAL event allows you to perform some actions + * after the command execution was interrupted. + * + * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent") + */ + public const SIGNAL = 'console.signal'; + + /** + * The TERMINATE event allows you to attach listeners after a command is + * executed by the console. + * + * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") + */ + public const TERMINATE = 'console.terminate'; + + /** + * The ERROR event occurs when an uncaught exception or error appears. + * + * This event allows you to deal with the exception/error or + * to modify the thrown exception. + * + * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") + */ + public const ERROR = 'console.error'; + + /** + * Event aliases. + * + * These aliases can be consumed by RegisterListenersPass. + */ + public const ALIASES = [ + ConsoleCommandEvent::class => self::COMMAND, + ConsoleErrorEvent::class => self::ERROR, + ConsoleSignalEvent::class => self::SIGNAL, + ConsoleTerminateEvent::class => self::TERMINATE, + ]; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Cursor.php b/lam/lib/3rdParty/composer/symfony/console/Cursor.php new file mode 100644 index 000000000..45243c796 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Cursor.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Pierre du Plessis + */ +final class Cursor +{ + private OutputInterface $output; + /** @var resource */ + private $input; + + /** + * @param resource|null $input + */ + public function __construct(OutputInterface $output, $input = null) + { + $this->output = $output; + $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+')); + } + + /** + * @return $this + */ + public function moveUp(int $lines = 1): static + { + $this->output->write(\sprintf("\x1b[%dA", $lines)); + + return $this; + } + + /** + * @return $this + */ + public function moveDown(int $lines = 1): static + { + $this->output->write(\sprintf("\x1b[%dB", $lines)); + + return $this; + } + + /** + * @return $this + */ + public function moveRight(int $columns = 1): static + { + $this->output->write(\sprintf("\x1b[%dC", $columns)); + + return $this; + } + + /** + * @return $this + */ + public function moveLeft(int $columns = 1): static + { + $this->output->write(\sprintf("\x1b[%dD", $columns)); + + return $this; + } + + /** + * @return $this + */ + public function moveToColumn(int $column): static + { + $this->output->write(\sprintf("\x1b[%dG", $column)); + + return $this; + } + + /** + * @return $this + */ + public function moveToPosition(int $column, int $row): static + { + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); + + return $this; + } + + /** + * @return $this + */ + public function savePosition(): static + { + $this->output->write("\x1b7"); + + return $this; + } + + /** + * @return $this + */ + public function restorePosition(): static + { + $this->output->write("\x1b8"); + + return $this; + } + + /** + * @return $this + */ + public function hide(): static + { + $this->output->write("\x1b[?25l"); + + return $this; + } + + /** + * @return $this + */ + public function show(): static + { + $this->output->write("\x1b[?25h\x1b[?0c"); + + return $this; + } + + /** + * Clears all the output from the current line. + * + * @return $this + */ + public function clearLine(): static + { + $this->output->write("\x1b[2K"); + + return $this; + } + + /** + * Clears all the output from the current line after the current position. + */ + public function clearLineAfter(): self + { + $this->output->write("\x1b[K"); + + return $this; + } + + /** + * Clears all the output from the cursors' current position to the end of the screen. + * + * @return $this + */ + public function clearOutput(): static + { + $this->output->write("\x1b[0J"); + + return $this; + } + + /** + * Clears the entire screen. + * + * @return $this + */ + public function clearScreen(): static + { + $this->output->write("\x1b[2J"); + + return $this; + } + + /** + * Returns the current cursor position as x,y coordinates. + */ + public function getCurrentPosition(): array + { + static $isTtySupported; + + if (!$isTtySupported ??= '/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT)) { + return [1, 1]; + } + + $sttyMode = shell_exec('stty -g'); + shell_exec('stty -icanon -echo'); + + @fwrite($this->input, "\033[6n"); + + $code = trim(fread($this->input, 1024)); + + shell_exec(\sprintf('stty %s', $sttyMode)); + + sscanf($code, "\033[%d;%dR", $row, $col); + + return [$col, $row]; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/DataCollector/CommandDataCollector.php b/lam/lib/3rdParty/composer/symfony/console/DataCollector/CommandDataCollector.php new file mode 100644 index 000000000..3cbe72b59 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/DataCollector/CommandDataCollector.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\DataCollector; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Debug\CliRequest; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\SignalRegistry\SignalMap; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * @internal + * + * @author Jules Pietri + */ +final class CommandDataCollector extends DataCollector +{ + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void + { + if (!$request instanceof CliRequest) { + return; + } + + $command = $request->command; + $application = $command->getApplication(); + + $this->data = [ + 'command' => $this->cloneVar($command->command), + 'exit_code' => $command->exitCode, + 'interrupted_by_signal' => $command->interruptedBySignal, + 'duration' => $command->duration, + 'max_memory_usage' => $command->maxMemoryUsage, + 'verbosity_level' => match ($command->output->getVerbosity()) { + OutputInterface::VERBOSITY_QUIET => 'quiet', + OutputInterface::VERBOSITY_NORMAL => 'normal', + OutputInterface::VERBOSITY_VERBOSE => 'verbose', + OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose', + OutputInterface::VERBOSITY_DEBUG => 'debug', + }, + 'interactive' => $command->isInteractive, + 'validate_input' => !$command->ignoreValidation, + 'enabled' => $command->isEnabled(), + 'visible' => !$command->isHidden(), + 'input' => $this->cloneVar($command->input), + 'output' => $this->cloneVar($command->output), + 'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs), + 'signalable' => $command->getSubscribedSignals(), + 'handled_signals' => $command->handledSignals, + 'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())), + ]; + + $baseDefinition = $application->getDefinition(); + + foreach ($command->arguments as $argName => $argValue) { + if ($baseDefinition->hasArgument($argName)) { + $this->data['application_inputs'][$argName] = $this->cloneVar($argValue); + } else { + $this->data['arguments'][$argName] = $this->cloneVar($argValue); + } + } + + foreach ($command->options as $optName => $optValue) { + if ($baseDefinition->hasOption($optName)) { + $this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue); + } else { + $this->data['options'][$optName] = $this->cloneVar($optValue); + } + } + } + + public function getName(): string + { + return 'command'; + } + + /** + * @return array{ + * class?: class-string, + * executor?: string, + * file: string, + * line: int, + * } + */ + public function getCommand(): array + { + $class = $this->data['command']->getType(); + $r = new \ReflectionMethod($class, 'execute'); + + if (Command::class !== $r->getDeclaringClass()) { + return [ + 'executor' => $class.'::'.$r->name, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + $r = new \ReflectionClass($class); + + return [ + 'class' => $class, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + public function getInterruptedBySignal(): ?string + { + if (isset($this->data['interrupted_by_signal'])) { + return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + } + + return null; + } + + public function getDuration(): string + { + return $this->data['duration']; + } + + public function getMaxMemoryUsage(): string + { + return $this->data['max_memory_usage']; + } + + public function getVerbosityLevel(): string + { + return $this->data['verbosity_level']; + } + + public function getInteractive(): bool + { + return $this->data['interactive']; + } + + public function getValidateInput(): bool + { + return $this->data['validate_input']; + } + + public function getEnabled(): bool + { + return $this->data['enabled']; + } + + public function getVisible(): bool + { + return $this->data['visible']; + } + + public function getInput(): Data + { + return $this->data['input']; + } + + public function getOutput(): Data + { + return $this->data['output']; + } + + /** + * @return Data[] + */ + public function getArguments(): array + { + return $this->data['arguments'] ?? []; + } + + /** + * @return Data[] + */ + public function getOptions(): array + { + return $this->data['options'] ?? []; + } + + /** + * @return Data[] + */ + public function getApplicationInputs(): array + { + return $this->data['application_inputs'] ?? []; + } + + /** + * @return Data[] + */ + public function getInteractiveInputs(): array + { + return $this->data['interactive_inputs'] ?? []; + } + + public function getSignalable(): array + { + return array_map( + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + $this->data['signalable'] + ); + } + + public function getHandledSignals(): array + { + $keys = array_map( + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + array_keys($this->data['handled_signals']) + ); + + return array_combine($keys, array_values($this->data['handled_signals'])); + } + + /** + * @return Data[] + */ + public function getHelperSet(): array + { + return $this->data['helper_set'] ?? []; + } + + public function reset(): void + { + $this->data = []; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Debug/CliRequest.php b/lam/lib/3rdParty/composer/symfony/console/Debug/CliRequest.php new file mode 100644 index 000000000..b023db07a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Debug/CliRequest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Debug; + +use Symfony\Component\Console\Command\TraceableCommand; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * @internal + */ +final class CliRequest extends Request +{ + public function __construct( + public readonly TraceableCommand $command, + ) { + parent::__construct( + attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'], + server: $_SERVER, + ); + } + + // Methods below allow to populate a profile, thus enable search and filtering + public function getUri(): string + { + if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) { + $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME').' console'; + } else { + $binary = $this->server->get('argv')[0]; + } + + return $binary.' '.$this->command->input; + } + + public function getMethod(): string + { + return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH'; + } + + public function getResponse(): Response + { + return new class($this->command->exitCode) extends Response { + public function __construct(private readonly int $exitCode) + { + parent::__construct(); + } + + public function getStatusCode(): int + { + return $this->exitCode; + } + }; + } + + public function getClientIp(): string + { + $application = $this->command->getApplication(); + + return $application->getName().' '.$application->getVersion(); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/lam/lib/3rdParty/composer/symfony/console/DependencyInjection/AddConsoleCommandPass.php new file mode 100644 index 000000000..3cf05734b --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\DependencyInjection; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Command\LazyCommand; +use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; + +/** + * Registers console commands. + * + * @author Grégoire Pineau + */ +class AddConsoleCommandPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + $commandServices = $container->findTaggedServiceIds('console.command', true); + $lazyCommandMap = []; + $lazyCommandRefs = []; + $serviceIds = []; + + foreach ($commandServices as $id => $tags) { + $definition = $container->getDefinition($id); + $definition->addTag('container.no_preload'); + $class = $container->getParameterBag()->resolveValue($definition->getClass()); + + if (isset($tags[0]['command'])) { + $aliases = $tags[0]['command']; + } else { + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + } + $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); + } + + $aliases = explode('|', $aliases ?? ''); + $commandName = array_shift($aliases); + + if ($isHidden = '' === $commandName) { + $commandName = array_shift($aliases); + } + + if (null === $commandName) { + if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) { + $commandId = 'console.command.public_alias.'.$id; + $container->setAlias($commandId, $id)->setPublic(true); + $id = $commandId; + } + $serviceIds[] = $id; + + continue; + } + + $description = $tags[0]['description'] ?? null; + + unset($tags[0]); + $lazyCommandMap[$commandName] = $id; + $lazyCommandRefs[$id] = new TypedReference($id, $class); + + foreach ($aliases as $alias) { + $lazyCommandMap[$alias] = $id; + } + + foreach ($tags as $tag) { + if (isset($tag['command'])) { + $aliases[] = $tag['command']; + $lazyCommandMap[$tag['command']] = $id; + } + + $description ??= $tag['description'] ?? null; + } + + $definition->addMethodCall('setName', [$commandName]); + + if ($aliases) { + $definition->addMethodCall('setAliases', [$aliases]); + } + + if ($isHidden) { + $definition->addMethodCall('setHidden', [true]); + } + + if (!$description) { + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + } + $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); + } + + if ($description) { + $definition->addMethodCall('setDescription', [$description]); + + $container->register('.'.$id.'.lazy', LazyCommand::class) + ->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]); + + $lazyCommandRefs[$id] = new Reference('.'.$id.'.lazy'); + } + } + + $container + ->register('console.command_loader', ContainerCommandLoader::class) + ->setPublic(true) + ->addTag('container.no_preload') + ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]); + + $container->setParameter('console.command.ids', $serviceIds); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/ApplicationDescription.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/ApplicationDescription.php new file mode 100644 index 000000000..3f38379c9 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/ApplicationDescription.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * @author Jean-François Simon + * + * @internal + */ +class ApplicationDescription +{ + public const GLOBAL_NAMESPACE = '_global'; + + private Application $application; + private ?string $namespace; + private bool $showHidden; + private array $namespaces; + + /** + * @var array + */ + private array $commands; + + /** + * @var array + */ + private array $aliases = []; + + public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false) + { + $this->application = $application; + $this->namespace = $namespace; + $this->showHidden = $showHidden; + } + + public function getNamespaces(): array + { + if (!isset($this->namespaces)) { + $this->inspectApplication(); + } + + return $this->namespaces; + } + + /** + * @return Command[] + */ + public function getCommands(): array + { + if (!isset($this->commands)) { + $this->inspectApplication(); + } + + return $this->commands; + } + + /** + * @throws CommandNotFoundException + */ + public function getCommand(string $name): Command + { + if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + + return $this->commands[$name] ?? $this->aliases[$name]; + } + + private function inspectApplication(): void + { + $this->commands = []; + $this->namespaces = []; + + $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); + foreach ($this->sortCommands($all) as $namespace => $commands) { + $names = []; + + /** @var Command $command */ + foreach ($commands as $name => $command) { + if (!$command->getName() || (!$this->showHidden && $command->isHidden())) { + continue; + } + + if ($command->getName() === $name) { + $this->commands[$name] = $command; + } else { + $this->aliases[$name] = $command; + } + + $names[] = $name; + } + + $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names]; + } + } + + private function sortCommands(array $commands): array + { + $namespacedCommands = []; + $globalCommands = []; + $sortedCommands = []; + foreach ($commands as $name => $command) { + $key = $this->application->extractNamespace($name, 1); + if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) { + $globalCommands[$name] = $command; + } else { + $namespacedCommands[$key][$name] = $command; + } + } + + if ($globalCommands) { + ksort($globalCommands); + $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; + } + + if ($namespacedCommands) { + ksort($namespacedCommands, \SORT_STRING); + foreach ($namespacedCommands as $key => $commandsSet) { + ksort($commandsSet); + $sortedCommands[$key] = $commandsSet; + } + } + + return $sortedCommands; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/Descriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/Descriptor.php new file mode 100644 index 000000000..2143a17c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/Descriptor.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Jean-François Simon + * + * @internal + */ +abstract class Descriptor implements DescriptorInterface +{ + protected OutputInterface $output; + + public function describe(OutputInterface $output, object $object, array $options = []): void + { + $this->output = $output; + + match (true) { + $object instanceof InputArgument => $this->describeInputArgument($object, $options), + $object instanceof InputOption => $this->describeInputOption($object, $options), + $object instanceof InputDefinition => $this->describeInputDefinition($object, $options), + $object instanceof Command => $this->describeCommand($object, $options), + $object instanceof Application => $this->describeApplication($object, $options), + default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), + }; + } + + protected function write(string $content, bool $decorated = false): void + { + $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); + } + + /** + * Describes an InputArgument instance. + */ + abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void; + + /** + * Describes an InputOption instance. + */ + abstract protected function describeInputOption(InputOption $option, array $options = []): void; + + /** + * Describes an InputDefinition instance. + */ + abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void; + + /** + * Describes a Command instance. + */ + abstract protected function describeCommand(Command $command, array $options = []): void; + + /** + * Describes an Application instance. + */ + abstract protected function describeApplication(Application $application, array $options = []): void; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/DescriptorInterface.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/DescriptorInterface.php new file mode 100644 index 000000000..ab468a256 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/DescriptorInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Descriptor interface. + * + * @author Jean-François Simon + */ +interface DescriptorInterface +{ + /** + * @return void + */ + public function describe(OutputInterface $output, object $object, array $options = []); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/JsonDescriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/JsonDescriptor.php new file mode 100644 index 000000000..9a8e696cd --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/JsonDescriptor.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * JSON descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class JsonDescriptor extends Descriptor +{ + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->writeData($this->getInputArgumentData($argument), $options); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $this->writeData($this->getInputOptionData($option), $options); + if ($option->isNegatable()) { + $this->writeData($this->getInputOptionData($option, true), $options); + } + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + $this->writeData($this->getInputDefinitionData($definition), $options); + } + + protected function describeCommand(Command $command, array $options = []): void + { + $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options); + } + + protected function describeApplication(Application $application, array $options = []): void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace, true); + $commands = []; + + foreach ($description->getCommands() as $command) { + $commands[] = $this->getCommandData($command, $options['short'] ?? false); + } + + $data = []; + if ('UNKNOWN' !== $application->getName()) { + $data['application']['name'] = $application->getName(); + if ('UNKNOWN' !== $application->getVersion()) { + $data['application']['version'] = $application->getVersion(); + } + } + + $data['commands'] = $commands; + + if ($describedNamespace) { + $data['namespace'] = $describedNamespace; + } else { + $data['namespaces'] = array_values($description->getNamespaces()); + } + + $this->writeData($data, $options); + } + + /** + * Writes data as json. + */ + private function writeData(array $data, array $options): void + { + $flags = $options['json_encoding'] ?? 0; + + $this->write(json_encode($data, $flags)); + } + + private function getInputArgumentData(InputArgument $argument): array + { + return [ + 'name' => $argument->getName(), + 'is_required' => $argument->isRequired(), + 'is_array' => $argument->isArray(), + 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()), + 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(), + ]; + } + + private function getInputOptionData(InputOption $option, bool $negated = false): array + { + return $negated ? [ + 'name' => '--no-'.$option->getName(), + 'shortcut' => '', + 'accept_value' => false, + 'is_value_required' => false, + 'is_multiple' => false, + 'description' => 'Negate the "--'.$option->getName().'" option', + 'default' => null === $option->getDefault() ? null : !$option->getDefault(), + ] : [ + 'name' => '--'.$option->getName(), + 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', + 'accept_value' => $option->acceptValue(), + 'is_value_required' => $option->isValueRequired(), + 'is_multiple' => $option->isArray(), + 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()), + 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(), + ]; + } + + private function getInputDefinitionData(InputDefinition $definition): array + { + $inputArguments = []; + foreach ($definition->getArguments() as $name => $argument) { + $inputArguments[$name] = $this->getInputArgumentData($argument); + } + + $inputOptions = []; + foreach ($definition->getOptions() as $name => $option) { + $inputOptions[$name] = $this->getInputOptionData($option); + if ($option->isNegatable()) { + $inputOptions['no-'.$name] = $this->getInputOptionData($option, true); + } + } + + return ['arguments' => $inputArguments, 'options' => $inputOptions]; + } + + private function getCommandData(Command $command, bool $short = false): array + { + $data = [ + 'name' => $command->getName(), + 'description' => $command->getDescription(), + ]; + + if ($short) { + $data += [ + 'usage' => $command->getAliases(), + ]; + } else { + $command->mergeApplicationDefinition(false); + + $data += [ + 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), + 'help' => $command->getProcessedHelp(), + 'definition' => $this->getInputDefinitionData($command->getDefinition()), + ]; + } + + $data['hidden'] = $command->isHidden(); + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/MarkdownDescriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/MarkdownDescriptor.php new file mode 100644 index 000000000..8b7075943 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/MarkdownDescriptor.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Markdown descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class MarkdownDescriptor extends Descriptor +{ + public function describe(OutputInterface $output, object $object, array $options = []): void + { + $decorated = $output->isDecorated(); + $output->setDecorated(false); + + parent::describe($output, $object, $options); + + $output->setDecorated($decorated); + } + + protected function write(string $content, bool $decorated = true): void + { + parent::write($content, $decorated); + } + + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->write( + '#### `'.($argument->getName() ?: '')."`\n\n" + .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') + .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n" + .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n" + .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`' + ); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $name = '--'.$option->getName(); + if ($option->isNegatable()) { + $name .= '|--no-'.$option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).''; + } + + $this->write( + '#### `'.$name.'`'."\n\n" + .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '') + .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n" + .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n" + .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n" + .'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no')."\n" + .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`' + ); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + if ($showArguments = \count($definition->getArguments()) > 0) { + $this->write('### Arguments'); + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + + if (\count($definition->getOptions()) > 0) { + if ($showArguments) { + $this->write("\n\n"); + } + + $this->write('### Options'); + foreach ($definition->getOptions() as $option) { + $this->write("\n\n"); + $this->describeInputOption($option); + } + } + } + + protected function describeCommand(Command $command, array $options = []): void + { + if ($options['short'] ?? false) { + $this->write( + '`'.$command->getName()."`\n" + .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + .'### Usage'."\n\n" + .array_reduce($command->getAliases(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") + ); + + return; + } + + $command->mergeApplicationDefinition(false); + + $this->write( + '`'.$command->getName()."`\n" + .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + .'### Usage'."\n\n" + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") + ); + + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + + protected function describeApplication(Application $application, array $options = []): void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace); + $title = $this->getApplicationTitle($application); + + $this->write($title."\n".str_repeat('=', Helper::width($title))); + + foreach ($description->getNamespaces() as $namespace) { + if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->write("\n\n"); + $this->write('**'.$namespace['id'].':**'); + } + + $this->write("\n\n"); + $this->write(implode("\n", array_map(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); + } + + foreach ($description->getCommands() as $command) { + $this->write("\n\n"); + $this->describeCommand($command, $options); + } + } + + private function getApplicationTitle(Application $application): string + { + if ('UNKNOWN' !== $application->getName()) { + if ('UNKNOWN' !== $application->getVersion()) { + return \sprintf('%s %s', $application->getName(), $application->getVersion()); + } + + return $application->getName(); + } + + return 'Console Tool'; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/ReStructuredTextDescriptor.php new file mode 100644 index 000000000..a2b754276 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -0,0 +1,272 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\String\UnicodeString; + +class ReStructuredTextDescriptor extends Descriptor +{ + //

    + private string $partChar = '='; + //

    + private string $chapterChar = '-'; + //

    + private string $sectionChar = '~'; + //

    + private string $subsectionChar = '.'; + //

    + private string $subsubsectionChar = '^'; + //
    + private string $paragraphsChar = '"'; + + private array $visibleNamespaces = []; + + public function describe(OutputInterface $output, object $object, array $options = []): void + { + $decorated = $output->isDecorated(); + $output->setDecorated(false); + + parent::describe($output, $object, $options); + + $output->setDecorated($decorated); + } + + /** + * Override parent method to set $decorated = true. + */ + protected function write(string $content, bool $decorated = true): void + { + parent::write($content, $decorated); + } + + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->write( + $argument->getName() ?: ''."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n" + .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') + .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n" + .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``' + ); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $name = '\-\-'.$option->getName(); + if ($option->isNegatable()) { + $name .= '|\-\-no-'.$option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-'.str_replace('|', '|-', $option->getShortcut()); + } + + $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : ''; + $optionDescription = (new UnicodeString($optionDescription))->ascii(); + $this->write( + $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n" + .$optionDescription + .'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n" + .'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n" + .'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n" + .'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n" + ); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + if ($showArguments = ((bool) $definition->getArguments())) { + $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n"; + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + + if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) { + if ($showArguments) { + $this->write("\n\n"); + } + + $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n"); + foreach ($nonDefaultOptions as $option) { + $this->describeInputOption($option); + $this->write("\n"); + } + } + } + + protected function describeCommand(Command $command, array $options = []): void + { + if ($options['short'] ?? false) { + $this->write( + '``'.$command->getName()."``\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n" + .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + return; + } + + $command->mergeApplicationDefinition(false); + + foreach ($command->getAliases() as $alias) { + $this->write('.. _'.$alias.":\n\n"); + } + $this->write( + $command->getName()."\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n" + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + + protected function describeApplication(Application $application, array $options = []): void + { + $description = new ApplicationDescription($application, $options['namespace'] ?? null); + $title = $this->getApplicationTitle($application); + + $this->write($title."\n".str_repeat($this->partChar, Helper::width($title))); + $this->createTableOfContents($description, $application); + $this->describeCommands($application, $options); + } + + private function getApplicationTitle(Application $application): string + { + if ('UNKNOWN' === $application->getName()) { + return 'Console Tool'; + } + if ('UNKNOWN' !== $application->getVersion()) { + return \sprintf('%s %s', $application->getName(), $application->getVersion()); + } + + return $application->getName(); + } + + private function describeCommands($application, array $options): void + { + $title = 'Commands'; + $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n"); + } else { + $commands = $application->all($namespace); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + + foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) { + $this->describeCommand($command, $options); + $this->write("\n\n"); + } + } + } + + private function createTableOfContents(ApplicationDescription $description, Application $application): void + { + $this->setVisibleNamespaces($description); + $chapterTitle = 'Table of Contents'; + $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + } else { + $commands = $application->all($namespace); + $this->write("\n\n"); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + $commands = $this->removeAliasesAndHiddenCommands($commands); + + $this->write("\n\n"); + $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands)))); + } + } + + private function getNonDefaultOptions(InputDefinition $definition): array + { + $globalOptions = [ + 'help', + 'quiet', + 'verbose', + 'version', + 'ansi', + 'no-interaction', + ]; + $nonDefaultOptions = []; + foreach ($definition->getOptions() as $option) { + // Skip global options. + if (!\in_array($option->getName(), $globalOptions)) { + $nonDefaultOptions[] = $option; + } + } + + return $nonDefaultOptions; + } + + private function setVisibleNamespaces(ApplicationDescription $description): void + { + $commands = $description->getCommands(); + foreach ($description->getNamespaces() as $namespace) { + try { + $namespaceCommands = $namespace['commands']; + foreach ($namespaceCommands as $key => $commandName) { + if (!\array_key_exists($commandName, $commands)) { + // If the array key does not exist, then this is an alias. + unset($namespaceCommands[$key]); + } elseif ($commands[$commandName]->isHidden()) { + unset($namespaceCommands[$key]); + } + } + if (!$namespaceCommands) { + // If the namespace contained only aliases or hidden commands, skip the namespace. + continue; + } + } catch (\Exception) { + } + $this->visibleNamespaces[] = $namespace['id']; + } + } + + private function removeAliasesAndHiddenCommands(array $commands): array + { + foreach ($commands as $key => $command) { + if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) { + unset($commands[$key]); + } + } + unset($commands['completion']); + + return $commands; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/TextDescriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/TextDescriptor.php new file mode 100644 index 000000000..51c411f46 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/TextDescriptor.php @@ -0,0 +1,317 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * Text descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class TextDescriptor extends Descriptor +{ + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + } else { + $default = ''; + } + + $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); + $spacingWidth = $totalWidth - \strlen($argument->getName()); + + $this->writeText(\sprintf(' %s %s%s%s', + $argument->getName(), + str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()), + $default + ), $options); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + } else { + $default = ''; + } + + $value = ''; + if ($option->acceptValue()) { + $value = '='.strtoupper($option->getName()); + + if ($option->isValueOptional()) { + $value = '['.$value.']'; + } + } + + $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); + $synopsis = \sprintf('%s%s', + $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', + \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) + ); + + $spacingWidth = $totalWidth - Helper::width($synopsis); + + $this->writeText(\sprintf(' %s %s%s%s%s', + $synopsis, + str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()), + $default, + $option->isArray() ? ' (multiple values allowed)' : '' + ), $options); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); + foreach ($definition->getArguments() as $argument) { + $totalWidth = max($totalWidth, Helper::width($argument->getName())); + } + + if ($definition->getArguments()) { + $this->writeText('Arguments:', $options); + $this->writeText("\n"); + foreach ($definition->getArguments() as $argument) { + $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth])); + $this->writeText("\n"); + } + } + + if ($definition->getArguments() && $definition->getOptions()) { + $this->writeText("\n"); + } + + if ($definition->getOptions()) { + $laterOptions = []; + + $this->writeText('Options:', $options); + foreach ($definition->getOptions() as $option) { + if (\strlen($option->getShortcut() ?? '') > 1) { + $laterOptions[] = $option; + continue; + } + $this->writeText("\n"); + $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth])); + } + foreach ($laterOptions as $option) { + $this->writeText("\n"); + $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth])); + } + } + } + + protected function describeCommand(Command $command, array $options = []): void + { + $command->mergeApplicationDefinition(false); + + if ($description = $command->getDescription()) { + $this->writeText('Description:', $options); + $this->writeText("\n"); + $this->writeText(' '.$description); + $this->writeText("\n\n"); + } + + $this->writeText('Usage:', $options); + foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) { + $this->writeText("\n"); + $this->writeText(' '.OutputFormatter::escape($usage), $options); + } + $this->writeText("\n"); + + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->writeText("\n"); + $this->describeInputDefinition($definition, $options); + $this->writeText("\n"); + } + + $help = $command->getProcessedHelp(); + if ($help && $help !== $description) { + $this->writeText("\n"); + $this->writeText('Help:', $options); + $this->writeText("\n"); + $this->writeText(' '.str_replace("\n", "\n ", $help), $options); + $this->writeText("\n"); + } + } + + protected function describeApplication(Application $application, array $options = []): void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace); + + if (isset($options['raw_text']) && $options['raw_text']) { + $width = $this->getColumnWidth($description->getCommands()); + + foreach ($description->getCommands() as $command) { + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText("\n"); + } + } else { + if ('' != $help = $application->getHelp()) { + $this->writeText("$help\n\n", $options); + } + + $this->writeText("Usage:\n", $options); + $this->writeText(" command [options] [arguments]\n\n", $options); + + $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); + + $this->writeText("\n"); + $this->writeText("\n"); + + $commands = $description->getCommands(); + $namespaces = $description->getNamespaces(); + if ($describedNamespace && $namespaces) { + // make sure all alias commands are included when describing a specific namespace + $describedNamespaceInfo = reset($namespaces); + foreach ($describedNamespaceInfo['commands'] as $name) { + $commands[$name] = $description->getCommand($name); + } + } + + // calculate max. width based on available commands per namespace + $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); + + if ($describedNamespace) { + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + } else { + $this->writeText('Available commands:', $options); + } + + foreach ($namespaces as $namespace) { + $namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name])); + + if (!$namespace['commands']) { + continue; + } + + if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->writeText("\n"); + $this->writeText(' '.$namespace['id'].'', $options); + } + + foreach ($namespace['commands'] as $name) { + $this->writeText("\n"); + $spacingWidth = $width - Helper::width($name); + $command = $commands[$name]; + $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; + $this->writeText(\sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); + } + } + + $this->writeText("\n"); + } + } + + private function writeText(string $content, array $options = []): void + { + $this->write( + isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, + isset($options['raw_output']) ? !$options['raw_output'] : true + ); + } + + /** + * Formats command aliases to show them in the command description. + */ + private function getCommandAliasesText(Command $command): string + { + $text = ''; + $aliases = $command->getAliases(); + + if ($aliases) { + $text = '['.implode('|', $aliases).'] '; + } + + return $text; + } + + /** + * Formats input option/argument default value. + */ + private function formatDefaultValue(mixed $default): string + { + if (\INF === $default) { + return 'INF'; + } + + if (\is_string($default)) { + $default = OutputFormatter::escape($default); + } elseif (\is_array($default)) { + foreach ($default as $key => $value) { + if (\is_string($value)) { + $default[$key] = OutputFormatter::escape($value); + } + } + } + + return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); + } + + /** + * @param array $commands + */ + private function getColumnWidth(array $commands): int + { + $widths = []; + + foreach ($commands as $command) { + if ($command instanceof Command) { + $widths[] = Helper::width($command->getName()); + foreach ($command->getAliases() as $alias) { + $widths[] = Helper::width($alias); + } + } else { + $widths[] = Helper::width($command); + } + } + + return $widths ? max($widths) + 2 : 0; + } + + /** + * @param InputOption[] $options + */ + private function calculateTotalWidthForOptions(array $options): int + { + $totalWidth = 0; + foreach ($options as $option) { + // "-" + shortcut + ", --" + name + $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName()); + if ($option->isNegatable()) { + $nameLength += 6 + Helper::width($option->getName()); // |--no- + name + } elseif ($option->acceptValue()) { + $valueLength = 1 + Helper::width($option->getName()); // = + value + $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] + + $nameLength += $valueLength; + } + $totalWidth = max($totalWidth, $nameLength); + } + + return $totalWidth; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Descriptor/XmlDescriptor.php b/lam/lib/3rdParty/composer/symfony/console/Descriptor/XmlDescriptor.php new file mode 100644 index 000000000..866c71856 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Descriptor/XmlDescriptor.php @@ -0,0 +1,232 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * XML descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class XmlDescriptor extends Descriptor +{ + public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($definitionXML = $dom->createElement('definition')); + + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($definition->getArguments() as $argument) { + $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); + } + + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($definition->getOptions() as $option) { + $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); + } + + return $dom; + } + + public function getCommandDocument(Command $command, bool $short = false): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($commandXML = $dom->createElement('command')); + + $commandXML->setAttribute('id', $command->getName()); + $commandXML->setAttribute('name', $command->getName()); + $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); + + $commandXML->appendChild($usagesXML = $dom->createElement('usages')); + + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription()))); + + if ($short) { + foreach ($command->getAliases() as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + } else { + $command->mergeApplicationDefinition(false); + + foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp()))); + + $definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); + $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); + } + + return $dom; + } + + public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($rootXml = $dom->createElement('symfony')); + + if ('UNKNOWN' !== $application->getName()) { + $rootXml->setAttribute('name', $application->getName()); + if ('UNKNOWN' !== $application->getVersion()) { + $rootXml->setAttribute('version', $application->getVersion()); + } + } + + $rootXml->appendChild($commandsXML = $dom->createElement('commands')); + + $description = new ApplicationDescription($application, $namespace, true); + + if ($namespace) { + $commandsXML->setAttribute('namespace', $namespace); + } + + foreach ($description->getCommands() as $command) { + $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short)); + } + + if (!$namespace) { + $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); + + foreach ($description->getNamespaces() as $namespaceDescription) { + $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); + $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); + + foreach ($namespaceDescription['commands'] as $name) { + $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); + $commandXML->appendChild($dom->createTextNode($name)); + } + } + } + + return $dom; + } + + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->writeDocument($this->getInputArgumentDocument($argument)); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $this->writeDocument($this->getInputOptionDocument($option)); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + $this->writeDocument($this->getInputDefinitionDocument($definition)); + } + + protected function describeCommand(Command $command, array $options = []): void + { + $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false)); + } + + protected function describeApplication(Application $application, array $options = []): void + { + $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false)); + } + + /** + * Appends document children to parent node. + */ + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void + { + foreach ($importedParent->childNodes as $childNode) { + $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); + } + } + + /** + * Writes DOM document. + */ + private function writeDocument(\DOMDocument $dom): void + { + $dom->formatOutput = true; + $this->write($dom->saveXML()); + } + + private function getInputArgumentDocument(InputArgument $argument): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + + $dom->appendChild($objectXML = $dom->createElement('argument')); + $objectXML->setAttribute('name', $argument->getName()); + $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + + return $dom; + } + + private function getInputOptionDocument(InputOption $option): \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--'.$option->getName()); + $pos = strpos($option->getShortcut() ?? '', '|'); + if (false !== $pos) { + $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos)); + $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut())); + } else { + $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); + } + $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); + $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); + $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + + if ($option->acceptValue()) { + $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : [])); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + + if (!empty($defaults)) { + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + + if ($option->isNegatable()) { + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--no-'.$option->getName()); + $objectXML->setAttribute('shortcut', ''); + $objectXML->setAttribute('accept_value', 0); + $objectXML->setAttribute('is_value_required', 0); + $objectXML->setAttribute('is_multiple', 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option')); + } + + return $dom; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleCommandEvent.php b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleCommandEvent.php new file mode 100644 index 000000000..0757a23f6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleCommandEvent.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +/** + * Allows to do things before the command is executed, like skipping the command or executing code before the command is + * going to be executed. + * + * Changing the input arguments will have no effect. + * + * @author Fabien Potencier + */ +final class ConsoleCommandEvent extends ConsoleEvent +{ + /** + * The return code for skipped commands, this will also be passed into the terminate event. + */ + public const RETURN_CODE_DISABLED = 113; + + /** + * Indicates if the command should be run or skipped. + */ + private bool $commandShouldRun = true; + + /** + * Disables the command, so it won't be run. + */ + public function disableCommand(): bool + { + return $this->commandShouldRun = false; + } + + public function enableCommand(): bool + { + return $this->commandShouldRun = true; + } + + /** + * Returns true if the command is runnable, false otherwise. + */ + public function commandShouldRun(): bool + { + return $this->commandShouldRun; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleErrorEvent.php b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleErrorEvent.php new file mode 100644 index 000000000..7be2ff83e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleErrorEvent.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Allows to handle throwables thrown while running a command. + * + * @author Wouter de Jong + */ +final class ConsoleErrorEvent extends ConsoleEvent +{ + private \Throwable $error; + private int $exitCode; + + public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null) + { + parent::__construct($command, $input, $output); + + $this->error = $error; + } + + public function getError(): \Throwable + { + return $this->error; + } + + public function setError(\Throwable $error): void + { + $this->error = $error; + } + + public function setExitCode(int $exitCode): void + { + $this->exitCode = $exitCode; + + $r = new \ReflectionProperty($this->error, 'code'); + $r->setValue($this->error, $this->exitCode); + } + + public function getExitCode(): int + { + return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleEvent.php b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleEvent.php new file mode 100644 index 000000000..6ba1615fe --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleEvent.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Allows to inspect input and output of a command. + * + * @author Francesco Levorato + */ +class ConsoleEvent extends Event +{ + protected $command; + + private InputInterface $input; + private OutputInterface $output; + + public function __construct(?Command $command, InputInterface $input, OutputInterface $output) + { + $this->command = $command; + $this->input = $input; + $this->output = $output; + } + + /** + * Gets the command that is executed. + */ + public function getCommand(): ?Command + { + return $this->command; + } + + /** + * Gets the input instance. + */ + public function getInput(): InputInterface + { + return $this->input; + } + + /** + * Gets the output instance. + */ + public function getOutput(): OutputInterface + { + return $this->output; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleSignalEvent.php b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleSignalEvent.php new file mode 100644 index 000000000..95af1f915 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleSignalEvent.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author marie + */ +final class ConsoleSignalEvent extends ConsoleEvent +{ + private int $handlingSignal; + private int|false $exitCode; + + public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0) + { + parent::__construct($command, $input, $output); + $this->handlingSignal = $handlingSignal; + $this->exitCode = $exitCode; + } + + public function getHandlingSignal(): int + { + return $this->handlingSignal; + } + + public function setExitCode(int $exitCode): void + { + if ($exitCode < 0 || $exitCode > 255) { + throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); + } + + $this->exitCode = $exitCode; + } + + public function abortExit(): void + { + $this->exitCode = false; + } + + public function getExitCode(): int|false + { + return $this->exitCode; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleTerminateEvent.php b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleTerminateEvent.php new file mode 100644 index 000000000..38f7253a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Event/ConsoleTerminateEvent.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Allows to manipulate the exit code of a command after its execution. + * + * @author Francesco Levorato + * @author Jules Pietri + */ +final class ConsoleTerminateEvent extends ConsoleEvent +{ + public function __construct( + Command $command, + InputInterface $input, + OutputInterface $output, + private int $exitCode, + private readonly ?int $interruptingSignal = null, + ) { + parent::__construct($command, $input, $output); + } + + public function setExitCode(int $exitCode): void + { + $this->exitCode = $exitCode; + } + + public function getExitCode(): int + { + return $this->exitCode; + } + + public function getInterruptingSignal(): ?int + { + return $this->interruptingSignal; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/EventListener/ErrorListener.php b/lam/lib/3rdParty/composer/symfony/console/EventListener/ErrorListener.php new file mode 100644 index 000000000..c9ec24434 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/EventListener/ErrorListener.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Event\ConsoleEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * @author James Halsall + * @author Robin Chalas + */ +class ErrorListener implements EventSubscriberInterface +{ + private ?LoggerInterface $logger; + + public function __construct(?LoggerInterface $logger = null) + { + $this->logger = $logger; + } + + /** + * @return void + */ + public function onConsoleError(ConsoleErrorEvent $event) + { + if (null === $this->logger) { + return; + } + + $error = $event->getError(); + + if (!$inputString = $this->getInputString($event)) { + $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); + + return; + } + + $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); + } + + /** + * @return void + */ + public function onConsoleTerminate(ConsoleTerminateEvent $event) + { + if (null === $this->logger) { + return; + } + + $exitCode = $event->getExitCode(); + + if (0 === $exitCode) { + return; + } + + if (!$inputString = $this->getInputString($event)) { + $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); + + return; + } + + $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]); + } + + public static function getSubscribedEvents(): array + { + return [ + ConsoleEvents::ERROR => ['onConsoleError', -128], + ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128], + ]; + } + + private static function getInputString(ConsoleEvent $event): ?string + { + $commandName = $event->getCommand()?->getName(); + $input = $event->getInput(); + + if ($input instanceof \Stringable) { + if ($commandName) { + return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input); + } + + return (string) $input; + } + + return $commandName; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/CommandNotFoundException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/CommandNotFoundException.php new file mode 100644 index 000000000..541b32b23 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/CommandNotFoundException.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * Represents an incorrect command name typed in the console. + * + * @author Jérôme Tamarelle + */ +class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface +{ + private array $alternatives; + + /** + * @param string $message Exception message to throw + * @param string[] $alternatives List of similar defined names + * @param int $code Exception code + * @param \Throwable|null $previous Previous exception used for the exception chaining + */ + public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + + $this->alternatives = $alternatives; + } + + /** + * @return string[] + */ + public function getAlternatives(): array + { + return $this->alternatives; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/ExceptionInterface.php b/lam/lib/3rdParty/composer/symfony/console/Exception/ExceptionInterface.php new file mode 100644 index 000000000..1624e13d0 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * ExceptionInterface. + * + * @author Jérôme Tamarelle + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidArgumentException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..07cc0b61d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidOptionException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidOptionException.php new file mode 100644 index 000000000..5cf62792e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/InvalidOptionException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * Represents an incorrect option name or value typed in the console. + * + * @author Jérôme Tamarelle + */ +class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/LogicException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/LogicException.php new file mode 100644 index 000000000..fc37b8d8a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/MissingInputException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/MissingInputException.php new file mode 100644 index 000000000..04f02ade4 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/MissingInputException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * Represents failure to read input from stdin. + * + * @author Gabriel Ostrolucký + */ +class MissingInputException extends RuntimeException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/NamespaceNotFoundException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/NamespaceNotFoundException.php new file mode 100644 index 000000000..dd16e4508 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/NamespaceNotFoundException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * Represents an incorrect namespace typed in the console. + * + * @author Pierre du Plessis + */ +class NamespaceNotFoundException extends CommandNotFoundException +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/RunCommandFailedException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/RunCommandFailedException.php new file mode 100644 index 000000000..5d87ec949 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/RunCommandFailedException.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +use Symfony\Component\Console\Messenger\RunCommandContext; + +/** + * @author Kevin Bond + */ +final class RunCommandFailedException extends RuntimeException +{ + public function __construct(\Throwable|string $exception, public readonly RunCommandContext $context) + { + parent::__construct( + $exception instanceof \Throwable ? $exception->getMessage() : $exception, + $exception instanceof \Throwable ? $exception->getCode() : 0, + $exception instanceof \Throwable ? $exception : null, + ); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Exception/RuntimeException.php b/lam/lib/3rdParty/composer/symfony/console/Exception/RuntimeException.php new file mode 100644 index 000000000..51d7d80ac --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatter.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatter.php new file mode 100644 index 000000000..5c11c7644 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatter.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatter implements OutputFormatterInterface +{ + private NullOutputFormatterStyle $style; + + public function format(?string $message): ?string + { + return null; + } + + public function getStyle(string $name): OutputFormatterStyleInterface + { + // to comply with the interface we must return a OutputFormatterStyleInterface + return $this->style ??= new NullOutputFormatterStyle(); + } + + public function hasStyle(string $name): bool + { + return false; + } + + public function isDecorated(): bool + { + return false; + } + + public function setDecorated(bool $decorated): void + { + // do nothing + } + + public function setStyle(string $name, OutputFormatterStyleInterface $style): void + { + // do nothing + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatterStyle.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatterStyle.php new file mode 100644 index 000000000..ae23decb1 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/NullOutputFormatterStyle.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatterStyle implements OutputFormatterStyleInterface +{ + public function apply(string $text): string + { + return $text; + } + + public function setBackground(?string $color = null): void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + // do nothing + } + + public function setForeground(?string $color = null): void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + // do nothing + } + + public function setOption(string $option): void + { + // do nothing + } + + public function setOptions(array $options): void + { + // do nothing + } + + public function unsetOption(string $option): void + { + // do nothing + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatter.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatter.php new file mode 100644 index 000000000..a30e44d84 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatter.php @@ -0,0 +1,290 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\Helper; + +use function Symfony\Component\String\b; + +/** + * Formatter class for console output. + * + * @author Konstantin Kudryashov + * @author Roland Franssen + */ +class OutputFormatter implements WrappableOutputFormatterInterface +{ + private bool $decorated; + private array $styles = []; + private OutputFormatterStyleStack $styleStack; + + public function __clone() + { + $this->styleStack = clone $this->styleStack; + foreach ($this->styles as $key => $value) { + $this->styles[$key] = clone $value; + } + } + + /** + * Escapes "<" and ">" special chars in given text. + */ + public static function escape(string $text): string + { + $text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text); + + return self::escapeTrailingBackslash($text); + } + + /** + * Escapes trailing "\" in given text. + * + * @internal + */ + public static function escapeTrailingBackslash(string $text): string + { + if (str_ends_with($text, '\\')) { + $len = \strlen($text); + $text = rtrim($text, '\\'); + $text = str_replace("\0", '', $text); + $text .= str_repeat("\0", $len - \strlen($text)); + } + + return $text; + } + + /** + * Initializes console output formatter. + * + * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances + */ + public function __construct(bool $decorated = false, array $styles = []) + { + $this->decorated = $decorated; + + $this->setStyle('error', new OutputFormatterStyle('white', 'red')); + $this->setStyle('info', new OutputFormatterStyle('green')); + $this->setStyle('comment', new OutputFormatterStyle('yellow')); + $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); + + foreach ($styles as $name => $style) { + $this->setStyle($name, $style); + } + + $this->styleStack = new OutputFormatterStyleStack(); + } + + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->decorated = $decorated; + } + + public function isDecorated(): bool + { + return $this->decorated; + } + + /** + * @return void + */ + public function setStyle(string $name, OutputFormatterStyleInterface $style) + { + $this->styles[strtolower($name)] = $style; + } + + public function hasStyle(string $name): bool + { + return isset($this->styles[strtolower($name)]); + } + + public function getStyle(string $name): OutputFormatterStyleInterface + { + if (!$this->hasStyle($name)) { + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); + } + + return $this->styles[strtolower($name)]; + } + + public function format(?string $message): ?string + { + return $this->formatAndWrap($message, 0); + } + + /** + * @return string + */ + public function formatAndWrap(?string $message, int $width) + { + if (null === $message) { + return ''; + } + + $offset = 0; + $output = ''; + $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; + $closeTagRegex = '[a-z][^<>]*+'; + $currentLineLength = 0; + preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); + foreach ($matches[0] as $i => $match) { + $pos = $match[1]; + $text = $match[0]; + + if (0 != $pos && '\\' == $message[$pos - 1]) { + continue; + } + + // convert byte position to character position. + $pos = Helper::length(substr($message, 0, $pos)); + // add the text up to the next tag + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + Helper::length($text); + + // opening tag? + if ($open = '/' !== $text[1]) { + $tag = $matches[1][$i][0]; + } else { + $tag = $matches[3][$i][0] ?? ''; + } + + if (!$open && !$tag) { + // + $this->styleStack->pop(); + } elseif (null === $style = $this->createStyleFromString($tag)) { + $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength); + } elseif ($open) { + $this->styleStack->push($style); + } else { + $this->styleStack->pop($style); + } + } + + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength); + + return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); + } + + public function getStyleStack(): OutputFormatterStyleStack + { + return $this->styleStack; + } + + /** + * Tries to create new style instance from string. + */ + private function createStyleFromString(string $string): ?OutputFormatterStyleInterface + { + if (isset($this->styles[$string])) { + return $this->styles[$string]; + } + + if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) { + return null; + } + + $style = new OutputFormatterStyle(); + foreach ($matches as $match) { + array_shift($match); + $match[0] = strtolower($match[0]); + + if ('fg' == $match[0]) { + $style->setForeground(strtolower($match[1])); + } elseif ('bg' == $match[0]) { + $style->setBackground(strtolower($match[1])); + } elseif ('href' === $match[0]) { + $url = preg_replace('{\\\\([<>])}', '$1', $match[1]); + $style->setHref($url); + } elseif ('options' === $match[0]) { + preg_match_all('([^,;]+)', strtolower($match[1]), $options); + $options = array_shift($options); + foreach ($options as $option) { + $style->setOption($option); + } + } else { + return null; + } + } + + return $style; + } + + /** + * Applies current style from stack to text, if must be applied. + */ + private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string + { + if ('' === $text) { + return ''; + } + + if (!$width) { + return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text; + } + + if (!$currentLineLength && '' !== $current) { + $text = ltrim($text); + } + + if ($currentLineLength) { + $lines = explode("\n", $text, 2); + $prefix = Helper::substr($lines[0], 0, $i = $width - $currentLineLength)."\n"; + $text = Helper::substr($lines[0], $i); + + if (isset($lines[1])) { + // $prefix may contain the full first line in which the \n is already a part of $prefix. + if ('' !== $text) { + $text .= "\n"; + } + + $text .= $lines[1]; + } + } else { + $prefix = ''; + } + + preg_match('~(\\n)$~', $text, $matches); + $text = $prefix.$this->addLineBreaks($text, $width); + $text = rtrim($text, "\n").($matches[1] ?? ''); + + if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) { + $text = "\n".$text; + } + + $lines = explode("\n", $text); + + foreach ($lines as $i => $line) { + $currentLineLength = 0 === $i ? $currentLineLength + Helper::length($line) : Helper::length($line); + if ($width <= $currentLineLength) { + $currentLineLength = 0; + } + } + + if ($this->isDecorated()) { + foreach ($lines as $i => $line) { + $lines[$i] = $this->styleStack->getCurrent()->apply($line); + } + } + + return implode("\n", $lines); + } + + private function addLineBreaks(string $text, int $width): string + { + $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8'; + + return b($text)->toUnicodeString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterInterface.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterInterface.php new file mode 100644 index 000000000..433cd4197 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterInterface.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterInterface +{ + /** + * Sets the decorated flag. + * + * @return void + */ + public function setDecorated(bool $decorated); + + /** + * Whether the output will decorate messages. + */ + public function isDecorated(): bool; + + /** + * Sets a new style. + * + * @return void + */ + public function setStyle(string $name, OutputFormatterStyleInterface $style); + + /** + * Checks if output formatter has style with specified name. + */ + public function hasStyle(string $name): bool; + + /** + * Gets style options from style with specified name. + * + * @throws \InvalidArgumentException When style isn't defined + */ + public function getStyle(string $name): OutputFormatterStyleInterface; + + /** + * Formats a message according to the given styles. + */ + public function format(?string $message): ?string; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyle.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyle.php new file mode 100644 index 000000000..21e7f5ab0 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyle.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +use Symfony\Component\Console\Color; + +/** + * Formatter style class for defining styles. + * + * @author Konstantin Kudryashov + */ +class OutputFormatterStyle implements OutputFormatterStyleInterface +{ + private Color $color; + private string $foreground; + private string $background; + private array $options; + private ?string $href = null; + private bool $handlesHrefGracefully; + + /** + * Initializes output formatter style. + * + * @param string|null $foreground The style foreground color name + * @param string|null $background The style background color name + */ + public function __construct(?string $foreground = null, ?string $background = null, array $options = []) + { + $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); + } + + /** + * @return void + */ + public function setForeground(?string $color = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); + } + + /** + * @return void + */ + public function setBackground(?string $color = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); + } + + public function setHref(string $url): void + { + $this->href = $url; + } + + /** + * @return void + */ + public function setOption(string $option) + { + $this->options[] = $option; + $this->color = new Color($this->foreground, $this->background, $this->options); + } + + /** + * @return void + */ + public function unsetOption(string $option) + { + $pos = array_search($option, $this->options); + if (false !== $pos) { + unset($this->options[$pos]); + } + + $this->color = new Color($this->foreground, $this->background, $this->options); + } + + /** + * @return void + */ + public function setOptions(array $options) + { + $this->color = new Color($this->foreground, $this->background, $this->options = $options); + } + + public function apply(string $text): string + { + $this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') + && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) + && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); + + if (null !== $this->href && $this->handlesHrefGracefully) { + $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; + } + + return $this->color->apply($text); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleInterface.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleInterface.php new file mode 100644 index 000000000..3b15098cb --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter style interface for defining styles. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterStyleInterface +{ + /** + * Sets style foreground color. + * + * @return void + */ + public function setForeground(?string $color); + + /** + * Sets style background color. + * + * @return void + */ + public function setBackground(?string $color); + + /** + * Sets some specific style option. + * + * @return void + */ + public function setOption(string $option); + + /** + * Unsets some specific style option. + * + * @return void + */ + public function unsetOption(string $option); + + /** + * Sets multiple style options at once. + * + * @return void + */ + public function setOptions(array $options); + + /** + * Applies the style to a given text. + */ + public function apply(string $text): string; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleStack.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleStack.php new file mode 100644 index 000000000..62d2ca0e7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @author Jean-François Simon + */ +class OutputFormatterStyleStack implements ResetInterface +{ + /** + * @var OutputFormatterStyleInterface[] + */ + private array $styles = []; + + private OutputFormatterStyleInterface $emptyStyle; + + public function __construct(?OutputFormatterStyleInterface $emptyStyle = null) + { + $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); + $this->reset(); + } + + /** + * Resets stack (ie. empty internal arrays). + * + * @return void + */ + public function reset() + { + $this->styles = []; + } + + /** + * Pushes a style in the stack. + * + * @return void + */ + public function push(OutputFormatterStyleInterface $style) + { + $this->styles[] = $style; + } + + /** + * Pops a style from the stack. + * + * @throws InvalidArgumentException When style tags incorrectly nested + */ + public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface + { + if (!$this->styles) { + return $this->emptyStyle; + } + + if (null === $style) { + return array_pop($this->styles); + } + + foreach (array_reverse($this->styles, true) as $index => $stackedStyle) { + if ($style->apply('') === $stackedStyle->apply('')) { + $this->styles = \array_slice($this->styles, 0, $index); + + return $stackedStyle; + } + } + + throw new InvalidArgumentException('Incorrectly nested style tag found.'); + } + + /** + * Computes current style with stacks top codes. + */ + public function getCurrent(): OutputFormatterStyleInterface + { + if (!$this->styles) { + return $this->emptyStyle; + } + + return $this->styles[\count($this->styles) - 1]; + } + + /** + * @return $this + */ + public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle): static + { + $this->emptyStyle = $emptyStyle; + + return $this; + } + + public function getEmptyStyle(): OutputFormatterStyleInterface + { + return $this->emptyStyle; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Formatter/WrappableOutputFormatterInterface.php b/lam/lib/3rdParty/composer/symfony/console/Formatter/WrappableOutputFormatterInterface.php new file mode 100644 index 000000000..746cd27e7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Formatter/WrappableOutputFormatterInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output that supports word wrapping. + * + * @author Roland Franssen + */ +interface WrappableOutputFormatterInterface extends OutputFormatterInterface +{ + /** + * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). + * + * @return string + */ + public function formatAndWrap(?string $message, int $width); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/DebugFormatterHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/DebugFormatterHelper.php new file mode 100644 index 000000000..dfdb8a82c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/DebugFormatterHelper.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Helps outputting debug information when running an external program from a command. + * + * An external program can be a Process, an HTTP request, or anything else. + * + * @author Fabien Potencier + */ +class DebugFormatterHelper extends Helper +{ + private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default']; + private array $started = []; + private int $count = -1; + + /** + * Starts a debug formatting session. + */ + public function start(string $id, string $message, string $prefix = 'RUN'): string + { + $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; + + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + } + + /** + * Adds progress to a formatting session. + */ + public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR'): string + { + $message = ''; + + if ($error) { + if (isset($this->started[$id]['out'])) { + $message .= "\n"; + unset($this->started[$id]['out']); + } + if (!isset($this->started[$id]['err'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $this->started[$id]['err'] = true; + } + + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + } else { + if (isset($this->started[$id]['err'])) { + $message .= "\n"; + unset($this->started[$id]['err']); + } + if (!isset($this->started[$id]['out'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); + $this->started[$id]['out'] = true; + } + + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + } + + return $message; + } + + /** + * Stops a formatting session. + */ + public function stop(string $id, string $message, bool $successful, string $prefix = 'RES'): string + { + $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; + + if ($successful) { + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + } + + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + + unset($this->started[$id]['out'], $this->started[$id]['err']); + + return $message; + } + + private function getBorder(string $id): string + { + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); + } + + public function getName(): string + { + return 'debug_formatter'; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/DescriptorHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/DescriptorHelper.php new file mode 100644 index 000000000..fda6779b9 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/DescriptorHelper.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Descriptor\DescriptorInterface; +use Symfony\Component\Console\Descriptor\JsonDescriptor; +use Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor; +use Symfony\Component\Console\Descriptor\TextDescriptor; +use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * This class adds helper method to describe objects in various formats. + * + * @author Jean-François Simon + */ +class DescriptorHelper extends Helper +{ + /** + * @var DescriptorInterface[] + */ + private array $descriptors = []; + + public function __construct() + { + $this + ->register('txt', new TextDescriptor()) + ->register('xml', new XmlDescriptor()) + ->register('json', new JsonDescriptor()) + ->register('md', new MarkdownDescriptor()) + ->register('rst', new ReStructuredTextDescriptor()) + ; + } + + /** + * Describes an object if supported. + * + * Available options are: + * * format: string, the output format name + * * raw_text: boolean, sets output type as raw + * + * @return void + * + * @throws InvalidArgumentException when the given format is not supported + */ + public function describe(OutputInterface $output, ?object $object, array $options = []) + { + $options = array_merge([ + 'raw_text' => false, + 'format' => 'txt', + ], $options); + + if (!isset($this->descriptors[$options['format']])) { + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); + } + + $descriptor = $this->descriptors[$options['format']]; + $descriptor->describe($output, $object, $options); + } + + /** + * Registers a descriptor. + * + * @return $this + */ + public function register(string $format, DescriptorInterface $descriptor): static + { + $this->descriptors[$format] = $descriptor; + + return $this; + } + + public function getName(): string + { + return 'descriptor'; + } + + public function getFormats(): array + { + return array_keys($this->descriptors); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/Dumper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/Dumper.php new file mode 100644 index 000000000..a3b8e3952 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/Dumper.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * @author Roland Franssen + */ +final class Dumper +{ + private OutputInterface $output; + private ?CliDumper $dumper; + private ?ClonerInterface $cloner; + private \Closure $handler; + + public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null) + { + $this->output = $output; + $this->dumper = $dumper; + $this->cloner = $cloner; + + if (class_exists(CliDumper::class)) { + $this->handler = function ($var): string { + $dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); + $dumper->setColors($this->output->isDecorated()); + + return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true)); + }; + } else { + $this->handler = fn ($var): string => match (true) { + null === $var => 'null', + true === $var => 'true', + false === $var => 'false', + \is_string($var) => '"'.$var.'"', + default => rtrim(print_r($var, true)), + }; + } + } + + public function __invoke(mixed $var): string + { + return ($this->handler)($var); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/FormatterHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/FormatterHelper.php new file mode 100644 index 000000000..3646b3d6f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/FormatterHelper.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatter; + +/** + * The Formatter class provides helpers to format messages. + * + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + */ + public function formatSection(string $section, string $message, string $style = 'info'): string + { + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); + } + + /** + * Formats a message as a block of text. + */ + public function formatBlock(string|array $messages, string $style, bool $large = false): string + { + if (!\is_array($messages)) { + $messages = [$messages]; + } + + $len = 0; + $lines = []; + foreach ($messages as $message) { + $message = OutputFormatter::escape($message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); + $len = max(self::width($message) + ($large ? 4 : 2), $len); + } + + $messages = $large ? [str_repeat(' ', $len)] : []; + for ($i = 0; isset($lines[$i]); ++$i) { + $messages[] = $lines[$i].str_repeat(' ', $len - self::width($lines[$i])); + } + if ($large) { + $messages[] = str_repeat(' ', $len); + } + + for ($i = 0; isset($messages[$i]); ++$i) { + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); + } + + return implode("\n", $messages); + } + + /** + * Truncates a message to the given length. + */ + public function truncate(string $message, int $length, string $suffix = '...'): string + { + $computedLength = $length - self::width($suffix); + + if ($computedLength > self::width($message)) { + return $message; + } + + return self::substr($message, 0, $length).$suffix; + } + + public function getName(): string + { + return 'formatter'; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/Helper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/Helper.php new file mode 100644 index 000000000..468d06689 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/Helper.php @@ -0,0 +1,180 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\String\UnicodeString; + +/** + * Helper is the base class for all helper classes. + * + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected $helperSet; + + /** + * @return void + */ + public function setHelperSet(?HelperSet $helperSet = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->helperSet = $helperSet; + } + + public function getHelperSet(): ?HelperSet + { + return $this->helperSet; + } + + /** + * Returns the width of a string, using mb_strwidth if it is available. + * The width is how many characters positions the string will use. + */ + public static function width(?string $string): int + { + $string ??= ''; + + if (preg_match('//u', $string)) { + $string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count); + + return (new UnicodeString($string))->width(false) + $count; + } + + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return \strlen($string); + } + + return mb_strwidth($string, $encoding); + } + + /** + * Returns the length of a string, using mb_strlen if it is available. + * The length is related to how many bytes the string will use. + */ + public static function length(?string $string): int + { + $string ??= ''; + + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->length(); + } + + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return \strlen($string); + } + + return mb_strlen($string, $encoding); + } + + /** + * Returns the subset of a string, using mb_substr if it is available. + */ + public static function substr(?string $string, int $from, ?int $length = null): string + { + $string ??= ''; + + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->slice($from, $length); + } + + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return substr($string, $from, $length); + } + + return mb_substr($string, $from, $length, $encoding); + } + + /** + * @return string + */ + public static function formatTime(int|float $secs, int $precision = 1) + { + $secs = (int) floor($secs); + + if (0 === $secs) { + return '< 1 sec'; + } + + static $timeFormats = [ + [1, '1 sec', 'secs'], + [60, '1 min', 'mins'], + [3600, '1 hr', 'hrs'], + [86400, '1 day', 'days'], + ]; + + $times = []; + foreach ($timeFormats as $index => $format) { + $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs; + + if (isset($times[$index - $precision])) { + unset($times[$index - $precision]); + } + + if (0 === $seconds) { + continue; + } + + $unitCount = ($seconds / $format[0]); + $times[$index] = 1 === $unitCount ? $format[1] : $unitCount.' '.$format[2]; + + if ($secs === $seconds) { + break; + } + + $secs -= $seconds; + } + + return implode(', ', array_reverse($times)); + } + + /** + * @return string + */ + public static function formatMemory(int $memory) + { + if ($memory >= 1024 * 1024 * 1024) { + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + } + + if ($memory >= 1024 * 1024) { + return \sprintf('%.1f MiB', $memory / 1024 / 1024); + } + + if ($memory >= 1024) { + return \sprintf('%d KiB', $memory / 1024); + } + + return \sprintf('%d B', $memory); + } + + /** + * @return string + */ + public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) + { + $isDecorated = $formatter->isDecorated(); + $formatter->setDecorated(false); + // remove <...> formatting + $string = $formatter->format($string ?? ''); + // remove already formatted characters + $string = preg_replace("/\033\[[^m]*m/", '', $string ?? ''); + // remove terminal hyperlinks + $string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? ''); + $formatter->setDecorated($isDecorated); + + return $string; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/HelperInterface.php b/lam/lib/3rdParty/composer/symfony/console/Helper/HelperInterface.php new file mode 100644 index 000000000..ab626c938 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/HelperInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * HelperInterface is the interface all helpers must implement. + * + * @author Fabien Potencier + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + * + * @return void + */ + public function setHelperSet(?HelperSet $helperSet); + + /** + * Gets the helper set associated with this helper. + */ + public function getHelperSet(): ?HelperSet; + + /** + * Returns the canonical name of this helper. + * + * @return string + */ + public function getName(); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/HelperSet.php b/lam/lib/3rdParty/composer/symfony/console/Helper/HelperSet.php new file mode 100644 index 000000000..8deb22ee7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/HelperSet.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @author Fabien Potencier + * + * @implements \IteratorAggregate + */ +class HelperSet implements \IteratorAggregate +{ + /** @var array */ + private array $helpers = []; + + /** + * @param HelperInterface[] $helpers + */ + public function __construct(array $helpers = []) + { + foreach ($helpers as $alias => $helper) { + $this->set($helper, \is_int($alias) ? null : $alias); + } + } + + /** + * @return void + */ + public function set(HelperInterface $helper, ?string $alias = null) + { + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) { + $this->helpers[$alias] = $helper; + } + + $helper->setHelperSet($this); + } + + /** + * Returns true if the helper if defined. + */ + public function has(string $name): bool + { + return isset($this->helpers[$name]); + } + + /** + * Gets a helper value. + * + * @throws InvalidArgumentException if the helper is not defined + */ + public function get(string $name): HelperInterface + { + if (!$this->has($name)) { + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); + } + + return $this->helpers[$name]; + } + + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->helpers); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/InputAwareHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/InputAwareHelper.php new file mode 100644 index 000000000..6f8225973 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/InputAwareHelper.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Input\InputAwareInterface; +use Symfony\Component\Console\Input\InputInterface; + +/** + * An implementation of InputAwareInterface for Helpers. + * + * @author Wouter J + */ +abstract class InputAwareHelper extends Helper implements InputAwareInterface +{ + protected $input; + + /** + * @return void + */ + public function setInput(InputInterface $input) + { + $this->input = $input; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/OutputWrapper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/OutputWrapper.php new file mode 100644 index 000000000..a615ed2f9 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/OutputWrapper.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow + * answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN). + * + * (?: + * # -- Words/Characters + * ( # (1 start) + * (?> # Atomic Group - Match words with valid breaks + * .{1,16} # 1-N characters + * # Followed by one of 4 prioritized, non-linebreak whitespace + * (?: # break types: + * (?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace + * [^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace ) + * | (?= \r? \n ) # 2. - Ahead a linebreak + * | $ # 3. - EOS + * | [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace + * ) + * ) # End atomic group + * | + * .{1,16} # No valid word breaks, just break on the N'th character + * ) # (1 end) + * (?: \r? \n )? # Optional linebreak after Words/Characters + * | + * # -- Or, Linebreak + * (?: \r? \n | $ ) # Stand alone linebreak or at EOS + * ) + * + * @author Krisztián Ferenczi + * + * @see https://stackoverflow.com/a/20434776/1476819 + */ +final class OutputWrapper +{ + private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; + private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+'; + private const URL_PATTERN = 'https?://\S+'; + + public function __construct( + private bool $allowCutUrls = false, + ) { + } + + public function wrap(string $text, int $width, string $break = "\n"): string + { + if (!$width) { + return $text; + } + + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $limitPattern = "{1,$width}"; + $patternBlocks = [$tagPattern]; + if (!$this->allowCutUrls) { + $patternBlocks[] = self::URL_PATTERN; + } + $patternBlocks[] = '.'; + $blocks = implode('|', $patternBlocks); + $rowPattern = "(?:$blocks)$limitPattern"; + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); + $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); + + return str_replace(' '.$break, $break, $output); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/ProcessHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/ProcessHelper.php new file mode 100644 index 000000000..ae55a83c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/ProcessHelper.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; + +/** + * The ProcessHelper class provides helpers to run external processes. + * + * @author Fabien Potencier + * + * @final + */ +class ProcessHelper extends Helper +{ + /** + * Runs an external process. + * + * @param array|Process $cmd An instance of Process or an array of the command and arguments + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + */ + public function run(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process + { + if (!class_exists(Process::class)) { + throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); + } + + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + $formatter = $this->getHelperSet()->get('debug_formatter'); + + if ($cmd instanceof Process) { + $cmd = [$cmd]; + } + + if (\is_string($cmd[0] ?? null)) { + $process = new Process($cmd); + $cmd = []; + } elseif (($cmd[0] ?? null) instanceof Process) { + $process = $cmd[0]; + unset($cmd[0]); + } else { + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + } + + if ($verbosity <= $output->getVerbosity()) { + $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine()))); + } + + if ($output->isDebug()) { + $callback = $this->wrapCallback($output, $process, $callback); + } + + $process->run($callback, $cmd); + + if ($verbosity <= $output->getVerbosity()) { + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); + $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); + } + + if (!$process->isSuccessful() && null !== $error) { + $output->writeln(\sprintf('%s', $this->escapeString($error))); + } + + return $process; + } + + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @param array|Process $cmd An instance of Process or a command to run + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @throws ProcessFailedException + * + * @see run() + */ + public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process + { + $process = $this->run($output, $cmd, $error, $callback); + + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + + return $process; + } + + /** + * Wraps a Process callback to add debugging output. + */ + public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + $formatter = $this->getHelperSet()->get('debug_formatter'); + + return function ($type, $buffer) use ($output, $process, $callback, $formatter) { + $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); + + if (null !== $callback) { + $callback($type, $buffer); + } + }; + } + + private function escapeString(string $str): string + { + return str_replace('<', '\\<', $str); + } + + public function getName(): string + { + return 'process'; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressBar.php b/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressBar.php new file mode 100644 index 000000000..8143acaff --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressBar.php @@ -0,0 +1,627 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Cursor; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\ConsoleSectionOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Terminal; + +/** + * The ProgressBar provides helpers to display progress output. + * + * @author Fabien Potencier + * @author Chris Jones + */ +final class ProgressBar +{ + public const FORMAT_VERBOSE = 'verbose'; + public const FORMAT_VERY_VERBOSE = 'very_verbose'; + public const FORMAT_DEBUG = 'debug'; + public const FORMAT_NORMAL = 'normal'; + + private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax'; + private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax'; + private const FORMAT_DEBUG_NOMAX = 'debug_nomax'; + private const FORMAT_NORMAL_NOMAX = 'normal_nomax'; + + private int $barWidth = 28; + private string $barChar; + private string $emptyBarChar = '-'; + private string $progressChar = '>'; + private ?string $format = null; + private ?string $internalFormat = null; + private ?int $redrawFreq = 1; + private int $writeCount = 0; + private float $lastWriteTime = 0; + private float $minSecondsBetweenRedraws = 0; + private float $maxSecondsBetweenRedraws = 1; + private OutputInterface $output; + private int $step = 0; + private int $startingStep = 0; + private ?int $max = null; + private int $startTime; + private int $stepWidth; + private float $percent = 0.0; + private array $messages = []; + private bool $overwrite = true; + private Terminal $terminal; + private ?string $previousMessage = null; + private Cursor $cursor; + private array $placeholders = []; + + private static array $formatters; + private static array $formats; + + /** + * @param int $max Maximum steps (0 if unknown) + */ + public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25) + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + $this->output = $output; + $this->setMaxSteps($max); + $this->terminal = new Terminal(); + + if (0 < $minSecondsBetweenRedraws) { + $this->redrawFreq = null; + $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws; + } + + if (!$this->output->isDecorated()) { + // disable overwrite when output does not support ANSI codes. + $this->overwrite = false; + + // set a reasonable redraw frequency so output isn't flooded + $this->redrawFreq = null; + } + + $this->startTime = time(); + $this->cursor = new Cursor($output); + } + + /** + * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar. + * + * This method also allow you to override an existing placeholder. + * + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable(ProgressBar):string $callable A PHP callable + */ + public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void + { + self::$formatters ??= self::initPlaceholderFormatters(); + + self::$formatters[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public static function getPlaceholderFormatterDefinition(string $name): ?callable + { + self::$formatters ??= self::initPlaceholderFormatters(); + + return self::$formatters[$name] ?? null; + } + + /** + * Sets a placeholder formatter for a given name, for this instance only. + * + * @param callable(ProgressBar):string $callable A PHP callable + */ + public function setPlaceholderFormatter(string $name, callable $callable): void + { + $this->placeholders[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public function getPlaceholderFormatter(string $name): ?callable + { + return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name); + } + + /** + * Sets a format for a given name. + * + * This method also allow you to override an existing format. + * + * @param string $name The format name + * @param string $format A format string + */ + public static function setFormatDefinition(string $name, string $format): void + { + self::$formats ??= self::initFormats(); + + self::$formats[$name] = $format; + } + + /** + * Gets the format for a given name. + * + * @param string $name The format name + */ + public static function getFormatDefinition(string $name): ?string + { + self::$formats ??= self::initFormats(); + + return self::$formats[$name] ?? null; + } + + /** + * Associates a text with a named placeholder. + * + * The text is displayed when the progress bar is rendered but only + * when the corresponding placeholder is part of the custom format line + * (by wrapping the name with %). + * + * @param string $message The text to associate with the placeholder + * @param string $name The name of the placeholder + */ + public function setMessage(string $message, string $name = 'message'): void + { + $this->messages[$name] = $message; + } + + public function getMessage(string $name = 'message'): ?string + { + return $this->messages[$name] ?? null; + } + + public function getStartTime(): int + { + return $this->startTime; + } + + public function getMaxSteps(): int + { + return $this->max; + } + + public function getProgress(): int + { + return $this->step; + } + + private function getStepWidth(): int + { + return $this->stepWidth; + } + + public function getProgressPercent(): float + { + return $this->percent; + } + + public function getBarOffset(): float + { + return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); + } + + public function getEstimated(): float + { + if (0 === $this->step || $this->step === $this->startingStep) { + return 0; + } + + return round((time() - $this->startTime) / ($this->step - $this->startingStep) * $this->max); + } + + public function getRemaining(): float + { + if (0 === $this->step || $this->step === $this->startingStep) { + return 0; + } + + return round((time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step)); + } + + public function setBarWidth(int $size): void + { + $this->barWidth = max(1, $size); + } + + public function getBarWidth(): int + { + return $this->barWidth; + } + + public function setBarCharacter(string $char): void + { + $this->barChar = $char; + } + + public function getBarCharacter(): string + { + return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); + } + + public function setEmptyBarCharacter(string $char): void + { + $this->emptyBarChar = $char; + } + + public function getEmptyBarCharacter(): string + { + return $this->emptyBarChar; + } + + public function setProgressCharacter(string $char): void + { + $this->progressChar = $char; + } + + public function getProgressCharacter(): string + { + return $this->progressChar; + } + + public function setFormat(string $format): void + { + $this->format = null; + $this->internalFormat = $format; + } + + /** + * Sets the redraw frequency. + * + * @param int|null $freq The frequency in steps + */ + public function setRedrawFrequency(?int $freq): void + { + $this->redrawFreq = null !== $freq ? max(1, $freq) : null; + } + + public function minSecondsBetweenRedraws(float $seconds): void + { + $this->minSecondsBetweenRedraws = $seconds; + } + + public function maxSecondsBetweenRedraws(float $seconds): void + { + $this->maxSecondsBetweenRedraws = $seconds; + } + + /** + * Returns an iterator that will automatically update the progress bar when iterated. + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable + */ + public function iterate(iterable $iterable, ?int $max = null): iterable + { + $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0)); + + foreach ($iterable as $key => $value) { + yield $key => $value; + + $this->advance(); + } + + $this->finish(); + } + + /** + * Starts the progress output. + * + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged + * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar) + */ + public function start(?int $max = null, int $startAt = 0): void + { + $this->startTime = time(); + $this->step = $startAt; + $this->startingStep = $startAt; + + $startAt > 0 ? $this->setProgress($startAt) : $this->percent = 0.0; + + if (null !== $max) { + $this->setMaxSteps($max); + } + + $this->display(); + } + + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + */ + public function advance(int $step = 1): void + { + $this->setProgress($this->step + $step); + } + + /** + * Sets whether to overwrite the progressbar, false for new line. + */ + public function setOverwrite(bool $overwrite): void + { + $this->overwrite = $overwrite; + } + + public function setProgress(int $step): void + { + if ($this->max && $step > $this->max) { + $this->max = $step; + } elseif ($step < 0) { + $step = 0; + } + + $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10); + $prevPeriod = (int) ($this->step / $redrawFreq); + $currPeriod = (int) ($step / $redrawFreq); + $this->step = $step; + $this->percent = $this->max ? (float) $this->step / $this->max : 0; + $timeInterval = microtime(true) - $this->lastWriteTime; + + // Draw regardless of other limits + if ($this->max === $step) { + $this->display(); + + return; + } + + // Throttling + if ($timeInterval < $this->minSecondsBetweenRedraws) { + return; + } + + // Draw each step period, but not too late + if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) { + $this->display(); + } + } + + public function setMaxSteps(int $max): void + { + $this->format = null; + $this->max = max(0, $max); + $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; + } + + /** + * Finishes the progress output. + */ + public function finish(): void + { + if (!$this->max) { + $this->max = $this->step; + } + + if ($this->step === $this->max && !$this->overwrite) { + // prevent double 100% output + return; + } + + $this->setProgress($this->max); + } + + /** + * Outputs the current progress string. + */ + public function display(): void + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + + $this->overwrite($this->buildLine()); + } + + /** + * Removes the progress bar from the current line. + * + * This is useful if you wish to write some output + * while a progress bar is running. + * Call display() to show the progress bar again. + */ + public function clear(): void + { + if (!$this->overwrite) { + return; + } + + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + + $this->overwrite(''); + } + + private function setRealFormat(string $format): void + { + // try to use the _nomax variant if available + if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) { + $this->format = self::getFormatDefinition($format.'_nomax'); + } elseif (null !== self::getFormatDefinition($format)) { + $this->format = self::getFormatDefinition($format); + } else { + $this->format = $format; + } + } + + /** + * Overwrites a previous message to the output. + */ + private function overwrite(string $message): void + { + if ($this->previousMessage === $message) { + return; + } + + $originalMessage = $message; + + if ($this->overwrite) { + if (null !== $this->previousMessage) { + if ($this->output instanceof ConsoleSectionOutput) { + $messageLines = explode("\n", $this->previousMessage); + $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + + foreach ($messageLines as $messageLine) { + $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); + if ($messageLineLength > $this->terminal->getWidth()) { + $lineCount += floor($messageLineLength / $this->terminal->getWidth()); + } + } + + $this->output->clear($lineCount); + } else { + $lineCount = substr_count($this->previousMessage, "\n"); + for ($i = 0; $i < $lineCount; ++$i) { + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + $this->cursor->moveUp(); + } + + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + } + } + } elseif ($this->step > 0) { + $message = \PHP_EOL.$message; + } + + $this->previousMessage = $originalMessage; + $this->lastWriteTime = microtime(true); + + $this->output->write($message); + ++$this->writeCount; + } + + private function determineBestFormat(): string + { + return match ($this->output->getVerbosity()) { + // OutputInterface::VERBOSITY_QUIET: display is disabled anyway + OutputInterface::VERBOSITY_VERBOSE => $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX, + OutputInterface::VERBOSITY_VERY_VERBOSE => $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX, + OutputInterface::VERBOSITY_DEBUG => $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX, + default => $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX, + }; + } + + private static function initPlaceholderFormatters(): array + { + return [ + 'bar' => function (self $bar, OutputInterface $output) { + $completeBars = $bar->getBarOffset(); + $display = str_repeat($bar->getBarCharacter(), $completeBars); + if ($completeBars < $bar->getBarWidth()) { + $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); + $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars); + } + + return $display; + }, + 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2), + 'remaining' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); + } + + return Helper::formatTime($bar->getRemaining(), 2); + }, + 'estimated' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); + } + + return Helper::formatTime($bar->getEstimated(), 2); + }, + 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), + 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), + 'max' => fn (self $bar) => $bar->getMaxSteps(), + 'percent' => fn (self $bar) => floor($bar->getProgressPercent() * 100), + ]; + } + + private static function initFormats(): array + { + return [ + self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', + self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', + + self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', + self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', + + self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', + self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', + + self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', + self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%', + ]; + } + + private function buildLine(): string + { + \assert(null !== $this->format); + + $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; + $callback = function ($matches) { + if ($formatter = $this->getPlaceholderFormatter($matches[1])) { + $text = $formatter($this, $this->output); + } elseif (isset($this->messages[$matches[1]])) { + $text = $this->messages[$matches[1]]; + } else { + return $matches[0]; + } + + if (isset($matches[2])) { + $text = \sprintf('%'.$matches[2], $text); + } + + return $text; + }; + $line = preg_replace_callback($regex, $callback, $this->format); + + // gets string length for each sub line with multiline format + $linesLength = array_map(fn ($subLine) => Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))), explode("\n", $line)); + + $linesWidth = max($linesLength); + + $terminalWidth = $this->terminal->getWidth(); + if ($linesWidth <= $terminalWidth) { + return $line; + } + + $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); + + return preg_replace_callback($regex, $callback, $this->format); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressIndicator.php b/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressIndicator.php new file mode 100644 index 000000000..92106caf6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/ProgressIndicator.php @@ -0,0 +1,235 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Kevin Bond + */ +class ProgressIndicator +{ + private const FORMATS = [ + 'normal' => ' %indicator% %message%', + 'normal_no_ansi' => ' %message%', + + 'verbose' => ' %indicator% %message% (%elapsed:6s%)', + 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', + + 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', + 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)', + ]; + + private OutputInterface $output; + private int $startTime; + private ?string $format = null; + private ?string $message = null; + private array $indicatorValues; + private int $indicatorCurrent; + private int $indicatorChangeInterval; + private float $indicatorUpdateTime; + private bool $started = false; + + /** + * @var array + */ + private static array $formatters; + + /** + * @param int $indicatorChangeInterval Change interval in milliseconds + * @param array|null $indicatorValues Animated indicator characters + */ + public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null) + { + $this->output = $output; + + $format ??= $this->determineBestFormat(); + $indicatorValues ??= ['-', '\\', '|', '/']; + $indicatorValues = array_values($indicatorValues); + + if (2 > \count($indicatorValues)) { + throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); + } + + $this->format = self::getFormatDefinition($format); + $this->indicatorChangeInterval = $indicatorChangeInterval; + $this->indicatorValues = $indicatorValues; + $this->startTime = time(); + } + + /** + * Sets the current indicator message. + * + * @return void + */ + public function setMessage(?string $message) + { + $this->message = $message; + + $this->display(); + } + + /** + * Starts the indicator output. + * + * @return void + */ + public function start(string $message) + { + if ($this->started) { + throw new LogicException('Progress indicator already started.'); + } + + $this->message = $message; + $this->started = true; + $this->startTime = time(); + $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; + $this->indicatorCurrent = 0; + + $this->display(); + } + + /** + * Advances the indicator. + * + * @return void + */ + public function advance() + { + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + + if (!$this->output->isDecorated()) { + return; + } + + $currentTime = $this->getCurrentTimeInMilliseconds(); + + if ($currentTime < $this->indicatorUpdateTime) { + return; + } + + $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval; + ++$this->indicatorCurrent; + + $this->display(); + } + + /** + * Finish the indicator with message. + * + * @return void + */ + public function finish(string $message) + { + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + + $this->message = $message; + $this->display(); + $this->output->writeln(''); + $this->started = false; + } + + /** + * Gets the format for a given name. + */ + public static function getFormatDefinition(string $name): ?string + { + return self::FORMATS[$name] ?? null; + } + + /** + * Sets a placeholder formatter for a given name. + * + * This method also allow you to override an existing placeholder. + * + * @return void + */ + public static function setPlaceholderFormatterDefinition(string $name, callable $callable) + { + self::$formatters ??= self::initPlaceholderFormatters(); + + self::$formatters[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name (including the delimiter char like %). + */ + public static function getPlaceholderFormatterDefinition(string $name): ?callable + { + self::$formatters ??= self::initPlaceholderFormatters(); + + return self::$formatters[$name] ?? null; + } + + private function display(): void + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + + $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { + if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { + return $formatter($this); + } + + return $matches[0]; + }, $this->format ?? '')); + } + + private function determineBestFormat(): string + { + return match ($this->output->getVerbosity()) { + // OutputInterface::VERBOSITY_QUIET: display is disabled anyway + OutputInterface::VERBOSITY_VERBOSE => $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi', + OutputInterface::VERBOSITY_VERY_VERBOSE, + OutputInterface::VERBOSITY_DEBUG => $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi', + default => $this->output->isDecorated() ? 'normal' : 'normal_no_ansi', + }; + } + + /** + * Overwrites a previous message to the output. + */ + private function overwrite(string $message): void + { + if ($this->output->isDecorated()) { + $this->output->write("\x0D\x1B[2K"); + $this->output->write($message); + } else { + $this->output->writeln($message); + } + } + + private function getCurrentTimeInMilliseconds(): float + { + return round(microtime(true) * 1000); + } + + /** + * @return array + */ + private static function initPlaceholderFormatters(): array + { + return [ + 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], + 'message' => fn (self $indicator) => $indicator->message, + 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime, 2), + 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), + ]; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/QuestionHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/QuestionHelper.php new file mode 100644 index 000000000..593b01b39 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/QuestionHelper.php @@ -0,0 +1,604 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Cursor; +use Symfony\Component\Console\Exception\MissingInputException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StreamableInputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\ConsoleSectionOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Terminal; + +use function Symfony\Component\String\s; + +/** + * The QuestionHelper class provides helpers to interact with the user. + * + * @author Fabien Potencier + */ +class QuestionHelper extends Helper +{ + /** + * @var resource|null + */ + private $inputStream; + + private static bool $stty = true; + private static bool $stdinIsInteractive; + + /** + * Asks a question to the user. + * + * @return mixed The user answer + * + * @throws RuntimeException If there is no data to read in the input stream + */ + public function ask(InputInterface $input, OutputInterface $output, Question $question): mixed + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + if (!$input->isInteractive()) { + return $this->getDefaultAnswer($question); + } + + if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { + $this->inputStream = $stream; + } + + try { + if (!$question->getValidator()) { + return $this->doAsk($output, $question); + } + + $interviewer = fn () => $this->doAsk($output, $question); + + return $this->validateAttempts($interviewer, $output, $question); + } catch (MissingInputException $exception) { + $input->setInteractive(false); + + if (null === $fallbackOutput = $this->getDefaultAnswer($question)) { + throw $exception; + } + + return $fallbackOutput; + } + } + + public function getName(): string + { + return 'question'; + } + + /** + * Prevents usage of stty. + * + * @return void + */ + public static function disableStty() + { + self::$stty = false; + } + + /** + * Asks the question to the user. + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function doAsk(OutputInterface $output, Question $question): mixed + { + $this->writePrompt($output, $question); + + $inputStream = $this->inputStream ?: \STDIN; + $autocomplete = $question->getAutocompleterCallback(); + + if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { + $ret = false; + if ($question->isHidden()) { + try { + $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable()); + $ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse; + } catch (RuntimeException $e) { + if (!$question->isHiddenFallback()) { + throw $e; + } + } + } + + if (false === $ret) { + $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true; + + if (!$isBlocked) { + stream_set_blocking($inputStream, true); + } + + $ret = $this->readInput($inputStream, $question); + + if (!$isBlocked) { + stream_set_blocking($inputStream, false); + } + + if (false === $ret) { + throw new MissingInputException('Aborted.'); + } + if ($question->isTrimmable()) { + $ret = trim($ret); + } + } + } else { + $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete); + $ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete; + } + + if ($output instanceof ConsoleSectionOutput) { + $output->addContent(''); // add EOL to the question + $output->addContent($ret); + } + + $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); + + if ($normalizer = $question->getNormalizer()) { + return $normalizer($ret); + } + + return $ret; + } + + private function getDefaultAnswer(Question $question): mixed + { + $default = $question->getDefault(); + + if (null === $default) { + return $default; + } + + if ($validator = $question->getValidator()) { + return \call_user_func($validator, $default); + } elseif ($question instanceof ChoiceQuestion) { + $choices = $question->getChoices(); + + if (!$question->isMultiselect()) { + return $choices[$default] ?? $default; + } + + $default = explode(',', $default); + foreach ($default as $k => $v) { + $v = $question->isTrimmable() ? trim($v) : $v; + $default[$k] = $choices[$v] ?? $v; + } + } + + return $default; + } + + /** + * Outputs the question prompt. + * + * @return void + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $message = $question->getQuestion(); + + if ($question instanceof ChoiceQuestion) { + $output->writeln(array_merge([ + $question->getQuestion(), + ], $this->formatChoiceQuestionChoices($question, 'info'))); + + $message = $question->getPrompt(); + } + + $output->write($message); + } + + /** + * @return string[] + */ + protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag): array + { + $messages = []; + + $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices()))); + + foreach ($choices as $key => $value) { + $padding = str_repeat(' ', $maxWidth - self::width($key)); + + $messages[] = \sprintf(" [<$tag>%s$padding] %s", $key, $value); + } + + return $messages; + } + + /** + * Outputs an error message. + * + * @return void + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { + $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); + } else { + $message = ''.$error->getMessage().''; + } + + $output->writeln($message); + } + + /** + * Autocompletes a question. + * + * @param resource $inputStream + */ + private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string + { + $cursor = new Cursor($output, $inputStream); + + $fullChoice = ''; + $ret = ''; + + $i = 0; + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + + $sttyMode = shell_exec('stty -g'); + $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null); + $r = [$inputStream]; + $w = []; + + // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) + shell_exec('stty -icanon -echo'); + + // Add highlighted text style + $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); + + // Read a keypress + while (!feof($inputStream)) { + while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) { + // Give signal handlers a chance to run + $r = [$inputStream]; + } + $c = fread($inputStream, 1); + + // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. + if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { + shell_exec('stty '.$sttyMode); + throw new MissingInputException('Aborted.'); + } elseif ("\177" === $c) { // Backspace Character + if (0 === $numMatches && 0 !== $i) { + --$i; + $cursor->moveLeft(s($fullChoice)->slice(-1)->width(false)); + + $fullChoice = self::substr($fullChoice, 0, $i); + } + + if (0 === $i) { + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + } else { + $numMatches = 0; + } + + // Pop the last character off the end of our string + $ret = self::substr($ret, 0, $i); + } elseif ("\033" === $c) { + // Did we read an escape sequence? + $c .= fread($inputStream, 2); + + // A = Up Arrow. B = Down Arrow + if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { + if ('A' === $c[2] && -1 === $ofs) { + $ofs = 0; + } + + if (0 === $numMatches) { + continue; + } + + $ofs += ('A' === $c[2]) ? -1 : 1; + $ofs = ($numMatches + $ofs) % $numMatches; + } + } elseif (\ord($c) < 32) { + if ("\t" === $c || "\n" === $c) { + if ($numMatches > 0 && -1 !== $ofs) { + $ret = (string) $matches[$ofs]; + // Echo out remaining chars for current match + $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); + $output->write($remainingCharacters); + $fullChoice .= $remainingCharacters; + $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding); + + $matches = array_filter( + $autocomplete($ret), + fn ($match) => '' === $ret || str_starts_with($match, $ret) + ); + $numMatches = \count($matches); + $ofs = -1; + } + + if ("\n" === $c) { + $output->write($c); + break; + } + + $numMatches = 0; + } + + continue; + } else { + if ("\x80" <= $c) { + $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]); + } + + $output->write($c); + $ret .= $c; + $fullChoice .= $c; + ++$i; + + $tempRet = $ret; + + if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { + $tempRet = $this->mostRecentlyEnteredValue($fullChoice); + } + + $numMatches = 0; + $ofs = 0; + + foreach ($autocomplete($ret) as $value) { + // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) + if (str_starts_with($value, $tempRet)) { + $matches[$numMatches++] = $value; + } + } + } + + $cursor->clearLineAfter(); + + if ($numMatches > 0 && -1 !== $ofs) { + $cursor->savePosition(); + // Write highlighted text, complete the partially entered response + $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))); + $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); + $cursor->restorePosition(); + } + } + + // Reset stty so it behaves normally again + shell_exec('stty '.$sttyMode); + + return $fullChoice; + } + + private function mostRecentlyEnteredValue(string $entered): string + { + // Determine the most recent value that the user entered + if (!str_contains($entered, ',')) { + return $entered; + } + + $choices = explode(',', $entered); + if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) { + return $lastChoice; + } + + return $entered; + } + + /** + * Gets a hidden response from user. + * + * @param resource $inputStream The handler resource + * @param bool $trimmable Is the answer trimmable + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; + + // handle code running from a phar + if (str_starts_with(__FILE__, 'phar:')) { + $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; + copy($exe, $tmpExe); + $exe = $tmpExe; + } + + $sExec = shell_exec('"'.$exe.'"'); + $value = $trimmable ? rtrim($sExec) : $sExec; + $output->writeln(''); + + if (isset($tmpExe)) { + unlink($tmpExe); + } + + return $value; + } + + if (self::$stty && Terminal::hasSttyAvailable()) { + $sttyMode = shell_exec('stty -g'); + shell_exec('stty -echo'); + } elseif ($this->isInteractiveInput($inputStream)) { + throw new RuntimeException('Unable to hide the response.'); + } + + $value = fgets($inputStream, 4096); + + if (4095 === \strlen($value)) { + $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output; + $errOutput->warning('The value was possibly truncated by your shell or terminal emulator'); + } + + if (self::$stty && Terminal::hasSttyAvailable()) { + shell_exec('stty '.$sttyMode); + } + + if (false === $value) { + throw new MissingInputException('Aborted.'); + } + if ($trimmable) { + $value = trim($value); + } + $output->writeln(''); + + return $value; + } + + /** + * Validates an attempt. + * + * @param callable $interviewer A callable that will ask for a question and return the result + * + * @throws \Exception In case the max number of attempts has been reached and no valid response has been given + */ + private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question): mixed + { + $error = null; + $attempts = $question->getMaxAttempts(); + + while (null === $attempts || $attempts--) { + if (null !== $error) { + $this->writeError($output, $error); + } + + try { + return $question->getValidator()($interviewer()); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $error) { + } + } + + throw $error; + } + + private function isInteractiveInput($inputStream): bool + { + if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) { + return false; + } + + if (isset(self::$stdinIsInteractive)) { + return self::$stdinIsInteractive; + } + + return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); + } + + /** + * Reads one or more lines of input and returns what is read. + * + * @param resource $inputStream The handler resource + * @param Question $question The question being asked + */ + private function readInput($inputStream, Question $question): string|false + { + if (!$question->isMultiline()) { + $cp = $this->setIOCodepage(); + $ret = fgets($inputStream, 4096); + + return $this->resetIOCodepage($cp, $ret); + } + + $multiLineStreamReader = $this->cloneInputStream($inputStream); + if (null === $multiLineStreamReader) { + return false; + } + + $ret = ''; + $cp = $this->setIOCodepage(); + while (false !== ($char = fgetc($multiLineStreamReader))) { + if ("\x4" === $char || \PHP_EOL === "{$ret}{$char}") { + break; + } + $ret .= $char; + } + + if (stream_get_meta_data($inputStream)['seekable']) { + fseek($inputStream, ftell($multiLineStreamReader)); + } + + return $this->resetIOCodepage($cp, $ret); + } + + private function setIOCodepage(): int + { + if (\function_exists('sapi_windows_cp_set')) { + $cp = sapi_windows_cp_get(); + sapi_windows_cp_set(sapi_windows_cp_get('oem')); + + return $cp; + } + + return 0; + } + + /** + * Sets console I/O to the specified code page and converts the user input. + */ + private function resetIOCodepage(int $cp, string|false $input): string|false + { + if (0 !== $cp) { + sapi_windows_cp_set($cp); + + if (false !== $input && '' !== $input) { + $input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input); + } + } + + return $input; + } + + /** + * Clones an input stream in order to act on one instance of the same + * stream without affecting the other instance. + * + * @param resource $inputStream The handler resource + * + * @return resource|null The cloned resource, null in case it could not be cloned + */ + private function cloneInputStream($inputStream) + { + $streamMetaData = stream_get_meta_data($inputStream); + $seekable = $streamMetaData['seekable'] ?? false; + $mode = $streamMetaData['mode'] ?? 'rb'; + $uri = $streamMetaData['uri'] ?? null; + + if (null === $uri) { + return null; + } + + $cloneStream = fopen($uri, $mode); + + // For seekable and writable streams, add all the same data to the + // cloned stream and then seek to the same offset. + if (true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) { + $offset = ftell($inputStream); + rewind($inputStream); + stream_copy_to_stream($inputStream, $cloneStream); + fseek($inputStream, $offset); + fseek($cloneStream, $offset); + } + + return $cloneStream; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/SymfonyQuestionHelper.php b/lam/lib/3rdParty/composer/symfony/console/Helper/SymfonyQuestionHelper.php new file mode 100644 index 000000000..11b4e4238 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/SymfonyQuestionHelper.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * Symfony Style Guide compliant question helper. + * + * @author Kevin Bond + */ +class SymfonyQuestionHelper extends QuestionHelper +{ + /** + * @return void + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); + $default = $question->getDefault(); + + if ($question->isMultiline()) { + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); + } + + switch (true) { + case null === $default: + $text = \sprintf(' %s:', $text); + + break; + + case $question instanceof ConfirmationQuestion: + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + + break; + + case $question instanceof ChoiceQuestion && $question->isMultiselect(): + $choices = $question->getChoices(); + $default = explode(',', $default); + + foreach ($default as $key => $value) { + $default[$key] = $choices[trim($value)]; + } + + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + + break; + + case $question instanceof ChoiceQuestion: + $choices = $question->getChoices(); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + + break; + + default: + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + } + + $output->writeln($text); + + $prompt = ' > '; + + if ($question instanceof ChoiceQuestion) { + $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); + + $prompt = $question->getPrompt(); + } + + $output->write($prompt); + } + + /** + * @return void + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if ($output instanceof SymfonyStyle) { + $output->newLine(); + $output->error($error->getMessage()); + + return; + } + + parent::writeError($output, $error); + } + + private function getEofShortcut(): string + { + if ('Windows' === \PHP_OS_FAMILY) { + return 'Ctrl+Z then Enter'; + } + + return 'Ctrl+D'; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/Table.php b/lam/lib/3rdParty/composer/symfony/console/Helper/Table.php new file mode 100644 index 000000000..469d228d6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/Table.php @@ -0,0 +1,967 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; +use Symfony\Component\Console\Output\ConsoleSectionOutput; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Provides helpers to display a table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Abdellatif Ait boudad + * @author Max Grigorian + * @author Dany Maillard + */ +class Table +{ + private const SEPARATOR_TOP = 0; + private const SEPARATOR_TOP_BOTTOM = 1; + private const SEPARATOR_MID = 2; + private const SEPARATOR_BOTTOM = 3; + private const BORDER_OUTSIDE = 0; + private const BORDER_INSIDE = 1; + private const DISPLAY_ORIENTATION_DEFAULT = 'default'; + private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal'; + private const DISPLAY_ORIENTATION_VERTICAL = 'vertical'; + + private ?string $headerTitle = null; + private ?string $footerTitle = null; + private array $headers = []; + private array $rows = []; + private array $effectiveColumnWidths = []; + private int $numberOfColumns; + private OutputInterface $output; + private TableStyle $style; + private array $columnStyles = []; + private array $columnWidths = []; + private array $columnMaxWidths = []; + private bool $rendered = false; + private string $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT; + + private static array $styles; + + public function __construct(OutputInterface $output) + { + $this->output = $output; + + self::$styles ??= self::initStyles(); + + $this->setStyle('default'); + } + + /** + * Sets a style definition. + * + * @return void + */ + public static function setStyleDefinition(string $name, TableStyle $style) + { + self::$styles ??= self::initStyles(); + + self::$styles[$name] = $style; + } + + /** + * Gets a style definition by name. + */ + public static function getStyleDefinition(string $name): TableStyle + { + self::$styles ??= self::initStyles(); + + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + } + + /** + * Sets table style. + * + * @return $this + */ + public function setStyle(TableStyle|string $name): static + { + $this->style = $this->resolveStyle($name); + + return $this; + } + + /** + * Gets the current table style. + */ + public function getStyle(): TableStyle + { + return $this->style; + } + + /** + * Sets table column style. + * + * @param TableStyle|string $name The style name or a TableStyle instance + * + * @return $this + */ + public function setColumnStyle(int $columnIndex, TableStyle|string $name): static + { + $this->columnStyles[$columnIndex] = $this->resolveStyle($name); + + return $this; + } + + /** + * Gets the current style for a column. + * + * If style was not set, it returns the global table style. + */ + public function getColumnStyle(int $columnIndex): TableStyle + { + return $this->columnStyles[$columnIndex] ?? $this->getStyle(); + } + + /** + * Sets the minimum width of a column. + * + * @return $this + */ + public function setColumnWidth(int $columnIndex, int $width): static + { + $this->columnWidths[$columnIndex] = $width; + + return $this; + } + + /** + * Sets the minimum width of all columns. + * + * @return $this + */ + public function setColumnWidths(array $widths): static + { + $this->columnWidths = []; + foreach ($widths as $index => $width) { + $this->setColumnWidth($index, $width); + } + + return $this; + } + + /** + * Sets the maximum width of a column. + * + * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while + * formatted strings are preserved. + * + * @return $this + */ + public function setColumnMaxWidth(int $columnIndex, int $width): static + { + if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); + } + + $this->columnMaxWidths[$columnIndex] = $width; + + return $this; + } + + /** + * @return $this + */ + public function setHeaders(array $headers): static + { + $headers = array_values($headers); + if ($headers && !\is_array($headers[0])) { + $headers = [$headers]; + } + + $this->headers = $headers; + + return $this; + } + + /** + * @return $this + */ + public function setRows(array $rows) + { + $this->rows = []; + + return $this->addRows($rows); + } + + /** + * @return $this + */ + public function addRows(array $rows): static + { + foreach ($rows as $row) { + $this->addRow($row); + } + + return $this; + } + + /** + * @return $this + */ + public function addRow(TableSeparator|array $row): static + { + if ($row instanceof TableSeparator) { + $this->rows[] = $row; + + return $this; + } + + $this->rows[] = array_values($row); + + return $this; + } + + /** + * Adds a row to the table, and re-renders the table. + * + * @return $this + */ + public function appendRow(TableSeparator|array $row): static + { + if (!$this->output instanceof ConsoleSectionOutput) { + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + } + + if ($this->rendered) { + $this->output->clear($this->calculateRowCount()); + } + + $this->addRow($row); + $this->render(); + + return $this; + } + + /** + * @return $this + */ + public function setRow(int|string $column, array $row): static + { + $this->rows[$column] = $row; + + return $this; + } + + /** + * @return $this + */ + public function setHeaderTitle(?string $title): static + { + $this->headerTitle = $title; + + return $this; + } + + /** + * @return $this + */ + public function setFooterTitle(?string $title): static + { + $this->footerTitle = $title; + + return $this; + } + + /** + * @return $this + */ + public function setHorizontal(bool $horizontal = true): static + { + $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT; + + return $this; + } + + /** + * @return $this + */ + public function setVertical(bool $vertical = true): static + { + $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT; + + return $this; + } + + /** + * Renders table to output. + * + * Example: + * + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + * + * @return void + */ + public function render() + { + $divider = new TableSeparator(); + $isCellWithColspan = static fn ($cell) => $cell instanceof TableCell && $cell->getColspan() >= 2; + + $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation; + $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation; + + $rows = []; + if ($horizontal) { + foreach ($this->headers[0] ?? [] as $i => $header) { + $rows[$i] = [$header]; + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + if (isset($row[$i])) { + $rows[$i][] = $row[$i]; + } elseif ($isCellWithColspan($rows[$i][0])) { + // Noop, there is a "title" + } else { + $rows[$i][] = null; + } + } + } + } elseif ($vertical) { + $formatter = $this->output->getFormatter(); + $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn ($max, $header) => max($max, Helper::width(Helper::removeDecoration($formatter, $header))), 0); + + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + if ($rows) { + $rows[] = [$divider]; + } + + $containsColspan = false; + foreach ($row as $cell) { + if ($containsColspan = $isCellWithColspan($cell)) { + break; + } + } + + $headers = $this->headers[0] ?? []; + $maxRows = max(\count($headers), \count($row)); + for ($i = 0; $i < $maxRows; ++$i) { + $cell = (string) ($row[$i] ?? ''); + + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $parts = explode($eol, $cell); + foreach ($parts as $idx => $part) { + if ($headers && !$containsColspan) { + if (0 === $idx) { + $rows[] = [\sprintf( + '%s%s: %s', + str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), + $headers[$i] ?? '', + $part + )]; + } else { + $rows[] = [\sprintf( + '%s %s', + str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $part + )]; + } + } elseif ('' !== $cell) { + $rows[] = [$part]; + } + } + } + } + } else { + $rows = array_merge($this->headers, [$divider], $this->rows); + } + + $this->calculateNumberOfColumns($rows); + + $rowGroups = $this->buildTableRows($rows); + $this->calculateColumnsWidth($rowGroups); + + $isHeader = !$horizontal; + $isFirstRow = $horizontal; + $hasTitle = (bool) $this->headerTitle; + + foreach ($rowGroups as $rowGroup) { + $isHeaderSeparatorRendered = false; + + foreach ($rowGroup as $row) { + if ($divider === $row) { + $isHeader = false; + $isFirstRow = true; + + continue; + } + + if ($row instanceof TableSeparator) { + $this->renderRowSeparator(); + + continue; + } + + if (!$row) { + continue; + } + + if ($isHeader && !$isHeaderSeparatorRendered) { + $this->renderRowSeparator( + self::SEPARATOR_TOP, + $hasTitle ? $this->headerTitle : null, + $hasTitle ? $this->style->getHeaderTitleFormat() : null + ); + $hasTitle = false; + $isHeaderSeparatorRendered = true; + } + + if ($isFirstRow) { + $this->renderRowSeparator( + $horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, + $hasTitle ? $this->headerTitle : null, + $hasTitle ? $this->style->getHeaderTitleFormat() : null + ); + $isFirstRow = false; + $hasTitle = false; + } + + if ($vertical) { + $isHeader = false; + $isFirstRow = false; + } + + if ($horizontal) { + $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); + } else { + $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); + } + } + } + $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); + + $this->cleanup(); + $this->rendered = true; + } + + /** + * Renders horizontal header separator. + * + * Example: + * + * +-----+-----------+-------+ + */ + private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null): void + { + if (!$count = $this->numberOfColumns) { + return; + } + + $borders = $this->style->getBorderChars(); + if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { + return; + } + + $crossings = $this->style->getCrossingChars(); + if (self::SEPARATOR_MID === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; + } elseif (self::SEPARATOR_TOP === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; + } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; + } else { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; + } + + $markup = $leftChar; + for ($column = 0; $column < $count; ++$column) { + $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]); + $markup .= $column === $count - 1 ? $rightChar : $midChar; + } + + if (null !== $title) { + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); + $markupLength = Helper::width($markup); + if ($titleLength > $limit = $markupLength - 4) { + $titleLength = $limit; + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + } + + $titleStart = intdiv($markupLength - $titleLength, 2); + if (false === mb_detect_encoding($markup, null, true)) { + $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength); + } else { + $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength); + } + } + + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); + } + + /** + * Renders vertical column separator. + */ + private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string + { + $borders = $this->style->getBorderChars(); + + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + } + + /** + * Renders table row. + * + * Example: + * + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + */ + private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null): void + { + $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); + $columns = $this->getRowColumns($row); + $last = \count($columns) - 1; + foreach ($columns as $i => $column) { + if ($firstCellFormat && 0 === $i) { + $rowContent .= $this->renderCell($row, $column, $firstCellFormat); + } else { + $rowContent .= $this->renderCell($row, $column, $cellFormat); + } + $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); + } + $this->output->writeln($rowContent); + } + + /** + * Renders table cell with padding. + */ + private function renderCell(array $row, int $column, string $cellFormat): string + { + $cell = $row[$column] ?? ''; + $width = $this->effectiveColumnWidths[$column]; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // add the width of the following columns(numbers of colspan). + foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { + $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; + } + } + + // str_pad won't work properly with multi-byte strings, we need to fix the padding + $width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0"); + $style = $this->getColumnStyle($column); + + if ($cell instanceof TableSeparator) { + return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); + } + + $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); + $content = \sprintf($style->getCellRowContentFormat(), $cell); + + $padType = $style->getPadType(); + if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { + $isNotStyledByTag = !preg_match('/^<(\w+|(\w+=[\w,]+;?)*)>.+<\/(\w+|(\w+=\w+;?)*)?>$/', $cell); + if ($isNotStyledByTag) { + $cellFormat = $cell->getStyle()->getCellFormat(); + if (!\is_string($cellFormat)) { + $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';'); + $cellFormat = '<'.$tag.'>%s'; + } + + if (str_contains($content, '')) { + $content = str_replace('', '', $content); + $width -= 3; + } + if (str_contains($content, '')) { + $content = str_replace('', '', $content); + $width -= \strlen(''); + } + } + + $padType = $cell->getStyle()->getPadByAlign(); + } + + return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); + } + + /** + * Calculate number of columns for this table. + */ + private function calculateNumberOfColumns(array $rows): void + { + $columns = [0]; + foreach ($rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + $columns[] = $this->getNumberOfColumns($row); + } + + $this->numberOfColumns = max($columns); + } + + private function buildTableRows(array $rows): TableRows + { + /** @var WrappableOutputFormatterInterface $formatter */ + $formatter = $this->output->getFormatter(); + $unmergedRows = []; + for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { + $rows = $this->fillNextRows($rows, $rowKey); + + // Remove any new line breaks and replace it with a new line + foreach ($rows[$rowKey] as $column => $cell) { + $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; + + $minWrappedWidth = 0; + $widthApplied = []; + $lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2; + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($this->columnMaxWidths[$i])) { + $minWrappedWidth += $this->columnMaxWidths[$i]; + $widthApplied[] = ['type' => 'max', 'column' => $i]; + } elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) { + $minWrappedWidth += $this->columnWidths[$i]; + $widthApplied[] = ['type' => 'min', 'column' => $i]; + } + } + if (1 === \count($widthApplied)) { + if ($colspan > 1) { + $minWrappedWidth *= $colspan; // previous logic + } + } elseif (\count($widthApplied) > 1) { + $minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder; + } + + $cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell)); + if ($minWrappedWidth && $cellWidth > $minWrappedWidth) { + $cell = $formatter->formatAndWrap($cell, $minWrappedWidth); + } + // update minimal columnWidths for spanned columns + if ($colspan > 1 && $minWrappedWidth > 0) { + $columnsMinWidthProcessed = []; + $cellWidth = min($cellWidth, $minWrappedWidth); + foreach ($widthApplied as $item) { + if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) { + $minWidthColumn = $this->columnMaxWidths[$item['column']]; + $this->columnWidths[$item['column']] = $minWidthColumn; + $columnsMinWidthProcessed[$item['column']] = true; + $cellWidth -= $minWidthColumn + $lengthColumnBorder; + } + } + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($columnsMinWidthProcessed[$i])) { + continue; + } + $this->columnWidths[$i] = $cellWidth + $lengthColumnBorder; + } + } + if (!str_contains($cell ?? '', "\n")) { + continue; + } + $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n"; + $escaped = implode($eol, array_map(OutputFormatter::escapeTrailingBackslash(...), explode($eol, $cell))); + $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; + $lines = explode($eol, str_replace($eol, ''.$eol, $cell)); + foreach ($lines as $lineKey => $line) { + if ($colspan > 1) { + $line = new TableCell($line, ['colspan' => $colspan]); + } + if (0 === $lineKey) { + $rows[$rowKey][$column] = $line; + } else { + if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { + $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); + } + $unmergedRows[$rowKey][$lineKey][$column] = $line; + } + } + } + } + + return new TableRows(function () use ($rows, $unmergedRows): \Traversable { + foreach ($rows as $rowKey => $row) { + $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)]; + + if (isset($unmergedRows[$rowKey])) { + foreach ($unmergedRows[$rowKey] as $row) { + $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row); + } + } + yield $rowGroup; + } + }); + } + + private function calculateRowCount(): int + { + $numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows)))); + + if ($this->headers) { + ++$numberOfRows; // Add row for header separator + } + + if ($this->rows) { + ++$numberOfRows; // Add row for footer separator + } + + return $numberOfRows; + } + + /** + * fill rows that contains rowspan > 1. + * + * @throws InvalidArgumentException + */ + private function fillNextRows(array $rows, int $line): array + { + $unmergedRows = []; + foreach ($rows[$line] as $column => $cell) { + if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); + } + if ($cell instanceof TableCell && $cell->getRowspan() > 1) { + $nbLines = $cell->getRowspan() - 1; + $lines = [$cell]; + if (str_contains($cell, "\n")) { + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $lines = explode($eol, str_replace($eol, ''.$eol.'', $cell)); + $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines; + + $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + unset($lines[0]); + } + + // create a two dimensional array (rowspan x colspan) + $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows); + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + $value = $lines[$unmergedRowKey - $line] ?? ''; + $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + if ($nbLines === $unmergedRowKey - $line) { + break; + } + } + } + } + + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + // we need to know if $unmergedRow will be merged or inserted into $rows + if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) { + foreach ($unmergedRow as $cellKey => $cell) { + // insert cell into row at cellKey position + array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); + } + } else { + $row = $this->copyRow($rows, $unmergedRowKey - 1); + foreach ($unmergedRow as $column => $cell) { + if (!empty($cell)) { + $row[$column] = $unmergedRow[$column]; + } + } + array_splice($rows, $unmergedRowKey, 0, [$row]); + } + } + + return $rows; + } + + /** + * fill cells for a row that contains colspan > 1. + */ + private function fillCells(iterable $row): iterable + { + $newRow = []; + + foreach ($row as $column => $cell) { + $newRow[] = $cell; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) { + // insert empty value at column position + $newRow[] = ''; + } + } + } + + return $newRow ?: $row; + } + + private function copyRow(array $rows, int $line): array + { + $row = $rows[$line]; + foreach ($row as $cellKey => $cellValue) { + $row[$cellKey] = ''; + if ($cellValue instanceof TableCell) { + $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); + } + } + + return $row; + } + + /** + * Gets number of columns by row. + */ + private function getNumberOfColumns(array $row): int + { + $columns = \count($row); + foreach ($row as $column) { + $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0; + } + + return $columns; + } + + /** + * Gets list of columns for the given row. + */ + private function getRowColumns(array $row): array + { + $columns = range(0, $this->numberOfColumns - 1); + foreach ($row as $cellKey => $cell) { + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // exclude grouped columns. + $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); + } + } + + return $columns; + } + + /** + * Calculates columns widths. + */ + private function calculateColumnsWidth(iterable $groups): void + { + for ($column = 0; $column < $this->numberOfColumns; ++$column) { + $lengths = []; + foreach ($groups as $group) { + foreach ($group as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + foreach ($row as $i => $cell) { + if ($cell instanceof TableCell) { + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::width($textContent); + if ($textLength > 0) { + $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan())); + foreach ($contentColumns as $position => $content) { + $row[$i + $position] = $content; + } + } + } + } + + $lengths[] = $this->getCellWidth($row, $column); + } + } + + $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; + } + } + + private function getColumnSeparatorWidth(): int + { + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + } + + private function getCellWidth(array $row, int $column): int + { + $cellWidth = 0; + + if (isset($row[$column])) { + $cell = $row[$column]; + $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); + } + + $columnWidth = $this->columnWidths[$column] ?? 0; + $cellWidth = max($cellWidth, $columnWidth); + + return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; + } + + /** + * Called after rendering to cleanup cache data. + */ + private function cleanup(): void + { + $this->effectiveColumnWidths = []; + unset($this->numberOfColumns); + } + + /** + * @return array + */ + private static function initStyles(): array + { + $borderless = new TableStyle(); + $borderless + ->setHorizontalBorderChars('=') + ->setVerticalBorderChars(' ') + ->setDefaultCrossingChar(' ') + ; + + $compact = new TableStyle(); + $compact + ->setHorizontalBorderChars('') + ->setVerticalBorderChars('') + ->setDefaultCrossingChar('') + ->setCellRowContentFormat('%s ') + ; + + $styleGuide = new TableStyle(); + $styleGuide + ->setHorizontalBorderChars('-') + ->setVerticalBorderChars(' ') + ->setDefaultCrossingChar(' ') + ->setCellHeaderFormat('%s') + ; + + $box = (new TableStyle()) + ->setHorizontalBorderChars('─') + ->setVerticalBorderChars('│') + ->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├') + ; + + $boxDouble = (new TableStyle()) + ->setHorizontalBorderChars('═', '─') + ->setVerticalBorderChars('║', '│') + ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣') + ; + + return [ + 'default' => new TableStyle(), + 'borderless' => $borderless, + 'compact' => $compact, + 'symfony-style-guide' => $styleGuide, + 'box' => $box, + 'box-double' => $boxDouble, + ]; + } + + private function resolveStyle(TableStyle|string $name): TableStyle + { + if ($name instanceof TableStyle) { + return $name; + } + + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/TableCell.php b/lam/lib/3rdParty/composer/symfony/console/Helper/TableCell.php new file mode 100644 index 000000000..ead32f283 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/TableCell.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * @author Abdellatif Ait boudad + */ +class TableCell +{ + private string $value; + private array $options = [ + 'rowspan' => 1, + 'colspan' => 1, + 'style' => null, + ]; + + public function __construct(string $value = '', array $options = []) + { + $this->value = $value; + + // check option names + if ($diff = array_diff(array_keys($options), array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + } + + if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { + throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".'); + } + + $this->options = array_merge($this->options, $options); + } + + /** + * Returns the cell value. + */ + public function __toString(): string + { + return $this->value; + } + + /** + * Gets number of colspan. + */ + public function getColspan(): int + { + return (int) $this->options['colspan']; + } + + /** + * Gets number of rowspan. + */ + public function getRowspan(): int + { + return (int) $this->options['rowspan']; + } + + public function getStyle(): ?TableCellStyle + { + return $this->options['style']; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/TableCellStyle.php b/lam/lib/3rdParty/composer/symfony/console/Helper/TableCellStyle.php new file mode 100644 index 000000000..1b1ef276e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/TableCellStyle.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * @author Yewhen Khoptynskyi + */ +class TableCellStyle +{ + public const DEFAULT_ALIGN = 'left'; + + private const TAG_OPTIONS = [ + 'fg', + 'bg', + 'options', + ]; + + private const ALIGN_MAP = [ + 'left' => \STR_PAD_RIGHT, + 'center' => \STR_PAD_BOTH, + 'right' => \STR_PAD_LEFT, + ]; + + private array $options = [ + 'fg' => 'default', + 'bg' => 'default', + 'options' => null, + 'align' => self::DEFAULT_ALIGN, + 'cellFormat' => null, + ]; + + public function __construct(array $options = []) + { + if ($diff = array_diff(array_keys($options), array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); + } + + if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); + } + + $this->options = array_merge($this->options, $options); + } + + public function getOptions(): array + { + return $this->options; + } + + /** + * Gets options we need for tag for example fg, bg. + * + * @return string[] + */ + public function getTagOptions(): array + { + return array_filter( + $this->getOptions(), + fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]), + \ARRAY_FILTER_USE_KEY + ); + } + + public function getPadByAlign(): int + { + return self::ALIGN_MAP[$this->getOptions()['align']]; + } + + public function getCellFormat(): ?string + { + return $this->getOptions()['cellFormat']; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/TableRows.php b/lam/lib/3rdParty/composer/symfony/console/Helper/TableRows.php new file mode 100644 index 000000000..97d07726e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/TableRows.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * @internal + */ +class TableRows implements \IteratorAggregate +{ + private \Closure $generator; + + public function __construct(\Closure $generator) + { + $this->generator = $generator; + } + + public function getIterator(): \Traversable + { + return ($this->generator)(); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/TableSeparator.php b/lam/lib/3rdParty/composer/symfony/console/Helper/TableSeparator.php new file mode 100644 index 000000000..e541c5315 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/TableSeparator.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Marks a row as being a separator. + * + * @author Fabien Potencier + */ +class TableSeparator extends TableCell +{ + public function __construct(array $options = []) + { + parent::__construct('', $options); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Helper/TableStyle.php b/lam/lib/3rdParty/composer/symfony/console/Helper/TableStyle.php new file mode 100644 index 000000000..be956c109 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Helper/TableStyle.php @@ -0,0 +1,362 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; + +/** + * Defines the styles for a Table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Dany Maillard + */ +class TableStyle +{ + private string $paddingChar = ' '; + private string $horizontalOutsideBorderChar = '-'; + private string $horizontalInsideBorderChar = '-'; + private string $verticalOutsideBorderChar = '|'; + private string $verticalInsideBorderChar = '|'; + private string $crossingChar = '+'; + private string $crossingTopRightChar = '+'; + private string $crossingTopMidChar = '+'; + private string $crossingTopLeftChar = '+'; + private string $crossingMidRightChar = '+'; + private string $crossingBottomRightChar = '+'; + private string $crossingBottomMidChar = '+'; + private string $crossingBottomLeftChar = '+'; + private string $crossingMidLeftChar = '+'; + private string $crossingTopLeftBottomChar = '+'; + private string $crossingTopMidBottomChar = '+'; + private string $crossingTopRightBottomChar = '+'; + private string $headerTitleFormat = ' %s '; + private string $footerTitleFormat = ' %s '; + private string $cellHeaderFormat = '%s'; + private string $cellRowFormat = '%s'; + private string $cellRowContentFormat = ' %s '; + private string $borderFormat = '%s'; + private int $padType = \STR_PAD_RIGHT; + + /** + * Sets padding character, used for cell padding. + * + * @return $this + */ + public function setPaddingChar(string $paddingChar): static + { + if (!$paddingChar) { + throw new LogicException('The padding char must not be empty.'); + } + + $this->paddingChar = $paddingChar; + + return $this; + } + + /** + * Gets padding character, used for cell padding. + */ + public function getPaddingChar(): string + { + return $this->paddingChar; + } + + /** + * Sets horizontal border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * 1 ISBN 2 Title │ Author ║ + * ╠═══════════════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + * + * @return $this + */ + public function setHorizontalBorderChars(string $outside, ?string $inside = null): static + { + $this->horizontalOutsideBorderChar = $outside; + $this->horizontalInsideBorderChar = $inside ?? $outside; + + return $this; + } + + /** + * Sets vertical border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * ║ ISBN │ Title │ Author ║ + * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ╟───────2───────┼──────────────────────────┼──────────────────╢ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + * + * @return $this + */ + public function setVerticalBorderChars(string $outside, ?string $inside = null): static + { + $this->verticalOutsideBorderChar = $outside; + $this->verticalInsideBorderChar = $inside ?? $outside; + + return $this; + } + + /** + * Gets border characters. + * + * @internal + */ + public function getBorderChars(): array + { + return [ + $this->horizontalOutsideBorderChar, + $this->verticalOutsideBorderChar, + $this->horizontalInsideBorderChar, + $this->verticalInsideBorderChar, + ]; + } + + /** + * Sets crossing characters. + * + * Example: + * + * 1═══════════════2══════════════════════════2══════════════════3 + * ║ ISBN │ Title │ Author ║ + * 8'══════════════0'═════════════════════════0'═════════════════4' + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * 8───────────────0──────────────────────────0──────────────────4 + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * 7═══════════════6══════════════════════════6══════════════════5 + * + * + * @param string $cross Crossing char (see #0 of example) + * @param string $topLeft Top left char (see #1 of example) + * @param string $topMid Top mid char (see #2 of example) + * @param string $topRight Top right char (see #3 of example) + * @param string $midRight Mid right char (see #4 of example) + * @param string $bottomRight Bottom right char (see #5 of example) + * @param string $bottomMid Bottom mid char (see #6 of example) + * @param string $bottomLeft Bottom left char (see #7 of example) + * @param string $midLeft Mid left char (see #8 of example) + * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null + * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null + * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null + * + * @return $this + */ + public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): static + { + $this->crossingChar = $cross; + $this->crossingTopLeftChar = $topLeft; + $this->crossingTopMidChar = $topMid; + $this->crossingTopRightChar = $topRight; + $this->crossingMidRightChar = $midRight; + $this->crossingBottomRightChar = $bottomRight; + $this->crossingBottomMidChar = $bottomMid; + $this->crossingBottomLeftChar = $bottomLeft; + $this->crossingMidLeftChar = $midLeft; + $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft; + $this->crossingTopMidBottomChar = $topMidBottom ?? $cross; + $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight; + + return $this; + } + + /** + * Sets default crossing character used for each cross. + * + * @see {@link setCrossingChars()} for setting each crossing individually. + */ + public function setDefaultCrossingChar(string $char): self + { + return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char); + } + + /** + * Gets crossing character. + */ + public function getCrossingChar(): string + { + return $this->crossingChar; + } + + /** + * Gets crossing characters. + * + * @internal + */ + public function getCrossingChars(): array + { + return [ + $this->crossingChar, + $this->crossingTopLeftChar, + $this->crossingTopMidChar, + $this->crossingTopRightChar, + $this->crossingMidRightChar, + $this->crossingBottomRightChar, + $this->crossingBottomMidChar, + $this->crossingBottomLeftChar, + $this->crossingMidLeftChar, + $this->crossingTopLeftBottomChar, + $this->crossingTopMidBottomChar, + $this->crossingTopRightBottomChar, + ]; + } + + /** + * Sets header cell format. + * + * @return $this + */ + public function setCellHeaderFormat(string $cellHeaderFormat): static + { + $this->cellHeaderFormat = $cellHeaderFormat; + + return $this; + } + + /** + * Gets header cell format. + */ + public function getCellHeaderFormat(): string + { + return $this->cellHeaderFormat; + } + + /** + * Sets row cell format. + * + * @return $this + */ + public function setCellRowFormat(string $cellRowFormat): static + { + $this->cellRowFormat = $cellRowFormat; + + return $this; + } + + /** + * Gets row cell format. + */ + public function getCellRowFormat(): string + { + return $this->cellRowFormat; + } + + /** + * Sets row cell content format. + * + * @return $this + */ + public function setCellRowContentFormat(string $cellRowContentFormat): static + { + $this->cellRowContentFormat = $cellRowContentFormat; + + return $this; + } + + /** + * Gets row cell content format. + */ + public function getCellRowContentFormat(): string + { + return $this->cellRowContentFormat; + } + + /** + * Sets table border format. + * + * @return $this + */ + public function setBorderFormat(string $borderFormat): static + { + $this->borderFormat = $borderFormat; + + return $this; + } + + /** + * Gets table border format. + */ + public function getBorderFormat(): string + { + return $this->borderFormat; + } + + /** + * Sets cell padding type. + * + * @return $this + */ + public function setPadType(int $padType): static + { + if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) { + throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); + } + + $this->padType = $padType; + + return $this; + } + + /** + * Gets cell padding type. + */ + public function getPadType(): int + { + return $this->padType; + } + + public function getHeaderTitleFormat(): string + { + return $this->headerTitleFormat; + } + + /** + * @return $this + */ + public function setHeaderTitleFormat(string $format): static + { + $this->headerTitleFormat = $format; + + return $this; + } + + public function getFooterTitleFormat(): string + { + return $this->footerTitleFormat; + } + + /** + * @return $this + */ + public function setFooterTitleFormat(string $format): static + { + $this->footerTitleFormat = $format; + + return $this; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/ArgvInput.php b/lam/lib/3rdParty/composer/symfony/console/Input/ArgvInput.php new file mode 100644 index 000000000..a33092aee --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/ArgvInput.php @@ -0,0 +1,370 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\RuntimeException; + +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overridden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running application. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + */ +class ArgvInput extends Input +{ + private array $tokens; + private array $parsed; + + public function __construct(?array $argv = null, ?InputDefinition $definition = null) + { + $argv ??= $_SERVER['argv'] ?? []; + + // strip the application name + array_shift($argv); + + $this->tokens = $argv; + + parent::__construct($definition); + } + + /** + * @return void + */ + protected function setTokens(array $tokens) + { + $this->tokens = $tokens; + } + + /** + * @return void + */ + protected function parse() + { + $parseOptions = true; + $this->parsed = $this->tokens; + while (null !== $token = array_shift($this->parsed)) { + $parseOptions = $this->parseToken($token, $parseOptions); + } + } + + protected function parseToken(string $token, bool $parseOptions): bool + { + if ($parseOptions && '' == $token) { + $this->parseArgument($token); + } elseif ($parseOptions && '--' == $token) { + return false; + } elseif ($parseOptions && str_starts_with($token, '--')) { + $this->parseLongOption($token); + } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { + $this->parseShortOption($token); + } else { + $this->parseArgument($token); + } + + return $parseOptions; + } + + /** + * Parses a short option. + */ + private function parseShortOption(string $token): void + { + $name = substr($token, 1); + + if (\strlen($name) > 1) { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { + // an option with a value (with no space) + $this->addShortOption($name[0], substr($name, 1)); + } else { + $this->parseShortOptionSet($name); + } + } else { + $this->addShortOption($name, null); + } + } + + /** + * Parses a short option set. + * + * @throws RuntimeException When option given doesn't exist + */ + private function parseShortOptionSet(string $name): void + { + $len = \strlen($name); + for ($i = 0; $i < $len; ++$i) { + if (!$this->definition->hasShortcut($name[$i])) { + $encoding = mb_detect_encoding($name, null, true); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); + } + + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptValue()) { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); + + break; + } else { + $this->addLongOption($option->getName(), null); + } + } + } + + /** + * Parses a long option. + */ + private function parseLongOption(string $token): void + { + $name = substr($token, 2); + + if (false !== $pos = strpos($name, '=')) { + if ('' === $value = substr($name, $pos + 1)) { + array_unshift($this->parsed, $value); + } + $this->addLongOption(substr($name, 0, $pos), $value); + } else { + $this->addLongOption($name, null); + } + } + + /** + * Parses an argument. + * + * @throws RuntimeException When too many arguments are given + */ + private function parseArgument(string $token): void + { + $c = \count($this->arguments); + + // if input is expecting another argument, add it + if ($this->definition->hasArgument($c)) { + $arg = $this->definition->getArgument($c); + $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token; + + // if last argument isArray(), append token to last argument + } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { + $arg = $this->definition->getArgument($c - 1); + $this->arguments[$arg->getName()][] = $token; + + // unexpected argument + } else { + $all = $this->definition->getArguments(); + $symfonyCommandName = null; + if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) { + $symfonyCommandName = $this->arguments['command'] ?? null; + unset($all[$key]); + } + + if (\count($all)) { + if ($symfonyCommandName) { + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); + } else { + $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); + } + } elseif ($symfonyCommandName) { + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + } else { + $message = \sprintf('No arguments expected, got "%s".', $token); + } + + throw new RuntimeException($message); + } + } + + /** + * Adds a short option value. + * + * @throws RuntimeException When option given doesn't exist + */ + private function addShortOption(string $shortcut, mixed $value): void + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @throws RuntimeException When option given doesn't exist + */ + private function addLongOption(string $name, mixed $value): void + { + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); + } + + $optionName = $this->definition->negationToName($name); + if (null !== $value) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + $this->options[$optionName] = false; + + return; + } + + $option = $this->definition->getOption($name); + + if (null !== $value && !$option->acceptValue()) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + + if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = array_shift($this->parsed); + if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) { + $value = $next; + } else { + array_unshift($this->parsed, $next); + } + } + + if (null === $value) { + if ($option->isValueRequired()) { + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); + } + + if (!$option->isArray() && !$option->isValueOptional()) { + $value = true; + } + } + + if ($option->isArray()) { + $this->options[$name][] = $value; + } else { + $this->options[$name] = $value; + } + } + + public function getFirstArgument(): ?string + { + $isOption = false; + foreach ($this->tokens as $i => $token) { + if ($token && '-' === $token[0]) { + if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) { + continue; + } + + // If it's a long option, consider that everything after "--" is the option name. + // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) + $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1); + if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { + // noop + } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { + $isOption = true; + } + + continue; + } + + if ($isOption) { + $isOption = false; + continue; + } + + return $token; + } + + return null; + } + + public function hasParameterOption(string|array $values, bool $onlyParams = false): bool + { + $values = (array) $values; + + foreach ($this->tokens as $token) { + if ($onlyParams && '--' === $token) { + return false; + } + foreach ($values as $value) { + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = str_starts_with($value, '--') ? $value.'=' : $value; + if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) { + return true; + } + } + } + + return false; + } + + public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed + { + $values = (array) $values; + $tokens = $this->tokens; + + while (0 < \count($tokens)) { + $token = array_shift($tokens); + if ($onlyParams && '--' === $token) { + return $default; + } + + foreach ($values as $value) { + if ($token === $value) { + return array_shift($tokens); + } + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = str_starts_with($value, '--') ? $value.'=' : $value; + if ('' !== $leading && str_starts_with($token, $leading)) { + return substr($token, \strlen($leading)); + } + } + } + + return $default; + } + + /** + * Returns a stringified representation of the args passed to the command. + */ + public function __toString(): string + { + $tokens = array_map(function ($token) { + if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { + return $match[1].$this->escapeToken($match[2]); + } + + if ($token && '-' !== $token[0]) { + return $this->escapeToken($token); + } + + return $token; + }, $this->tokens); + + return implode(' ', $tokens); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/ArrayInput.php b/lam/lib/3rdParty/composer/symfony/console/Input/ArrayInput.php new file mode 100644 index 000000000..b9f753394 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/ArrayInput.php @@ -0,0 +1,196 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\InvalidOptionException; + +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); + * + * @author Fabien Potencier + */ +class ArrayInput extends Input +{ + private array $parameters; + + public function __construct(array $parameters, ?InputDefinition $definition = null) + { + $this->parameters = $parameters; + + parent::__construct($definition); + } + + public function getFirstArgument(): ?string + { + foreach ($this->parameters as $param => $value) { + if ($param && \is_string($param) && '-' === $param[0]) { + continue; + } + + return $value; + } + + return null; + } + + public function hasParameterOption(string|array $values, bool $onlyParams = false): bool + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if (!\is_int($k)) { + $v = $k; + } + + if ($onlyParams && '--' === $v) { + return false; + } + + if (\in_array($v, $values)) { + return true; + } + } + + return false; + } + + public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) { + return $default; + } + + if (\is_int($k)) { + if (\in_array($v, $values)) { + return true; + } + } elseif (\in_array($k, $values)) { + return $v; + } + } + + return $default; + } + + /** + * Returns a stringified representation of the args passed to the command. + */ + public function __toString(): string + { + $params = []; + foreach ($this->parameters as $param => $val) { + if ($param && \is_string($param) && '-' === $param[0]) { + $glue = ('-' === $param[1]) ? '=' : ' '; + if (\is_array($val)) { + foreach ($val as $v) { + $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : ''); + } + } else { + $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : ''); + } + } else { + $params[] = \is_array($val) ? implode(' ', array_map($this->escapeToken(...), $val)) : $this->escapeToken($val); + } + } + + return implode(' ', $params); + } + + /** + * @return void + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) { + if ('--' === $key) { + return; + } + if (str_starts_with($key, '--')) { + $this->addLongOption(substr($key, 2), $value); + } elseif (str_starts_with($key, '-')) { + $this->addShortOption(substr($key, 1), $value); + } else { + $this->addArgument($key, $value); + } + } + } + + /** + * Adds a short option value. + * + * @throws InvalidOptionException When option given doesn't exist + */ + private function addShortOption(string $shortcut, mixed $value): void + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @throws InvalidOptionException When option given doesn't exist + * @throws InvalidOptionException When a required value is missing + */ + private function addLongOption(string $name, mixed $value): void + { + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); + } + + $optionName = $this->definition->negationToName($name); + $this->options[$optionName] = false; + + return; + } + + $option = $this->definition->getOption($name); + + if (null === $value) { + if ($option->isValueRequired()) { + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); + } + + if (!$option->isValueOptional()) { + $value = true; + } + } + + $this->options[$name] = $value; + } + + /** + * Adds an argument value. + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + private function addArgument(string|int $name, mixed $value): void + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/Input.php b/lam/lib/3rdParty/composer/symfony/console/Input/Input.php new file mode 100644 index 000000000..d3a3c7fd2 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/Input.php @@ -0,0 +1,193 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; + +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @author Fabien Potencier + */ +abstract class Input implements InputInterface, StreamableInputInterface +{ + protected $definition; + /** @var resource */ + protected $stream; + protected $options = []; + protected $arguments = []; + protected $interactive = true; + + public function __construct(?InputDefinition $definition = null) + { + if (null === $definition) { + $this->definition = new InputDefinition(); + } else { + $this->bind($definition); + $this->validate(); + } + } + + /** + * @return void + */ + public function bind(InputDefinition $definition) + { + $this->arguments = []; + $this->options = []; + $this->definition = $definition; + + $this->parse(); + } + + /** + * Processes command line arguments. + * + * @return void + */ + abstract protected function parse(); + + /** + * @return void + */ + public function validate() + { + $definition = $this->definition; + $givenArguments = $this->arguments; + + $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); + + if (\count($missingArguments) > 0) { + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); + } + } + + public function isInteractive(): bool + { + return $this->interactive; + } + + /** + * @return void + */ + public function setInteractive(bool $interactive) + { + $this->interactive = $interactive; + } + + public function getArguments(): array + { + return array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + + public function getArgument(string $name): mixed + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + + return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); + } + + /** + * @return void + */ + public function setArgument(string $name, mixed $value) + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } + + public function hasArgument(string $name): bool + { + return $this->definition->hasArgument($name); + } + + public function getOptions(): array + { + return array_merge($this->definition->getOptionDefaults(), $this->options); + } + + public function getOption(string $name): mixed + { + if ($this->definition->hasNegation($name)) { + if (null === $value = $this->getOption($this->definition->negationToName($name))) { + return $value; + } + + return !$value; + } + + if (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + + return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + + /** + * @return void + */ + public function setOption(string $name, mixed $value) + { + if ($this->definition->hasNegation($name)) { + $this->options[$this->definition->negationToName($name)] = !$value; + + return; + } elseif (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + + $this->options[$name] = $value; + } + + public function hasOption(string $name): bool + { + return $this->definition->hasOption($name) || $this->definition->hasNegation($name); + } + + /** + * Escapes a token through escapeshellarg if it contains unsafe chars. + */ + public function escapeToken(string $token): string + { + return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); + } + + /** + * @param resource $stream + * + * @return void + */ + public function setStream($stream) + { + $this->stream = $stream; + } + + /** + * @return resource + */ + public function getStream() + { + return $this->stream; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/InputArgument.php b/lam/lib/3rdParty/composer/symfony/console/Input/InputArgument.php new file mode 100644 index 000000000..fd203919f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/InputArgument.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; + +/** + * Represents a command line argument. + * + * @author Fabien Potencier + */ +class InputArgument +{ + public const REQUIRED = 1; + public const OPTIONAL = 2; + public const IS_ARRAY = 4; + + private string $name; + private int $mode; + private string|int|bool|array|float|null $default; + private array|\Closure $suggestedValues; + private string $description; + + /** + * @param string $name The argument name + * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY + * @param string $description A description text + * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @throws InvalidArgumentException When argument mode is not valid + */ + public function __construct(string $name, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, \Closure|array $suggestedValues = []) + { + if (null === $mode) { + $mode = self::OPTIONAL; + } elseif ($mode > 7 || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + $this->suggestedValues = $suggestedValues; + + $this->setDefault($default); + } + + /** + * Returns the argument name. + */ + public function getName(): string + { + return $this->name; + } + + /** + * Returns true if the argument is required. + * + * @return bool true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired(): bool + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + + /** + * Returns true if the argument can take multiple values. + * + * @return bool true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray(): bool + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @return void + * + * @throws LogicException When incorrect default value is given + */ + public function setDefault(string|bool|int|float|array|null $default = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->isRequired() && null !== $default) { + throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array argument must be an array.'); + } + } + + $this->default = $default; + } + + /** + * Returns the default value. + */ + public function getDefault(): string|bool|int|float|array|null + { + return $this->default; + } + + public function hasCompletion(): bool + { + return [] !== $this->suggestedValues; + } + + /** + * Adds suggestions to $suggestions for the current completion input. + * + * @see Command::complete() + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $values = $this->suggestedValues; + if ($values instanceof \Closure && !\is_array($values = $values($input))) { + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + } + if ($values) { + $suggestions->suggestValues($values); + } + } + + /** + * Returns the description text. + */ + public function getDescription(): string + { + return $this->description; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/InputAwareInterface.php b/lam/lib/3rdParty/composer/symfony/console/Input/InputAwareInterface.php new file mode 100644 index 000000000..0ad27b455 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/InputAwareInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * InputAwareInterface should be implemented by classes that depends on the + * Console Input. + * + * @author Wouter J + */ +interface InputAwareInterface +{ + /** + * Sets the Console Input. + * + * @return void + */ + public function setInput(InputInterface $input); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/InputDefinition.php b/lam/lib/3rdParty/composer/symfony/console/Input/InputDefinition.php new file mode 100644 index 000000000..b5c202838 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/InputDefinition.php @@ -0,0 +1,416 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; + +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition([ + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), + * ]); + * + * @author Fabien Potencier + */ +class InputDefinition +{ + private array $arguments = []; + private int $requiredCount = 0; + private ?InputArgument $lastArrayArgument = null; + private ?InputArgument $lastOptionalArgument = null; + private array $options = []; + private array $negations = []; + private array $shortcuts = []; + + /** + * @param array $definition An array of InputArgument and InputOption instance + */ + public function __construct(array $definition = []) + { + $this->setDefinition($definition); + } + + /** + * Sets the definition of the input. + * + * @return void + */ + public function setDefinition(array $definition) + { + $arguments = []; + $options = []; + foreach ($definition as $item) { + if ($item instanceof InputOption) { + $options[] = $item; + } else { + $arguments[] = $item; + } + } + + $this->setArguments($arguments); + $this->setOptions($options); + } + + /** + * Sets the InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void + */ + public function setArguments(array $arguments = []) + { + $this->arguments = []; + $this->requiredCount = 0; + $this->lastOptionalArgument = null; + $this->lastArrayArgument = null; + $this->addArguments($arguments); + } + + /** + * Adds an array of InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void + */ + public function addArguments(?array $arguments = []) + { + if (null !== $arguments) { + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + } + } + + /** + * @return void + * + * @throws LogicException When incorrect argument is given + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) { + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); + } + + if (null !== $this->lastArrayArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + } + + if ($argument->isRequired() && null !== $this->lastOptionalArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + } + + if ($argument->isArray()) { + $this->lastArrayArgument = $argument; + } + + if ($argument->isRequired()) { + ++$this->requiredCount; + } else { + $this->lastOptionalArgument = $argument; + } + + $this->arguments[$argument->getName()] = $argument; + } + + /** + * Returns an InputArgument by name or by position. + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function getArgument(string|int $name): InputArgument + { + if (!$this->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + + $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; + + return $arguments[$name]; + } + + /** + * Returns true if an InputArgument object exists by name or position. + */ + public function hasArgument(string|int $name): bool + { + $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; + + return isset($arguments[$name]); + } + + /** + * Gets the array of InputArgument objects. + * + * @return InputArgument[] + */ + public function getArguments(): array + { + return $this->arguments; + } + + /** + * Returns the number of InputArguments. + */ + public function getArgumentCount(): int + { + return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments); + } + + /** + * Returns the number of required InputArguments. + */ + public function getArgumentRequiredCount(): int + { + return $this->requiredCount; + } + + /** + * @return array + */ + public function getArgumentDefaults(): array + { + $values = []; + foreach ($this->arguments as $argument) { + $values[$argument->getName()] = $argument->getDefault(); + } + + return $values; + } + + /** + * Sets the InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @return void + */ + public function setOptions(array $options = []) + { + $this->options = []; + $this->shortcuts = []; + $this->negations = []; + $this->addOptions($options); + } + + /** + * Adds an array of InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @return void + */ + public function addOptions(array $options = []) + { + foreach ($options as $option) { + $this->addOption($option); + } + } + + /** + * @return void + * + * @throws LogicException When option given already exist + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + if (isset($this->negations[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + + if ($option->getShortcut()) { + foreach (explode('|', $option->getShortcut()) as $shortcut) { + if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); + } + } + } + + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) { + foreach (explode('|', $option->getShortcut()) as $shortcut) { + $this->shortcuts[$shortcut] = $option->getName(); + } + } + + if ($option->isNegatable()) { + $negatedName = 'no-'.$option->getName(); + if (isset($this->options[$negatedName])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); + } + $this->negations[$negatedName] = $option->getName(); + } + } + + /** + * Returns an InputOption by name. + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption(string $name): InputOption + { + if (!$this->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); + } + + return $this->options[$name]; + } + + /** + * Returns true if an InputOption object exists by name. + * + * This method can't be used to check if the user included the option when + * executing the command (use getOption() instead). + */ + public function hasOption(string $name): bool + { + return isset($this->options[$name]); + } + + /** + * Gets the array of InputOption objects. + * + * @return InputOption[] + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * Returns true if an InputOption object exists by shortcut. + */ + public function hasShortcut(string $name): bool + { + return isset($this->shortcuts[$name]); + } + + /** + * Returns true if an InputOption object exists by negated name. + */ + public function hasNegation(string $name): bool + { + return isset($this->negations[$name]); + } + + /** + * Gets an InputOption by shortcut. + */ + public function getOptionForShortcut(string $shortcut): InputOption + { + return $this->getOption($this->shortcutToName($shortcut)); + } + + /** + * @return array + */ + public function getOptionDefaults(): array + { + $values = []; + foreach ($this->options as $option) { + $values[$option->getName()] = $option->getDefault(); + } + + return $values; + } + + /** + * Returns the InputOption name given a shortcut. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function shortcutToName(string $shortcut): string + { + if (!isset($this->shortcuts[$shortcut])) { + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + + return $this->shortcuts[$shortcut]; + } + + /** + * Returns the InputOption name given a negation. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function negationToName(string $negation): string + { + if (!isset($this->negations[$negation])) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); + } + + return $this->negations[$negation]; + } + + /** + * Gets the synopsis. + */ + public function getSynopsis(bool $short = false): string + { + $elements = []; + + if ($short && $this->getOptions()) { + $elements[] = '[options]'; + } elseif (!$short) { + foreach ($this->getOptions() as $option) { + $value = ''; + if ($option->acceptValue()) { + $value = \sprintf( + ' %s%s%s', + $option->isValueOptional() ? '[' : '', + strtoupper($option->getName()), + $option->isValueOptional() ? ']' : '' + ); + } + + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + } + } + + if (\count($elements) && $this->getArguments()) { + $elements[] = '[--]'; + } + + $tail = ''; + foreach ($this->getArguments() as $argument) { + $element = '<'.$argument->getName().'>'; + if ($argument->isArray()) { + $element .= '...'; + } + + if (!$argument->isRequired()) { + $element = '['.$element; + $tail .= ']'; + } + + $elements[] = $element; + } + + return implode(' ', $elements).$tail; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/InputInterface.php b/lam/lib/3rdParty/composer/symfony/console/Input/InputInterface.php new file mode 100644 index 000000000..aaed5fd01 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/InputInterface.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; + +/** + * InputInterface is the interface implemented by all input classes. + * + * @author Fabien Potencier + * + * @method string __toString() Returns a stringified representation of the args passed to the command. + * InputArguments MUST be escaped as well as the InputOption values passed to the command. + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + */ + public function getFirstArgument(): ?string; + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + */ + public function hasParameterOption(string|array $values, bool $onlyParams = false): bool; + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param string|bool|int|float|array|null $default The default value to return if no result is found + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + * + * @return mixed + */ + public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false); + + /** + * Binds the current Input instance with the given arguments and options. + * + * @return void + * + * @throws RuntimeException + */ + public function bind(InputDefinition $definition); + + /** + * Validates the input. + * + * @return void + * + * @throws RuntimeException When not enough arguments are given + */ + public function validate(); + + /** + * Returns all the given arguments merged with the default values. + * + * @return array + */ + public function getArguments(): array; + + /** + * Returns the argument value for a given argument name. + * + * @return mixed + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function getArgument(string $name); + + /** + * Sets an argument value by name. + * + * @return void + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function setArgument(string $name, mixed $value); + + /** + * Returns true if an InputArgument object exists by name or position. + */ + public function hasArgument(string $name): bool; + + /** + * Returns all the given options merged with the default values. + * + * @return array + */ + public function getOptions(): array; + + /** + * Returns the option value for a given option name. + * + * @return mixed + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption(string $name); + + /** + * Sets an option value by name. + * + * @return void + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function setOption(string $name, mixed $value); + + /** + * Returns true if an InputOption object exists by name. + */ + public function hasOption(string $name): bool; + + /** + * Is this input means interactive? + */ + public function isInteractive(): bool; + + /** + * Sets the input interactivity. + * + * @return void + */ + public function setInteractive(bool $interactive); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/InputOption.php b/lam/lib/3rdParty/composer/symfony/console/Input/InputOption.php new file mode 100644 index 000000000..3adc8c424 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/InputOption.php @@ -0,0 +1,255 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; + +/** + * Represents a command line option. + * + * @author Fabien Potencier + */ +class InputOption +{ + /** + * Do not accept input for the option (e.g. --yell). This is the default behavior of options. + */ + public const VALUE_NONE = 1; + + /** + * A value must be passed when the option is used (e.g. --iterations=5 or -i5). + */ + public const VALUE_REQUIRED = 2; + + /** + * The option may or may not have a value (e.g. --yell or --yell=loud). + */ + public const VALUE_OPTIONAL = 4; + + /** + * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). + */ + public const VALUE_IS_ARRAY = 8; + + /** + * The option may have either positive or negative value (e.g. --ansi or --no-ansi). + */ + public const VALUE_NEGATABLE = 16; + + private string $name; + private string|array|null $shortcut; + private int $mode; + private string|int|bool|array|float|null $default; + private array|\Closure $suggestedValues; + private string $description; + + /** + * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int|null $mode The option mode: One of the VALUE_* constants + * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + */ + public function __construct(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, array|\Closure $suggestedValues = []) + { + if (str_starts_with($name, '--')) { + $name = substr($name, 2); + } + + if (empty($name)) { + throw new InvalidArgumentException('An option name cannot be empty.'); + } + + if ('' === $shortcut || [] === $shortcut || false === $shortcut) { + $shortcut = null; + } + + if (null !== $shortcut) { + if (\is_array($shortcut)) { + $shortcut = implode('|', $shortcut); + } + $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); + $shortcuts = array_filter($shortcuts, 'strlen'); + $shortcut = implode('|', $shortcuts); + + if ('' === $shortcut) { + throw new InvalidArgumentException('An option shortcut cannot be empty.'); + } + } + + if (null === $mode) { + $mode = self::VALUE_NONE; + } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + $this->suggestedValues = $suggestedValues; + + if ($suggestedValues && !$this->acceptValue()) { + throw new LogicException('Cannot set suggested values if the option does not accept a value.'); + } + if ($this->isArray() && !$this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); + } + if ($this->isNegatable() && $this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); + } + + $this->setDefault($default); + } + + /** + * Returns the option shortcut. + */ + public function getShortcut(): ?string + { + return $this->shortcut; + } + + /** + * Returns the option name. + */ + public function getName(): string + { + return $this->name; + } + + /** + * Returns true if the option accepts a value. + * + * @return bool true if value mode is not self::VALUE_NONE, false otherwise + */ + public function acceptValue(): bool + { + return $this->isValueRequired() || $this->isValueOptional(); + } + + /** + * Returns true if the option requires a value. + * + * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise + */ + public function isValueRequired(): bool + { + return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); + } + + /** + * Returns true if the option takes an optional value. + * + * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise + */ + public function isValueOptional(): bool + { + return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); + } + + /** + * Returns true if the option can take multiple values. + * + * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise + */ + public function isArray(): bool + { + return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); + } + + public function isNegatable(): bool + { + return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); + } + + /** + * @return void + */ + public function setDefault(string|bool|int|float|array|null $default = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { + throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array option must be an array.'); + } + } + + $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false; + } + + /** + * Returns the default value. + */ + public function getDefault(): string|bool|int|float|array|null + { + return $this->default; + } + + /** + * Returns the description text. + */ + public function getDescription(): string + { + return $this->description; + } + + public function hasCompletion(): bool + { + return [] !== $this->suggestedValues; + } + + /** + * Adds suggestions to $suggestions for the current completion input. + * + * @see Command::complete() + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $values = $this->suggestedValues; + if ($values instanceof \Closure && !\is_array($values = $values($input))) { + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + } + if ($values) { + $suggestions->suggestValues($values); + } + } + + /** + * Checks whether the given option equals this one. + */ + public function equals(self $option): bool + { + return $option->getName() === $this->getName() + && $option->getShortcut() === $this->getShortcut() + && $option->getDefault() === $this->getDefault() + && $option->isNegatable() === $this->isNegatable() + && $option->isArray() === $this->isArray() + && $option->isValueRequired() === $this->isValueRequired() + && $option->isValueOptional() === $this->isValueOptional() + ; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/StreamableInputInterface.php b/lam/lib/3rdParty/composer/symfony/console/Input/StreamableInputInterface.php new file mode 100644 index 000000000..4b95fcb11 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/StreamableInputInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * StreamableInputInterface is the interface implemented by all input classes + * that have an input stream. + * + * @author Robin Chalas + */ +interface StreamableInputInterface extends InputInterface +{ + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + * + * @return void + */ + public function setStream($stream); + + /** + * Returns the input stream. + * + * @return resource|null + */ + public function getStream(); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Input/StringInput.php b/lam/lib/3rdParty/composer/symfony/console/Input/StringInput.php new file mode 100644 index 000000000..9b94784af --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Input/StringInput.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @author Fabien Potencier + */ +class StringInput extends ArgvInput +{ + /** + * @deprecated since Symfony 6.1 + */ + public const REGEX_STRING = '([^\s]+?)(?:\s|(?setTokens($this->tokenize($input)); + } + + /** + * Tokenizes a string. + * + * @throws InvalidArgumentException When unable to parse input (should never happen) + */ + private function tokenize(string $input): array + { + $tokens = []; + $length = \strlen($input); + $cursor = 0; + $token = null; + while ($cursor < $length) { + if ('\\' === $input[$cursor]) { + $token .= $input[++$cursor] ?? ''; + ++$cursor; + continue; + } + + if (preg_match('/\s+/A', $input, $match, 0, $cursor)) { + if (null !== $token) { + $tokens[] = $token; + $token = null; + } + } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) { + $token .= $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1))); + } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) { + $token .= stripcslashes(substr($match[0], 1, -1)); + } elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) { + $token .= $match[1]; + } else { + // should never happen + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); + } + + $cursor += \strlen($match[0]); + } + + if (null !== $token) { + $tokens[] = $token; + } + + return $tokens; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/LICENSE b/lam/lib/3rdParty/composer/symfony/console/LICENSE new file mode 100644 index 000000000..0138f8f07 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/console/Logger/ConsoleLogger.php b/lam/lib/3rdParty/composer/symfony/console/Logger/ConsoleLogger.php new file mode 100644 index 000000000..70432b7de --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Logger/ConsoleLogger.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Logger; + +use Psr\Log\AbstractLogger; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LogLevel; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * PSR-3 compliant console logger. + * + * @author Kévin Dunglas + * + * @see https://www.php-fig.org/psr/psr-3/ + */ +class ConsoleLogger extends AbstractLogger +{ + public const INFO = 'info'; + public const ERROR = 'error'; + + private OutputInterface $output; + private array $verbosityLevelMap = [ + LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, + LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, + LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, + LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, + LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, + LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, + ]; + private array $formatLevelMap = [ + LogLevel::EMERGENCY => self::ERROR, + LogLevel::ALERT => self::ERROR, + LogLevel::CRITICAL => self::ERROR, + LogLevel::ERROR => self::ERROR, + LogLevel::WARNING => self::INFO, + LogLevel::NOTICE => self::INFO, + LogLevel::INFO => self::INFO, + LogLevel::DEBUG => self::INFO, + ]; + private bool $errored = false; + + public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) + { + $this->output = $output; + $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; + $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; + } + + public function log($level, $message, array $context = []): void + { + if (!isset($this->verbosityLevelMap[$level])) { + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); + } + + $output = $this->output; + + // Write to the error output if necessary and available + if (self::ERROR === $this->formatLevelMap[$level]) { + if ($this->output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->errored = true; + } + + // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. + // We only do it for efficiency here as the message formatting is relatively expensive. + if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + } + } + + /** + * Returns true when any messages have been logged at error levels. + */ + public function hasErrored(): bool + { + return $this->errored; + } + + /** + * Interpolates context values into the message placeholders. + * + * @author PHP Framework Interoperability Group + */ + private function interpolate(string $message, array $context): string + { + if (!str_contains($message, '{')) { + return $message; + } + + $replacements = []; + foreach ($context as $key => $val) { + if (null === $val || \is_scalar($val) || $val instanceof \Stringable) { + $replacements["{{$key}}"] = $val; + } elseif ($val instanceof \DateTimeInterface) { + $replacements["{{$key}}"] = $val->format(\DateTimeInterface::RFC3339); + } elseif (\is_object($val)) { + $replacements["{{$key}}"] = '[object '.$val::class.']'; + } else { + $replacements["{{$key}}"] = '['.\gettype($val).']'; + } + } + + return strtr($message, $replacements); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandContext.php b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandContext.php new file mode 100644 index 000000000..2ee5415c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandContext.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +/** + * @author Kevin Bond + */ +final class RunCommandContext +{ + public function __construct( + public readonly RunCommandMessage $message, + public readonly int $exitCode, + public readonly string $output, + ) { + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessage.php b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessage.php new file mode 100644 index 000000000..b530c438c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessage.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +use Symfony\Component\Console\Exception\RunCommandFailedException; + +/** + * @author Kevin Bond + */ +class RunCommandMessage implements \Stringable +{ + /** + * @param bool $throwOnFailure If the command has a non-zero exit code, throw {@see RunCommandFailedException} + * @param bool $catchExceptions @see Application::setCatchExceptions() + */ + public function __construct( + public readonly string $input, + public readonly bool $throwOnFailure = true, + public readonly bool $catchExceptions = false, + ) { + } + + public function __toString(): string + { + return $this->input; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessageHandler.php b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessageHandler.php new file mode 100644 index 000000000..3f4286542 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Messenger/RunCommandMessageHandler.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\RunCommandFailedException; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; + +/** + * @author Kevin Bond + */ +final class RunCommandMessageHandler +{ + public function __construct(private readonly Application $application) + { + } + + public function __invoke(RunCommandMessage $message): RunCommandContext + { + $input = new StringInput($message->input); + $output = new BufferedOutput(); + + $this->application->setCatchExceptions($message->catchExceptions); + + try { + $exitCode = $this->application->run($input, $output); + } catch (UnrecoverableExceptionInterface|RecoverableExceptionInterface $e) { + throw $e; + } catch (\Throwable $e) { + throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); + } + + if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + } + + return new RunCommandContext($message, $exitCode, $output->fetch()); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/AnsiColorMode.php b/lam/lib/3rdParty/composer/symfony/console/Output/AnsiColorMode.php new file mode 100644 index 000000000..dcdd1d5c4 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/AnsiColorMode.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * @author Fabien Potencier + * @author Julien Boudry + */ +enum AnsiColorMode +{ + /* + * Classical 4-bit Ansi colors, including 8 classical colors and 8 bright color. Output syntax is "ESC[${foreGroundColorcode};${backGroundColorcode}m" + * Must be compatible with all terminals and it's the minimal version supported. + */ + case Ansi4; + + /* + * 8-bit Ansi colors (240 different colors + 16 duplicate color codes, ensuring backward compatibility). + * Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m" + * Should be compatible with most terminals. + */ + case Ansi8; + + /* + * 24-bit Ansi colors (RGB). + * Output syntax is: "ESC[38;2;${foreGroundColorcodeRed};${foreGroundColorcodeGreen};${foreGroundColorcodeBlue};48;2;${backGroundColorcodeRed};${backGroundColorcodeGreen};${backGroundColorcodeBlue}m" + * May be compatible with many modern terminals. + */ + case Ansi24; + + /** + * Converts an RGB hexadecimal color to the corresponding Ansi code. + */ + public function convertFromHexToAnsiColorCode(string $hexColor): string + { + $hexColor = str_replace('#', '', $hexColor); + + if (3 === \strlen($hexColor)) { + $hexColor = $hexColor[0].$hexColor[0].$hexColor[1].$hexColor[1].$hexColor[2].$hexColor[2]; + } + + if (6 !== \strlen($hexColor)) { + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); + } + + $color = hexdec($hexColor); + + $r = ($color >> 16) & 255; + $g = ($color >> 8) & 255; + $b = $color & 255; + + return match ($this) { + self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), + self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), + self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), + }; + } + + private function convertFromRGB(int $r, int $g, int $b): int + { + return match ($this) { + self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b), + self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b), + default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."), + }; + } + + private function degradeHexColorToAnsi4(int $r, int $g, int $b): int + { + return round($b / 255) << 2 | (round($g / 255) << 1) | round($r / 255); + } + + /** + * Inspired from https://github.com/ajalt/colormath/blob/e464e0da1b014976736cf97250063248fc77b8e7/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/Ansi256.kt code (MIT license). + */ + private function degradeHexColorToAnsi8(int $r, int $g, int $b): int + { + if ($r === $g && $g === $b) { + if ($r < 8) { + return 16; + } + + if ($r > 248) { + return 231; + } + + return (int) round(($r - 8) / 247 * 24) + 232; + } else { + return 16 + + (36 * (int) round($r / 255 * 5)) + + (6 * (int) round($g / 255 * 5)) + + (int) round($b / 255 * 5); + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/BufferedOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/BufferedOutput.php new file mode 100644 index 000000000..ef5099bfd --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/BufferedOutput.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +/** + * @author Jean-François Simon + */ +class BufferedOutput extends Output +{ + private string $buffer = ''; + + /** + * Empties buffer and returns its content. + */ + public function fetch(): string + { + $content = $this->buffer; + $this->buffer = ''; + + return $content; + } + + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + $this->buffer .= $message; + + if ($newline) { + $this->buffer .= \PHP_EOL; + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutput.php new file mode 100644 index 000000000..5837e74a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutput.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. + * + * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); + * + * @author Fabien Potencier + */ +class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface +{ + private OutputInterface $stderr; + private array $consoleSectionOutputs = []; + + /** + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) + { + parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); + + if (null === $formatter) { + // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated); + + return; + } + + $actualDecorated = $this->isDecorated(); + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); + + if (null === $decorated) { + $this->setDecorated($actualDecorated && $this->stderr->isDecorated()); + } + } + + /** + * Creates a new output section. + */ + public function section(): ConsoleSectionOutput + { + return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); + } + + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + parent::setDecorated($decorated); + $this->stderr->setDecorated($decorated); + } + + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + parent::setFormatter($formatter); + $this->stderr->setFormatter($formatter); + } + + /** + * @return void + */ + public function setVerbosity(int $level) + { + parent::setVerbosity($level); + $this->stderr->setVerbosity($level); + } + + public function getErrorOutput(): OutputInterface + { + return $this->stderr; + } + + /** + * @return void + */ + public function setErrorOutput(OutputInterface $error) + { + $this->stderr = $error; + } + + /** + * Returns true if current environment supports writing console output to + * STDOUT. + */ + protected function hasStdoutSupport(): bool + { + return false === $this->isRunningOS400(); + } + + /** + * Returns true if current environment supports writing console output to + * STDERR. + */ + protected function hasStderrSupport(): bool + { + return false === $this->isRunningOS400(); + } + + /** + * Checks if current executing environment is IBM iSeries (OS400), which + * doesn't properly convert character-encodings between ASCII to EBCDIC. + */ + private function isRunningOS400(): bool + { + $checks = [ + \function_exists('php_uname') ? php_uname('s') : '', + getenv('OSTYPE'), + \PHP_OS, + ]; + + return false !== stripos(implode(';', $checks), 'OS400'); + } + + /** + * @return resource + */ + private function openOutputStream() + { + if (!$this->hasStdoutSupport()) { + return fopen('php://output', 'w'); + } + + // Use STDOUT when possible to prevent from opening too many file descriptors + return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); + } + + /** + * @return resource + */ + private function openErrorStream() + { + if (!$this->hasStderrSupport()) { + return fopen('php://output', 'w'); + } + + // Use STDERR when possible to prevent from opening too many file descriptors + return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w')); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutputInterface.php b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutputInterface.php new file mode 100644 index 000000000..9c0049c8f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleOutputInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +/** + * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. + * This adds information about stderr and section output stream. + * + * @author Dariusz Górecki + */ +interface ConsoleOutputInterface extends OutputInterface +{ + /** + * Gets the OutputInterface for errors. + */ + public function getErrorOutput(): OutputInterface; + + /** + * @return void + */ + public function setErrorOutput(OutputInterface $error); + + public function section(): ConsoleSectionOutput; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleSectionOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleSectionOutput.php new file mode 100644 index 000000000..04d587cf2 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/ConsoleSectionOutput.php @@ -0,0 +1,244 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Terminal; + +/** + * @author Pierre du Plessis + * @author Gabriel Ostrolucký + */ +class ConsoleSectionOutput extends StreamOutput +{ + private array $content = []; + private int $lines = 0; + private array $sections; + private Terminal $terminal; + private int $maxHeight = 0; + + /** + * @param resource $stream + * @param ConsoleSectionOutput[] $sections + */ + public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter) + { + parent::__construct($stream, $verbosity, $decorated, $formatter); + array_unshift($sections, $this); + $this->sections = &$sections; + $this->terminal = new Terminal(); + } + + /** + * Defines a maximum number of lines for this section. + * + * When more lines are added, the section will automatically scroll to the + * end (i.e. remove the first lines to comply with the max height). + */ + public function setMaxHeight(int $maxHeight): void + { + // when changing max height, clear output of current section and redraw again with the new height + $previousMaxHeight = $this->maxHeight; + $this->maxHeight = $maxHeight; + $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines); + + parent::doWrite($this->getVisibleContent(), false); + parent::doWrite($existingContent, false); + } + + /** + * Clears previous output for this section. + * + * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared + * + * @return void + */ + public function clear(?int $lines = null) + { + if (empty($this->content) || !$this->isDecorated()) { + return; + } + + if ($lines) { + array_splice($this->content, -$lines); + } else { + $lines = $this->lines; + $this->content = []; + } + + $this->lines -= $lines; + + parent::doWrite($this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $lines) : $lines), false); + } + + /** + * Overwrites the previous output with a new message. + * + * @return void + */ + public function overwrite(string|iterable $message) + { + $this->clear(); + $this->writeln($message); + } + + public function getContent(): string + { + return implode('', $this->content); + } + + public function getVisibleContent(): string + { + if (0 === $this->maxHeight) { + return $this->getContent(); + } + + return implode('', \array_slice($this->content, -$this->maxHeight)); + } + + /** + * @internal + */ + public function addContent(string $input, bool $newline = true): int + { + $width = $this->terminal->getWidth(); + $lines = explode(\PHP_EOL, $input); + $linesAdded = 0; + $count = \count($lines) - 1; + foreach ($lines as $i => $lineContent) { + // re-add the line break (that has been removed in the above `explode()` for + // - every line that is not the last line + // - if $newline is required, also add it to the last line + if ($i < $count || $newline) { + $lineContent .= \PHP_EOL; + } + + // skip line if there is no text (or newline for that matter) + if ('' === $lineContent) { + continue; + } + + // For the first line, check if the previous line (last entry of `$this->content`) + // needs to be continued (i.e. does not end with a line break). + if (0 === $i + && (false !== $lastLine = end($this->content)) + && !str_ends_with($lastLine, \PHP_EOL) + ) { + // deduct the line count of the previous line + $this->lines -= (int) ceil($this->getDisplayLength($lastLine) / $width) ?: 1; + // concatenate previous and new line + $lineContent = $lastLine.$lineContent; + // replace last entry of `$this->content` with the new expanded line + array_splice($this->content, -1, 1, $lineContent); + } else { + // otherwise just add the new content + $this->content[] = $lineContent; + } + + $linesAdded += (int) ceil($this->getDisplayLength($lineContent) / $width) ?: 1; + } + + $this->lines += $linesAdded; + + return $linesAdded; + } + + /** + * @internal + */ + public function addNewLineOfInputSubmit(): void + { + $this->content[] = \PHP_EOL; + ++$this->lines; + } + + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + // Simulate newline behavior for consistent output formatting, avoiding extra logic + if (!$newline && str_ends_with($message, \PHP_EOL)) { + $message = substr($message, 0, -\strlen(\PHP_EOL)); + $newline = true; + } + + if (!$this->isDecorated()) { + parent::doWrite($message, $newline); + + return; + } + + // Check if the previous line (last entry of `$this->content`) needs to be continued + // (i.e. does not end with a line break). In which case, it needs to be erased first. + $linesToClear = $deleteLastLine = ($lastLine = end($this->content) ?: '') && !str_ends_with($lastLine, \PHP_EOL) ? 1 : 0; + + $linesAdded = $this->addContent($message, $newline); + + if ($lineOverflow = $this->maxHeight > 0 && $this->lines > $this->maxHeight) { + // on overflow, clear the whole section and redraw again (to remove the first lines) + $linesToClear = $this->maxHeight; + } + + $erasedContent = $this->popStreamContentUntilCurrentSection($linesToClear); + + if ($lineOverflow) { + // redraw existing lines of the section + $previousLinesOfSection = \array_slice($this->content, $this->lines - $this->maxHeight, $this->maxHeight - $linesAdded); + parent::doWrite(implode('', $previousLinesOfSection), false); + } + + // if the last line was removed, re-print its content together with the new content. + // otherwise, just print the new content. + parent::doWrite($deleteLastLine ? $lastLine.$message : $message, true); + parent::doWrite($erasedContent, false); + } + + /** + * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits + * current section. Then it erases content it crawled through. Optionally, it erases part of current section too. + */ + private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string + { + $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection; + $erasedContent = []; + + foreach ($this->sections as $section) { + if ($section === $this) { + break; + } + + $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines; + if ('' !== $sectionContent = $section->getVisibleContent()) { + if (!str_ends_with($sectionContent, \PHP_EOL)) { + $sectionContent .= \PHP_EOL; + } + $erasedContent[] = $sectionContent; + } + } + + if ($numberOfLinesToClear > 0) { + // move cursor up n lines + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false); + // erase to end of screen + parent::doWrite("\x1b[0J", false); + } + + return implode('', array_reverse($erasedContent)); + } + + private function getDisplayLength(string $text): int + { + return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace("\t", ' ', $text))); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/NullOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/NullOutput.php new file mode 100644 index 000000000..f3aa15b1d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/NullOutput.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\NullOutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @author Fabien Potencier + * @author Tobias Schultze + */ +class NullOutput implements OutputInterface +{ + private NullOutputFormatter $formatter; + + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + // do nothing + } + + public function getFormatter(): OutputFormatterInterface + { + // to comply with the interface we must return a OutputFormatterInterface + return $this->formatter ??= new NullOutputFormatter(); + } + + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + // do nothing + } + + public function isDecorated(): bool + { + return false; + } + + /** + * @return void + */ + public function setVerbosity(int $level) + { + // do nothing + } + + public function getVerbosity(): int + { + return self::VERBOSITY_QUIET; + } + + public function isQuiet(): bool + { + return true; + } + + public function isVerbose(): bool + { + return false; + } + + public function isVeryVerbose(): bool + { + return false; + } + + public function isDebug(): bool + { + return false; + } + + /** + * @return void + */ + public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) + { + // do nothing + } + + /** + * @return void + */ + public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) + { + // do nothing + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/Output.php b/lam/lib/3rdParty/composer/symfony/console/Output/Output.php new file mode 100644 index 000000000..00f481e03 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/Output.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * Base class for output classes. + * + * There are five levels of verbosity: + * + * * normal: no option passed (normal output) + * * verbose: -v (more output) + * * very verbose: -vv (highly extended output) + * * debug: -vvv (all debug output) + * * quiet: -q (no output) + * + * @author Fabien Potencier + */ +abstract class Output implements OutputInterface +{ + private int $verbosity; + private OutputFormatterInterface $formatter; + + /** + * @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool $decorated Whether to decorate messages + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) + { + $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; + $this->formatter = $formatter ?? new OutputFormatter(); + $this->formatter->setDecorated($decorated); + } + + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->formatter = $formatter; + } + + public function getFormatter(): OutputFormatterInterface + { + return $this->formatter; + } + + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->formatter->setDecorated($decorated); + } + + public function isDecorated(): bool + { + return $this->formatter->isDecorated(); + } + + /** + * @return void + */ + public function setVerbosity(int $level) + { + $this->verbosity = $level; + } + + public function getVerbosity(): int + { + return $this->verbosity; + } + + public function isQuiet(): bool + { + return self::VERBOSITY_QUIET === $this->verbosity; + } + + public function isVerbose(): bool + { + return self::VERBOSITY_VERBOSE <= $this->verbosity; + } + + public function isVeryVerbose(): bool + { + return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; + } + + public function isDebug(): bool + { + return self::VERBOSITY_DEBUG <= $this->verbosity; + } + + /** + * @return void + */ + public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) + { + $this->write($messages, true, $options); + } + + /** + * @return void + */ + public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) + { + if (!is_iterable($messages)) { + $messages = [$messages]; + } + + $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN; + $type = $types & $options ?: self::OUTPUT_NORMAL; + + $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG; + $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL; + + if ($verbosity > $this->getVerbosity()) { + return; + } + + foreach ($messages as $message) { + switch ($type) { + case OutputInterface::OUTPUT_NORMAL: + $message = $this->formatter->format($message); + break; + case OutputInterface::OUTPUT_RAW: + break; + case OutputInterface::OUTPUT_PLAIN: + $message = strip_tags($this->formatter->format($message)); + break; + } + + $this->doWrite($message ?? '', $newline); + } + } + + /** + * Writes a message to the output. + * + * @return void + */ + abstract protected function doWrite(string $message, bool $newline); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/OutputInterface.php b/lam/lib/3rdParty/composer/symfony/console/Output/OutputInterface.php new file mode 100644 index 000000000..19a817901 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/OutputInterface.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @author Fabien Potencier + */ +interface OutputInterface +{ + public const VERBOSITY_QUIET = 16; + public const VERBOSITY_NORMAL = 32; + public const VERBOSITY_VERBOSE = 64; + public const VERBOSITY_VERY_VERBOSE = 128; + public const VERBOSITY_DEBUG = 256; + + public const OUTPUT_NORMAL = 1; + public const OUTPUT_RAW = 2; + public const OUTPUT_PLAIN = 4; + + /** + * Writes a message to the output. + * + * @param bool $newline Whether to add a newline + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), + * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void + */ + public function write(string|iterable $messages, bool $newline = false, int $options = 0); + + /** + * Writes a message to the output and adds a newline at the end. + * + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), + * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void + */ + public function writeln(string|iterable $messages, int $options = 0); + + /** + * Sets the verbosity of the output. + * + * @param self::VERBOSITY_* $level + * + * @return void + */ + public function setVerbosity(int $level); + + /** + * Gets the current verbosity of the output. + * + * @return self::VERBOSITY_* + */ + public function getVerbosity(): int; + + /** + * Returns whether verbosity is quiet (-q). + */ + public function isQuiet(): bool; + + /** + * Returns whether verbosity is verbose (-v). + */ + public function isVerbose(): bool; + + /** + * Returns whether verbosity is very verbose (-vv). + */ + public function isVeryVerbose(): bool; + + /** + * Returns whether verbosity is debug (-vvv). + */ + public function isDebug(): bool; + + /** + * Sets the decorated flag. + * + * @return void + */ + public function setDecorated(bool $decorated); + + /** + * Gets the decorated flag. + */ + public function isDecorated(): bool; + + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter); + + /** + * Returns current output formatter instance. + */ + public function getFormatter(): OutputFormatterInterface; +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/StreamOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/StreamOutput.php new file mode 100644 index 000000000..f51d03763 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/StreamOutput.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @author Fabien Potencier + */ +class StreamOutput extends Output +{ + /** @var resource */ + private $stream; + + /** + * @param resource $stream A stream resource + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @throws InvalidArgumentException When first argument is not a real stream + */ + public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) + { + if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { + throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + + $this->stream = $stream; + + $decorated ??= $this->hasColorSupport(); + + parent::__construct($verbosity, $decorated, $formatter); + } + + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + if ($newline) { + $message .= \PHP_EOL; + } + + @fwrite($this->stream, $message); + + fflush($this->stream); + } + + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo + * terminals via named pipes, so we can only check the environment. + * + * Reference: Composer\XdebugHandler\Process::supportsColor + * https://github.com/composer/xdebug-handler + * + * @return bool true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport(): bool + { + // Follow https://no-color.org/ + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { + return false; + } + + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) { + return true; + } + + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { + return true; + } + + if ('dumb' === $term = (string) getenv('TERM')) { + return false; + } + + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Output/TrimmedBufferOutput.php b/lam/lib/3rdParty/composer/symfony/console/Output/TrimmedBufferOutput.php new file mode 100644 index 000000000..90ee45aae --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Output/TrimmedBufferOutput.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * A BufferedOutput that keeps only the last N chars. + * + * @author Jérémy Derussé + */ +class TrimmedBufferOutput extends Output +{ + private int $maxLength; + private string $buffer = ''; + + public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) + { + if ($maxLength <= 0) { + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + } + + parent::__construct($verbosity, $decorated, $formatter); + $this->maxLength = $maxLength; + } + + /** + * Empties buffer and returns its content. + */ + public function fetch(): string + { + $content = $this->buffer; + $this->buffer = ''; + + return $content; + } + + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + $this->buffer .= $message; + + if ($newline) { + $this->buffer .= \PHP_EOL; + } + + $this->buffer = substr($this->buffer, 0 - $this->maxLength); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Question/ChoiceQuestion.php b/lam/lib/3rdParty/composer/symfony/console/Question/ChoiceQuestion.php new file mode 100644 index 000000000..9445ccc0c --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Question/ChoiceQuestion.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +use Symfony\Component\Console\Exception\InvalidArgumentException; + +/** + * Represents a choice question. + * + * @author Fabien Potencier + */ +class ChoiceQuestion extends Question +{ + private array $choices; + private bool $multiselect = false; + private string $prompt = ' > '; + private string $errorMessage = 'Value "%s" is invalid'; + + /** + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param string|bool|int|float|null $default The default answer to return + */ + public function __construct(string $question, array $choices, string|bool|int|float|null $default = null) + { + if (!$choices) { + throw new \LogicException('Choice question must have at least 1 choice available.'); + } + + parent::__construct($question, $default); + + $this->choices = $choices; + $this->setValidator($this->getDefaultValidator()); + $this->setAutocompleterValues($choices); + } + + /** + * Returns available choices. + */ + public function getChoices(): array + { + return $this->choices; + } + + /** + * Sets multiselect option. + * + * When multiselect is set to true, multiple choices can be answered. + * + * @return $this + */ + public function setMultiselect(bool $multiselect): static + { + $this->multiselect = $multiselect; + $this->setValidator($this->getDefaultValidator()); + + return $this; + } + + /** + * Returns whether the choices are multiselect. + */ + public function isMultiselect(): bool + { + return $this->multiselect; + } + + /** + * Gets the prompt for choices. + */ + public function getPrompt(): string + { + return $this->prompt; + } + + /** + * Sets the prompt for choices. + * + * @return $this + */ + public function setPrompt(string $prompt): static + { + $this->prompt = $prompt; + + return $this; + } + + /** + * Sets the error message for invalid values. + * + * The error message has a string placeholder (%s) for the invalid value. + * + * @return $this + */ + public function setErrorMessage(string $errorMessage): static + { + $this->errorMessage = $errorMessage; + $this->setValidator($this->getDefaultValidator()); + + return $this; + } + + private function getDefaultValidator(): callable + { + $choices = $this->choices; + $errorMessage = $this->errorMessage; + $multiselect = $this->multiselect; + $isAssoc = $this->isAssoc($choices); + + return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) { + if ($multiselect) { + // Check for a separated comma values + if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); + } + + $selectedChoices = explode(',', (string) $selected); + } else { + $selectedChoices = [$selected]; + } + + if ($this->isTrimmable()) { + foreach ($selectedChoices as $k => $v) { + $selectedChoices[$k] = trim((string) $v); + } + } + + $multiselectChoices = []; + foreach ($selectedChoices as $value) { + $results = []; + foreach ($choices as $key => $choice) { + if ($choice === $value) { + $results[] = $key; + } + } + + if (\count($results) > 1) { + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); + } + + $result = array_search($value, $choices); + + if (!$isAssoc) { + if (false !== $result) { + $result = $choices[$result]; + } elseif (isset($choices[$value])) { + $result = $choices[$value]; + } + } elseif (false === $result && isset($choices[$value])) { + $result = $value; + } + + if (false === $result) { + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); + } + + // For associative choices, consistently return the key as string: + $multiselectChoices[] = $isAssoc ? (string) $result : $result; + } + + if ($multiselect) { + return $multiselectChoices; + } + + return current($multiselectChoices); + }; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Question/ConfirmationQuestion.php b/lam/lib/3rdParty/composer/symfony/console/Question/ConfirmationQuestion.php new file mode 100644 index 000000000..40eab2429 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Question/ConfirmationQuestion.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +/** + * Represents a yes/no question. + * + * @author Fabien Potencier + */ +class ConfirmationQuestion extends Question +{ + private string $trueAnswerRegex; + + /** + * @param string $question The question to ask to the user + * @param bool $default The default answer to return, true or false + * @param string $trueAnswerRegex A regex to match the "yes" answer + */ + public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i') + { + parent::__construct($question, $default); + + $this->trueAnswerRegex = $trueAnswerRegex; + $this->setNormalizer($this->getDefaultNormalizer()); + } + + /** + * Returns the default answer normalizer. + */ + private function getDefaultNormalizer(): callable + { + $default = $this->getDefault(); + $regex = $this->trueAnswerRegex; + + return function ($answer) use ($default, $regex) { + if (\is_bool($answer)) { + return $answer; + } + + $answerIsTrue = (bool) preg_match($regex, $answer); + if (false === $default) { + return $answer && $answerIsTrue; + } + + return '' === $answer || $answerIsTrue; + }; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Question/Question.php b/lam/lib/3rdParty/composer/symfony/console/Question/Question.php new file mode 100644 index 000000000..ecbde56d5 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Question/Question.php @@ -0,0 +1,291 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\LogicException; + +/** + * Represents a Question. + * + * @author Fabien Potencier + */ +class Question +{ + private string $question; + private ?int $attempts = null; + private bool $hidden = false; + private bool $hiddenFallback = true; + private ?\Closure $autocompleterCallback = null; + private ?\Closure $validator = null; + private string|int|bool|float|null $default; + private ?\Closure $normalizer = null; + private bool $trimmable = true; + private bool $multiline = false; + + /** + * @param string $question The question to ask to the user + * @param string|bool|int|float|null $default The default answer to return if the user enters nothing + */ + public function __construct(string $question, string|bool|int|float|null $default = null) + { + $this->question = $question; + $this->default = $default; + } + + /** + * Returns the question. + */ + public function getQuestion(): string + { + return $this->question; + } + + /** + * Returns the default answer. + */ + public function getDefault(): string|bool|int|float|null + { + return $this->default; + } + + /** + * Returns whether the user response accepts newline characters. + */ + public function isMultiline(): bool + { + return $this->multiline; + } + + /** + * Sets whether the user response should accept newline characters. + * + * @return $this + */ + public function setMultiline(bool $multiline): static + { + $this->multiline = $multiline; + + return $this; + } + + /** + * Returns whether the user response must be hidden. + */ + public function isHidden(): bool + { + return $this->hidden; + } + + /** + * Sets whether the user response must be hidden or not. + * + * @return $this + * + * @throws LogicException In case the autocompleter is also used + */ + public function setHidden(bool $hidden): static + { + if ($this->autocompleterCallback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + + $this->hidden = $hidden; + + return $this; + } + + /** + * In case the response cannot be hidden, whether to fallback on non-hidden question or not. + */ + public function isHiddenFallback(): bool + { + return $this->hiddenFallback; + } + + /** + * Sets whether to fallback on non-hidden question if the response cannot be hidden. + * + * @return $this + */ + public function setHiddenFallback(bool $fallback): static + { + $this->hiddenFallback = $fallback; + + return $this; + } + + /** + * Gets values for the autocompleter. + */ + public function getAutocompleterValues(): ?iterable + { + $callback = $this->getAutocompleterCallback(); + + return $callback ? $callback('') : null; + } + + /** + * Sets values for the autocompleter. + * + * @return $this + * + * @throws LogicException + */ + public function setAutocompleterValues(?iterable $values): static + { + if (\is_array($values)) { + $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); + + $callback = static fn () => $values; + } elseif ($values instanceof \Traversable) { + $callback = static function () use ($values) { + static $valueCache; + + return $valueCache ??= iterator_to_array($values, false); + }; + } else { + $callback = null; + } + + return $this->setAutocompleterCallback($callback); + } + + /** + * Gets the callback function used for the autocompleter. + */ + public function getAutocompleterCallback(): ?callable + { + return $this->autocompleterCallback; + } + + /** + * Sets the callback function used for the autocompleter. + * + * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. + * + * @return $this + */ + public function setAutocompleterCallback(?callable $callback = null): static + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->hidden && null !== $callback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + + $this->autocompleterCallback = null === $callback ? null : $callback(...); + + return $this; + } + + /** + * Sets a validator for the question. + * + * @return $this + */ + public function setValidator(?callable $validator = null): static + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->validator = null === $validator ? null : $validator(...); + + return $this; + } + + /** + * Gets the validator for the question. + */ + public function getValidator(): ?callable + { + return $this->validator; + } + + /** + * Sets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @return $this + * + * @throws InvalidArgumentException in case the number of attempts is invalid + */ + public function setMaxAttempts(?int $attempts): static + { + if (null !== $attempts && $attempts < 1) { + throw new InvalidArgumentException('Maximum number of attempts must be a positive value.'); + } + + $this->attempts = $attempts; + + return $this; + } + + /** + * Gets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + */ + public function getMaxAttempts(): ?int + { + return $this->attempts; + } + + /** + * Sets a normalizer for the response. + * + * The normalizer can be a callable (a string), a closure or a class implementing __invoke. + * + * @return $this + */ + public function setNormalizer(callable $normalizer): static + { + $this->normalizer = $normalizer(...); + + return $this; + } + + /** + * Gets the normalizer for the response. + * + * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. + */ + public function getNormalizer(): ?callable + { + return $this->normalizer; + } + + /** + * @return bool + */ + protected function isAssoc(array $array) + { + return (bool) \count(array_filter(array_keys($array), 'is_string')); + } + + public function isTrimmable(): bool + { + return $this->trimmable; + } + + /** + * @return $this + */ + public function setTrimmable(bool $trimmable): static + { + $this->trimmable = $trimmable; + + return $this; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/README.md b/lam/lib/3rdParty/composer/symfony/console/README.md new file mode 100644 index 000000000..e9013182a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/README.md @@ -0,0 +1,36 @@ +Console Component +================= + +The Console component eases the creation of beautiful and testable command line +interfaces. + +Sponsor +------- + +The Console component for Symfony 6.4 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and +fix your projects. They provide a wide range of professional services including development, +consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. +They are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/console.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +Credits +------- + +`Resources/bin/hiddeninput.exe` is a third party binary provided within this +component. Find sources and license at https://github.com/Seldaek/hidden-input. + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/lam/lib/3rdParty/composer/symfony/console/Resources/completion.bash b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.bash new file mode 100644 index 000000000..64c6a338f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.bash @@ -0,0 +1,94 @@ +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +_sf_{{ COMMAND_NAME }}() { + + # Use the default completion for shell redirect operators. + for w in '>' '>>' '&>' '<'; do + if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then + compopt -o filenames + COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) + return 0 + fi + done + + # Use newline as only separator to allow space in completion values + local IFS=$'\n' + local sf_cmd="${COMP_WORDS[0]}" + + # for an alias, get the real script behind it + sf_cmd_type=$(type -t $sf_cmd) + if [[ $sf_cmd_type == "alias" ]]; then + sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/") + elif [[ $sf_cmd_type == "file" ]]; then + sf_cmd=$(type -p $sf_cmd) + fi + + if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then + return 1 + fi + + local cur prev words cword + _get_comp_words_by_ref -n := cur prev words cword + + local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-a{{ VERSION }}") + for w in ${words[@]}; do + w=$(printf -- '%b' "$w") + # remove quotes from typed values + quote="${w:0:1}" + if [ "$quote" == \' ]; then + w="${w%\'}" + w="${w#\'}" + elif [ "$quote" == \" ]; then + w="${w%\"}" + w="${w#\"}" + fi + # empty values are ignored + if [ ! -z "$w" ]; then + completecmd+=("-i$w") + fi + done + + local sfcomplete + if sfcomplete=$(${completecmd[@]} 2>&1); then + local quote suggestions + quote=${cur:0:1} + + # Use single quotes by default if suggestions contains backslash (FQCN) + if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then + quote=\' + fi + + if [ "$quote" == \' ]; then + # single quotes: no additional escaping (does not accept ' in values) + suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) + elif [ "$quote" == \" ]; then + # double quotes: double escaping for \ $ ` " + suggestions=$(for s in $sfcomplete; do + s=${s//\\/\\\\} + s=${s//\$/\\\$} + s=${s//\`/\\\`} + s=${s//\"/\\\"} + printf $'%q%q%q\n' "$quote" "$s" "$quote"; + done) + else + # no quotes: double escaping + suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) + fi + COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) + __ltrim_colon_completions "$cur" + else + if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then + >&2 echo + >&2 echo $sfcomplete + fi + + return 1 + fi +} + +complete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} diff --git a/lam/lib/3rdParty/composer/symfony/console/Resources/completion.fish b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.fish new file mode 100644 index 000000000..1c34292ae --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.fish @@ -0,0 +1,29 @@ +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +function _sf_{{ COMMAND_NAME }} + set sf_cmd (commandline -o) + set c (count (commandline -oc)) + + set completecmd "$sf_cmd[1]" "_complete" "--no-interaction" "-sfish" "-a{{ VERSION }}" + + for i in $sf_cmd + if [ $i != "" ] + set completecmd $completecmd "-i$i" + end + end + + set completecmd $completecmd "-c$c" + + set sfcomplete ($completecmd) + + for i in $sfcomplete + echo $i + end +end + +complete -c '{{ COMMAND_NAME }}' -a '(_sf_{{ COMMAND_NAME }})' -f diff --git a/lam/lib/3rdParty/composer/symfony/console/Resources/completion.zsh b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.zsh new file mode 100644 index 000000000..ff76fe5fa --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Resources/completion.zsh @@ -0,0 +1,82 @@ +#compdef {{ COMMAND_NAME }} + +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +# +# zsh completions for {{ COMMAND_NAME }} +# +# References: +# - https://github.com/spf13/cobra/blob/master/zsh_completions.go +# - https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Console/Resources/completion.bash +# +_sf_{{ COMMAND_NAME }}() { + local lastParam flagPrefix requestComp out comp + local -a completions + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $CURRENT location, so we need + # to truncate the command-line ($words) up to the $CURRENT location. + # (We cannot use $CURSOR as its value does not work when a command is an alias.) + words=("${=words[1,CURRENT]}") lastParam=${words[-1]} + + # For zsh, when completing a flag with an = (e.g., {{ COMMAND_NAME }} -n=) + # completions must be prefixed with the flag + setopt local_options BASH_REMATCH + if [[ "${lastParam}" =~ '-.*=' ]]; then + # We are dealing with a flag with an = + flagPrefix="-P ${BASH_REMATCH}" + fi + + # Prepare the command to obtain completions + requestComp="${words[0]} ${words[1]} _complete --no-interaction -szsh -a{{ VERSION }} -c$((CURRENT-1))" i="" + for w in ${words[@]}; do + w=$(printf -- '%b' "$w") + # remove quotes from typed values + quote="${w:0:1}" + if [ "$quote" = \' ]; then + w="${w%\'}" + w="${w#\'}" + elif [ "$quote" = \" ]; then + w="${w%\"}" + w="${w#\"}" + fi + # empty values are ignored + if [ ! -z "$w" ]; then + i="${i}-i${w} " + fi + done + + # Ensure at least 1 input + if [ "${i}" = "" ]; then + requestComp="${requestComp} -i\" \"" + else + requestComp="${requestComp} ${i}" + fi + + # Use eval to handle any environment variables and such + out=$(eval ${requestComp} 2>/dev/null) + + while IFS='\n' read -r comp; do + if [ -n "$comp" ]; then + # If requested, completions are returned with a description. + # The description is preceded by a TAB character. + # For zsh's _describe, we need to use a : instead of a TAB. + # We first need to escape any : as part of the completion itself. + comp=${comp//:/\\:} + local tab=$(printf '\t') + comp=${comp//$tab/:} + completions+=${comp} + fi + done < <(printf "%s\n" "${out[@]}") + + # Let inbuilt _describe handle completions + eval _describe "completions" completions $flagPrefix + return $? +} + +compdef _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} diff --git a/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalMap.php b/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalMap.php new file mode 100644 index 000000000..2f9aa67c1 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalMap.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\SignalRegistry; + +/** + * @author Grégoire Pineau + */ +class SignalMap +{ + private static array $map; + + public static function getSignalName(int $signal): ?string + { + if (!\extension_loaded('pcntl')) { + return null; + } + + if (!isset(self::$map)) { + $r = new \ReflectionExtension('pcntl'); + $c = $r->getConstants(); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); + self::$map = array_flip($map); + } + + return self::$map[$signal] ?? null; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalRegistry.php b/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalRegistry.php new file mode 100644 index 000000000..ef2e5f04e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/SignalRegistry/SignalRegistry.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\SignalRegistry; + +final class SignalRegistry +{ + private array $signalHandlers = []; + + public function __construct() + { + if (\function_exists('pcntl_async_signals')) { + pcntl_async_signals(true); + } + } + + public function register(int $signal, callable $signalHandler): void + { + if (!isset($this->signalHandlers[$signal])) { + $previousCallback = pcntl_signal_get_handler($signal); + + if (\is_callable($previousCallback)) { + $this->signalHandlers[$signal][] = $previousCallback; + } + } + + $this->signalHandlers[$signal][] = $signalHandler; + + pcntl_signal($signal, $this->handle(...)); + } + + public static function isSupported(): bool + { + return \function_exists('pcntl_signal'); + } + + /** + * @internal + */ + public function handle(int $signal): void + { + $count = \count($this->signalHandlers[$signal]); + + foreach ($this->signalHandlers[$signal] as $i => $signalHandler) { + $hasNext = $i !== $count - 1; + $signalHandler($signal, $hasNext); + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/SingleCommandApplication.php b/lam/lib/3rdParty/composer/symfony/console/SingleCommandApplication.php new file mode 100644 index 000000000..ff1c17247 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/SingleCommandApplication.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Grégoire Pineau + */ +class SingleCommandApplication extends Command +{ + private string $version = 'UNKNOWN'; + private bool $autoExit = true; + private bool $running = false; + + /** + * @return $this + */ + public function setVersion(string $version): static + { + $this->version = $version; + + return $this; + } + + /** + * @final + * + * @return $this + */ + public function setAutoExit(bool $autoExit): static + { + $this->autoExit = $autoExit; + + return $this; + } + + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int + { + if ($this->running) { + return parent::run($input, $output); + } + + // We use the command name as the application name + $application = new Application($this->getName() ?: 'UNKNOWN', $this->version); + $application->setAutoExit($this->autoExit); + // Fix the usage of the command displayed with "--help" + $this->setName($_SERVER['argv'][0]); + $application->add($this); + $application->setDefaultCommand($this->getName(), true); + + $this->running = true; + try { + $ret = $application->run($input, $output); + } finally { + $this->running = false; + } + + return $ret ?? 1; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Style/OutputStyle.php b/lam/lib/3rdParty/composer/symfony/console/Style/OutputStyle.php new file mode 100644 index 000000000..ddfa8decc --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Style/OutputStyle.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Decorates output to add console style guide helpers. + * + * @author Kevin Bond + */ +abstract class OutputStyle implements OutputInterface, StyleInterface +{ + private OutputInterface $output; + + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + + /** + * @return void + */ + public function newLine(int $count = 1) + { + $this->output->write(str_repeat(\PHP_EOL, $count)); + } + + public function createProgressBar(int $max = 0): ProgressBar + { + return new ProgressBar($this->output, $max); + } + + /** + * @return void + */ + public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) + { + $this->output->write($messages, $newline, $type); + } + + /** + * @return void + */ + public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) + { + $this->output->writeln($messages, $type); + } + + /** + * @return void + */ + public function setVerbosity(int $level) + { + $this->output->setVerbosity($level); + } + + public function getVerbosity(): int + { + return $this->output->getVerbosity(); + } + + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->output->setDecorated($decorated); + } + + public function isDecorated(): bool + { + return $this->output->isDecorated(); + } + + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->output->setFormatter($formatter); + } + + public function getFormatter(): OutputFormatterInterface + { + return $this->output->getFormatter(); + } + + public function isQuiet(): bool + { + return $this->output->isQuiet(); + } + + public function isVerbose(): bool + { + return $this->output->isVerbose(); + } + + public function isVeryVerbose(): bool + { + return $this->output->isVeryVerbose(); + } + + public function isDebug(): bool + { + return $this->output->isDebug(); + } + + /** + * @return OutputInterface + */ + protected function getErrorOutput() + { + if (!$this->output instanceof ConsoleOutputInterface) { + return $this->output; + } + + return $this->output->getErrorOutput(); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Style/StyleInterface.php b/lam/lib/3rdParty/composer/symfony/console/Style/StyleInterface.php new file mode 100644 index 000000000..6bced158a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Style/StyleInterface.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +/** + * Output style helpers. + * + * @author Kevin Bond + */ +interface StyleInterface +{ + /** + * Formats a command title. + * + * @return void + */ + public function title(string $message); + + /** + * Formats a section title. + * + * @return void + */ + public function section(string $message); + + /** + * Formats a list. + * + * @return void + */ + public function listing(array $elements); + + /** + * Formats informational text. + * + * @return void + */ + public function text(string|array $message); + + /** + * Formats a success result bar. + * + * @return void + */ + public function success(string|array $message); + + /** + * Formats an error result bar. + * + * @return void + */ + public function error(string|array $message); + + /** + * Formats an warning result bar. + * + * @return void + */ + public function warning(string|array $message); + + /** + * Formats a note admonition. + * + * @return void + */ + public function note(string|array $message); + + /** + * Formats a caution admonition. + * + * @return void + */ + public function caution(string|array $message); + + /** + * Formats a table. + * + * @return void + */ + public function table(array $headers, array $rows); + + /** + * Asks a question. + */ + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed; + + /** + * Asks a question with the user input hidden. + */ + public function askHidden(string $question, ?callable $validator = null): mixed; + + /** + * Asks for confirmation. + */ + public function confirm(string $question, bool $default = true): bool; + + /** + * Asks a choice question. + */ + public function choice(string $question, array $choices, mixed $default = null): mixed; + + /** + * Add newline(s). + * + * @return void + */ + public function newLine(int $count = 1); + + /** + * Starts the progress output. + * + * @return void + */ + public function progressStart(int $max = 0); + + /** + * Advances the progress output X steps. + * + * @return void + */ + public function progressAdvance(int $step = 1); + + /** + * Finishes the progress output. + * + * @return void + */ + public function progressFinish(); +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Style/SymfonyStyle.php b/lam/lib/3rdParty/composer/symfony/console/Style/SymfonyStyle.php new file mode 100644 index 000000000..135f4fd0e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Style/SymfonyStyle.php @@ -0,0 +1,514 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Helper\OutputWrapper; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableCell; +use Symfony\Component\Console\Helper\TableSeparator; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\ConsoleSectionOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\TrimmedBufferOutput; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Terminal; + +/** + * Output decorator helpers for the Symfony Style Guide. + * + * @author Kevin Bond + */ +class SymfonyStyle extends OutputStyle +{ + public const MAX_LINE_LENGTH = 120; + + private InputInterface $input; + private OutputInterface $output; + private SymfonyQuestionHelper $questionHelper; + private ProgressBar $progressBar; + private int $lineLength; + private TrimmedBufferOutput $bufferedOutput; + + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; + $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + + parent::__construct($this->output = $output); + } + + /** + * Formats a message as a block of text. + * + * @return void + */ + public function block(string|array $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) + { + $messages = \is_array($messages) ? array_values($messages) : [$messages]; + + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); + $this->newLine(); + } + + /** + * @return void + */ + public function title(string $message) + { + $this->autoPrependBlock(); + $this->writeln([ + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + ]); + $this->newLine(); + } + + /** + * @return void + */ + public function section(string $message) + { + $this->autoPrependBlock(); + $this->writeln([ + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + ]); + $this->newLine(); + } + + /** + * @return void + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements); + + $this->writeln($elements); + $this->newLine(); + } + + /** + * @return void + */ + public function text(string|array $message) + { + $this->autoPrependText(); + + $messages = \is_array($message) ? array_values($message) : [$message]; + foreach ($messages as $message) { + $this->writeln(\sprintf(' %s', $message)); + } + } + + /** + * Formats a command comment. + * + * @return void + */ + public function comment(string|array $message) + { + $this->block($message, null, null, ' // ', false, false); + } + + /** + * @return void + */ + public function success(string|array $message) + { + $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); + } + + /** + * @return void + */ + public function error(string|array $message) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); + } + + /** + * @return void + */ + public function warning(string|array $message) + { + $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true); + } + + /** + * @return void + */ + public function note(string|array $message) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ! '); + } + + /** + * Formats an info message. + * + * @return void + */ + public function info(string|array $message) + { + $this->block($message, 'INFO', 'fg=green', ' ', true); + } + + /** + * @return void + */ + public function caution(string|array $message) + { + $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); + } + + /** + * @return void + */ + public function table(array $headers, array $rows) + { + $this->createTable() + ->setHeaders($headers) + ->setRows($rows) + ->render() + ; + + $this->newLine(); + } + + /** + * Formats a horizontal table. + * + * @return void + */ + public function horizontalTable(array $headers, array $rows) + { + $this->createTable() + ->setHorizontal(true) + ->setHeaders($headers) + ->setRows($rows) + ->render() + ; + + $this->newLine(); + } + + /** + * Formats a list of key/value horizontally. + * + * Each row can be one of: + * * 'A title' + * * ['key' => 'value'] + * * new TableSeparator() + * + * @return void + */ + public function definitionList(string|array|TableSeparator ...$list) + { + $headers = []; + $row = []; + foreach ($list as $value) { + if ($value instanceof TableSeparator) { + $headers[] = $value; + $row[] = $value; + continue; + } + if (\is_string($value)) { + $headers[] = new TableCell($value, ['colspan' => 2]); + $row[] = null; + continue; + } + if (!\is_array($value)) { + throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.'); + } + $headers[] = key($value); + $row[] = current($value); + } + + $this->horizontalTable($headers, [$row]); + } + + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed + { + $question = new Question($question, $default); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + public function askHidden(string $question, ?callable $validator = null): mixed + { + $question = new Question($question); + + $question->setHidden(true); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + public function confirm(string $question, bool $default = true): bool + { + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + + public function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed + { + if (null !== $default) { + $values = array_flip($choices); + $default = $values[$default] ?? $default; + } + + $questionChoice = new ChoiceQuestion($question, $choices, $default); + $questionChoice->setMultiselect($multiSelect); + + return $this->askQuestion($questionChoice); + } + + /** + * @return void + */ + public function progressStart(int $max = 0) + { + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + + /** + * @return void + */ + public function progressAdvance(int $step = 1) + { + $this->getProgressBar()->advance($step); + } + + /** + * @return void + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + unset($this->progressBar); + } + + public function createProgressBar(int $max = 0): ProgressBar + { + $progressBar = parent::createProgressBar($max); + + if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) { + $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 + $progressBar->setProgressCharacter(''); + $progressBar->setBarCharacter('▓'); // dark shade character \u2593 + } + + return $progressBar; + } + + /** + * @see ProgressBar::iterate() + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable + */ + public function progressIterate(iterable $iterable, ?int $max = null): iterable + { + yield from $this->createProgressBar()->iterate($iterable, $max); + + $this->newLine(2); + } + + public function askQuestion(Question $question): mixed + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + + $this->questionHelper ??= new SymfonyQuestionHelper(); + + $answer = $this->questionHelper->ask($this->input, $this, $question); + + if ($this->input->isInteractive()) { + if ($this->output instanceof ConsoleSectionOutput) { + // add the new line of the `return` to submit the input to ConsoleSectionOutput, because ConsoleSectionOutput is holding all it's lines. + // this is relevant when a `ConsoleSectionOutput::clear` is called. + $this->output->addNewLineOfInputSubmit(); + } + $this->newLine(); + $this->bufferedOutput->write("\n"); + } + + return $answer; + } + + /** + * @return void + */ + public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) + { + if (!is_iterable($messages)) { + $messages = [$messages]; + } + + foreach ($messages as $message) { + parent::writeln($message, $type); + $this->writeBuffer($message, true, $type); + } + } + + /** + * @return void + */ + public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) + { + if (!is_iterable($messages)) { + $messages = [$messages]; + } + + foreach ($messages as $message) { + parent::write($message, $newline, $type); + $this->writeBuffer($message, $newline, $type); + } + } + + /** + * @return void + */ + public function newLine(int $count = 1) + { + parent::newLine($count); + $this->bufferedOutput->write(str_repeat("\n", $count)); + } + + /** + * Returns a new instance which makes use of stderr if available. + */ + public function getErrorStyle(): self + { + return new self($this->input, $this->getErrorOutput()); + } + + public function createTable(): Table + { + $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output; + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + + return (new Table($output))->setStyle($style); + } + + private function getProgressBar(): ProgressBar + { + return $this->progressBar + ?? throw new RuntimeException('The ProgressBar is not started.'); + } + + private function autoPrependBlock(): void + { + $chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + + if (!isset($chars[0])) { + $this->newLine(); // empty history, so we should start with a new line. + + return; + } + // Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - substr_count($chars, "\n")); + } + + private function autoPrependText(): void + { + $fetched = $this->bufferedOutput->fetch(); + // Prepend new line if last char isn't EOL: + if ($fetched && !str_ends_with($fetched, "\n")) { + $this->newLine(); + } + } + + private function writeBuffer(string $message, bool $newLine, int $type): void + { + // We need to know if the last chars are PHP_EOL + $this->bufferedOutput->write($message, $newLine, $type); + } + + private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array + { + $indentLength = 0; + $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); + $lines = []; + + if (null !== $type) { + $type = \sprintf('[%s] ', $type); + $indentLength = Helper::width($type); + $lineIndentation = str_repeat(' ', $indentLength); + } + + // wrap and add newlines for each element + $outputWrapper = new OutputWrapper(); + foreach ($messages as $key => $message) { + if ($escape) { + $message = OutputFormatter::escape($message); + } + + $lines = array_merge( + $lines, + explode(\PHP_EOL, $outputWrapper->wrap( + $message, + $this->lineLength - $prefixLength - $indentLength, + \PHP_EOL + )) + ); + + if (\count($messages) > 1 && $key < \count($messages) - 1) { + $lines[] = ''; + } + } + + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + array_unshift($lines, ''); + $lines[] = ''; + } + + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; + } + + $line = $prefix.$line; + $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); + + if ($style) { + $line = \sprintf('<%s>%s', $style, $line); + } + } + + return $lines; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Terminal.php b/lam/lib/3rdParty/composer/symfony/console/Terminal.php new file mode 100644 index 000000000..f094adedc --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Terminal.php @@ -0,0 +1,235 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Output\AnsiColorMode; + +class Terminal +{ + public const DEFAULT_COLOR_MODE = AnsiColorMode::Ansi4; + + private static ?AnsiColorMode $colorMode = null; + private static ?int $width = null; + private static ?int $height = null; + private static ?bool $stty = null; + + /** + * About Ansi color types: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + * For more information about true color support with terminals https://github.com/termstandard/colors/. + */ + public static function getColorMode(): AnsiColorMode + { + // Use Cache from previous run (or user forced mode) + if (null !== self::$colorMode) { + return self::$colorMode; + } + + // Try with $COLORTERM first + if (\is_string($colorterm = getenv('COLORTERM'))) { + $colorterm = strtolower($colorterm); + + if (str_contains($colorterm, 'truecolor')) { + self::setColorMode(AnsiColorMode::Ansi24); + + return self::$colorMode; + } + + if (str_contains($colorterm, '256color')) { + self::setColorMode(AnsiColorMode::Ansi8); + + return self::$colorMode; + } + } + + // Try with $TERM + if (\is_string($term = getenv('TERM'))) { + $term = strtolower($term); + + if (str_contains($term, 'truecolor')) { + self::setColorMode(AnsiColorMode::Ansi24); + + return self::$colorMode; + } + + if (str_contains($term, '256color')) { + self::setColorMode(AnsiColorMode::Ansi8); + + return self::$colorMode; + } + } + + self::setColorMode(self::DEFAULT_COLOR_MODE); + + return self::$colorMode; + } + + /** + * Force a terminal color mode rendering. + */ + public static function setColorMode(?AnsiColorMode $colorMode): void + { + self::$colorMode = $colorMode; + } + + /** + * Gets the terminal width. + */ + public function getWidth(): int + { + $width = getenv('COLUMNS'); + if (false !== $width) { + return (int) trim($width); + } + + if (null === self::$width) { + self::initDimensions(); + } + + return self::$width ?: 80; + } + + /** + * Gets the terminal height. + */ + public function getHeight(): int + { + $height = getenv('LINES'); + if (false !== $height) { + return (int) trim($height); + } + + if (null === self::$height) { + self::initDimensions(); + } + + return self::$height ?: 50; + } + + /** + * @internal + */ + public static function hasSttyAvailable(): bool + { + if (null !== self::$stty) { + return self::$stty; + } + + // skip check if shell_exec function is disabled + if (!\function_exists('shell_exec')) { + return false; + } + + return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); + } + + private static function initDimensions(): void + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $ansicon = getenv('ANSICON'); + if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) { + // extract [w, H] from "wxh (WxH)" + // or [w, h] from "wxh" + self::$width = (int) $matches[1]; + self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; + } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { + // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) + // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT + self::initDimensionsUsingStty(); + } elseif (null !== $dimensions = self::getConsoleMode()) { + // extract [w, h] from "wxh" + self::$width = (int) $dimensions[0]; + self::$height = (int) $dimensions[1]; + } + } else { + self::initDimensionsUsingStty(); + } + } + + /** + * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). + */ + private static function hasVt100Support(): bool + { + return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w')); + } + + /** + * Initializes dimensions using the output of an stty columns line. + */ + private static function initDimensionsUsingStty(): void + { + if ($sttyString = self::getSttyColumns()) { + if (preg_match('/rows.(\d+);.columns.(\d+);/is', $sttyString, $matches)) { + // extract [w, h] from "rows h; columns w;" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/is', $sttyString, $matches)) { + // extract [w, h] from "; h rows; w columns" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } + } + } + + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return int[]|null An array composed of the width and the height or null if it could not be parsed + */ + private static function getConsoleMode(): ?array + { + $info = self::readFromProcess('mode CON'); + + if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { + return null; + } + + return [(int) $matches[2], (int) $matches[1]]; + } + + /** + * Runs and parses stty -a if it's available, suppressing any error output. + */ + private static function getSttyColumns(): ?string + { + return self::readFromProcess(['stty', '-a']); + } + + private static function readFromProcess(string|array $command): ?string + { + if (!\function_exists('proc_open')) { + return null; + } + + $descriptorspec = [ + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + + $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0; + + if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) { + return null; + } + + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + if ($cp) { + sapi_windows_cp_set($cp); + } + + return $info; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Tester/ApplicationTester.php b/lam/lib/3rdParty/composer/symfony/console/Tester/ApplicationTester.php new file mode 100644 index 000000000..58aee54d6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Tester/ApplicationTester.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArrayInput; + +/** + * Eases the testing of console applications. + * + * When testing an application, don't forget to disable the auto exit flag: + * + * $application = new Application(); + * $application->setAutoExit(false); + * + * @author Fabien Potencier + */ +class ApplicationTester +{ + use TesterTrait; + + private Application $application; + + public function __construct(Application $application) + { + $this->application = $application; + } + + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @return int The command exit code + */ + public function run(array $input, array $options = []): int + { + $prevShellVerbosity = getenv('SHELL_VERBOSITY'); + + try { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + if ($this->inputs) { + $this->input->setStream(self::createStream($this->inputs)); + } + + $this->initOutput($options); + + return $this->statusCode = $this->application->run($this->input, $this->output); + } finally { + // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it + // to its previous value to avoid one test's verbosity to spread to the following tests + if (false === $prevShellVerbosity) { + if (\function_exists('putenv')) { + @putenv('SHELL_VERBOSITY'); + } + unset($_ENV['SHELL_VERBOSITY']); + unset($_SERVER['SHELL_VERBOSITY']); + } else { + if (\function_exists('putenv')) { + @putenv('SHELL_VERBOSITY='.$prevShellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity; + } + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Tester/CommandCompletionTester.php b/lam/lib/3rdParty/composer/symfony/console/Tester/CommandCompletionTester.php new file mode 100644 index 000000000..a90fe52ef --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Tester/CommandCompletionTester.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; + +/** + * Eases the testing of command completion. + * + * @author Jérôme Tamarelle + */ +class CommandCompletionTester +{ + private Command $command; + + public function __construct(Command $command) + { + $this->command = $command; + } + + /** + * Create completion suggestions from input tokens. + */ + public function complete(array $input): array + { + $currentIndex = \count($input); + if ('' === end($input)) { + array_pop($input); + } + array_unshift($input, $this->command->getName()); + + $completionInput = CompletionInput::fromTokens($input, $currentIndex); + $completionInput->bind($this->command->getDefinition()); + $suggestions = new CompletionSuggestions(); + + $this->command->complete($completionInput, $suggestions); + + $options = []; + foreach ($suggestions->getOptionSuggestions() as $option) { + $options[] = '--'.$option->getName(); + } + + return array_map('strval', array_merge($options, $suggestions->getValueSuggestions())); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Tester/CommandTester.php b/lam/lib/3rdParty/composer/symfony/console/Tester/CommandTester.php new file mode 100644 index 000000000..2ff813b7d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Tester/CommandTester.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; + +/** + * Eases the testing of console commands. + * + * @author Fabien Potencier + * @author Robin Chalas + */ +class CommandTester +{ + use TesterTrait; + + private Command $command; + + public function __construct(Command $command) + { + $this->command = $command; + } + + /** + * Executes the command. + * + * Available execution options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @param array $input An array of command arguments and options + * @param array $options An array of execution options + * + * @return int The command exit code + */ + public function execute(array $input, array $options = []): int + { + // set the command name automatically if the application requires + // this argument and no command name was passed + if (!isset($input['command']) + && (null !== $application = $this->command->getApplication()) + && $application->getDefinition()->hasArgument('command') + ) { + $input = array_merge(['command' => $this->command->getName()], $input); + } + + $this->input = new ArrayInput($input); + // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. + $this->input->setStream(self::createStream($this->inputs)); + + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + if (!isset($options['decorated'])) { + $options['decorated'] = false; + } + + $this->initOutput($options); + + return $this->statusCode = $this->command->run($this->input, $this->output); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Tester/Constraint/CommandIsSuccessful.php b/lam/lib/3rdParty/composer/symfony/console/Tester/Constraint/CommandIsSuccessful.php new file mode 100644 index 000000000..d677c27aa --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Tester/Constraint/CommandIsSuccessful.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Console\Command\Command; + +final class CommandIsSuccessful extends Constraint +{ + public function toString(): string + { + return 'is successful'; + } + + protected function matches($other): bool + { + return Command::SUCCESS === $other; + } + + protected function failureDescription($other): string + { + return 'the command '.$this->toString(); + } + + protected function additionalFailureDescription($other): string + { + $mapping = [ + Command::FAILURE => 'Command failed.', + Command::INVALID => 'Command was invalid.', + ]; + + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/Tester/TesterTrait.php b/lam/lib/3rdParty/composer/symfony/console/Tester/TesterTrait.php new file mode 100644 index 000000000..127556d1d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/Tester/TesterTrait.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use PHPUnit\Framework\Assert; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful; + +/** + * @author Amrouche Hamza + */ +trait TesterTrait +{ + private StreamOutput $output; + private array $inputs = []; + private bool $captureStreamsIndependently = false; + private InputInterface $input; + private int $statusCode; + + /** + * Gets the display returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + */ + public function getDisplay(bool $normalize = false): string + { + if (!isset($this->output)) { + throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?'); + } + + rewind($this->output->getStream()); + + $display = stream_get_contents($this->output->getStream()); + + if ($normalize) { + $display = str_replace(\PHP_EOL, "\n", $display); + } + + return $display; + } + + /** + * Gets the output written to STDERR by the application. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + */ + public function getErrorOutput(bool $normalize = false): string + { + if (!$this->captureStreamsIndependently) { + throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); + } + + rewind($this->output->getErrorOutput()->getStream()); + + $display = stream_get_contents($this->output->getErrorOutput()->getStream()); + + if ($normalize) { + $display = str_replace(\PHP_EOL, "\n", $display); + } + + return $display; + } + + /** + * Gets the input instance used by the last execution of the command or application. + */ + public function getInput(): InputInterface + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the command or application. + */ + public function getOutput(): OutputInterface + { + return $this->output; + } + + /** + * Gets the status code returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + */ + public function getStatusCode(): int + { + return $this->statusCode ?? throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?'); + } + + public function assertCommandIsSuccessful(string $message = ''): void + { + Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message); + } + + /** + * Sets the user inputs. + * + * @param array $inputs An array of strings representing each input + * passed to the command input stream + * + * @return $this + */ + public function setInputs(array $inputs): static + { + $this->inputs = $inputs; + + return $this; + } + + /** + * Initializes the output property. + * + * Available options: + * + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + */ + private function initOutput(array $options): void + { + $this->captureStreamsIndependently = $options['capture_stderr_separately'] ?? false; + if (!$this->captureStreamsIndependently) { + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + } else { + $this->output = new ConsoleOutput( + $options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL, + $options['decorated'] ?? null + ); + + $errorOutput = new StreamOutput(fopen('php://memory', 'w', false)); + $errorOutput->setFormatter($this->output->getFormatter()); + $errorOutput->setVerbosity($this->output->getVerbosity()); + $errorOutput->setDecorated($this->output->isDecorated()); + + $reflectedOutput = new \ReflectionObject($this->output); + $strErrProperty = $reflectedOutput->getProperty('stderr'); + $strErrProperty->setValue($this->output, $errorOutput); + + $reflectedParent = $reflectedOutput->getParentClass(); + $streamProperty = $reflectedParent->getProperty('stream'); + $streamProperty->setValue($this->output, fopen('php://memory', 'w', false)); + } + } + + /** + * @return resource + */ + private static function createStream(array $inputs) + { + $stream = fopen('php://memory', 'r+', false); + + foreach ($inputs as $input) { + fwrite($stream, $input.\PHP_EOL); + + if (str_contains($input, \PHP_EOL)) { + fwrite($stream, "\x4"); + } + } + + rewind($stream); + + return $stream; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/console/composer.json b/lam/lib/3rdParty/composer/symfony/console/composer.json new file mode 100644 index 000000000..1610f7341 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/console/composer.json @@ -0,0 +1,55 @@ +{ + "name": "symfony/console", + "type": "library", + "description": "Eases the creation of beautiful and testable command line interfaces", + "keywords": ["console", "cli", "command-line", "terminal"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "require-dev": { + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "psr/log": "^1|^2|^3" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Console\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/lam/lib/3rdParty/composer/symfony/deprecation-contracts/composer.json b/lam/lib/3rdParty/composer/symfony/deprecation-contracts/composer.json index ceb6c0796..5533b5c3f 100644 --- a/lam/lib/3rdParty/composer/symfony/deprecation-contracts/composer.json +++ b/lam/lib/3rdParty/composer/symfony/deprecation-contracts/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/lam/lib/3rdParty/composer/symfony/http-client-contracts/ResponseInterface.php b/lam/lib/3rdParty/composer/symfony/http-client-contracts/ResponseInterface.php index 387345cc1..44611cd8b 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client-contracts/ResponseInterface.php +++ b/lam/lib/3rdParty/composer/symfony/http-client-contracts/ResponseInterface.php @@ -13,7 +13,6 @@ namespace Symfony\Contracts\HttpClient; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; @@ -37,7 +36,7 @@ interface ResponseInterface * * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes * - * @return string[][] The headers of the response keyed by header names in lowercase + * @return array> The headers of the response keyed by header names in lowercase * * @throws TransportExceptionInterface When a network error occurs * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached diff --git a/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/Fixtures/web/index.php b/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/Fixtures/web/index.php index a75001785..399f8bdde 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/Fixtures/web/index.php +++ b/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/Fixtures/web/index.php @@ -42,6 +42,7 @@ switch (parse_url($vars['REQUEST_URI'], \PHP_URL_PATH)) { exit; case '/head': + header('X-Request-Vars: '.json_encode($vars, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); header('Content-Length: '.strlen($json), true); break; @@ -198,6 +199,16 @@ switch (parse_url($vars['REQUEST_URI'], \PHP_URL_PATH)) { ]); exit; + + case '/custom': + if (isset($_GET['status'])) { + http_response_code((int) $_GET['status']); + } + if (isset($_GET['headers']) && is_array($_GET['headers'])) { + foreach ($_GET['headers'] as $header) { + header($header); + } + } } header('Content-Type: application/json', true); diff --git a/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/HttpClientTestCase.php b/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/HttpClientTestCase.php index 76b306077..9a528f698 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/HttpClientTestCase.php +++ b/lam/lib/3rdParty/composer/symfony/http-client-contracts/Test/HttpClientTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Contracts\HttpClient\Test; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -25,7 +26,7 @@ abstract class HttpClientTestCase extends TestCase { public static function setUpBeforeClass(): void { - if (!function_exists('ob_gzhandler')) { + if (!\function_exists('ob_gzhandler')) { static::markTestSkipped('The "ob_gzhandler" function is not available.'); } @@ -36,7 +37,6 @@ abstract class HttpClientTestCase extends TestCase { TestHttpServer::stop(8067); TestHttpServer::stop(8077); - TestHttpServer::stop(8087); } abstract protected function getHttpClient(string $testCase): HttpClientInterface; @@ -1026,6 +1026,7 @@ abstract class HttpClientTestCase extends TestCase /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testAutoEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1099,6 +1100,7 @@ abstract class HttpClientTestCase extends TestCase /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testUserlandEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1121,6 +1123,7 @@ abstract class HttpClientTestCase extends TestCase /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testGzipBroken() { $client = $this->getHttpClient(__FUNCTION__); diff --git a/lam/lib/3rdParty/composer/symfony/http-client-contracts/composer.json b/lam/lib/3rdParty/composer/symfony/http-client-contracts/composer.json index efb146ec1..a67a7530d 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client-contracts/composer.json +++ b/lam/lib/3rdParty/composer/symfony/http-client-contracts/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/lam/lib/3rdParty/composer/symfony/http-client/AmpHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/AmpHttpClient.php index a095d2081..1d4745ffb 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/AmpHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/AmpHttpClient.php @@ -166,7 +166,7 @@ final class AmpHttpClient implements HttpClientInterface, LoggerAwareInterface, foreach ($pushedResponses as [$pushedUrl, $pushDeferred]) { $pushDeferred->fail(new CancelledException()); - $this->logger?->debug(sprintf('Unused pushed response: "%s"', $pushedUrl)); + $this->logger?->debug(\sprintf('Unused pushed response: "%s"', $pushedUrl)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/CachingHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/CachingHttpClient.php index 34bc1189a..97826d20a 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/CachingHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/CachingHttpClient.php @@ -42,7 +42,7 @@ class CachingHttpClient implements HttpClientInterface, ResetInterface public function __construct(HttpClientInterface $client, StoreInterface $store, array $defaultOptions = []) { if (!class_exists(HttpClientKernel::class)) { - throw new \LogicException(sprintf('Using "%s" requires the HttpKernel component, try running "composer require symfony/http-kernel".', __CLASS__)); + throw new \LogicException(\sprintf('Using "%s" requires the HttpKernel component, try running "composer require symfony/http-kernel".', __CLASS__)); } $this->client = $client; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Chunk/ServerSentEvent.php b/lam/lib/3rdParty/composer/symfony/http-client/Chunk/ServerSentEvent.php index 723150618..e6dddf617 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Chunk/ServerSentEvent.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Chunk/ServerSentEvent.php @@ -89,17 +89,17 @@ final class ServerSentEvent extends DataChunk implements ChunkInterface } if ('' === $this->data) { - throw new JsonException(sprintf('Server-Sent Event%s data is empty.', '' !== $this->id ? sprintf(' "%s"', $this->id) : '')); + throw new JsonException(\sprintf('Server-Sent Event%s data is empty.', '' !== $this->id ? \sprintf(' "%s"', $this->id) : '')); } try { $jsonData = json_decode($this->data, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { - throw new JsonException(sprintf('Decoding Server-Sent Event%s failed: ', '' !== $this->id ? sprintf(' "%s"', $this->id) : '').$e->getMessage(), $e->getCode()); + throw new JsonException(\sprintf('Decoding Server-Sent Event%s failed: ', '' !== $this->id ? \sprintf(' "%s"', $this->id) : '').$e->getMessage(), $e->getCode()); } if (!\is_array($jsonData)) { - throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned in Server-Sent Event%s.', get_debug_type($jsonData), '' !== $this->id ? sprintf(' "%s"', $this->id) : '')); + throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned in Server-Sent Event%s.', get_debug_type($jsonData), '' !== $this->id ? \sprintf(' "%s"', $this->id) : '')); } return $this->jsonData = $jsonData; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/CurlHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/CurlHttpClient.php index 7d9962005..b3d6f2adb 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/CurlHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/CurlHttpClient.php @@ -152,14 +152,14 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, if (\is_array($options['auth_ntlm'])) { $count = \count($options['auth_ntlm']); if ($count <= 0 || $count > 2) { - throw new InvalidArgumentException(sprintf('Option "auth_ntlm" must contain 1 or 2 elements, %d given.', $count)); + throw new InvalidArgumentException(\sprintf('Option "auth_ntlm" must contain 1 or 2 elements, %d given.', $count)); } $options['auth_ntlm'] = implode(':', $options['auth_ntlm']); } if (!\is_string($options['auth_ntlm'])) { - throw new InvalidArgumentException(sprintf('Option "auth_ntlm" must be a string or an array, "%s" given.', get_debug_type($options['auth_ntlm']))); + throw new InvalidArgumentException(\sprintf('Option "auth_ntlm" must be a string or an array, "%s" given.', get_debug_type($options['auth_ntlm']))); } $curlopts[\CURLOPT_USERPWD] = $options['auth_ntlm']; @@ -197,13 +197,12 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, $curlopts[\CURLOPT_RESOLVE] = $resolve; } + $curlopts[\CURLOPT_CUSTOMREQUEST] = $method; if ('POST' === $method) { // Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303 $curlopts[\CURLOPT_POST] = true; } elseif ('HEAD' === $method) { $curlopts[\CURLOPT_NOBODY] = true; - } else { - $curlopts[\CURLOPT_CUSTOMREQUEST] = $method; } if ('\\' !== \DIRECTORY_SEPARATOR && $options['timeout'] < 1) { @@ -238,7 +237,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, if (!\is_string($body)) { if (\is_resource($body)) { - $curlopts[\CURLOPT_INFILE] = $body; + $curlopts[\CURLOPT_READDATA] = $body; } else { $curlopts[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) { static $eof = false; @@ -298,28 +297,31 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, unset($multi->pushedResponses[$url]); if (self::acceptPushForRequest($method, $options, $pushedResponse)) { - $this->logger?->debug(sprintf('Accepting pushed response: "%s %s"', $method, $url)); + $this->logger?->debug(\sprintf('Accepting pushed response: "%s %s"', $method, $url)); // Reinitialize the pushed response with request's options $ch = $pushedResponse->handle; $pushedResponse = $pushedResponse->response; $pushedResponse->__construct($multi, $url, $options, $this->logger); } else { - $this->logger?->debug(sprintf('Rejecting pushed response: "%s"', $url)); + $this->logger?->debug(\sprintf('Rejecting pushed response: "%s"', $url)); $pushedResponse = null; } } if (!$pushedResponse) { $ch = curl_init(); - $this->logger?->info(sprintf('Request: "%s %s"', $method, $url)); + $this->logger?->info(\sprintf('Request: "%s %s"', $method, $url)); $curlopts += [\CURLOPT_SHARE => $multi->share]; } foreach ($curlopts as $opt => $value) { + if (\PHP_INT_SIZE === 8 && \defined('CURLOPT_INFILESIZE_LARGE') && \CURLOPT_INFILESIZE === $opt && $value >= 1 << 31) { + $opt = \CURLOPT_INFILESIZE_LARGE; + } if (null !== $value && !curl_setopt($ch, $opt, $value) && \CURLOPT_CERTINFO !== $opt && (!\defined('CURLOPT_HEADEROPT') || \CURLOPT_HEADEROPT !== $opt)) { $constantName = $this->findConstantName($opt); - throw new TransportException(sprintf('Curl option "%s" is not supported.', $constantName ?? $opt)); + throw new TransportException(\sprintf('Curl option "%s" is not supported.', $constantName ?? $opt)); } } @@ -386,7 +388,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, { if (!$eof && \strlen($buffer) < $length) { if (!\is_string($data = $body($length))) { - throw new TransportException(sprintf('The return value of the "body" option callback must be a string, "%s" returned.', get_debug_type($data))); + throw new TransportException(\sprintf('The return value of the "body" option callback must be a string, "%s" returned.', get_debug_type($data))); } $buffer .= $data; @@ -473,7 +475,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, \CURLOPT_RESOLVE => 'resolve', \CURLOPT_NOSIGNAL => 'timeout', \CURLOPT_HTTPHEADER => 'headers', - \CURLOPT_INFILE => 'body', + \CURLOPT_READDATA => 'body', \CURLOPT_READFUNCTION => 'body', \CURLOPT_INFILESIZE => 'body', \CURLOPT_POSTFIELDS => 'body', @@ -549,7 +551,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, foreach ($options as $opt => $optValue) { if (isset($curloptsToConfig[$opt])) { $constName = $this->findConstantName($opt) ?? $opt; - throw new InvalidArgumentException(sprintf('Cannot set "%s" with "extra.curl", use option "%s" instead.', $constName, $curloptsToConfig[$opt])); + throw new InvalidArgumentException(\sprintf('Cannot set "%s" with "extra.curl", use option "%s" instead.', $constName, $curloptsToConfig[$opt])); } if (\in_array($opt, $methodOpts)) { @@ -558,7 +560,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, if (\in_array($opt, $curloptsToCheck)) { $constName = $this->findConstantName($opt) ?? $opt; - throw new InvalidArgumentException(sprintf('Cannot set "%s" with "extra.curl".', $constName)); + throw new InvalidArgumentException(\sprintf('Cannot set "%s" with "extra.curl".', $constName)); } } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/DataCollector/HttpClientDataCollector.php b/lam/lib/3rdParty/composer/symfony/http-client/DataCollector/HttpClientDataCollector.php index a749aa61c..7c58a0eaa 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/DataCollector/HttpClientDataCollector.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/DataCollector/HttpClientDataCollector.php @@ -233,8 +233,8 @@ final class HttpClientDataCollector extends DataCollector implements LateDataCol } if (preg_match('/^> ([A-Z]+)/', $line, $match)) { - $command[] = sprintf('--request %s', $match[1]); - $command[] = sprintf('--url %s', escapeshellarg($url)); + $command[] = \sprintf('--request %s', $match[1]); + $command[] = \sprintf('--url %s', escapeshellarg($url)); continue; } @@ -252,7 +252,7 @@ final class HttpClientDataCollector extends DataCollector implements LateDataCol { static $useProcess; - if ($useProcess ??= function_exists('proc_open') && class_exists(Process::class)) { + if ($useProcess ??= \function_exists('proc_open') && class_exists(Process::class)) { return substr((new Process(['', $payload]))->getCommandLine(), 3); } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/EventSourceHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/EventSourceHttpClient.php index b5f88ddba..440268ec6 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/EventSourceHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/EventSourceHttpClient.php @@ -53,7 +53,7 @@ final class EventSourceHttpClient implements HttpClientInterface, ResetInterface public function request(string $method, string $url, array $options = []): ResponseInterface { - $state = new class() { + $state = new class { public ?string $buffer = null; public ?string $lastEventId = null; public float $reconnectionTime; @@ -110,7 +110,7 @@ final class EventSourceHttpClient implements HttpClientInterface, ResetInterface if (preg_match('/^text\/event-stream(;|$)/i', $context->getHeaders()['content-type'][0] ?? '')) { $state->buffer = ''; } elseif (null !== $lastError || (null !== $state->buffer && 200 === $context->getStatusCode())) { - throw new EventSourceException(sprintf('Response content-type is "%s" while "text/event-stream" was expected for "%s".', $context->getHeaders()['content-type'][0] ?? '', $context->getInfo('url'))); + throw new EventSourceException(\sprintf('Response content-type is "%s" while "text/event-stream" was expected for "%s".', $context->getHeaders()['content-type'][0] ?? '', $context->getInfo('url'))); } else { $context->passthru(); } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Exception/HttpExceptionTrait.php b/lam/lib/3rdParty/composer/symfony/http-client/Exception/HttpExceptionTrait.php index 264ef24b2..fa99ed386 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Exception/HttpExceptionTrait.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Exception/HttpExceptionTrait.php @@ -27,7 +27,7 @@ trait HttpExceptionTrait $this->response = $response; $code = $response->getInfo('http_code'); $url = $response->getInfo('url'); - $message = sprintf('HTTP %d returned for "%s".', $code, $url); + $message = \sprintf('HTTP %d returned for "%s".', $code, $url); $httpCodeFound = false; $isJson = false; @@ -37,7 +37,7 @@ trait HttpExceptionTrait break; } - $message = sprintf('%s returned for "%s".', $h, $url); + $message = \sprintf('%s returned for "%s".', $h, $url); $httpCodeFound = true; } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/HttpClientTrait.php b/lam/lib/3rdParty/composer/symfony/http-client/HttpClientTrait.php index 89446ff8c..6d1946f72 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/HttpClientTrait.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/HttpClientTrait.php @@ -46,7 +46,7 @@ trait HttpClientTrait { if (null !== $method) { if (\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) { - throw new InvalidArgumentException(sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); + throw new InvalidArgumentException(\sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); } if (!$method) { throw new InvalidArgumentException('The HTTP method cannot be empty.'); @@ -61,11 +61,11 @@ trait HttpClientTrait $options['buffer'] = static function (array $headers) use ($buffer) { if (!\is_bool($buffer = $buffer($headers))) { if (!\is_array($bufferInfo = @stream_get_meta_data($buffer))) { - throw new \LogicException(sprintf('The closure passed as option "buffer" must return bool or stream resource, got "%s".', get_debug_type($buffer))); + throw new \LogicException(\sprintf('The closure passed as option "buffer" must return bool or stream resource, got "%s".', get_debug_type($buffer))); } if (false === strpbrk($bufferInfo['mode'], 'acew+')) { - throw new \LogicException(sprintf('The stream returned by the closure passed as option "buffer" must be writeable, got mode "%s".', $bufferInfo['mode'])); + throw new \LogicException(\sprintf('The stream returned by the closure passed as option "buffer" must be writeable, got mode "%s".', $bufferInfo['mode'])); } } @@ -73,11 +73,11 @@ trait HttpClientTrait }; } elseif (!\is_bool($buffer)) { if (!\is_array($bufferInfo = @stream_get_meta_data($buffer))) { - throw new InvalidArgumentException(sprintf('Option "buffer" must be bool, stream resource or Closure, "%s" given.', get_debug_type($buffer))); + throw new InvalidArgumentException(\sprintf('Option "buffer" must be bool, stream resource or Closure, "%s" given.', get_debug_type($buffer))); } if (false === strpbrk($bufferInfo['mode'], 'acew+')) { - throw new InvalidArgumentException(sprintf('The stream in option "buffer" must be writeable, mode "%s" given.', $bufferInfo['mode'])); + throw new InvalidArgumentException(\sprintf('The stream in option "buffer" must be writeable, mode "%s" given.', $bufferInfo['mode'])); } } @@ -128,25 +128,25 @@ trait HttpClientTrait // Validate on_progress if (isset($options['on_progress']) && !\is_callable($onProgress = $options['on_progress'])) { - throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, "%s" given.', get_debug_type($onProgress))); + throw new InvalidArgumentException(\sprintf('Option "on_progress" must be callable, "%s" given.', get_debug_type($onProgress))); } if (\is_array($options['auth_basic'] ?? null)) { $count = \count($options['auth_basic']); if ($count <= 0 || $count > 2) { - throw new InvalidArgumentException(sprintf('Option "auth_basic" must contain 1 or 2 elements, "%s" given.', $count)); + throw new InvalidArgumentException(\sprintf('Option "auth_basic" must contain 1 or 2 elements, "%s" given.', $count)); } $options['auth_basic'] = implode(':', $options['auth_basic']); } if (!\is_string($options['auth_basic'] ?? '')) { - throw new InvalidArgumentException(sprintf('Option "auth_basic" must be string or an array, "%s" given.', get_debug_type($options['auth_basic']))); + throw new InvalidArgumentException(\sprintf('Option "auth_basic" must be string or an array, "%s" given.', get_debug_type($options['auth_basic']))); } if (isset($options['auth_bearer'])) { if (!\is_string($options['auth_bearer'])) { - throw new InvalidArgumentException(sprintf('Option "auth_bearer" must be a string, "%s" given.', get_debug_type($options['auth_bearer']))); + throw new InvalidArgumentException(\sprintf('Option "auth_bearer" must be a string, "%s" given.', get_debug_type($options['auth_bearer']))); } if (preg_match('{[^\x21-\x7E]}', $options['auth_bearer'])) { throw new InvalidArgumentException('Invalid character found in option "auth_bearer": '.json_encode($options['auth_bearer']).'.'); @@ -263,11 +263,11 @@ trait HttpClientTrait $msg = 'try using "%s" instead.'; } - throw new InvalidArgumentException(sprintf('Option "auth_ntlm" is not supported by "%s", '.$msg, __CLASS__, CurlHttpClient::class)); + throw new InvalidArgumentException(\sprintf('Option "auth_ntlm" is not supported by "%s", '.$msg, __CLASS__, CurlHttpClient::class)); } if ('vars' === $name) { - throw new InvalidArgumentException(sprintf('Option "vars" is not supported by "%s", try using "%s" instead.', __CLASS__, UriTemplateHttpClient::class)); + throw new InvalidArgumentException(\sprintf('Option "vars" is not supported by "%s", try using "%s" instead.', __CLASS__, UriTemplateHttpClient::class)); } $alternatives = []; @@ -278,7 +278,7 @@ trait HttpClientTrait } } - throw new InvalidArgumentException(sprintf('Unsupported option "%s" passed to "%s", did you mean "%s"?', $name, __CLASS__, implode('", "', $alternatives ?: array_keys($defaultOptions)))); + throw new InvalidArgumentException(\sprintf('Unsupported option "%s" passed to "%s", did you mean "%s"?', $name, __CLASS__, implode('", "', $alternatives ?: array_keys($defaultOptions)))); } return $options; @@ -300,13 +300,13 @@ trait HttpClientTrait if (\is_int($name)) { if (!\is_string($values)) { - throw new InvalidArgumentException(sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); + throw new InvalidArgumentException(\sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); } [$name, $values] = explode(':', $values, 2); $values = [ltrim($values)]; } elseif (!is_iterable($values)) { if (\is_object($values)) { - throw new InvalidArgumentException(sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); + throw new InvalidArgumentException(\sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); } $values = (array) $values; @@ -319,7 +319,7 @@ trait HttpClientTrait $normalizedHeaders[$lcName][] = $value = $name.': '.$value; if (\strlen($value) !== strcspn($value, "\r\n\0")) { - throw new InvalidArgumentException(sprintf('Invalid header: CR/LF/NUL found in "%s".', $value)); + throw new InvalidArgumentException(\sprintf('Invalid header: CR/LF/NUL found in "%s".', $value)); } } } @@ -356,9 +356,11 @@ trait HttpClientTrait } }); - $body = http_build_query($body, '', '&'); + if ('' === $body = http_build_query($body, '', '&')) { + return ''; + } - if ('' === $body || !$streams && !str_contains($normalizedHeaders['content-type'][0] ?? '', 'multipart/form-data')) { + if (!$streams && !str_contains($normalizedHeaders['content-type'][0] ?? '', 'multipart/form-data')) { if (!str_contains($normalizedHeaders['content-type'][0] ?? '', 'application/x-www-form-urlencoded')) { $normalizedHeaders['content-type'] = ['Content-Type: application/x-www-form-urlencoded']; } @@ -390,10 +392,10 @@ trait HttpClientTrait $v = $streams[$v]; if (!\is_array($m = @stream_get_meta_data($v))) { - throw new TransportException(sprintf('Invalid "%s" resource found in body part "%s".', get_resource_type($v), $k)); + throw new TransportException(\sprintf('Invalid "%s" resource found in body part "%s".', get_resource_type($v), $k)); } if (feof($v)) { - throw new TransportException(sprintf('Uploaded stream ended for body part "%s".', $k)); + throw new TransportException(\sprintf('Uploaded stream ended for body part "%s".', $k)); } $m += stream_context_get_options($v)['http'] ?? []; @@ -449,7 +451,7 @@ trait HttpClientTrait while (null !== $h && !feof($h)) { if (false === $part = fread($h, $size)) { - throw new TransportException(sprintf('Error while reading uploaded stream for body part "%s".', $k)); + throw new TransportException(\sprintf('Error while reading uploaded stream for body part "%s".', $k)); } yield $part; @@ -498,7 +500,7 @@ trait HttpClientTrait } if (!\is_array(@stream_get_meta_data($body))) { - throw new InvalidArgumentException(sprintf('Option "body" must be string, stream resource, iterable or callable, "%s" given.', get_debug_type($body))); + throw new InvalidArgumentException(\sprintf('Option "body" must be string, stream resource, iterable or callable, "%s" given.', get_debug_type($body))); } return $body; @@ -531,14 +533,14 @@ trait HttpClientTrait 40 => ['sha1' => $fingerprint], 44 => ['pin-sha256' => [$fingerprint]], 64 => ['sha256' => $fingerprint], - default => throw new InvalidArgumentException(sprintf('Cannot auto-detect fingerprint algorithm for "%s".', $fingerprint)), + default => throw new InvalidArgumentException(\sprintf('Cannot auto-detect fingerprint algorithm for "%s".', $fingerprint)), }; } elseif (\is_array($fingerprint)) { foreach ($fingerprint as $algo => $hash) { $fingerprint[$algo] = 'pin-sha256' === $algo ? (array) $hash : str_replace(':', '', $hash); } } else { - throw new InvalidArgumentException(sprintf('Option "peer_fingerprint" must be string or array, "%s" given.', get_debug_type($fingerprint))); + throw new InvalidArgumentException(\sprintf('Option "peer_fingerprint" must be string or array, "%s" given.', get_debug_type($fingerprint))); } return $fingerprint; @@ -572,15 +574,15 @@ trait HttpClientTrait $givenUrl = $url; if (null !== $base && '' === ($base['scheme'] ?? '').($base['authority'] ?? '')) { - throw new InvalidArgumentException(sprintf('Invalid "base_uri" option: host or scheme is missing in "%s".', implode('', $base))); + throw new InvalidArgumentException(\sprintf('Invalid "base_uri" option: host or scheme is missing in "%s".', implode('', $base))); } if (null === $url['scheme'] && (null === $base || null === $base['scheme'])) { - throw new InvalidArgumentException(sprintf('Invalid URL: scheme is missing in "%s". Did you forget to add "http(s)://"?', implode('', $base ?? $url))); + throw new InvalidArgumentException(\sprintf('Invalid URL: scheme is missing in "%s". Did you forget to add "http(s)://"?', implode('', $base ?? $url))); } if (null === $base && '' === $url['scheme'].$url['authority']) { - throw new InvalidArgumentException(sprintf('Invalid URL: no "base_uri" option was provided and host or scheme is missing in "%s".', implode('', $url))); + throw new InvalidArgumentException(\sprintf('Invalid URL: no "base_uri" option was provided and host or scheme is missing in "%s".', implode('', $url))); } if (null !== $url['scheme']) { @@ -641,7 +643,7 @@ trait HttpClientTrait $tail = ''; if (false === $parts = parse_url(\strlen($url) !== strcspn($url, '?#') ? $url : $url.$tail = '#')) { - throw new InvalidArgumentException(sprintf('Malformed URL "%s".', $url)); + throw new InvalidArgumentException(\sprintf('Malformed URL "%s".', $url)); } if ($query) { @@ -661,7 +663,7 @@ trait HttpClientTrait if (null !== $scheme) { if (!isset($allowedSchemes[$scheme = strtolower($scheme)])) { - throw new InvalidArgumentException(sprintf('Unsupported scheme in "%s": "%s" expected.', $url, implode('" or "', array_keys($allowedSchemes)))); + throw new InvalidArgumentException(\sprintf('Unsupported scheme in "%s": "%s" expected.', $url, implode('" or "', array_keys($allowedSchemes)))); } $port = $allowedSchemes[$scheme] === $port ? 0 : $port; @@ -670,7 +672,7 @@ trait HttpClientTrait if (null !== $host) { if (!\defined('INTL_IDNA_VARIANT_UTS46') && preg_match('/[\x80-\xFF]/', $host)) { - throw new InvalidArgumentException(sprintf('Unsupported IDN "%s", try enabling the "intl" PHP extension or running "composer require symfony/polyfill-intl-idn".', $host)); + throw new InvalidArgumentException(\sprintf('Unsupported IDN "%s", try enabling the "intl" PHP extension or running "composer require symfony/polyfill-intl-idn".', $host)); } $host = \defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46) ?: strtolower($host) : strtolower($host); @@ -809,7 +811,7 @@ trait HttpClientTrait } elseif ('https' === $proxy['scheme']) { $proxyUrl = 'ssl://'.$proxy['host'].':'.($proxy['port'] ?? '443'); } else { - throw new TransportException(sprintf('Unsupported proxy scheme "%s": "http" or "https" expected.', $proxy['scheme'])); + throw new TransportException(\sprintf('Unsupported proxy scheme "%s": "http" or "https" expected.', $proxy['scheme'])); } $noProxy ??= $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/HttplugClient.php b/lam/lib/3rdParty/composer/symfony/http-client/HttplugClient.php index b0a6d4a8c..a4c798230 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/HttplugClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/HttplugClient.php @@ -114,7 +114,7 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa public function sendAsyncRequest(RequestInterface $request): HttplugPromise { if (!$promisePool = $this->promisePool) { - throw new \LogicException(sprintf('You cannot use "%s()" as the "guzzlehttp/promises" package is not installed. Try running "composer require guzzlehttp/promises".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use "%s()" as the "guzzlehttp/promises" package is not installed. Try running "composer require guzzlehttp/promises".', __METHOD__)); } try { @@ -165,7 +165,7 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa } elseif (class_exists(Request::class)) { $request = new Request($method, $uri); } else { - throw new \LogicException(sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); } $request = $request @@ -198,11 +198,15 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa } elseif (\is_resource($content)) { $stream = $this->streamFactory->createStreamFromResource($content); } else { - throw new \InvalidArgumentException(sprintf('"%s()" expects string, resource or StreamInterface, "%s" given.', __METHOD__, get_debug_type($content))); + throw new \InvalidArgumentException(\sprintf('"%s()" expects string, resource or StreamInterface, "%s" given.', __METHOD__, get_debug_type($content))); } if ($stream->isSeekable()) { - $stream->seek(0); + try { + $stream->seek(0); + } catch (\RuntimeException) { + // ignore + } } return $stream; @@ -243,7 +247,7 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa return new Uri($uri); } - throw new \LogicException(sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); } public function __sleep(): array @@ -274,7 +278,11 @@ final class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFa $body = $request->getBody(); if ($body->isSeekable()) { - $body->seek(0); + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } } $options = [ diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpBody.php b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpBody.php index bd995e17d..e88054bf2 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpBody.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpBody.php @@ -139,7 +139,7 @@ class AmpBody implements RequestBody, InputStream } if (!\is_string($data)) { - throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + throw new TransportException(\sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); } return new Success($data); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpClientState.php b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpClientState.php index c5e6968ef..e6c2fa5e5 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpClientState.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpClientState.php @@ -144,7 +144,7 @@ final class AmpClientState extends ClientState $options['capture_peer_cert_chain'] && $context = $context->withPeerCapturing(); $options['crypto_method'] && $context = $context->withMinimumVersion($options['crypto_method']); - $connector = $handleConnector = new class() implements Connector { + $connector = $handleConnector = new class implements Connector { public DnsConnector $connector; public string $uri; /** @var resource|null */ @@ -201,11 +201,11 @@ final class AmpClientState extends ClientState if ($this->maxPendingPushes <= \count($this->pushedResponses[$authority] ?? [])) { $fifoUrl = key($this->pushedResponses[$authority]); unset($this->pushedResponses[$authority][$fifoUrl]); - $this->logger?->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + $this->logger?->debug(\sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); } $url = (string) $request->getUri(); - $this->logger?->debug(sprintf('Queueing pushed response: "%s"', $url)); + $this->logger?->debug(\sprintf('Queueing pushed response: "%s"', $url)); $this->pushedResponses[$authority][] = [$url, $deferred, $request, $response, [ 'proxy' => $options['proxy'], 'bindto' => $options['bindto'], diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpListener.php b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpListener.php index 221a8cba9..b50b952f0 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpListener.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Internal/AmpListener.php @@ -89,7 +89,7 @@ class AmpListener implements EventListener $this->info['primary_port'] = $stream->getRemoteAddress()->getPort(); $this->info['pretransfer_time'] = microtime(true) - $this->info['start_time']; - $this->info['debug'] .= sprintf("* Connected to %s (%s) port %d\n", $request->getUri()->getHost(), $host, $this->info['primary_port']); + $this->info['debug'] .= \sprintf("* Connected to %s (%s) port %d\n", $request->getUri()->getHost(), $host, $this->info['primary_port']); if ((isset($this->info['peer_certificate_chain']) || $this->pinSha256) && null !== $tlsInfo = $stream->getTlsInfo()) { foreach ($tlsInfo->getPeerCertificates() as $cert) { @@ -104,7 +104,7 @@ class AmpListener implements EventListener $pin = base64_encode(hash('sha256', $pin, true)); if (!\in_array($pin, $this->pinSha256, true)) { - throw new TransportException(sprintf('SSL public key does not match pinned public key for "%s".', $this->info['url'])); + throw new TransportException(\sprintf('SSL public key does not match pinned public key for "%s".', $this->info['url'])); } } } @@ -121,7 +121,7 @@ class AmpListener implements EventListener $requestUri = $uri->getHost().': '.($uri->getPort() ?? ('https' === $uri->getScheme() ? 443 : 80)); } - $this->info['debug'] .= sprintf("> %s %s HTTP/%s \r\n", $method, $requestUri, $request->getProtocolVersions()[0]); + $this->info['debug'] .= \sprintf("> %s %s HTTP/%s \r\n", $method, $requestUri, $request->getProtocolVersions()[0]); foreach ($request->getRawHeaders() as [$name, $value]) { $this->info['debug'] .= $name.': '.$value."\r\n"; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Internal/CurlClientState.php b/lam/lib/3rdParty/composer/symfony/http-client/Internal/CurlClientState.php index 2a15248eb..60aab7152 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Internal/CurlClientState.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Internal/CurlClientState.php @@ -50,7 +50,7 @@ final class CurlClientState extends ClientState curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); } if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS') && 0 < $maxHostConnections) { - $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, $maxHostConnections) ? 4294967295 : $maxHostConnections; + $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, $maxHostConnections) ? min(50 * $maxHostConnections, 4294967295) : $maxHostConnections; } if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) { curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections); @@ -81,9 +81,8 @@ final class CurlClientState extends ClientState public function reset(): void { foreach ($this->pushedResponses as $url => $response) { - $this->logger?->debug(sprintf('Unused pushed response: "%s"', $url)); + $this->logger?->debug(\sprintf('Unused pushed response: "%s"', $url)); curl_multi_remove_handle($this->handle, $response->handle); - curl_close($response->handle); } $this->pushedResponses = []; @@ -112,7 +111,7 @@ final class CurlClientState extends ClientState } if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) { - $this->logger?->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + $this->logger?->debug(\sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); return \CURL_PUSH_DENY; } @@ -123,7 +122,7 @@ final class CurlClientState extends ClientState // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, // ignoring domains mentioned as alt-name in the certificate for now (same as curl). if (!str_starts_with($origin, $url.'/')) { - $this->logger?->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + $this->logger?->debug(\sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); return \CURL_PUSH_DENY; } @@ -131,11 +130,11 @@ final class CurlClientState extends ClientState if ($maxPendingPushes <= \count($this->pushedResponses)) { $fifoUrl = key($this->pushedResponses); unset($this->pushedResponses[$fifoUrl]); - $this->logger?->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + $this->logger?->debug(\sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); } $url .= $headers[':path'][0]; - $this->logger?->debug(sprintf('Queueing pushed response: "%s"', $url)); + $this->logger?->debug(\sprintf('Queueing pushed response: "%s"', $url)); $this->pushedResponses[$url] = new PushedResponse(new CurlResponse($this, $pushed), $headers, $this->openHandles[(int) $parent][1] ?? [], $pushed); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Internal/HttplugWaitLoop.php b/lam/lib/3rdParty/composer/symfony/http-client/Internal/HttplugWaitLoop.php index bebe13560..1412fcf45 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Internal/HttplugWaitLoop.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Internal/HttplugWaitLoop.php @@ -145,7 +145,11 @@ final class HttplugWaitLoop } if ($body->isSeekable()) { - $body->seek(0); + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } } return $psrResponse->withBody($body); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/MockHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/MockHttpClient.php index 4ddbc6bc5..093c02714 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/MockHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/MockHttpClient.php @@ -78,7 +78,7 @@ class MockHttpClient implements HttpClientInterface, ResetInterface ++$this->requestsCount; if (!$response instanceof ResponseInterface) { - throw new TransportException(sprintf('The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "%s" given.', get_debug_type($response))); + throw new TransportException(\sprintf('The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "%s" given.', get_debug_type($response))); } return MockResponse::fromRequest($method, $url, $options, $response); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/NativeHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/NativeHttpClient.php index 7e13cbc56..da01191d4 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/NativeHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/NativeHttpClient.php @@ -142,7 +142,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac $maxDuration = 0 < $options['max_duration'] ? $options['max_duration'] : \INF; $onProgress = static function (...$progress) use ($onProgress, &$info, $maxDuration) { if ($info['total_time'] >= $maxDuration) { - throw new TransportException(sprintf('Max duration was reached for "%s".', implode('', $info['url']))); + throw new TransportException(\sprintf('Max duration was reached for "%s".', implode('', $info['url']))); } $progressInfo = $info; @@ -165,7 +165,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac $maxDuration = $options['max_duration']; $onProgress = static function () use (&$info, $maxDuration): void { if ($info['total_time'] >= $maxDuration) { - throw new TransportException(sprintf('Max duration was reached for "%s".', implode('', $info['url']))); + throw new TransportException(\sprintf('Max duration was reached for "%s".', implode('', $info['url']))); } }; } @@ -195,7 +195,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; } - $this->logger?->info(sprintf('Request: "%s %s"', $method, implode('', $url))); + $this->logger?->info(\sprintf('Request: "%s %s"', $method, implode('', $url))); if (!isset($options['normalized_headers']['user-agent'])) { $options['headers'][] = 'User-Agent: Symfony HttpClient (Native)'; @@ -301,7 +301,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac while ('' !== $data = $body(self::$CHUNK_SIZE)) { if (!\is_string($data)) { - throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + throw new TransportException(\sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); } $result .= $data; @@ -340,7 +340,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac $now = microtime(true); if (!$ip = gethostbynamel($host)) { - throw new TransportException(sprintf('Could not resolve host "%s".', $host)); + throw new TransportException(\sprintf('Could not resolve host "%s".', $host)); } $multi->dnsCache[$host] = $ip = $ip[0]; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/NoPrivateNetworkHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/NoPrivateNetworkHttpClient.php index b38b0178b..fe46cddac 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/NoPrivateNetworkHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/NoPrivateNetworkHttpClient.php @@ -20,7 +20,6 @@ use Symfony\Component\HttpFoundation\IpUtils; use Symfony\Contracts\HttpClient\ChunkInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -use Symfony\Contracts\HttpClient\ResponseStreamInterface; use Symfony\Contracts\Service\ResetInterface; /** @@ -31,12 +30,12 @@ use Symfony\Contracts\Service\ResetInterface; */ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface { - use HttpClientTrait; use AsyncDecoratorTrait; + use HttpClientTrait; private array $defaultOptions = self::OPTIONS_DEFAULTS; private HttpClientInterface $client; - private array|null $subnets; + private ?array $subnets; private int $ipFlags; private \ArrayObject $dnsCache; @@ -47,7 +46,7 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa public function __construct(HttpClientInterface $client, string|array|null $subnets = null) { if (!class_exists(IpUtils::class)) { - throw new \LogicException(sprintf('You cannot use "%s" if the HttpFoundation component is not installed. Try running "composer require symfony/http-foundation".', __CLASS__)); + throw new \LogicException(\sprintf('You cannot use "%s" if the HttpFoundation component is not installed. Try running "composer require symfony/http-foundation".', __CLASS__)); } if (null === $subnets) { @@ -81,17 +80,6 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa $ip = self::dnsResolve($dnsCache, $host, $this->ipFlags, $options); self::ipCheck($ip, $this->subnets, $this->ipFlags, $host, $url); - if (0 < $maxRedirects = $options['max_redirects']) { - $options['max_redirects'] = 0; - $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers']; - - if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { - $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { - return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); - }); - } - } - $onProgress = $options['on_progress'] ?? null; $subnets = $this->subnets; $ipFlags = $this->ipFlags; @@ -99,7 +87,7 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, $ipFlags): void { static $lastPrimaryIp = ''; - if (($info['primary_ip'] ?? '') !== $lastPrimaryIp) { + if (!\in_array($info['primary_ip'] ?? '', ['', $lastPrimaryIp], true)) { self::ipCheck($info['primary_ip'], $subnets, $ipFlags, null, $info['url']); $lastPrimaryIp = $info['primary_ip']; } @@ -107,6 +95,19 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa null !== $onProgress && $onProgress($dlNow, $dlSize, $info); }; + if (0 >= $maxRedirects = $options['max_redirects']) { + return new AsyncResponse($this->client, $method, $url, $options); + } + + $options['max_redirects'] = 0; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers']; + + if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { + return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use (&$method, &$options, $maxRedirects, &$redirectHeaders, $subnets, $ipFlags, $dnsCache): \Generator { if (null !== $chunk->getError() || $chunk->isTimeout() || !$chunk->isFirst()) { yield $chunk; @@ -137,7 +138,7 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa $filterContentHeaders = static function ($h) { return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:'); }; - $options['header'] = array_filter($options['header'], $filterContentHeaders); + $options['headers'] = array_filter($options['headers'], $filterContentHeaders); $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders); $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders); } @@ -158,11 +159,6 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa }); } - public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface - { - return $this->client->stream($responses, $timeout); - } - public function setLogger(LoggerInterface $logger): void { if ($this->client instanceof LoggerAwareInterface) { @@ -208,7 +204,7 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa if ($ip = dns_get_record($host, \DNS_AAAA)) { $ip = $ip[0]['ipv6']; - } elseif (extension_loaded('sockets')) { + } elseif (\extension_loaded('sockets')) { if (!$info = socket_addrinfo_lookup($host, 0, ['ai_socktype' => \SOCK_STREAM, 'ai_family' => \AF_INET6])) { return $host; } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Psr18Client.php b/lam/lib/3rdParty/composer/symfony/http-client/Psr18Client.php index d46a7b14d..b0e404b59 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Psr18Client.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Psr18Client.php @@ -90,7 +90,11 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str $body = $request->getBody(); if ($body->isSeekable()) { - $body->seek(0); + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } } $options = [ @@ -128,7 +132,7 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str return new Request($method, $uri); } - throw new \LogicException(sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); } public function createStream(string $content = ''): StreamInterface @@ -136,7 +140,11 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str $stream = $this->streamFactory->createStream($content); if ($stream->isSeekable()) { - $stream->seek(0); + try { + $stream->seek(0); + } catch (\RuntimeException) { + // ignore + } } return $stream; @@ -166,7 +174,7 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str return new Uri($uri); } - throw new \LogicException(sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use "%s()" as no PSR-17 factories have been found. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', __METHOD__)); } public function reset(): void diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/AmpResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/AmpResponse.php index e01d97eb8..de949b36a 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/AmpResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/AmpResponse.php @@ -99,7 +99,8 @@ final class AmpResponse implements ResponseInterface, StreamableInterface $throttleWatcher = null; - $this->id = $id = self::$nextId++; + $this->id = $id = self::$nextId; + self::$nextId = str_increment(self::$nextId); Loop::defer(static function () use ($request, $multi, $id, &$info, &$headers, $canceller, &$options, $onProgress, &$handle, $logger, &$pause) { return new Coroutine(self::generateResponse($request, $multi, $id, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause)); }); @@ -179,19 +180,17 @@ final class AmpResponse implements ResponseInterface, StreamableInterface /** * @param AmpClientState $multi */ - private static function perform(ClientState $multi, ?array &$responses = null): void + private static function perform(ClientState $multi, ?array $responses = null): void { - if ($responses) { - foreach ($responses as $response) { - try { - if ($response->info['start_time']) { - $response->info['total_time'] = microtime(true) - $response->info['start_time']; - ($response->onProgress)(); - } - } catch (\Throwable $e) { - $multi->handlesActivity[$response->id][] = null; - $multi->handlesActivity[$response->id][] = $e; + foreach ($responses ?? [] as $response) { + try { + if ($response->info['start_time']) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + ($response->onProgress)(); } + } catch (\Throwable $e) { + $multi->handlesActivity[$response->id][] = null; + $multi->handlesActivity[$response->id][] = $e; } } } @@ -224,9 +223,9 @@ final class AmpResponse implements ResponseInterface, StreamableInterface }); try { - /* @var Response $response */ + /** @var Response $response */ if (null === $response = yield from self::getPushedResponse($request, $multi, $info, $headers, $options, $logger)) { - $logger?->info(sprintf('Request: "%s %s"', $info['http_method'], $info['url'])); + $logger?->info(\sprintf('Request: "%s %s"', $info['http_method'], $info['url'])); $response = yield from self::followRedirects($request, $multi, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause); } @@ -290,7 +289,7 @@ final class AmpResponse implements ResponseInterface, StreamableInterface return $response; } - $urlResolver = new class() { + $urlResolver = new class { use HttpClientTrait { parseUrl as public; resolveUrl as public; @@ -310,7 +309,7 @@ final class AmpResponse implements ResponseInterface, StreamableInterface return $response; } - $logger?->info(sprintf('Redirecting: "%s %s"', $status, $info['url'])); + $logger?->info(\sprintf('Redirecting: "%s %s"', $status, $info['url'])); try { // Discard body of redirects @@ -369,7 +368,7 @@ final class AmpResponse implements ResponseInterface, StreamableInterface $headers = []; } - $h = sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatus(), $response->getReason()); + $h = \sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatus(), $response->getReason()); $info['debug'] .= "< {$h}\r\n"; $info['response_headers'][] = $h; @@ -416,14 +415,14 @@ final class AmpResponse implements ResponseInterface, StreamableInterface foreach ($response->getHeaderArray('vary') as $vary) { foreach (preg_split('/\s*+,\s*+/', $vary) as $v) { if ('*' === $v || ($pushedRequest->getHeaderArray($v) !== $request->getHeaderArray($v) && 'accept-encoding' !== strtolower($v))) { - $logger?->debug(sprintf('Skipping pushed response: "%s"', $info['url'])); + $logger?->debug(\sprintf('Skipping pushed response: "%s"', $info['url'])); continue 3; } } } $pushDeferred->resolve(); - $logger?->debug(sprintf('Accepting pushed response: "%s %s"', $info['http_method'], $info['url'])); + $logger?->debug(\sprintf('Accepting pushed response: "%s %s"', $info['http_method'], $info['url'])); self::addResponseHeaders($response, $info, $headers); unset($multi->pushedResponses[$authority][$i]); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncContext.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncContext.php index 4f4d10616..cd8a23afc 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncContext.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncContext.php @@ -167,7 +167,7 @@ final class AsyncContext } if (0 < ($info['max_duration'] ?? 0) && 0 < ($info['total_time'] ?? 0)) { if (0 >= $options['max_duration'] = $info['max_duration'] - $info['total_time']) { - throw new TransportException(sprintf('Max duration was reached for "%s".', $info['url'])); + throw new TransportException(\sprintf('Max duration was reached for "%s".', $info['url'])); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncResponse.php index 25f6409b6..30083369d 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/AsyncResponse.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpClient\Response; use Symfony\Component\HttpClient\Chunk\ErrorChunk; -use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Chunk\LastChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Contracts\HttpClient\ChunkInterface; @@ -226,7 +225,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface foreach ($responses as $r) { if (!$r instanceof self) { - throw new \TypeError(sprintf('"%s::stream()" expects parameter 1 to be an iterable of AsyncResponse objects, "%s" given.', $class ?? static::class, get_debug_type($r))); + throw new \TypeError(\sprintf('"%s::stream()" expects parameter 1 to be an iterable of AsyncResponse objects, "%s" given.', $class ?? static::class, get_debug_type($r))); } if (null !== $e = $r->info['error'] ?? null) { @@ -245,7 +244,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface $wrappedResponses[] = $r->response; if ($r->stream) { - yield from self::passthruStream($response = $r->response, $r, new FirstChunk(), $asyncMap); + yield from self::passthruStream($response = $r->response, $r, $asyncMap, new LastChunk()); if (!isset($asyncMap[$response])) { array_pop($wrappedResponses); @@ -276,15 +275,9 @@ class AsyncResponse implements ResponseInterface, StreamableInterface } if (!$r->passthru) { - if (null !== $chunk->getError() || $chunk->isLast()) { - unset($asyncMap[$response]); - } elseif (null !== $r->content && '' !== ($content = $chunk->getContent()) && \strlen($content) !== fwrite($r->content, $content)) { - $chunk = new ErrorChunk($r->offset, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($content)))); - $r->info['error'] = $chunk->getError(); - $r->response->cancel(); - } + $r->stream = (static fn () => yield $chunk)(); + yield from self::passthruStream($response, $r, $asyncMap); - yield $r => $chunk; continue; } @@ -293,7 +286,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface } elseif ($chunk->isFirst()) { $r->yieldedState = self::FIRST_CHUNK_YIELDED; } elseif (self::FIRST_CHUNK_YIELDED !== $r->yieldedState && null === $chunk->getInformationalStatus()) { - throw new \LogicException(sprintf('Instance of "%s" is already consumed and cannot be managed by "%s". A decorated client should not call any of the response\'s methods in its "request()" method.', get_debug_type($response), $class ?? static::class)); + throw new \LogicException(\sprintf('Instance of "%s" is already consumed and cannot be managed by "%s". A decorated client should not call any of the response\'s methods in its "request()" method.', get_debug_type($response), $class ?? static::class)); } foreach (self::passthru($r->client, $r, $chunk, $asyncMap) as $chunk) { @@ -343,17 +336,17 @@ class AsyncResponse implements ResponseInterface, StreamableInterface } if (!$stream instanceof \Iterator) { - throw new \LogicException(sprintf('A chunk passthru must return an "Iterator", "%s" returned.', get_debug_type($stream))); + throw new \LogicException(\sprintf('A chunk passthru must return an "Iterator", "%s" returned.', get_debug_type($stream))); } $r->stream = $stream; - yield from self::passthruStream($response, $r, null, $asyncMap); + yield from self::passthruStream($response, $r, $asyncMap); } /** * @param \SplObjectStorage|null $asyncMap */ - private static function passthruStream(ResponseInterface $response, self $r, ?ChunkInterface $chunk, ?\SplObjectStorage $asyncMap): \Generator + private static function passthruStream(ResponseInterface $response, self $r, ?\SplObjectStorage $asyncMap, ?ChunkInterface $chunk = null): \Generator { while (true) { try { @@ -379,7 +372,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface $chunk = $r->stream->current(); if (!$chunk instanceof ChunkInterface) { - throw new \LogicException(sprintf('A chunk passthru must yield instances of "%s", "%s" yielded.', ChunkInterface::class, get_debug_type($chunk))); + throw new \LogicException(\sprintf('A chunk passthru must yield instances of "%s", "%s" yielded.', ChunkInterface::class, get_debug_type($chunk))); } if (null !== $chunk->getError()) { @@ -406,7 +399,7 @@ class AsyncResponse implements ResponseInterface, StreamableInterface } if (null !== $r->content && \strlen($content) !== fwrite($r->content, $content)) { - $chunk = new ErrorChunk($r->offset, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($content)))); + $chunk = new ErrorChunk($r->offset, new TransportException(\sprintf('Failed writing %d bytes to the response buffer.', \strlen($content)))); $r->info['error'] = $chunk->getError(); $r->response->cancel(); } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/CommonResponseTrait.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/CommonResponseTrait.php index 96944c2fc..e6a9e4303 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/CommonResponseTrait.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/CommonResponseTrait.php @@ -87,11 +87,11 @@ trait CommonResponseTrait try { $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { - throw new JsonException($e->getMessage().sprintf(' for "%s".', $this->getInfo('url')), $e->getCode()); + throw new JsonException($e->getMessage().\sprintf(' for "%s".', $this->getInfo('url')), $e->getCode()); } if (!\is_array($content)) { - throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned for "%s".', get_debug_type($content), $this->getInfo('url'))); + throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned for "%s".', get_debug_type($content), $this->getInfo('url'))); } if (null !== $this->content) { diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/CurlResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/CurlResponse.php index 4cb2a3097..7e95bbcfb 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/CurlResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/CurlResponse.php @@ -139,7 +139,7 @@ final class CurlResponse implements ResponseInterface, StreamableInterface curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { if ('H' === (curl_getinfo($ch, \CURLINFO_PRIVATE)[0] ?? null)) { $multi->handlesActivity[$id][] = null; - $multi->handlesActivity[$id][] = new TransportException(sprintf('Unsupported protocol for "%s"', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + $multi->handlesActivity[$id][] = new TransportException(\sprintf('Unsupported protocol for "%s"', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); return 0; } @@ -265,13 +265,13 @@ final class CurlResponse implements ResponseInterface, StreamableInterface /** * @param CurlClientState $multi */ - private static function perform(ClientState $multi, ?array &$responses = null): void + private static function perform(ClientState $multi, ?array $responses = null): void { if ($multi->performing) { if ($responses) { - $response = current($responses); + $response = $responses[array_key_first($responses)]; $multi->handlesActivity[(int) $response->handle][] = null; - $multi->handlesActivity[(int) $response->handle][] = new TransportException(sprintf('Userland callback cannot use the client nor the response while processing "%s".', curl_getinfo($response->handle, \CURLINFO_EFFECTIVE_URL))); + $multi->handlesActivity[(int) $response->handle][] = new TransportException(\sprintf('Userland callback cannot use the client nor the response while processing "%s".', curl_getinfo($response->handle, \CURLINFO_EFFECTIVE_URL))); } return; @@ -312,7 +312,16 @@ final class CurlResponse implements ResponseInterface, StreamableInterface } $multi->handlesActivity[$id][] = null; - $multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) || (curl_error($ch) === 'OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0' && -1.0 === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) && \in_array('close', array_map('strtolower', $responses[$id]->headers['connection']), true)) ? null : new TransportException(ucfirst(curl_error($ch) ?: curl_strerror($result)).sprintf(' for "%s".', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + $multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) + || '_0' === $waitFor + || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) + || ('C' === $waitFor[0] + && 'OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0' === curl_error($ch) + && -1.0 === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) + && \in_array('close', array_map('strtolower', $responses[$id]->headers['connection'] ?? []), true) + ) + ? null + : new TransportException(ucfirst(curl_error($ch) ?: curl_strerror($result)).\sprintf(' for "%s".', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); } } finally { $multi->performing = false; @@ -438,7 +447,7 @@ final class CurlResponse implements ResponseInterface, StreamableInterface curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor); } elseif (null !== $info['redirect_url'] && $logger) { - $logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url'])); + $logger->info(\sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url'])); } $location = null; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/MockResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/MockResponse.php index 0493bcb7c..7bbe5993c 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/MockResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/MockResponse.php @@ -167,7 +167,7 @@ class MockResponse implements ResponseInterface, StreamableInterface $runningResponses[0][1][$response->id] = $response; } - protected static function perform(ClientState $multi, array &$responses): void + protected static function perform(ClientState $multi, array $responses): void { foreach ($responses as $response) { $id = $response->id; @@ -240,7 +240,7 @@ class MockResponse implements ResponseInterface, StreamableInterface } elseif ($body instanceof \Closure) { while ('' !== $data = $body(16372)) { if (!\is_string($data)) { - throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + throw new TransportException(\sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); } // "notify" upload progress @@ -296,7 +296,7 @@ class MockResponse implements ResponseInterface, StreamableInterface if ('' === $chunk = (string) $chunk) { // simulate an idle timeout - $response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url'])); + $response->body[] = new ErrorChunk($offset, \sprintf('Idle timeout reached for "%s".', $response->info['url'])); } else { $response->body[] = $chunk; $offset += \strlen($chunk); @@ -320,7 +320,7 @@ class MockResponse implements ResponseInterface, StreamableInterface $onProgress($offset, $dlSize, $response->info); if ($dlSize && $offset !== $dlSize) { - throw new TransportException(sprintf('Transfer closed with %d bytes remaining to read.', $dlSize - $offset)); + throw new TransportException(\sprintf('Transfer closed with %d bytes remaining to read.', $dlSize - $offset)); } } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/NativeResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/NativeResponse.php index 77350700a..54312884c 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/NativeResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/NativeResponse.php @@ -79,7 +79,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface }; $this->canary = new Canary(static function () use ($multi, $id) { - if (null !== ($host = $multi->openHandles[$id][6] ?? null) && 0 >= --$multi->hosts[$host]) { + if (null !== ($host = $multi->openHandles[$id][6] ?? null) && isset($multi->hosts[$host]) && 0 >= --$multi->hosts[$host]) { unset($multi->hosts[$host]); } unset($multi->openHandles[$id], $multi->handlesActivity[$id]); @@ -123,7 +123,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface throw new TransportException($msg); } - $this->logger?->info(sprintf('%s for "%s".', $msg, $url ?? $this->url)); + $this->logger?->info(\sprintf('%s for "%s".', $msg, $url ?? $this->url)); }); try { @@ -142,7 +142,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface $this->info['request_header'] = $this->info['url']['path'].$this->info['url']['query']; } - $this->info['request_header'] = sprintf("> %s %s HTTP/%s \r\n", $context['http']['method'], $this->info['request_header'], $context['http']['protocol_version']); + $this->info['request_header'] = \sprintf("> %s %s HTTP/%s \r\n", $context['http']['method'], $this->info['request_header'], $context['http']['protocol_version']); $this->info['request_header'] .= implode("\r\n", $context['http']['header'])."\r\n\r\n"; if (\array_key_exists('peer_name', $context['ssl']) && null === $context['ssl']['peer_name']) { @@ -159,7 +159,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface break; } - $this->logger?->info(sprintf('Redirecting: "%s %s"', $this->info['http_code'], $url ?? $this->url)); + $this->logger?->info(\sprintf('Redirecting: "%s %s"', $this->info['http_code'], $url ?? $this->url)); } } catch (\Throwable $e) { $this->close(); @@ -228,7 +228,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface /** * @param NativeClientState $multi */ - private static function perform(ClientState $multi, ?array &$responses = null): void + private static function perform(ClientState $multi, ?array $responses = null): void { foreach ($multi->openHandles as $i => [$pauseExpiry, $h, $buffer, $onProgress]) { if ($pauseExpiry) { @@ -294,7 +294,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface if (null === $e) { if (0 < $remaining) { - $e = new TransportException(sprintf('Transfer closed with %s bytes remaining to read.', $remaining)); + $e = new TransportException(\sprintf('Transfer closed with %s bytes remaining to read.', $remaining)); } elseif (-1 === $remaining && fwrite($buffer, '-') && '' !== stream_get_contents($buffer, -1, 0)) { $e = new TransportException('Transfer closed with outstanding data remaining from chunked response.'); } @@ -302,7 +302,7 @@ final class NativeResponse implements ResponseInterface, StreamableInterface $multi->handlesActivity[$i][] = null; $multi->handlesActivity[$i][] = $e; - if (null !== ($host = $multi->openHandles[$i][6] ?? null) && 0 >= --$multi->hosts[$host]) { + if (null !== ($host = $multi->openHandles[$i][6] ?? null) && isset($multi->hosts[$host]) && 0 >= --$multi->hosts[$host]) { unset($multi->hosts[$host]); } unset($multi->openHandles[$i]); diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/StreamWrapper.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/StreamWrapper.php index a66802704..bf9eebcb8 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/StreamWrapper.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/StreamWrapper.php @@ -30,7 +30,7 @@ class StreamWrapper private ResponseInterface $response; /** @var resource|string|null */ - private $content = null; + private $content; /** @var resource|callable|null */ private $handle; @@ -56,7 +56,7 @@ class StreamWrapper } if (null === $client && !method_exists($response, 'stream')) { - throw new \InvalidArgumentException(sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); + throw new \InvalidArgumentException(\sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); } static $registered = false; @@ -94,7 +94,7 @@ class StreamWrapper { if ('r' !== $mode) { if ($options & \STREAM_REPORT_ERRORS) { - trigger_error(sprintf('Invalid mode "%s": only "r" is supported.', $mode), \E_USER_WARNING); + trigger_error(\sprintf('Invalid mode "%s": only "r" is supported.', $mode), \E_USER_WARNING); } return false; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/TraceableResponse.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/TraceableResponse.php index d65c8066d..0137e2117 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/TraceableResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/TraceableResponse.php @@ -173,7 +173,7 @@ class TraceableResponse implements ResponseInterface, StreamableInterface foreach ($responses as $r) { if (!$r instanceof self) { - throw new \TypeError(sprintf('"%s::stream()" expects parameter 1 to be an iterable of TraceableResponse objects, "%s" given.', TraceableHttpClient::class, get_debug_type($r))); + throw new \TypeError(\sprintf('"%s::stream()" expects parameter 1 to be an iterable of TraceableResponse objects, "%s" given.', TraceableHttpClient::class, get_debug_type($r))); } $traceableMap[$r->response] = $r; diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Response/TransportResponseTrait.php b/lam/lib/3rdParty/composer/symfony/http-client/Response/TransportResponseTrait.php index 7b65fd799..4cc110fbc 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Response/TransportResponseTrait.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Response/TransportResponseTrait.php @@ -92,7 +92,7 @@ trait TransportResponseTrait /** * Performs all pending non-blocking operations. */ - abstract protected static function perform(ClientState $multi, array &$responses): void; + abstract protected static function perform(ClientState $multi, array $responses): void; /** * Waits for network activity. @@ -150,10 +150,15 @@ trait TransportResponseTrait $lastActivity = hrtime(true) / 1E9; $elapsedTimeout = 0; - if ($fromLastTimeout = 0.0 === $timeout && '-0' === (string) $timeout) { - $timeout = null; - } elseif ($fromLastTimeout = 0 > $timeout) { - $timeout = -$timeout; + if ((0.0 === $timeout && '-0' === (string) $timeout) || 0 > $timeout) { + $timeout = $timeout ? -$timeout : null; + + /** @var ClientState $multi */ + foreach ($runningResponses as [$multi]) { + if (null !== $multi->lastTimeout) { + $elapsedTimeout = max($elapsedTimeout, $lastActivity - $multi->lastTimeout); + } + } } while (true) { @@ -162,8 +167,7 @@ trait TransportResponseTrait $timeoutMin = $timeout ?? \INF; /** @var ClientState $multi */ - foreach ($runningResponses as $i => [$multi]) { - $responses = &$runningResponses[$i][1]; + foreach ($runningResponses as $i => [$multi, &$responses]) { self::perform($multi, $responses); foreach ($responses as $j => $response) { @@ -171,34 +175,33 @@ trait TransportResponseTrait $timeoutMin = min($timeoutMin, $response->timeout, 1); $chunk = false; - if ($fromLastTimeout && null !== $multi->lastTimeout) { - $elapsedTimeout = hrtime(true) / 1E9 - $multi->lastTimeout; - } - if (isset($multi->handlesActivity[$j])) { $multi->lastTimeout = null; + $elapsedTimeout = 0; } elseif (!isset($multi->openHandles[$j])) { + $hasActivity = true; unset($responses[$j]); continue; } elseif ($elapsedTimeout >= $timeoutMax) { - $multi->handlesActivity[$j] = [new ErrorChunk($response->offset, sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))]; + $multi->handlesActivity[$j] = [new ErrorChunk($response->offset, \sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))]; $multi->lastTimeout ??= $lastActivity; + $elapsedTimeout = $timeoutMax; } else { continue; } - while ($multi->handlesActivity[$j] ?? false) { - $hasActivity = true; - $elapsedTimeout = 0; + $lastActivity = null; + $hasActivity = true; + while ($multi->handlesActivity[$j] ?? false) { if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) { if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) { - $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Error while processing content unencoding for "%s".', $response->getInfo('url')))]; + $multi->handlesActivity[$j] = [null, new TransportException(\sprintf('Error while processing content unencoding for "%s".', $response->getInfo('url')))]; continue; } if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) { - $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))]; + $multi->handlesActivity[$j] = [null, new TransportException(\sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))]; continue; } @@ -227,11 +230,10 @@ trait TransportResponseTrait } } elseif ($chunk instanceof ErrorChunk) { unset($responses[$j]); - $elapsedTimeout = $timeoutMax; } elseif ($chunk instanceof FirstChunk) { if ($response->logger) { $info = $response->getInfo(); - $response->logger->info(sprintf('Response: "%s %s"', $info['http_code'], $info['url'])); + $response->logger->info(\sprintf('Response: "%s %s"', $info['http_code'], $info['url'])); } $response->inflate = \extension_loaded('zlib') && $response->inflate && 'gzip' === ($response->headers['content-encoding'][0] ?? null) ? inflate_init(\ZLIB_ENCODING_GZIP) : null; @@ -274,10 +276,12 @@ trait TransportResponseTrait if ($chunk instanceof ErrorChunk && !$chunk->didThrow()) { // Ensure transport exceptions are always thrown $chunk->getContent(); + throw new \LogicException('A transport exception should have been thrown.'); } } if (!$responses) { + $hasActivity = true; unset($runningResponses[$i]); } @@ -291,7 +295,7 @@ trait TransportResponseTrait } if ($hasActivity) { - $lastActivity = hrtime(true) / 1E9; + $lastActivity ??= hrtime(true) / 1E9; continue; } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Retry/GenericRetryStrategy.php b/lam/lib/3rdParty/composer/symfony/http-client/Retry/GenericRetryStrategy.php index ecfa5cd3c..2ba8b7fad 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Retry/GenericRetryStrategy.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Retry/GenericRetryStrategy.php @@ -54,22 +54,22 @@ class GenericRetryStrategy implements RetryStrategyInterface $this->statusCodes = $statusCodes; if ($delayMs < 0) { - throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMs)); + throw new InvalidArgumentException(\sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMs)); } $this->delayMs = $delayMs; if ($multiplier < 1) { - throw new InvalidArgumentException(sprintf('Multiplier must be greater than or equal to one: "%s" given.', $multiplier)); + throw new InvalidArgumentException(\sprintf('Multiplier must be greater than or equal to one: "%s" given.', $multiplier)); } $this->multiplier = $multiplier; if ($maxDelayMs < 0) { - throw new InvalidArgumentException(sprintf('Max delay must be greater than or equal to zero: "%s" given.', $maxDelayMs)); + throw new InvalidArgumentException(\sprintf('Max delay must be greater than or equal to zero: "%s" given.', $maxDelayMs)); } $this->maxDelayMs = $maxDelayMs; if ($jitter < 0 || $jitter > 1) { - throw new InvalidArgumentException(sprintf('Jitter must be between 0 and 1: "%s" given.', $jitter)); + throw new InvalidArgumentException(\sprintf('Jitter must be between 0 and 1: "%s" given.', $jitter)); } $this->jitter = $jitter; } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/RetryableHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/RetryableHttpClient.php index d3b779420..76aad263a 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/RetryableHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/RetryableHttpClient.php @@ -100,7 +100,7 @@ class RetryableHttpClient implements HttpClientInterface, ResetInterface if ('' !== $context->getInfo('primary_ip')) { $shouldRetry = $this->strategy->shouldRetry($context, null, $exception); if (null === $shouldRetry) { - throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with an exception.', $this->strategy::class)); + throw new \LogicException(\sprintf('The "%s::shouldRetry()" method must not return null when called with an exception.', $this->strategy::class)); } if (false === $shouldRetry) { @@ -131,7 +131,7 @@ class RetryableHttpClient implements HttpClientInterface, ResetInterface } if (null === $shouldRetry = $this->strategy->shouldRetry($context, $content, null)) { - throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with a body.', $this->strategy::class)); + throw new \LogicException(\sprintf('The "%s::shouldRetry()" method must not return null when called with a body.', $this->strategy::class)); } if (false === $shouldRetry) { diff --git a/lam/lib/3rdParty/composer/symfony/http-client/ScopingHttpClient.php b/lam/lib/3rdParty/composer/symfony/http-client/ScopingHttpClient.php index 0d09a3522..da5bdb85b 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/ScopingHttpClient.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/ScopingHttpClient.php @@ -39,7 +39,7 @@ class ScopingHttpClient implements HttpClientInterface, ResetInterface, LoggerAw $this->defaultRegexp = $defaultRegexp; if (null !== $defaultRegexp && !isset($defaultOptionsByRegexp[$defaultRegexp])) { - throw new InvalidArgumentException(sprintf('No options are mapped to the provided "%s" default regexp.', $defaultRegexp)); + throw new InvalidArgumentException(\sprintf('No options are mapped to the provided "%s" default regexp.', $defaultRegexp)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/Test/HarFileResponseFactory.php b/lam/lib/3rdParty/composer/symfony/http-client/Test/HarFileResponseFactory.php index 7265709a0..e307861b8 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/Test/HarFileResponseFactory.php +++ b/lam/lib/3rdParty/composer/symfony/http-client/Test/HarFileResponseFactory.php @@ -34,7 +34,7 @@ class HarFileResponseFactory public function __invoke(string $method, string $url, array $options): ResponseInterface { if (!is_file($this->archiveFile)) { - throw new \InvalidArgumentException(sprintf('Invalid file path provided: "%s".', $this->archiveFile)); + throw new \InvalidArgumentException(\sprintf('Invalid file path provided: "%s".', $this->archiveFile)); } $json = json_decode(json: file_get_contents($this->archiveFile), associative: true, flags: \JSON_THROW_ON_ERROR); @@ -77,7 +77,7 @@ class HarFileResponseFactory return new MockResponse($body, $info); } - throw new TransportException(sprintf('File "%s" does not contain a response for HTTP request "%s" "%s".', $this->archiveFile, $method, $url)); + throw new TransportException(\sprintf('File "%s" does not contain a response for HTTP request "%s" "%s".', $this->archiveFile, $method, $url)); } /** @@ -91,7 +91,7 @@ class HarFileResponseFactory return match ($encoding) { 'base64' => base64_decode($text), null => $text, - default => throw new \InvalidArgumentException(sprintf('Unsupported encoding "%s", currently only base64 is supported.', $encoding)), + default => throw new \InvalidArgumentException(\sprintf('Unsupported encoding "%s", currently only base64 is supported.', $encoding)), }; } } diff --git a/lam/lib/3rdParty/composer/symfony/http-client/composer.json b/lam/lib/3rdParty/composer/symfony/http-client/composer.json index 23437d536..d36276ce0 100644 --- a/lam/lib/3rdParty/composer/symfony/http-client/composer.json +++ b/lam/lib/3rdParty/composer/symfony/http-client/composer.json @@ -25,7 +25,8 @@ "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.3|^3.5.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "require-dev": { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/BinaryFileResponse.php b/lam/lib/3rdParty/composer/symfony/http-foundation/BinaryFileResponse.php index 41a244b81..2c14d3668 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/BinaryFileResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/BinaryFileResponse.php @@ -229,7 +229,7 @@ class BinaryFileResponse extends Response $path = $location.substr($path, \strlen($pathPrefix)); // Only set X-Accel-Redirect header if a valid URI can be produced // as nginx does not serve arbitrary file paths. - $this->headers->set($type, $path); + $this->headers->set($type, rawurlencode($path)); $this->maxlen = 0; break; } @@ -259,13 +259,13 @@ class BinaryFileResponse extends Response $end = min($end, $fileSize - 1); if ($start < 0 || $start > $end) { $this->setStatusCode(416); - $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); + $this->headers->set('Content-Range', \sprintf('bytes */%s', $fileSize)); } elseif ($end - $start < $fileSize - 1) { $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; $this->offset = $start; $this->setStatusCode(206); - $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); + $this->headers->set('Content-Range', \sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); $this->headers->set('Content-Length', $end - $start + 1); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Cookie.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Cookie.php index 4a3b73608..05c6c62d5 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Cookie.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Cookie.php @@ -101,7 +101,7 @@ class Cookie { // from PHP source code if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) { - throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); + throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $name)); } if (empty($name)) { @@ -211,7 +211,7 @@ class Cookie public function withRaw(bool $raw = true): static { if ($raw && false !== strpbrk($this->name, self::RESERVED_CHARS_LIST)) { - throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $this->name)); + throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $this->name)); } $cookie = clone $this; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/AccessDeniedException.php b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/AccessDeniedException.php index 136d2a9f5..79ab0fce3 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/AccessDeniedException.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/AccessDeniedException.php @@ -20,6 +20,6 @@ class AccessDeniedException extends FileException { public function __construct(string $path) { - parent::__construct(sprintf('The file %s could not be accessed', $path)); + parent::__construct(\sprintf('The file %s could not be accessed', $path)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/FileNotFoundException.php b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/FileNotFoundException.php index 31bdf68fe..3a5eb039b 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/FileNotFoundException.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/FileNotFoundException.php @@ -20,6 +20,6 @@ class FileNotFoundException extends FileException { public function __construct(string $path) { - parent::__construct(sprintf('The file "%s" does not exist', $path)); + parent::__construct(\sprintf('The file "%s" does not exist', $path)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/UnexpectedTypeException.php b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/UnexpectedTypeException.php index 905bd5962..09b1c7e18 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/UnexpectedTypeException.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/File/Exception/UnexpectedTypeException.php @@ -15,6 +15,6 @@ class UnexpectedTypeException extends FileException { public function __construct(mixed $value, string $expectedType) { - parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value))); + parent::__construct(\sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value))); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/File/File.php b/lam/lib/3rdParty/composer/symfony/http-foundation/File/File.php index 34ca5a537..c369ecbfb 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/File/File.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/File/File.php @@ -93,7 +93,7 @@ class File extends \SplFileInfo restore_error_handler(); } if (!$renamed) { - throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); + throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @chmod($target, 0666 & ~umask()); @@ -106,7 +106,7 @@ class File extends \SplFileInfo $content = file_get_contents($this->getPathname()); if (false === $content) { - throw new FileException(sprintf('Could not get the content of the file "%s".', $this->getPathname())); + throw new FileException(\sprintf('Could not get the content of the file "%s".', $this->getPathname())); } return $content; @@ -116,10 +116,10 @@ class File extends \SplFileInfo { if (!is_dir($directory)) { if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) { - throw new FileException(sprintf('Unable to create the "%s" directory.', $directory)); + throw new FileException(\sprintf('Unable to create the "%s" directory.', $directory)); } } elseif (!is_writable($directory)) { - throw new FileException(sprintf('Unable to write in the "%s" directory.', $directory)); + throw new FileException(\sprintf('Unable to write in the "%s" directory.', $directory)); } $target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name)); diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/File/UploadedFile.php b/lam/lib/3rdParty/composer/symfony/http-foundation/File/UploadedFile.php index f475d028d..85aab2872 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/File/UploadedFile.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/File/UploadedFile.php @@ -174,7 +174,7 @@ class UploadedFile extends File restore_error_handler(); } if (!$moved) { - throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); + throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @chmod($target, 0666 & ~umask()); @@ -264,6 +264,6 @@ class UploadedFile extends File $maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0; $message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.'; - return sprintf($message, $this->getClientOriginalName(), $maxFilesize); + return \sprintf($message, $this->getClientOriginalName(), $maxFilesize); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderBag.php b/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderBag.php index 4dd777f16..e8072addd 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderBag.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderBag.php @@ -51,7 +51,7 @@ class HeaderBag implements \IteratorAggregate, \Countable, \Stringable foreach ($headers as $name => $values) { $name = ucwords($name, '-'); foreach ($values as $value) { - $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value); + $content .= \sprintf("%-{$max}s %s\r\n", $name.':', $value); } } @@ -204,7 +204,7 @@ class HeaderBag implements \IteratorAggregate, \Countable, \Stringable } if (false === $date = \DateTimeImmutable::createFromFormat(\DATE_RFC2822, $value)) { - throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value)); + throw new \RuntimeException(\sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value)); } return $date; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderUtils.php b/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderUtils.php index 110896e17..ad47f2204 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderUtils.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/HeaderUtils.php @@ -165,7 +165,7 @@ class HeaderUtils public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string { if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) { - throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); + throw new \InvalidArgumentException(\sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); } if ('' === $filenameFallback) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/InputBag.php b/lam/lib/3rdParty/composer/symfony/http-foundation/InputBag.php index 5acf35fec..08b927571 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/InputBag.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/InputBag.php @@ -29,13 +29,13 @@ final class InputBag extends ParameterBag public function get(string $key, mixed $default = null): string|int|float|bool|null { if (null !== $default && !\is_scalar($default) && !$default instanceof \Stringable) { - throw new \InvalidArgumentException(sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default))); + throw new \InvalidArgumentException(\sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default))); } $value = parent::get($key, $this); if (null !== $value && $this !== $value && !\is_scalar($value) && !$value instanceof \Stringable) { - throw new BadRequestException(sprintf('Input value "%s" contains a non-scalar value.', $key)); + throw new BadRequestException(\sprintf('Input value "%s" contains a non-scalar value.', $key)); } return $this === $value ? $default : $value; @@ -68,7 +68,7 @@ final class InputBag extends ParameterBag public function set(string $key, mixed $value): void { if (null !== $value && !\is_scalar($value) && !\is_array($value) && !$value instanceof \Stringable) { - throw new \InvalidArgumentException(sprintf('Expected a scalar, or an array as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($value))); + throw new \InvalidArgumentException(\sprintf('Expected a scalar, or an array as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($value))); } $this->parameters[$key] = $value; @@ -112,11 +112,11 @@ final class InputBag extends ParameterBag } if (\is_array($value) && !(($options['flags'] ?? 0) & (\FILTER_REQUIRE_ARRAY | \FILTER_FORCE_ARRAY))) { - throw new BadRequestException(sprintf('Input value "%s" contains an array, but "FILTER_REQUIRE_ARRAY" or "FILTER_FORCE_ARRAY" flags were not set.', $key)); + throw new BadRequestException(\sprintf('Input value "%s" contains an array, but "FILTER_REQUIRE_ARRAY" or "FILTER_FORCE_ARRAY" flags were not set.', $key)); } if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { - throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); + throw new \InvalidArgumentException(\sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); } $options['flags'] ??= 0; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/IpUtils.php b/lam/lib/3rdParty/composer/symfony/http-foundation/IpUtils.php index ceab620c2..8b52d2a9d 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/IpUtils.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/IpUtils.php @@ -102,7 +102,7 @@ class IpUtils return self::setCacheResult($cacheKey, false); } - return self::setCacheResult($cacheKey, 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask)); + return self::setCacheResult($cacheKey, 0 === substr_compare(\sprintf('%032b', ip2long($requestIp)), \sprintf('%032b', ip2long($address)), 0, $netmask)); } /** @@ -182,6 +182,16 @@ class IpUtils */ public static function anonymize(string $ip): string { + /* + * If the IP contains a % symbol, then it is a local-link address with scoping according to RFC 4007 + * In that case, we only care about the part before the % symbol, as the following functions, can only work with + * the IP address itself. As the scope can leak information (containing interface name), we do not want to + * include it in our anonymized IP data. + */ + if (str_contains($ip, '%')) { + $ip = substr($ip, 0, strpos($ip, '%')); + } + $wrappedIPv6 = false; if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) { $wrappedIPv6 = true; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/JsonResponse.php b/lam/lib/3rdParty/composer/symfony/http-foundation/JsonResponse.php index 93c5751f2..616bccfee 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/JsonResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/JsonResponse.php @@ -41,7 +41,7 @@ class JsonResponse extends Response parent::__construct('', $status, $headers); if ($json && !\is_string($data) && !is_numeric($data) && !\is_callable([$data, '__toString'])) { - throw new \TypeError(sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data))); + throw new \TypeError(\sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data))); } $data ??= new \ArrayObject(); @@ -176,7 +176,7 @@ class JsonResponse extends Response // Not using application/javascript for compatibility reasons with older browsers. $this->headers->set('Content-Type', 'text/javascript'); - return $this->setContent(sprintf('/**/%s(%s);', $this->callback, $this->data)); + return $this->setContent(\sprintf('/**/%s(%s);', $this->callback, $this->data)); } // Only set the header when there is none or when it equals 'text/javascript' (from a previous update with callback) diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/ParameterBag.php b/lam/lib/3rdParty/composer/symfony/http-foundation/ParameterBag.php index 48fa4b233..2bd8cb15f 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/ParameterBag.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/ParameterBag.php @@ -45,7 +45,7 @@ class ParameterBag implements \IteratorAggregate, \Countable } if (!\is_array($value = $this->parameters[$key] ?? [])) { - throw new BadRequestException(sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value))); + throw new BadRequestException(\sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value))); } return $value; @@ -141,7 +141,7 @@ class ParameterBag implements \IteratorAggregate, \Countable { $value = $this->get($key, $default); if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException(sprintf('Parameter value "%s" cannot be converted to "string".', $key)); + throw new UnexpectedValueException(\sprintf('Parameter value "%s" cannot be converted to "string".', $key)); } return (string) $value; @@ -185,7 +185,7 @@ class ParameterBag implements \IteratorAggregate, \Countable try { return $class::from($value); } catch (\ValueError|\TypeError $e) { - throw new UnexpectedValueException(sprintf('Parameter "%s" cannot be converted to enum: %s.', $key, $e->getMessage()), $e->getCode(), $e); + throw new UnexpectedValueException(\sprintf('Parameter "%s" cannot be converted to enum: %s.', $key, $e->getMessage()), $e->getCode(), $e); } } @@ -212,11 +212,11 @@ class ParameterBag implements \IteratorAggregate, \Countable } if (\is_object($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException(sprintf('Parameter value "%s" cannot be filtered.', $key)); + throw new UnexpectedValueException(\sprintf('Parameter value "%s" cannot be filtered.', $key)); } if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { - throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); + throw new \InvalidArgumentException(\sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); } $options['flags'] ??= 0; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/RedirectResponse.php b/lam/lib/3rdParty/composer/symfony/http-foundation/RedirectResponse.php index 408629e36..220dcf616 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/RedirectResponse.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/RedirectResponse.php @@ -39,7 +39,7 @@ class RedirectResponse extends Response $this->setTargetUrl($url); if (!$this->isRedirect()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status)); + throw new \InvalidArgumentException(\sprintf('The HTTP status code is not a redirect ("%s" given).', $status)); } if (301 == $status && !\array_key_exists('cache-control', array_change_key_case($headers, \CASE_LOWER))) { @@ -71,7 +71,7 @@ class RedirectResponse extends Response $this->targetUrl = $url; $this->setContent( - sprintf(' + \sprintf(' diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Request.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Request.php index 922014133..ec2d08d1a 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Request.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Request.php @@ -537,7 +537,7 @@ class Request } return - sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". + \sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". $this->headers. $cookieHeader."\r\n". $content; @@ -638,7 +638,7 @@ class Request */ public static function setTrustedHosts(array $hostPatterns) { - self::$trustedHostPatterns = array_map(fn ($hostPattern) => sprintf('{%s}i', $hostPattern), $hostPatterns); + self::$trustedHostPatterns = array_map(fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), $hostPatterns); // we need to reset trusted hosts on trusted host patterns change self::$trustedHosts = []; } @@ -1160,7 +1160,7 @@ class Request } $this->isHostValid = false; - throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host)); + throw new SuspiciousOperationException(\sprintf('Invalid Host "%s".', $host)); } if (\count(self::$trustedHostPatterns) > 0) { @@ -1183,7 +1183,7 @@ class Request } $this->isHostValid = false; - throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host)); + throw new SuspiciousOperationException(\sprintf('Untrusted Host "%s".', $host)); } return $host; @@ -1466,7 +1466,7 @@ class Request public function getProtocolVersion(): ?string { if ($this->isFromTrustedProxy()) { - preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via') ?? '', $matches); + preg_match('~^(HTTP/)?([1-9]\.[0-9])\b~', $this->headers->get('Via') ?? '', $matches); if ($matches) { return 'HTTP/'.$matches[2]; @@ -1545,7 +1545,7 @@ class Request } if (!\is_array($content)) { - throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); + throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); } return new InputBag($content); @@ -1571,7 +1571,7 @@ class Request } if (!\is_array($content)) { - throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); + throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); } return $content; @@ -1978,7 +1978,7 @@ class Request $len = \strlen($prefix); - if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) { + if (preg_match(\sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) { return $match[0]; } @@ -2070,7 +2070,7 @@ class Request } $this->isForwardedValid = false; - throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::TRUSTED_HEADERS[self::HEADER_FORWARDED], self::TRUSTED_HEADERS[$type])); + throw new ConflictingHeadersException(\sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::TRUSTED_HEADERS[self::HEADER_FORWARDED], self::TRUSTED_HEADERS[$type])); } private function normalizeAndFilterClientIps(array $clientIps, string $ip): array diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/RequestStack.php b/lam/lib/3rdParty/composer/symfony/http-foundation/RequestStack.php index 5aa8ba793..ca61eef29 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/RequestStack.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/RequestStack.php @@ -106,4 +106,11 @@ class RequestStack throw new SessionNotFoundException(); } + + public function resetRequestFormats(): void + { + static $resetRequestFormats; + $resetRequestFormats ??= \Closure::bind(static fn () => self::$formats = null, null, Request::class); + $resetRequestFormats(); + } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Response.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Response.php index a43e7a9ac..e476e29d1 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Response.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Response.php @@ -241,7 +241,7 @@ class Response public function __toString(): string { return - sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". + \sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". $this->headers."\r\n". $this->getContent(); } @@ -393,7 +393,7 @@ class Response $statusCode ??= $this->statusCode; // status - header(sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode); + header(\sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode); return $this; } @@ -499,7 +499,7 @@ class Response { $this->statusCode = $code; if ($this->isInvalid()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); + throw new \InvalidArgumentException(\sprintf('The HTTP status code "%s" is not valid.', $code)); } if (null === $text) { @@ -1011,7 +1011,7 @@ class Response public function setCache(array $options): static { if ($diff = array_diff(array_keys($options), array_keys(self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES))) { - throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', $diff))); + throw new \InvalidArgumentException(\sprintf('Response does not support the following options: "%s".', implode('", "', $diff))); } if (isset($options['etag'])) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/ResponseHeaderBag.php b/lam/lib/3rdParty/composer/symfony/http-foundation/ResponseHeaderBag.php index 376357d01..8db8dce4e 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/ResponseHeaderBag.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/ResponseHeaderBag.php @@ -212,7 +212,7 @@ class ResponseHeaderBag extends HeaderBag public function getCookies(string $format = self::COOKIES_FLAT): array { if (!\in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY])) { - throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY]))); + throw new \InvalidArgumentException(\sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY]))); } if (self::COOKIES_ARRAY === $format) { @@ -240,7 +240,7 @@ class ResponseHeaderBag extends HeaderBag */ public function clearCookie(string $name, ?string $path = '/', ?string $domain = null, bool $secure = false, bool $httpOnly = true, ?string $sameSite = null /* , bool $partitioned = false */) { - $partitioned = 6 < \func_num_args() ? \func_get_arg(6) : false; + $partitioned = 6 < \func_num_args() ? func_get_arg(6) : false; $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite, $partitioned)); } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/SessionUtils.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/SessionUtils.php index 504c5848e..57aa565ff 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/SessionUtils.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/SessionUtils.php @@ -28,8 +28,8 @@ final class SessionUtils public static function popSessionCookie(string $sessionName, #[\SensitiveParameter] string $sessionId): ?string { $sessionCookie = null; - $sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName)); - $sessionCookieWithId = sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId)); + $sessionCookiePrefix = \sprintf(' %s=', urlencode($sessionName)); + $sessionCookieWithId = \sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId)); $otherCookies = []; foreach (headers_list() as $h) { if (0 !== stripos($h, 'Set-Cookie:')) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php index 288c24232..fd8562377 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php @@ -32,7 +32,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess { $this->sessionName = $sessionName; if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) { - header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire'))); + header(\sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire'))); } return true; @@ -88,7 +88,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess { if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL)) { if (!isset($this->sessionName)) { - throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class)); + throw new \LogicException(\sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class)); } $cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId); diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php index 411a8d1f0..70ac76248 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php @@ -22,7 +22,7 @@ class IdentityMarshaller implements MarshallerInterface { foreach ($values as $key => $value) { if (!\is_string($value)) { - throw new \LogicException(sprintf('%s accepts only string as data.', __METHOD__)); + throw new \LogicException(\sprintf('%s accepts only string as data.', __METHOD__)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php index 91a023ddb..9647f42bb 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -47,7 +47,7 @@ class MemcachedSessionHandler extends AbstractSessionHandler $this->memcached = $memcached; if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime', 'ttl'])) { - throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); + throw new \InvalidArgumentException(\sprintf('The following options are not supported "%s".', implode(', ', $diff))); } $this->ttl = $options['expiretime'] ?? $options['ttl'] ?? null; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php index f8c6151a4..284cd869d 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php @@ -34,7 +34,7 @@ class NativeFileSessionHandler extends \SessionHandler if ($count = substr_count($savePath, ';')) { if ($count > 2) { - throw new \InvalidArgumentException(sprintf('Invalid argument $savePath \'%s\'.', $savePath)); + throw new \InvalidArgumentException(\sprintf('Invalid argument $savePath \'%s\'.', $savePath)); } // characters after last ';' are the path @@ -42,7 +42,7 @@ class NativeFileSessionHandler extends \SessionHandler } if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) { - throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir)); + throw new \RuntimeException(\sprintf('Session Storage was not able to create directory "%s".', $baseDir)); } if ($savePath !== \ini_get('session.save_path')) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php index 9cee76ddf..af5ce10b6 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php @@ -155,7 +155,7 @@ class PdoSessionHandler extends AbstractSessionHandler { if ($pdoOrDsn instanceof \PDO) { if (\PDO::ERRMODE_EXCEPTION !== $pdoOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) { - throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); + throw new \InvalidArgumentException(\sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); } $this->pdo = $pdoOrDsn; @@ -222,7 +222,7 @@ class PdoSessionHandler extends AbstractSessionHandler $table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); break; default: - throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)); + throw new \DomainException(\sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)); } $table->setPrimaryKey([$this->idCol]); $table->addIndex([$this->lifetimeCol], $this->lifetimeCol.'_idx'); @@ -257,7 +257,7 @@ class PdoSessionHandler extends AbstractSessionHandler 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", - default => throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)), + default => throw new \DomainException(\sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)), }; try { @@ -538,7 +538,7 @@ class PdoSessionHandler extends AbstractSessionHandler return $dsn; default: - throw new \InvalidArgumentException(sprintf('The scheme "%s" is not supported by the PdoSessionHandler URL configuration. Pass a PDO DSN directly.', $params['scheme'])); + throw new \InvalidArgumentException(\sprintf('The scheme "%s" is not supported by the PdoSessionHandler URL configuration. Pass a PDO DSN directly.', $params['scheme'])); } } @@ -734,7 +734,7 @@ class PdoSessionHandler extends AbstractSessionHandler case 'sqlite': throw new \DomainException('SQLite does not support advisory locks.'); default: - throw new \DomainException(sprintf('Advisory locks are currently not implemented for PDO driver "%s".', $this->driver)); + throw new \DomainException(\sprintf('Advisory locks are currently not implemented for PDO driver "%s".', $this->driver)); } } @@ -776,7 +776,7 @@ class PdoSessionHandler extends AbstractSessionHandler // we already locked when starting transaction break; default: - throw new \DomainException(sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver)); + throw new \DomainException(\sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php index b696eee4b..78cd4e7c2 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php @@ -44,7 +44,7 @@ class RedisSessionHandler extends AbstractSessionHandler array $options = [], ) { if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) { - throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); + throw new \InvalidArgumentException(\sprintf('The following options are not supported "%s".', implode(', ', $diff))); } $this->prefix = $options['prefix'] ?? 'sf_s'; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php index ff5b70d81..43a9eb84e 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php @@ -49,7 +49,7 @@ class SessionHandlerFactory return new PdoSessionHandler($connection); case !\is_string($connection): - throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', get_debug_type($connection))); + throw new \InvalidArgumentException(\sprintf('Unsupported Connection: "%s".', get_debug_type($connection))); case str_starts_with($connection, 'file://'): $savePath = substr($connection, 7); @@ -94,6 +94,6 @@ class SessionHandlerFactory return new PdoSessionHandler($connection, $options); } - throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', $connection)); + throw new \InvalidArgumentException(\sprintf('Unsupported Connection: "%s".', $connection)); } } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php index 1f8668744..38afc1257 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php @@ -24,7 +24,7 @@ class StrictSessionHandler extends AbstractSessionHandler public function __construct(\SessionHandlerInterface $handler) { if ($handler instanceof \SessionUpdateTimestampHandlerInterface) { - throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class)); + throw new \LogicException(\sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class)); } $this->handler = $handler; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php index f02793d3e..65ab34f91 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php @@ -174,7 +174,7 @@ class MockArraySessionStorage implements SessionStorageInterface public function getBag(string $name): SessionBagInterface { if (!isset($this->bags[$name])) { - throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); + throw new \InvalidArgumentException(\sprintf('The SessionBagInterface "%s" is not registered.', $name)); } if (!$this->started) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php index ef6d9d8f8..84c2c4363 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php @@ -35,7 +35,7 @@ class MockFileSessionStorage extends MockArraySessionStorage $savePath ??= sys_get_temp_dir(); if (!is_dir($savePath) && !@mkdir($savePath, 0777, true) && !is_dir($savePath)) { - throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $savePath)); + throw new \RuntimeException(\sprintf('Session Storage was not able to create directory "%s".', $savePath)); } $this->savePath = $savePath; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/NativeSessionStorage.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/NativeSessionStorage.php index f63de5740..c8801cc25 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/NativeSessionStorage.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Session/Storage/NativeSessionStorage.php @@ -129,7 +129,7 @@ class NativeSessionStorage implements SessionStorageInterface } if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL) && headers_sent($file, $line)) { - throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); + throw new \RuntimeException(\sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); } $sessionId = $_COOKIE[session_name()] ?? null; @@ -139,7 +139,7 @@ class NativeSessionStorage implements SessionStorageInterface * ---------- Part 1 * * The part `[a-zA-Z0-9,-]` is related to the PHP ini directive `session.sid_bits_per_character` defined as 6. - * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character. + * See https://php.net/session.configuration#ini.session.sid-bits-per-character * Allowed values are integers such as: * - 4 for range `a-f0-9` * - 5 for range `a-v0-9` @@ -148,7 +148,7 @@ class NativeSessionStorage implements SessionStorageInterface * ---------- Part 2 * * The part `{22,250}` is related to the PHP ini directive `session.sid_length`. - * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length. + * See https://php.net/session.configuration#ini.session.sid-length * Allowed values are integers between 22 and 256, but we use 250 for the max. * * Where does the 250 come from? @@ -249,7 +249,7 @@ class NativeSessionStorage implements SessionStorageInterface $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) { if (\E_WARNING === $type && str_starts_with($msg, 'session_write_close():')) { $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler; - $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', $handler::class); + $msg = \sprintf('session_write_close(): Failed to write session data with "%s" handler', $handler::class); } return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false; @@ -302,7 +302,7 @@ class NativeSessionStorage implements SessionStorageInterface public function getBag(string $name): SessionBagInterface { if (!isset($this->bags[$name])) { - throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); + throw new \InvalidArgumentException(\sprintf('The SessionBagInterface "%s" is not registered.', $name)); } if (!$this->started && $this->saveHandler->isActive()) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php index 6e1142681..8fc9aa2a0 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php @@ -27,7 +27,7 @@ final class RequestAttributeValueSame extends Constraint public function toString(): string { - return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); + return \sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); } /** diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php index 768007b95..285f45bf7 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php @@ -32,14 +32,14 @@ final class ResponseCookieValueSame extends Constraint public function toString(): string { - $str = sprintf('has cookie "%s"', $this->name); + $str = \sprintf('has cookie "%s"', $this->name); if ('/' !== $this->path) { - $str .= sprintf(' with path "%s"', $this->path); + $str .= \sprintf(' with path "%s"', $this->path); } if ($this->domain) { - $str .= sprintf(' for domain "%s"', $this->domain); + $str .= \sprintf(' for domain "%s"', $this->domain); } - $str .= sprintf(' with value "%s"', $this->value); + $str .= \sprintf(' with value "%s"', $this->value); return $str; } diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php index 8eccea9d1..a11809d04 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php @@ -30,12 +30,12 @@ final class ResponseHasCookie extends Constraint public function toString(): string { - $str = sprintf('has cookie "%s"', $this->name); + $str = \sprintf('has cookie "%s"', $this->name); if ('/' !== $this->path) { - $str .= sprintf(' with path "%s"', $this->path); + $str .= \sprintf(' with path "%s"', $this->path); } if ($this->domain) { - $str .= sprintf(' for domain "%s"', $this->domain); + $str .= \sprintf(' for domain "%s"', $this->domain); } return $str; diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php index 08522c89c..e5cb48adf 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php @@ -25,7 +25,7 @@ final class ResponseHasHeader extends Constraint public function toString(): string { - return sprintf('has header "%s"', $this->headerName); + return \sprintf('has header "%s"', $this->headerName); } /** diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php index 9286ec715..833ffd9f2 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php @@ -23,7 +23,7 @@ final class ResponseHeaderLocationSame extends Constraint public function toString(): string { - return sprintf('has header "Location" matching "%s"', $this->expectedValue); + return \sprintf('has header "Location" matching "%s"', $this->expectedValue); } protected function matches($other): bool @@ -53,7 +53,7 @@ final class ResponseHeaderLocationSame extends Constraint } if (str_starts_with($url, '//')) { - return sprintf('%s:%s', $this->request->getScheme(), $url); + return \sprintf('%s:%s', $this->request->getScheme(), $url); } if (str_starts_with($url, '/')) { diff --git a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php index 8141df972..02b5921d2 100644 --- a/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php +++ b/lam/lib/3rdParty/composer/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php @@ -27,7 +27,7 @@ final class ResponseHeaderSame extends Constraint public function toString(): string { - return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + return \sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); } /** diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/Ctype.php b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/Ctype.php new file mode 100644 index 000000000..ba75a2c95 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/Ctype.php @@ -0,0 +1,232 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Ctype; + +/** + * Ctype implementation through regex. + * + * @internal + * + * @author Gert de Pagter + */ +final class Ctype +{ + /** + * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. + * + * @see https://php.net/ctype-alnum + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_alnum($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is a letter, FALSE otherwise. + * + * @see https://php.net/ctype-alpha + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_alpha($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); + } + + /** + * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. + * + * @see https://php.net/ctype-cntrl + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_cntrl($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); + } + + /** + * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. + * + * @see https://php.net/ctype-digit + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_digit($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. + * + * @see https://php.net/ctype-graph + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_graph($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); + } + + /** + * Returns TRUE if every character in text is a lowercase letter. + * + * @see https://php.net/ctype-lower + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_lower($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); + } + + /** + * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. + * + * @see https://php.net/ctype-print + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_print($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); + } + + /** + * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. + * + * @see https://php.net/ctype-punct + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_punct($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); + } + + /** + * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. + * + * @see https://php.net/ctype-space + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_space($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); + } + + /** + * Returns TRUE if every character in text is an uppercase letter. + * + * @see https://php.net/ctype-upper + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_upper($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); + } + + /** + * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. + * + * @see https://php.net/ctype-xdigit + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_xdigit($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); + } + + /** + * Converts integers to their char versions according to normal ctype behaviour, if needed. + * + * If an integer between -128 and 255 inclusive is provided, + * it is interpreted as the ASCII value of a single character + * (negative values have 256 added in order to allow characters in the Extended ASCII range). + * Any other integer is interpreted as a string containing the decimal digits of the integer. + * + * @param mixed $int + * @param string $function + * + * @return mixed + */ + private static function convert_int_to_char_for_ctype($int, $function) + { + if (!\is_int($int)) { + return $int; + } + + if ($int < -128 || $int > 255) { + return (string) $int; + } + + if (\PHP_VERSION_ID >= 80100) { + @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED); + } + + if ($int < 0) { + $int += 256; + } + + return \chr($int); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/LICENSE b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/LICENSE new file mode 100644 index 000000000..7536caeae --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/README.md b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/README.md new file mode 100644 index 000000000..b144d03c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/README.md @@ -0,0 +1,12 @@ +Symfony Polyfill / Ctype +======================== + +This component provides `ctype_*` functions to users who run php versions without the ctype extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap.php b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap.php new file mode 100644 index 000000000..d54524b31 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Ctype as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('ctype_alnum')) { + function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } +} +if (!function_exists('ctype_alpha')) { + function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } +} +if (!function_exists('ctype_cntrl')) { + function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } +} +if (!function_exists('ctype_digit')) { + function ctype_digit($text) { return p\Ctype::ctype_digit($text); } +} +if (!function_exists('ctype_graph')) { + function ctype_graph($text) { return p\Ctype::ctype_graph($text); } +} +if (!function_exists('ctype_lower')) { + function ctype_lower($text) { return p\Ctype::ctype_lower($text); } +} +if (!function_exists('ctype_print')) { + function ctype_print($text) { return p\Ctype::ctype_print($text); } +} +if (!function_exists('ctype_punct')) { + function ctype_punct($text) { return p\Ctype::ctype_punct($text); } +} +if (!function_exists('ctype_space')) { + function ctype_space($text) { return p\Ctype::ctype_space($text); } +} +if (!function_exists('ctype_upper')) { + function ctype_upper($text) { return p\Ctype::ctype_upper($text); } +} +if (!function_exists('ctype_xdigit')) { + function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap80.php b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap80.php new file mode 100644 index 000000000..ab2f8611d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap80.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Ctype as p; + +if (!function_exists('ctype_alnum')) { + function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); } +} +if (!function_exists('ctype_alpha')) { + function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); } +} +if (!function_exists('ctype_cntrl')) { + function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); } +} +if (!function_exists('ctype_digit')) { + function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); } +} +if (!function_exists('ctype_graph')) { + function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); } +} +if (!function_exists('ctype_lower')) { + function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); } +} +if (!function_exists('ctype_print')) { + function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); } +} +if (!function_exists('ctype_punct')) { + function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); } +} +if (!function_exists('ctype_space')) { + function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); } +} +if (!function_exists('ctype_upper')) { + function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); } +} +if (!function_exists('ctype_xdigit')) { + function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-ctype/composer.json b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/composer.json new file mode 100644 index 000000000..131ca7adb --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/polyfill-ctype", + "type": "library", + "description": "Symfony polyfill for ctype functions", + "keywords": ["polyfill", "compatibility", "portable", "ctype"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/Grapheme.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/Grapheme.php new file mode 100644 index 000000000..f9e9e5741 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/Grapheme.php @@ -0,0 +1,279 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Grapheme; + +\define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\X' : Grapheme::GRAPHEME_CLUSTER_RX); + +/** + * Partial intl implementation in pure PHP. + * + * Implemented: + * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8 + * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string + * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack + * - grapheme_strlen - Get string length in grapheme units + * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string + * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string + * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string + * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack + * - grapheme_substr - Return part of a string + * - grapheme_str_split - Splits a string into an array of individual or chunks of graphemes + * + * @author Nicolas Grekas + * + * @internal + */ +final class Grapheme +{ + // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) + // This regular expression is a work around for http://bugs.exim.org/1279 + public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])'; + + private const CASE_FOLD = [ + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], + ]; + + public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) + { + if (0 > $start) { + $start = \strlen($s) + $start; + } + + if (!\is_scalar($s)) { + $hasError = false; + set_error_handler(function () use (&$hasError) { $hasError = true; }); + $next = substr($s, $start); + restore_error_handler(); + if ($hasError) { + substr($s, $start); + $s = ''; + } else { + $s = $next; + } + } else { + $s = substr($s, $start); + } + $size = (int) $size; + $type = (int) $type; + $start = (int) $start; + + if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); + } + + if (!isset($s[0]) || 0 > $size || 0 > $start) { + return false; + } + if (0 === $size) { + return ''; + } + + $next = $start; + + $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); + + if (!isset($s[1])) { + return false; + } + + $i = 1; + $ret = ''; + + do { + if (\GRAPHEME_EXTR_COUNT === $type) { + --$size; + } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { + $size -= \strlen($s[$i]); + } else { + $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE'); + } + + if ($size >= 0) { + $ret .= $s[$i]; + } + } while (isset($s[++$i]) && $size > 0); + + $next += \strlen($ret); + + return $ret; + } + + public static function grapheme_strlen($s) + { + preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len); + + return 0 === $len && '' !== $s ? null : $len; + } + + public static function grapheme_substr($s, $start, $len = null) + { + if (null === $len) { + $len = 2147483647; + } + + preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s); + + $slen = \count($s[0]); + $start = (int) $start; + + if (0 > $start) { + $start += $slen; + } + if (0 > $start) { + if (\PHP_VERSION_ID < 80000) { + return false; + } + + $start = 0; + } + if ($start >= $slen) { + return \PHP_VERSION_ID >= 80000 ? '' : false; + } + + $rem = $slen - $start; + + if (0 > $len) { + $len += $rem; + } + if (0 === $len) { + return ''; + } + if (0 > $len) { + return \PHP_VERSION_ID >= 80000 ? '' : false; + } + if ($len > $rem) { + $len = $rem; + } + + return implode('', \array_slice($s[0], $start, $len)); + } + + public static function grapheme_strpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 0); + } + + public static function grapheme_stripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 1); + } + + public static function grapheme_strrpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 2); + } + + public static function grapheme_strripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 3); + } + + public static function grapheme_stristr($s, $needle, $beforeNeedle = false) + { + return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); + } + + public static function grapheme_strstr($s, $needle, $beforeNeedle = false) + { + return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); + } + + public static function grapheme_str_split($s, $len = 1) + { + if (0 > $len || 1073741823 < $len) { + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.'); + } + + if ('' === $s) { + return []; + } + + if (!preg_match_all('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', $s, $matches)) { + return false; + } + + if (1 === $len) { + return $matches[0]; + } + + $chunks = array_chunk($matches[0], $len); + + foreach ($chunks as &$chunk) { + $chunk = implode('', $chunk); + } + + return $chunks; + } + + private static function grapheme_position($s, $needle, $offset, $mode) + { + $needle = (string) $needle; + if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) { + return false; + } + $s = (string) $s; + if (!preg_match('/./us', $s)) { + return false; + } + if ($offset > 0) { + $s = self::grapheme_substr($s, $offset); + } elseif ($offset < 0) { + if (2 > $mode) { + $offset += self::grapheme_strlen($s); + $s = self::grapheme_substr($s, $offset); + if (0 > $offset) { + $offset = 0; + } + } elseif (0 > $offset += self::grapheme_strlen($needle)) { + $s = self::grapheme_substr($s, 0, $offset); + $offset = 0; + } else { + $offset = 0; + } + } + + // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, + // we can use normal binary string functions here. For case-insensitive searches, + // case fold the strings first. + $caseInsensitive = $mode & 1; + $reverse = $mode & 2; + if ($caseInsensitive) { + // Use the same case folding mode as mbstring does for mb_stripos(). + // Stick to SIMPLE case folding to avoid changing the length of the string, which + // might result in offsets being shifted. + $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; + $s = mb_convert_case($s, $mode, 'UTF-8'); + $needle = mb_convert_case($needle, $mode, 'UTF-8'); + + if (!\defined('MB_CASE_FOLD_SIMPLE')) { + $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); + } + } + if ($reverse) { + $needlePos = strrpos($s, $needle); + } else { + $needlePos = strpos($s, $needle); + } + + return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/LICENSE b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/LICENSE new file mode 100644 index 000000000..6e3afce69 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/README.md b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/README.md new file mode 100644 index 000000000..5d7c67875 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/README.md @@ -0,0 +1,32 @@ +Symfony Polyfill / Intl: Grapheme +================================= + +This component provides a partial, native PHP implementation of the +[Grapheme functions](https://php.net/intl.grapheme) from the +[Intl](https://php.net/intl) extension. + +- [`grapheme_extract`](https://php.net/grapheme_extract): Extract a sequence of grapheme + clusters from a text buffer, which must be encoded in UTF-8 +- [`grapheme_stripos`](https://php.net/grapheme_stripos): Find position (in grapheme units) + of first occurrence of a case-insensitive string +- [`grapheme_stristr`](https://php.net/grapheme_stristr): Returns part of haystack string + from the first occurrence of case-insensitive needle to the end of haystack +- [`grapheme_strlen`](https://php.net/grapheme_strlen): Get string length in grapheme units +- [`grapheme_strpos`](https://php.net/grapheme_strpos): Find position (in grapheme units) + of first occurrence of a string +- [`grapheme_strripos`](https://php.net/grapheme_strripos): Find position (in grapheme units) + of last occurrence of a case-insensitive string +- [`grapheme_strrpos`](https://php.net/grapheme_strrpos): Find position (in grapheme units) + of last occurrence of a string +- [`grapheme_strstr`](https://php.net/grapheme_strstr): Returns part of haystack string from + the first occurrence of needle to the end of haystack +- [`grapheme_substr`](https://php.net/grapheme_substr): Return part of a string +- [`grapheme_str_split`](https://php.net/grapheme_str_split): Splits a string into an array of individual or chunks of graphemes + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap.php new file mode 100644 index 000000000..374dbd3a7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Grapheme as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!defined('GRAPHEME_EXTR_COUNT')) { + define('GRAPHEME_EXTR_COUNT', 0); +} +if (!defined('GRAPHEME_EXTR_MAXBYTES')) { + define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!defined('GRAPHEME_EXTR_MAXCHARS')) { + define('GRAPHEME_EXTR_MAXCHARS', 2); +} + +if (!function_exists('grapheme_extract')) { + function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); } +} +if (!function_exists('grapheme_stripos')) { + function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); } +} +if (!function_exists('grapheme_stristr')) { + function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); } +} +if (!function_exists('grapheme_strlen')) { + function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); } +} +if (!function_exists('grapheme_strpos')) { + function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); } +} +if (!function_exists('grapheme_strripos')) { + function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); } +} +if (!function_exists('grapheme_strrpos')) { + function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); } +} +if (!function_exists('grapheme_strstr')) { + function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); } +} +if (!function_exists('grapheme_substr')) { + function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } +} +if (!function_exists('grapheme_str_split')) { + function grapheme_str_split($string, $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap80.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap80.php new file mode 100644 index 000000000..d71175530 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/bootstrap80.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Grapheme as p; + +if (!function_exists('grapheme_str_split')) { + function grapheme_str_split(string $string, int $length = 1): array|false { return p\Grapheme::grapheme_str_split($string, $length); } +} + +if (extension_loaded('intl')) { + return; +} + +if (!defined('GRAPHEME_EXTR_COUNT')) { + define('GRAPHEME_EXTR_COUNT', 0); +} +if (!defined('GRAPHEME_EXTR_MAXBYTES')) { + define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!defined('GRAPHEME_EXTR_MAXCHARS')) { + define('GRAPHEME_EXTR_MAXCHARS', 2); +} + +if (!function_exists('grapheme_extract')) { + function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); } +} +if (!function_exists('grapheme_stripos')) { + function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); } +} +if (!function_exists('grapheme_stristr')) { + function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } +} +if (!function_exists('grapheme_strlen')) { + function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); } +} +if (!function_exists('grapheme_strpos')) { + function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); } +} +if (!function_exists('grapheme_strripos')) { + function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); } +} +if (!function_exists('grapheme_strrpos')) { + function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); } +} +if (!function_exists('grapheme_strstr')) { + function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } +} +if (!function_exists('grapheme_substr')) { + function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/composer.json b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/composer.json new file mode 100644 index 000000000..0eea417d7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-grapheme/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/polyfill-intl-grapheme", + "type": "library", + "description": "Symfony polyfill for intl's grapheme_* functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "grapheme"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Grapheme\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/LICENSE b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/LICENSE new file mode 100644 index 000000000..6e3afce69 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Normalizer.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Normalizer.php new file mode 100644 index 000000000..81704ab37 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Normalizer.php @@ -0,0 +1,310 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Normalizer; + +/** + * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. + * + * It has been validated with Unicode 6.3 Normalization Conformance Test. + * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. + * + * @author Nicolas Grekas + * + * @internal + */ +class Normalizer +{ + public const FORM_D = \Normalizer::FORM_D; + public const FORM_KD = \Normalizer::FORM_KD; + public const FORM_C = \Normalizer::FORM_C; + public const FORM_KC = \Normalizer::FORM_KC; + public const NFD = \Normalizer::NFD; + public const NFKD = \Normalizer::NFKD; + public const NFC = \Normalizer::NFC; + public const NFKC = \Normalizer::NFKC; + + private static $C; + private static $D; + private static $KD; + private static $cC; + private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + + public static function isNormalized(string $s, int $form = self::FORM_C) + { + if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { + return false; + } + if (!isset($s[strspn($s, self::$ASCII)])) { + return true; + } + if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { + return true; + } + + return self::normalize($s, $form) === $s; + } + + public static function normalize(string $s, int $form = self::FORM_C) + { + if (!preg_match('//u', $s)) { + return false; + } + + switch ($form) { + case self::NFC: $C = true; $K = false; break; + case self::NFD: $C = false; $K = false; break; + case self::NFKC: $C = true; $K = true; break; + case self::NFKD: $C = false; $K = true; break; + default: + if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { + return $s; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + } + + if ('' === $s) { + return ''; + } + + if ($K && null === self::$KD) { + self::$KD = self::getData('compatibilityDecomposition'); + } + + if (null === self::$D) { + self::$D = self::getData('canonicalDecomposition'); + self::$cC = self::getData('combiningClass'); + } + + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { + mb_internal_encoding('8bit'); + } + + $r = self::decompose($s, $K); + + if ($C) { + if (null === self::$C) { + self::$C = self::getData('canonicalComposition'); + } + + $r = self::recompose($r); + } + if (null !== $mbEncoding) { + mb_internal_encoding($mbEncoding); + } + + return $r; + } + + private static function recompose($s) + { + $ASCII = self::$ASCII; + $compMap = self::$C; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + + $result = $tail = ''; + + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; + $len = \strlen($s); + + $lastUchr = substr($s, 0, $i); + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + if ($j = strspn($s, $ASCII, $i + 1)) { + $lastUchr .= substr($s, $i, $j); + $i += $j; + } + + $result .= $lastUchr; + $lastUchr = $s[$i]; + $lastUcls = 0; + ++$i; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + + if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr + || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr + || $lastUcls) { + // Table lookup and combining chars composition + + $ucls = $combClass[$uchr] ?? 0; + + if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { + $lastUchr = $compMap[$lastUchr.$uchr]; + } elseif ($lastUcls = $ucls) { + $tail .= $uchr; + } else { + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + $result .= $lastUchr; + $lastUchr = $uchr; + } + } else { + // Hangul chars + + $L = \ord($lastUchr[2]) - 0x80; + $V = \ord($uchr[2]) - 0xA1; + $T = 0; + + $uchr = substr($s, $i + $ulen, 3); + + if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { + $T = \ord($uchr[2]) - 0xA7; + 0 > $T && $T += 0x40; + $ulen += 3; + } + + $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; + $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); + } + + $i += $ulen; + } + + return $result.$lastUchr.$tail; + } + + private static function decompose($s, $c) + { + $result = ''; + + $ASCII = self::$ASCII; + $decompMap = self::$D; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + if ($c) { + $compatMap = self::$KD; + } + + $c = []; + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $j = 1 + strspn($s, $ASCII, $i + 1); + $result .= substr($s, $i, $j); + $i += $j; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { + // Table lookup + + if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { + $uchr = $j; + + $j = \strlen($uchr); + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; + + if ($ulen != $j) { + // Put trailing chars in $s + + $j -= $ulen; + $i -= $j; + + if (0 > $i) { + $s = str_repeat(' ', -$i).$s; + $len -= $i; + $i = 0; + } + + while ($j--) { + $s[$i + $j] = $uchr[$ulen + $j]; + } + + $uchr = substr($uchr, 0, $ulen); + } + } + if (isset($combClass[$uchr])) { + // Combining chars, for sorting + + if (!isset($c[$combClass[$uchr]])) { + $c[$combClass[$uchr]] = ''; + } + $c[$combClass[$uchr]] .= $uchr; + continue; + } + } else { + // Hangul chars + + $uchr = unpack('C*', $uchr); + $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; + + $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) + ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); + + if ($j %= 28) { + $uchr .= $j < 25 + ? ("\xE1\x86".\chr(0xA7 + $j)) + : ("\xE1\x87".\chr(0x67 + $j)); + } + } + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $result .= $uchr; + } + + if ($c) { + ksort($c); + $result .= implode('', $c); + } + + return $result; + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/README.md b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/README.md new file mode 100644 index 000000000..b9b762e85 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/README.md @@ -0,0 +1,14 @@ +Symfony Polyfill / Intl: Normalizer +=================================== + +This component provides a fallback implementation for the +[`Normalizer`](https://php.net/Normalizer) class provided +by the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php new file mode 100644 index 000000000..0fdfc890a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php @@ -0,0 +1,17 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '΅' => '΅', + 'Ά' => 'Ά', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ὲ' => 'ὲ', + 'ὴ' => 'ὴ', + 'ὶ' => 'ὶ', + 'ὸ' => 'ὸ', + 'ὺ' => 'ὺ', + 'ὼ' => 'ὼ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'ᾼ' => 'ᾼ', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Ὴ' => 'Ὴ', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ὼ' => 'Ὼ', + 'ῼ' => 'ῼ', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', +); diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php new file mode 100644 index 000000000..5a3e8e096 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php @@ -0,0 +1,2065 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '̀' => '̀', + '́' => '́', + '̓' => '̓', + '̈́' => '̈́', + 'ʹ' => 'ʹ', + ';' => ';', + '΅' => '΅', + 'Ά' => 'Ά', + '·' => '·', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'क़' => 'क़', + 'ख़' => 'ख़', + 'ग़' => 'ग़', + 'ज़' => 'ज़', + 'ड़' => 'ड़', + 'ढ़' => 'ढ़', + 'फ़' => 'फ़', + 'य़' => 'य़', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ড়' => 'ড়', + 'ঢ়' => 'ঢ়', + 'য়' => 'য়', + 'ਲ਼' => 'ਲ਼', + 'ਸ਼' => 'ਸ਼', + 'ਖ਼' => 'ਖ਼', + 'ਗ਼' => 'ਗ਼', + 'ਜ਼' => 'ਜ਼', + 'ਫ਼' => 'ਫ਼', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ଡ଼' => 'ଡ଼', + 'ଢ଼' => 'ଢ଼', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'གྷ' => 'གྷ', + 'ཌྷ' => 'ཌྷ', + 'དྷ' => 'དྷ', + 'བྷ' => 'བྷ', + 'ཛྷ' => 'ཛྷ', + 'ཀྵ' => 'ཀྵ', + 'ཱི' => 'ཱི', + 'ཱུ' => 'ཱུ', + 'ྲྀ' => 'ྲྀ', + 'ླྀ' => 'ླྀ', + 'ཱྀ' => 'ཱྀ', + 'ྒྷ' => 'ྒྷ', + 'ྜྷ' => 'ྜྷ', + 'ྡྷ' => 'ྡྷ', + 'ྦྷ' => 'ྦྷ', + 'ྫྷ' => 'ྫྷ', + 'ྐྵ' => 'ྐྵ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ά' => 'ά', + 'ὲ' => 'ὲ', + 'έ' => 'έ', + 'ὴ' => 'ὴ', + 'ή' => 'ή', + 'ὶ' => 'ὶ', + 'ί' => 'ί', + 'ὸ' => 'ὸ', + 'ό' => 'ό', + 'ὺ' => 'ὺ', + 'ύ' => 'ύ', + 'ὼ' => 'ὼ', + 'ώ' => 'ώ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'Ά' => 'Ά', + 'ᾼ' => 'ᾼ', + 'ι' => 'ι', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Έ' => 'Έ', + 'Ὴ' => 'Ὴ', + 'Ή' => 'Ή', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ΐ' => 'ΐ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + 'Ί' => 'Ί', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ΰ' => 'ΰ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ύ' => 'Ύ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + '΅' => '΅', + '`' => '`', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ό' => 'Ό', + 'Ὼ' => 'Ὼ', + 'Ώ' => 'Ώ', + 'ῼ' => 'ῼ', + '´' => '´', + ' ' => ' ', + ' ' => ' ', + 'Ω' => 'Ω', + 'K' => 'K', + 'Å' => 'Å', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '〈' => '〈', + '〉' => '〉', + '⫝̸' => '⫝̸', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '豈' => '豈', + '更' => '更', + '車' => '車', + '賈' => '賈', + '滑' => '滑', + '串' => '串', + '句' => '句', + '龜' => '龜', + '龜' => '龜', + '契' => '契', + '金' => '金', + '喇' => '喇', + '奈' => '奈', + '懶' => '懶', + '癩' => '癩', + '羅' => '羅', + '蘿' => '蘿', + '螺' => '螺', + '裸' => '裸', + '邏' => '邏', + '樂' => '樂', + '洛' => '洛', + '烙' => '烙', + '珞' => '珞', + '落' => '落', + '酪' => '酪', + '駱' => '駱', + '亂' => '亂', + '卵' => '卵', + '欄' => '欄', + '爛' => '爛', + '蘭' => '蘭', + '鸞' => '鸞', + '嵐' => '嵐', + '濫' => '濫', + '藍' => '藍', + '襤' => '襤', + '拉' => '拉', + '臘' => '臘', + '蠟' => '蠟', + '廊' => '廊', + '朗' => '朗', + '浪' => '浪', + '狼' => '狼', + '郎' => '郎', + '來' => '來', + '冷' => '冷', + '勞' => '勞', + '擄' => '擄', + '櫓' => '櫓', + '爐' => '爐', + '盧' => '盧', + '老' => '老', + '蘆' => '蘆', + '虜' => '虜', + '路' => '路', + '露' => '露', + '魯' => '魯', + '鷺' => '鷺', + '碌' => '碌', + '祿' => '祿', + '綠' => '綠', + '菉' => '菉', + '錄' => '錄', + '鹿' => '鹿', + '論' => '論', + '壟' => '壟', + '弄' => '弄', + '籠' => '籠', + '聾' => '聾', + '牢' => '牢', + '磊' => '磊', + '賂' => '賂', + '雷' => '雷', + '壘' => '壘', + '屢' => '屢', + '樓' => '樓', + '淚' => '淚', + '漏' => '漏', + '累' => '累', + '縷' => '縷', + '陋' => '陋', + '勒' => '勒', + '肋' => '肋', + '凜' => '凜', + '凌' => '凌', + '稜' => '稜', + '綾' => '綾', + '菱' => '菱', + '陵' => '陵', + '讀' => '讀', + '拏' => '拏', + '樂' => '樂', + '諾' => '諾', + '丹' => '丹', + '寧' => '寧', + '怒' => '怒', + '率' => '率', + '異' => '異', + '北' => '北', + '磻' => '磻', + '便' => '便', + '復' => '復', + '不' => '不', + '泌' => '泌', + '數' => '數', + '索' => '索', + '參' => '參', + '塞' => '塞', + '省' => '省', + '葉' => '葉', + '說' => '說', + '殺' => '殺', + '辰' => '辰', + '沈' => '沈', + '拾' => '拾', + '若' => '若', + '掠' => '掠', + '略' => '略', + '亮' => '亮', + '兩' => '兩', + '凉' => '凉', + '梁' => '梁', + '糧' => '糧', + '良' => '良', + '諒' => '諒', + '量' => '量', + '勵' => '勵', + '呂' => '呂', + '女' => '女', + '廬' => '廬', + '旅' => '旅', + '濾' => '濾', + '礪' => '礪', + '閭' => '閭', + '驪' => '驪', + '麗' => '麗', + '黎' => '黎', + '力' => '力', + '曆' => '曆', + '歷' => '歷', + '轢' => '轢', + '年' => '年', + '憐' => '憐', + '戀' => '戀', + '撚' => '撚', + '漣' => '漣', + '煉' => '煉', + '璉' => '璉', + '秊' => '秊', + '練' => '練', + '聯' => '聯', + '輦' => '輦', + '蓮' => '蓮', + '連' => '連', + '鍊' => '鍊', + '列' => '列', + '劣' => '劣', + '咽' => '咽', + '烈' => '烈', + '裂' => '裂', + '說' => '說', + '廉' => '廉', + '念' => '念', + '捻' => '捻', + '殮' => '殮', + '簾' => '簾', + '獵' => '獵', + '令' => '令', + '囹' => '囹', + '寧' => '寧', + '嶺' => '嶺', + '怜' => '怜', + '玲' => '玲', + '瑩' => '瑩', + '羚' => '羚', + '聆' => '聆', + '鈴' => '鈴', + '零' => '零', + '靈' => '靈', + '領' => '領', + '例' => '例', + '禮' => '禮', + '醴' => '醴', + '隸' => '隸', + '惡' => '惡', + '了' => '了', + '僚' => '僚', + '寮' => '寮', + '尿' => '尿', + '料' => '料', + '樂' => '樂', + '燎' => '燎', + '療' => '療', + '蓼' => '蓼', + '遼' => '遼', + '龍' => '龍', + '暈' => '暈', + '阮' => '阮', + '劉' => '劉', + '杻' => '杻', + '柳' => '柳', + '流' => '流', + '溜' => '溜', + '琉' => '琉', + '留' => '留', + '硫' => '硫', + '紐' => '紐', + '類' => '類', + '六' => '六', + '戮' => '戮', + '陸' => '陸', + '倫' => '倫', + '崙' => '崙', + '淪' => '淪', + '輪' => '輪', + '律' => '律', + '慄' => '慄', + '栗' => '栗', + '率' => '率', + '隆' => '隆', + '利' => '利', + '吏' => '吏', + '履' => '履', + '易' => '易', + '李' => '李', + '梨' => '梨', + '泥' => '泥', + '理' => '理', + '痢' => '痢', + '罹' => '罹', + '裏' => '裏', + '裡' => '裡', + '里' => '里', + '離' => '離', + '匿' => '匿', + '溺' => '溺', + '吝' => '吝', + '燐' => '燐', + '璘' => '璘', + '藺' => '藺', + '隣' => '隣', + '鱗' => '鱗', + '麟' => '麟', + '林' => '林', + '淋' => '淋', + '臨' => '臨', + '立' => '立', + '笠' => '笠', + '粒' => '粒', + '狀' => '狀', + '炙' => '炙', + '識' => '識', + '什' => '什', + '茶' => '茶', + '刺' => '刺', + '切' => '切', + '度' => '度', + '拓' => '拓', + '糖' => '糖', + '宅' => '宅', + '洞' => '洞', + '暴' => '暴', + '輻' => '輻', + '行' => '行', + '降' => '降', + '見' => '見', + '廓' => '廓', + '兀' => '兀', + '嗀' => '嗀', + '塚' => '塚', + '晴' => '晴', + '凞' => '凞', + '猪' => '猪', + '益' => '益', + '礼' => '礼', + '神' => '神', + '祥' => '祥', + '福' => '福', + '靖' => '靖', + '精' => '精', + '羽' => '羽', + '蘒' => '蘒', + '諸' => '諸', + '逸' => '逸', + '都' => '都', + '飯' => '飯', + '飼' => '飼', + '館' => '館', + '鶴' => '鶴', + '郞' => '郞', + '隷' => '隷', + '侮' => '侮', + '僧' => '僧', + '免' => '免', + '勉' => '勉', + '勤' => '勤', + '卑' => '卑', + '喝' => '喝', + '嘆' => '嘆', + '器' => '器', + '塀' => '塀', + '墨' => '墨', + '層' => '層', + '屮' => '屮', + '悔' => '悔', + '慨' => '慨', + '憎' => '憎', + '懲' => '懲', + '敏' => '敏', + '既' => '既', + '暑' => '暑', + '梅' => '梅', + '海' => '海', + '渚' => '渚', + '漢' => '漢', + '煮' => '煮', + '爫' => '爫', + '琢' => '琢', + '碑' => '碑', + '社' => '社', + '祉' => '祉', + '祈' => '祈', + '祐' => '祐', + '祖' => '祖', + '祝' => '祝', + '禍' => '禍', + '禎' => '禎', + '穀' => '穀', + '突' => '突', + '節' => '節', + '練' => '練', + '縉' => '縉', + '繁' => '繁', + '署' => '署', + '者' => '者', + '臭' => '臭', + '艹' => '艹', + '艹' => '艹', + '著' => '著', + '褐' => '褐', + '視' => '視', + '謁' => '謁', + '謹' => '謹', + '賓' => '賓', + '贈' => '贈', + '辶' => '辶', + '逸' => '逸', + '難' => '難', + '響' => '響', + '頻' => '頻', + '恵' => '恵', + '𤋮' => '𤋮', + '舘' => '舘', + '並' => '並', + '况' => '况', + '全' => '全', + '侀' => '侀', + '充' => '充', + '冀' => '冀', + '勇' => '勇', + '勺' => '勺', + '喝' => '喝', + '啕' => '啕', + '喙' => '喙', + '嗢' => '嗢', + '塚' => '塚', + '墳' => '墳', + '奄' => '奄', + '奔' => '奔', + '婢' => '婢', + '嬨' => '嬨', + '廒' => '廒', + '廙' => '廙', + '彩' => '彩', + '徭' => '徭', + '惘' => '惘', + '慎' => '慎', + '愈' => '愈', + '憎' => '憎', + '慠' => '慠', + '懲' => '懲', + '戴' => '戴', + '揄' => '揄', + '搜' => '搜', + '摒' => '摒', + '敖' => '敖', + '晴' => '晴', + '朗' => '朗', + '望' => '望', + '杖' => '杖', + '歹' => '歹', + '殺' => '殺', + '流' => '流', + '滛' => '滛', + '滋' => '滋', + '漢' => '漢', + '瀞' => '瀞', + '煮' => '煮', + '瞧' => '瞧', + '爵' => '爵', + '犯' => '犯', + '猪' => '猪', + '瑱' => '瑱', + '甆' => '甆', + '画' => '画', + '瘝' => '瘝', + '瘟' => '瘟', + '益' => '益', + '盛' => '盛', + '直' => '直', + '睊' => '睊', + '着' => '着', + '磌' => '磌', + '窱' => '窱', + '節' => '節', + '类' => '类', + '絛' => '絛', + '練' => '練', + '缾' => '缾', + '者' => '者', + '荒' => '荒', + '華' => '華', + '蝹' => '蝹', + '襁' => '襁', + '覆' => '覆', + '視' => '視', + '調' => '調', + '諸' => '諸', + '請' => '請', + '謁' => '謁', + '諾' => '諾', + '諭' => '諭', + '謹' => '謹', + '變' => '變', + '贈' => '贈', + '輸' => '輸', + '遲' => '遲', + '醙' => '醙', + '鉶' => '鉶', + '陼' => '陼', + '難' => '難', + '靖' => '靖', + '韛' => '韛', + '響' => '響', + '頋' => '頋', + '頻' => '頻', + '鬒' => '鬒', + '龜' => '龜', + '𢡊' => '𢡊', + '𢡄' => '𢡄', + '𣏕' => '𣏕', + '㮝' => '㮝', + '䀘' => '䀘', + '䀹' => '䀹', + '𥉉' => '𥉉', + '𥳐' => '𥳐', + '𧻓' => '𧻓', + '齃' => '齃', + '龎' => '龎', + 'יִ' => 'יִ', + 'ײַ' => 'ײַ', + 'שׁ' => 'שׁ', + 'שׂ' => 'שׂ', + 'שּׁ' => 'שּׁ', + 'שּׂ' => 'שּׂ', + 'אַ' => 'אַ', + 'אָ' => 'אָ', + 'אּ' => 'אּ', + 'בּ' => 'בּ', + 'גּ' => 'גּ', + 'דּ' => 'דּ', + 'הּ' => 'הּ', + 'וּ' => 'וּ', + 'זּ' => 'זּ', + 'טּ' => 'טּ', + 'יּ' => 'יּ', + 'ךּ' => 'ךּ', + 'כּ' => 'כּ', + 'לּ' => 'לּ', + 'מּ' => 'מּ', + 'נּ' => 'נּ', + 'סּ' => 'סּ', + 'ףּ' => 'ףּ', + 'פּ' => 'פּ', + 'צּ' => 'צּ', + 'קּ' => 'קּ', + 'רּ' => 'רּ', + 'שּ' => 'שּ', + 'תּ' => 'תּ', + 'וֹ' => 'וֹ', + 'בֿ' => 'בֿ', + 'כֿ' => 'כֿ', + 'פֿ' => 'פֿ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', + '𝅗𝅥' => '𝅗𝅥', + '𝅘𝅥' => '𝅘𝅥', + '𝅘𝅥𝅮' => '𝅘𝅥𝅮', + '𝅘𝅥𝅯' => '𝅘𝅥𝅯', + '𝅘𝅥𝅰' => '𝅘𝅥𝅰', + '𝅘𝅥𝅱' => '𝅘𝅥𝅱', + '𝅘𝅥𝅲' => '𝅘𝅥𝅲', + '𝆹𝅥' => '𝆹𝅥', + '𝆺𝅥' => '𝆺𝅥', + '𝆹𝅥𝅮' => '𝆹𝅥𝅮', + '𝆺𝅥𝅮' => '𝆺𝅥𝅮', + '𝆹𝅥𝅯' => '𝆹𝅥𝅯', + '𝆺𝅥𝅯' => '𝆺𝅥𝅯', + '丽' => '丽', + '丸' => '丸', + '乁' => '乁', + '𠄢' => '𠄢', + '你' => '你', + '侮' => '侮', + '侻' => '侻', + '倂' => '倂', + '偺' => '偺', + '備' => '備', + '僧' => '僧', + '像' => '像', + '㒞' => '㒞', + '𠘺' => '𠘺', + '免' => '免', + '兔' => '兔', + '兤' => '兤', + '具' => '具', + '𠔜' => '𠔜', + '㒹' => '㒹', + '內' => '內', + '再' => '再', + '𠕋' => '𠕋', + '冗' => '冗', + '冤' => '冤', + '仌' => '仌', + '冬' => '冬', + '况' => '况', + '𩇟' => '𩇟', + '凵' => '凵', + '刃' => '刃', + '㓟' => '㓟', + '刻' => '刻', + '剆' => '剆', + '割' => '割', + '剷' => '剷', + '㔕' => '㔕', + '勇' => '勇', + '勉' => '勉', + '勤' => '勤', + '勺' => '勺', + '包' => '包', + '匆' => '匆', + '北' => '北', + '卉' => '卉', + '卑' => '卑', + '博' => '博', + '即' => '即', + '卽' => '卽', + '卿' => '卿', + '卿' => '卿', + '卿' => '卿', + '𠨬' => '𠨬', + '灰' => '灰', + '及' => '及', + '叟' => '叟', + '𠭣' => '𠭣', + '叫' => '叫', + '叱' => '叱', + '吆' => '吆', + '咞' => '咞', + '吸' => '吸', + '呈' => '呈', + '周' => '周', + '咢' => '咢', + '哶' => '哶', + '唐' => '唐', + '啓' => '啓', + '啣' => '啣', + '善' => '善', + '善' => '善', + '喙' => '喙', + '喫' => '喫', + '喳' => '喳', + '嗂' => '嗂', + '圖' => '圖', + '嘆' => '嘆', + '圗' => '圗', + '噑' => '噑', + '噴' => '噴', + '切' => '切', + '壮' => '壮', + '城' => '城', + '埴' => '埴', + '堍' => '堍', + '型' => '型', + '堲' => '堲', + '報' => '報', + '墬' => '墬', + '𡓤' => '𡓤', + '売' => '売', + '壷' => '壷', + '夆' => '夆', + '多' => '多', + '夢' => '夢', + '奢' => '奢', + '𡚨' => '𡚨', + '𡛪' => '𡛪', + '姬' => '姬', + '娛' => '娛', + '娧' => '娧', + '姘' => '姘', + '婦' => '婦', + '㛮' => '㛮', + '㛼' => '㛼', + '嬈' => '嬈', + '嬾' => '嬾', + '嬾' => '嬾', + '𡧈' => '𡧈', + '寃' => '寃', + '寘' => '寘', + '寧' => '寧', + '寳' => '寳', + '𡬘' => '𡬘', + '寿' => '寿', + '将' => '将', + '当' => '当', + '尢' => '尢', + '㞁' => '㞁', + '屠' => '屠', + '屮' => '屮', + '峀' => '峀', + '岍' => '岍', + '𡷤' => '𡷤', + '嵃' => '嵃', + '𡷦' => '𡷦', + '嵮' => '嵮', + '嵫' => '嵫', + '嵼' => '嵼', + '巡' => '巡', + '巢' => '巢', + '㠯' => '㠯', + '巽' => '巽', + '帨' => '帨', + '帽' => '帽', + '幩' => '幩', + '㡢' => '㡢', + '𢆃' => '𢆃', + '㡼' => '㡼', + '庰' => '庰', + '庳' => '庳', + '庶' => '庶', + '廊' => '廊', + '𪎒' => '𪎒', + '廾' => '廾', + '𢌱' => '𢌱', + '𢌱' => '𢌱', + '舁' => '舁', + '弢' => '弢', + '弢' => '弢', + '㣇' => '㣇', + '𣊸' => '𣊸', + '𦇚' => '𦇚', + '形' => '形', + '彫' => '彫', + '㣣' => '㣣', + '徚' => '徚', + '忍' => '忍', + '志' => '志', + '忹' => '忹', + '悁' => '悁', + '㤺' => '㤺', + '㤜' => '㤜', + '悔' => '悔', + '𢛔' => '𢛔', + '惇' => '惇', + '慈' => '慈', + '慌' => '慌', + '慎' => '慎', + '慌' => '慌', + '慺' => '慺', + '憎' => '憎', + '憲' => '憲', + '憤' => '憤', + '憯' => '憯', + '懞' => '懞', + '懲' => '懲', + '懶' => '懶', + '成' => '成', + '戛' => '戛', + '扝' => '扝', + '抱' => '抱', + '拔' => '拔', + '捐' => '捐', + '𢬌' => '𢬌', + '挽' => '挽', + '拼' => '拼', + '捨' => '捨', + '掃' => '掃', + '揤' => '揤', + '𢯱' => '𢯱', + '搢' => '搢', + '揅' => '揅', + '掩' => '掩', + '㨮' => '㨮', + '摩' => '摩', + '摾' => '摾', + '撝' => '撝', + '摷' => '摷', + '㩬' => '㩬', + '敏' => '敏', + '敬' => '敬', + '𣀊' => '𣀊', + '旣' => '旣', + '書' => '書', + '晉' => '晉', + '㬙' => '㬙', + '暑' => '暑', + '㬈' => '㬈', + '㫤' => '㫤', + '冒' => '冒', + '冕' => '冕', + '最' => '最', + '暜' => '暜', + '肭' => '肭', + '䏙' => '䏙', + '朗' => '朗', + '望' => '望', + '朡' => '朡', + '杞' => '杞', + '杓' => '杓', + '𣏃' => '𣏃', + '㭉' => '㭉', + '柺' => '柺', + '枅' => '枅', + '桒' => '桒', + '梅' => '梅', + '𣑭' => '𣑭', + '梎' => '梎', + '栟' => '栟', + '椔' => '椔', + '㮝' => '㮝', + '楂' => '楂', + '榣' => '榣', + '槪' => '槪', + '檨' => '檨', + '𣚣' => '𣚣', + '櫛' => '櫛', + '㰘' => '㰘', + '次' => '次', + '𣢧' => '𣢧', + '歔' => '歔', + '㱎' => '㱎', + '歲' => '歲', + '殟' => '殟', + '殺' => '殺', + '殻' => '殻', + '𣪍' => '𣪍', + '𡴋' => '𡴋', + '𣫺' => '𣫺', + '汎' => '汎', + '𣲼' => '𣲼', + '沿' => '沿', + '泍' => '泍', + '汧' => '汧', + '洖' => '洖', + '派' => '派', + '海' => '海', + '流' => '流', + '浩' => '浩', + '浸' => '浸', + '涅' => '涅', + '𣴞' => '𣴞', + '洴' => '洴', + '港' => '港', + '湮' => '湮', + '㴳' => '㴳', + '滋' => '滋', + '滇' => '滇', + '𣻑' => '𣻑', + '淹' => '淹', + '潮' => '潮', + '𣽞' => '𣽞', + '𣾎' => '𣾎', + '濆' => '濆', + '瀹' => '瀹', + '瀞' => '瀞', + '瀛' => '瀛', + '㶖' => '㶖', + '灊' => '灊', + '災' => '災', + '灷' => '灷', + '炭' => '炭', + '𠔥' => '𠔥', + '煅' => '煅', + '𤉣' => '𤉣', + '熜' => '熜', + '𤎫' => '𤎫', + '爨' => '爨', + '爵' => '爵', + '牐' => '牐', + '𤘈' => '𤘈', + '犀' => '犀', + '犕' => '犕', + '𤜵' => '𤜵', + '𤠔' => '𤠔', + '獺' => '獺', + '王' => '王', + '㺬' => '㺬', + '玥' => '玥', + '㺸' => '㺸', + '㺸' => '㺸', + '瑇' => '瑇', + '瑜' => '瑜', + '瑱' => '瑱', + '璅' => '璅', + '瓊' => '瓊', + '㼛' => '㼛', + '甤' => '甤', + '𤰶' => '𤰶', + '甾' => '甾', + '𤲒' => '𤲒', + '異' => '異', + '𢆟' => '𢆟', + '瘐' => '瘐', + '𤾡' => '𤾡', + '𤾸' => '𤾸', + '𥁄' => '𥁄', + '㿼' => '㿼', + '䀈' => '䀈', + '直' => '直', + '𥃳' => '𥃳', + '𥃲' => '𥃲', + '𥄙' => '𥄙', + '𥄳' => '𥄳', + '眞' => '眞', + '真' => '真', + '真' => '真', + '睊' => '睊', + '䀹' => '䀹', + '瞋' => '瞋', + '䁆' => '䁆', + '䂖' => '䂖', + '𥐝' => '𥐝', + '硎' => '硎', + '碌' => '碌', + '磌' => '磌', + '䃣' => '䃣', + '𥘦' => '𥘦', + '祖' => '祖', + '𥚚' => '𥚚', + '𥛅' => '𥛅', + '福' => '福', + '秫' => '秫', + '䄯' => '䄯', + '穀' => '穀', + '穊' => '穊', + '穏' => '穏', + '𥥼' => '𥥼', + '𥪧' => '𥪧', + '𥪧' => '𥪧', + '竮' => '竮', + '䈂' => '䈂', + '𥮫' => '𥮫', + '篆' => '篆', + '築' => '築', + '䈧' => '䈧', + '𥲀' => '𥲀', + '糒' => '糒', + '䊠' => '䊠', + '糨' => '糨', + '糣' => '糣', + '紀' => '紀', + '𥾆' => '𥾆', + '絣' => '絣', + '䌁' => '䌁', + '緇' => '緇', + '縂' => '縂', + '繅' => '繅', + '䌴' => '䌴', + '𦈨' => '𦈨', + '𦉇' => '𦉇', + '䍙' => '䍙', + '𦋙' => '𦋙', + '罺' => '罺', + '𦌾' => '𦌾', + '羕' => '羕', + '翺' => '翺', + '者' => '者', + '𦓚' => '𦓚', + '𦔣' => '𦔣', + '聠' => '聠', + '𦖨' => '𦖨', + '聰' => '聰', + '𣍟' => '𣍟', + '䏕' => '䏕', + '育' => '育', + '脃' => '脃', + '䐋' => '䐋', + '脾' => '脾', + '媵' => '媵', + '𦞧' => '𦞧', + '𦞵' => '𦞵', + '𣎓' => '𣎓', + '𣎜' => '𣎜', + '舁' => '舁', + '舄' => '舄', + '辞' => '辞', + '䑫' => '䑫', + '芑' => '芑', + '芋' => '芋', + '芝' => '芝', + '劳' => '劳', + '花' => '花', + '芳' => '芳', + '芽' => '芽', + '苦' => '苦', + '𦬼' => '𦬼', + '若' => '若', + '茝' => '茝', + '荣' => '荣', + '莭' => '莭', + '茣' => '茣', + '莽' => '莽', + '菧' => '菧', + '著' => '著', + '荓' => '荓', + '菊' => '菊', + '菌' => '菌', + '菜' => '菜', + '𦰶' => '𦰶', + '𦵫' => '𦵫', + '𦳕' => '𦳕', + '䔫' => '䔫', + '蓱' => '蓱', + '蓳' => '蓳', + '蔖' => '蔖', + '𧏊' => '𧏊', + '蕤' => '蕤', + '𦼬' => '𦼬', + '䕝' => '䕝', + '䕡' => '䕡', + '𦾱' => '𦾱', + '𧃒' => '𧃒', + '䕫' => '䕫', + '虐' => '虐', + '虜' => '虜', + '虧' => '虧', + '虩' => '虩', + '蚩' => '蚩', + '蚈' => '蚈', + '蜎' => '蜎', + '蛢' => '蛢', + '蝹' => '蝹', + '蜨' => '蜨', + '蝫' => '蝫', + '螆' => '螆', + '䗗' => '䗗', + '蟡' => '蟡', + '蠁' => '蠁', + '䗹' => '䗹', + '衠' => '衠', + '衣' => '衣', + '𧙧' => '𧙧', + '裗' => '裗', + '裞' => '裞', + '䘵' => '䘵', + '裺' => '裺', + '㒻' => '㒻', + '𧢮' => '𧢮', + '𧥦' => '𧥦', + '䚾' => '䚾', + '䛇' => '䛇', + '誠' => '誠', + '諭' => '諭', + '變' => '變', + '豕' => '豕', + '𧲨' => '𧲨', + '貫' => '貫', + '賁' => '賁', + '贛' => '贛', + '起' => '起', + '𧼯' => '𧼯', + '𠠄' => '𠠄', + '跋' => '跋', + '趼' => '趼', + '跰' => '跰', + '𠣞' => '𠣞', + '軔' => '軔', + '輸' => '輸', + '𨗒' => '𨗒', + '𨗭' => '𨗭', + '邔' => '邔', + '郱' => '郱', + '鄑' => '鄑', + '𨜮' => '𨜮', + '鄛' => '鄛', + '鈸' => '鈸', + '鋗' => '鋗', + '鋘' => '鋘', + '鉼' => '鉼', + '鏹' => '鏹', + '鐕' => '鐕', + '𨯺' => '𨯺', + '開' => '開', + '䦕' => '䦕', + '閷' => '閷', + '𨵷' => '𨵷', + '䧦' => '䧦', + '雃' => '雃', + '嶲' => '嶲', + '霣' => '霣', + '𩅅' => '𩅅', + '𩈚' => '𩈚', + '䩮' => '䩮', + '䩶' => '䩶', + '韠' => '韠', + '𩐊' => '𩐊', + '䪲' => '䪲', + '𩒖' => '𩒖', + '頋' => '頋', + '頋' => '頋', + '頩' => '頩', + '𩖶' => '𩖶', + '飢' => '飢', + '䬳' => '䬳', + '餩' => '餩', + '馧' => '馧', + '駂' => '駂', + '駾' => '駾', + '䯎' => '䯎', + '𩬰' => '𩬰', + '鬒' => '鬒', + '鱀' => '鱀', + '鳽' => '鳽', + '䳎' => '䳎', + '䳭' => '䳭', + '鵧' => '鵧', + '𪃎' => '𪃎', + '䳸' => '䳸', + '𪄅' => '𪄅', + '𪈎' => '𪈎', + '𪊑' => '𪊑', + '麻' => '麻', + '䵖' => '䵖', + '黹' => '黹', + '黾' => '黾', + '鼅' => '鼅', + '鼏' => '鼏', + '鼖' => '鼖', + '鼻' => '鼻', + '𪘀' => '𪘀', +); diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php new file mode 100644 index 000000000..ec90f36eb --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php @@ -0,0 +1,876 @@ + 230, + '́' => 230, + '̂' => 230, + '̃' => 230, + '̄' => 230, + '̅' => 230, + '̆' => 230, + '̇' => 230, + '̈' => 230, + '̉' => 230, + '̊' => 230, + '̋' => 230, + '̌' => 230, + '̍' => 230, + '̎' => 230, + '̏' => 230, + '̐' => 230, + '̑' => 230, + '̒' => 230, + '̓' => 230, + '̔' => 230, + '̕' => 232, + '̖' => 220, + '̗' => 220, + '̘' => 220, + '̙' => 220, + '̚' => 232, + '̛' => 216, + '̜' => 220, + '̝' => 220, + '̞' => 220, + '̟' => 220, + '̠' => 220, + '̡' => 202, + '̢' => 202, + '̣' => 220, + '̤' => 220, + '̥' => 220, + '̦' => 220, + '̧' => 202, + '̨' => 202, + '̩' => 220, + '̪' => 220, + '̫' => 220, + '̬' => 220, + '̭' => 220, + '̮' => 220, + '̯' => 220, + '̰' => 220, + '̱' => 220, + '̲' => 220, + '̳' => 220, + '̴' => 1, + '̵' => 1, + '̶' => 1, + '̷' => 1, + '̸' => 1, + '̹' => 220, + '̺' => 220, + '̻' => 220, + '̼' => 220, + '̽' => 230, + '̾' => 230, + '̿' => 230, + '̀' => 230, + '́' => 230, + '͂' => 230, + '̓' => 230, + '̈́' => 230, + 'ͅ' => 240, + '͆' => 230, + '͇' => 220, + '͈' => 220, + '͉' => 220, + '͊' => 230, + '͋' => 230, + '͌' => 230, + '͍' => 220, + '͎' => 220, + '͐' => 230, + '͑' => 230, + '͒' => 230, + '͓' => 220, + '͔' => 220, + '͕' => 220, + '͖' => 220, + '͗' => 230, + '͘' => 232, + '͙' => 220, + '͚' => 220, + '͛' => 230, + '͜' => 233, + '͝' => 234, + '͞' => 234, + '͟' => 233, + '͠' => 234, + '͡' => 234, + '͢' => 233, + 'ͣ' => 230, + 'ͤ' => 230, + 'ͥ' => 230, + 'ͦ' => 230, + 'ͧ' => 230, + 'ͨ' => 230, + 'ͩ' => 230, + 'ͪ' => 230, + 'ͫ' => 230, + 'ͬ' => 230, + 'ͭ' => 230, + 'ͮ' => 230, + 'ͯ' => 230, + '҃' => 230, + '҄' => 230, + '҅' => 230, + '҆' => 230, + '҇' => 230, + '֑' => 220, + '֒' => 230, + '֓' => 230, + '֔' => 230, + '֕' => 230, + '֖' => 220, + '֗' => 230, + '֘' => 230, + '֙' => 230, + '֚' => 222, + '֛' => 220, + '֜' => 230, + '֝' => 230, + '֞' => 230, + '֟' => 230, + '֠' => 230, + '֡' => 230, + '֢' => 220, + '֣' => 220, + '֤' => 220, + '֥' => 220, + '֦' => 220, + '֧' => 220, + '֨' => 230, + '֩' => 230, + '֪' => 220, + '֫' => 230, + '֬' => 230, + '֭' => 222, + '֮' => 228, + '֯' => 230, + 'ְ' => 10, + 'ֱ' => 11, + 'ֲ' => 12, + 'ֳ' => 13, + 'ִ' => 14, + 'ֵ' => 15, + 'ֶ' => 16, + 'ַ' => 17, + 'ָ' => 18, + 'ֹ' => 19, + 'ֺ' => 19, + 'ֻ' => 20, + 'ּ' => 21, + 'ֽ' => 22, + 'ֿ' => 23, + 'ׁ' => 24, + 'ׂ' => 25, + 'ׄ' => 230, + 'ׅ' => 220, + 'ׇ' => 18, + 'ؐ' => 230, + 'ؑ' => 230, + 'ؒ' => 230, + 'ؓ' => 230, + 'ؔ' => 230, + 'ؕ' => 230, + 'ؖ' => 230, + 'ؗ' => 230, + 'ؘ' => 30, + 'ؙ' => 31, + 'ؚ' => 32, + 'ً' => 27, + 'ٌ' => 28, + 'ٍ' => 29, + 'َ' => 30, + 'ُ' => 31, + 'ِ' => 32, + 'ّ' => 33, + 'ْ' => 34, + 'ٓ' => 230, + 'ٔ' => 230, + 'ٕ' => 220, + 'ٖ' => 220, + 'ٗ' => 230, + '٘' => 230, + 'ٙ' => 230, + 'ٚ' => 230, + 'ٛ' => 230, + 'ٜ' => 220, + 'ٝ' => 230, + 'ٞ' => 230, + 'ٟ' => 220, + 'ٰ' => 35, + 'ۖ' => 230, + 'ۗ' => 230, + 'ۘ' => 230, + 'ۙ' => 230, + 'ۚ' => 230, + 'ۛ' => 230, + 'ۜ' => 230, + '۟' => 230, + '۠' => 230, + 'ۡ' => 230, + 'ۢ' => 230, + 'ۣ' => 220, + 'ۤ' => 230, + 'ۧ' => 230, + 'ۨ' => 230, + '۪' => 220, + '۫' => 230, + '۬' => 230, + 'ۭ' => 220, + 'ܑ' => 36, + 'ܰ' => 230, + 'ܱ' => 220, + 'ܲ' => 230, + 'ܳ' => 230, + 'ܴ' => 220, + 'ܵ' => 230, + 'ܶ' => 230, + 'ܷ' => 220, + 'ܸ' => 220, + 'ܹ' => 220, + 'ܺ' => 230, + 'ܻ' => 220, + 'ܼ' => 220, + 'ܽ' => 230, + 'ܾ' => 220, + 'ܿ' => 230, + '݀' => 230, + '݁' => 230, + '݂' => 220, + '݃' => 230, + '݄' => 220, + '݅' => 230, + '݆' => 220, + '݇' => 230, + '݈' => 220, + '݉' => 230, + '݊' => 230, + '߫' => 230, + '߬' => 230, + '߭' => 230, + '߮' => 230, + '߯' => 230, + '߰' => 230, + '߱' => 230, + '߲' => 220, + '߳' => 230, + '߽' => 220, + 'ࠖ' => 230, + 'ࠗ' => 230, + '࠘' => 230, + '࠙' => 230, + 'ࠛ' => 230, + 'ࠜ' => 230, + 'ࠝ' => 230, + 'ࠞ' => 230, + 'ࠟ' => 230, + 'ࠠ' => 230, + 'ࠡ' => 230, + 'ࠢ' => 230, + 'ࠣ' => 230, + 'ࠥ' => 230, + 'ࠦ' => 230, + 'ࠧ' => 230, + 'ࠩ' => 230, + 'ࠪ' => 230, + 'ࠫ' => 230, + 'ࠬ' => 230, + '࠭' => 230, + '࡙' => 220, + '࡚' => 220, + '࡛' => 220, + '࣓' => 220, + 'ࣔ' => 230, + 'ࣕ' => 230, + 'ࣖ' => 230, + 'ࣗ' => 230, + 'ࣘ' => 230, + 'ࣙ' => 230, + 'ࣚ' => 230, + 'ࣛ' => 230, + 'ࣜ' => 230, + 'ࣝ' => 230, + 'ࣞ' => 230, + 'ࣟ' => 230, + '࣠' => 230, + '࣡' => 230, + 'ࣣ' => 220, + 'ࣤ' => 230, + 'ࣥ' => 230, + 'ࣦ' => 220, + 'ࣧ' => 230, + 'ࣨ' => 230, + 'ࣩ' => 220, + '࣪' => 230, + '࣫' => 230, + '࣬' => 230, + '࣭' => 220, + '࣮' => 220, + '࣯' => 220, + 'ࣰ' => 27, + 'ࣱ' => 28, + 'ࣲ' => 29, + 'ࣳ' => 230, + 'ࣴ' => 230, + 'ࣵ' => 230, + 'ࣶ' => 220, + 'ࣷ' => 230, + 'ࣸ' => 230, + 'ࣹ' => 220, + 'ࣺ' => 220, + 'ࣻ' => 230, + 'ࣼ' => 230, + 'ࣽ' => 230, + 'ࣾ' => 230, + 'ࣿ' => 230, + '़' => 7, + '्' => 9, + '॑' => 230, + '॒' => 220, + '॓' => 230, + '॔' => 230, + '়' => 7, + '্' => 9, + '৾' => 230, + '਼' => 7, + '੍' => 9, + '઼' => 7, + '્' => 9, + '଼' => 7, + '୍' => 9, + '்' => 9, + '్' => 9, + 'ౕ' => 84, + 'ౖ' => 91, + '಼' => 7, + '್' => 9, + '഻' => 9, + '഼' => 9, + '്' => 9, + '්' => 9, + 'ุ' => 103, + 'ู' => 103, + 'ฺ' => 9, + '่' => 107, + '้' => 107, + '๊' => 107, + '๋' => 107, + 'ຸ' => 118, + 'ູ' => 118, + '຺' => 9, + '່' => 122, + '້' => 122, + '໊' => 122, + '໋' => 122, + '༘' => 220, + '༙' => 220, + '༵' => 220, + '༷' => 220, + '༹' => 216, + 'ཱ' => 129, + 'ི' => 130, + 'ུ' => 132, + 'ེ' => 130, + 'ཻ' => 130, + 'ོ' => 130, + 'ཽ' => 130, + 'ྀ' => 130, + 'ྂ' => 230, + 'ྃ' => 230, + '྄' => 9, + '྆' => 230, + '྇' => 230, + '࿆' => 220, + '့' => 7, + '္' => 9, + '်' => 9, + 'ႍ' => 220, + '፝' => 230, + '፞' => 230, + '፟' => 230, + '᜔' => 9, + '᜴' => 9, + '្' => 9, + '៝' => 230, + 'ᢩ' => 228, + '᤹' => 222, + '᤺' => 230, + '᤻' => 220, + 'ᨗ' => 230, + 'ᨘ' => 220, + '᩠' => 9, + '᩵' => 230, + '᩶' => 230, + '᩷' => 230, + '᩸' => 230, + '᩹' => 230, + '᩺' => 230, + '᩻' => 230, + '᩼' => 230, + '᩿' => 220, + '᪰' => 230, + '᪱' => 230, + '᪲' => 230, + '᪳' => 230, + '᪴' => 230, + '᪵' => 220, + '᪶' => 220, + '᪷' => 220, + '᪸' => 220, + '᪹' => 220, + '᪺' => 220, + '᪻' => 230, + '᪼' => 230, + '᪽' => 220, + 'ᪿ' => 220, + 'ᫀ' => 220, + '᬴' => 7, + '᭄' => 9, + '᭫' => 230, + '᭬' => 220, + '᭭' => 230, + '᭮' => 230, + '᭯' => 230, + '᭰' => 230, + '᭱' => 230, + '᭲' => 230, + '᭳' => 230, + '᮪' => 9, + '᮫' => 9, + '᯦' => 7, + '᯲' => 9, + '᯳' => 9, + '᰷' => 7, + '᳐' => 230, + '᳑' => 230, + '᳒' => 230, + '᳔' => 1, + '᳕' => 220, + '᳖' => 220, + '᳗' => 220, + '᳘' => 220, + '᳙' => 220, + '᳚' => 230, + '᳛' => 230, + '᳜' => 220, + '᳝' => 220, + '᳞' => 220, + '᳟' => 220, + '᳠' => 230, + '᳢' => 1, + '᳣' => 1, + '᳤' => 1, + '᳥' => 1, + '᳦' => 1, + '᳧' => 1, + '᳨' => 1, + '᳭' => 220, + '᳴' => 230, + '᳸' => 230, + '᳹' => 230, + '᷀' => 230, + '᷁' => 230, + '᷂' => 220, + '᷃' => 230, + '᷄' => 230, + '᷅' => 230, + '᷆' => 230, + '᷇' => 230, + '᷈' => 230, + '᷉' => 230, + '᷊' => 220, + '᷋' => 230, + '᷌' => 230, + '᷍' => 234, + '᷎' => 214, + '᷏' => 220, + '᷐' => 202, + '᷑' => 230, + '᷒' => 230, + 'ᷓ' => 230, + 'ᷔ' => 230, + 'ᷕ' => 230, + 'ᷖ' => 230, + 'ᷗ' => 230, + 'ᷘ' => 230, + 'ᷙ' => 230, + 'ᷚ' => 230, + 'ᷛ' => 230, + 'ᷜ' => 230, + 'ᷝ' => 230, + 'ᷞ' => 230, + 'ᷟ' => 230, + 'ᷠ' => 230, + 'ᷡ' => 230, + 'ᷢ' => 230, + 'ᷣ' => 230, + 'ᷤ' => 230, + 'ᷥ' => 230, + 'ᷦ' => 230, + 'ᷧ' => 230, + 'ᷨ' => 230, + 'ᷩ' => 230, + 'ᷪ' => 230, + 'ᷫ' => 230, + 'ᷬ' => 230, + 'ᷭ' => 230, + 'ᷮ' => 230, + 'ᷯ' => 230, + 'ᷰ' => 230, + 'ᷱ' => 230, + 'ᷲ' => 230, + 'ᷳ' => 230, + 'ᷴ' => 230, + '᷵' => 230, + '᷶' => 232, + '᷷' => 228, + '᷸' => 228, + '᷹' => 220, + '᷻' => 230, + '᷼' => 233, + '᷽' => 220, + '᷾' => 230, + '᷿' => 220, + '⃐' => 230, + '⃑' => 230, + '⃒' => 1, + '⃓' => 1, + '⃔' => 230, + '⃕' => 230, + '⃖' => 230, + '⃗' => 230, + '⃘' => 1, + '⃙' => 1, + '⃚' => 1, + '⃛' => 230, + '⃜' => 230, + '⃡' => 230, + '⃥' => 1, + '⃦' => 1, + '⃧' => 230, + '⃨' => 220, + '⃩' => 230, + '⃪' => 1, + '⃫' => 1, + '⃬' => 220, + '⃭' => 220, + '⃮' => 220, + '⃯' => 220, + '⃰' => 230, + '⳯' => 230, + '⳰' => 230, + '⳱' => 230, + '⵿' => 9, + 'ⷠ' => 230, + 'ⷡ' => 230, + 'ⷢ' => 230, + 'ⷣ' => 230, + 'ⷤ' => 230, + 'ⷥ' => 230, + 'ⷦ' => 230, + 'ⷧ' => 230, + 'ⷨ' => 230, + 'ⷩ' => 230, + 'ⷪ' => 230, + 'ⷫ' => 230, + 'ⷬ' => 230, + 'ⷭ' => 230, + 'ⷮ' => 230, + 'ⷯ' => 230, + 'ⷰ' => 230, + 'ⷱ' => 230, + 'ⷲ' => 230, + 'ⷳ' => 230, + 'ⷴ' => 230, + 'ⷵ' => 230, + 'ⷶ' => 230, + 'ⷷ' => 230, + 'ⷸ' => 230, + 'ⷹ' => 230, + 'ⷺ' => 230, + 'ⷻ' => 230, + 'ⷼ' => 230, + 'ⷽ' => 230, + 'ⷾ' => 230, + 'ⷿ' => 230, + '〪' => 218, + '〫' => 228, + '〬' => 232, + '〭' => 222, + '〮' => 224, + '〯' => 224, + '゙' => 8, + '゚' => 8, + '꙯' => 230, + 'ꙴ' => 230, + 'ꙵ' => 230, + 'ꙶ' => 230, + 'ꙷ' => 230, + 'ꙸ' => 230, + 'ꙹ' => 230, + 'ꙺ' => 230, + 'ꙻ' => 230, + '꙼' => 230, + '꙽' => 230, + 'ꚞ' => 230, + 'ꚟ' => 230, + '꛰' => 230, + '꛱' => 230, + '꠆' => 9, + '꠬' => 9, + '꣄' => 9, + '꣠' => 230, + '꣡' => 230, + '꣢' => 230, + '꣣' => 230, + '꣤' => 230, + '꣥' => 230, + '꣦' => 230, + '꣧' => 230, + '꣨' => 230, + '꣩' => 230, + '꣪' => 230, + '꣫' => 230, + '꣬' => 230, + '꣭' => 230, + '꣮' => 230, + '꣯' => 230, + '꣰' => 230, + '꣱' => 230, + '꤫' => 220, + '꤬' => 220, + '꤭' => 220, + '꥓' => 9, + '꦳' => 7, + '꧀' => 9, + 'ꪰ' => 230, + 'ꪲ' => 230, + 'ꪳ' => 230, + 'ꪴ' => 220, + 'ꪷ' => 230, + 'ꪸ' => 230, + 'ꪾ' => 230, + '꪿' => 230, + '꫁' => 230, + '꫶' => 9, + '꯭' => 9, + 'ﬞ' => 26, + '︠' => 230, + '︡' => 230, + '︢' => 230, + '︣' => 230, + '︤' => 230, + '︥' => 230, + '︦' => 230, + '︧' => 220, + '︨' => 220, + '︩' => 220, + '︪' => 220, + '︫' => 220, + '︬' => 220, + '︭' => 220, + '︮' => 230, + '︯' => 230, + '𐇽' => 220, + '𐋠' => 220, + '𐍶' => 230, + '𐍷' => 230, + '𐍸' => 230, + '𐍹' => 230, + '𐍺' => 230, + '𐨍' => 220, + '𐨏' => 230, + '𐨸' => 230, + '𐨹' => 1, + '𐨺' => 220, + '𐨿' => 9, + '𐫥' => 230, + '𐫦' => 220, + '𐴤' => 230, + '𐴥' => 230, + '𐴦' => 230, + '𐴧' => 230, + '𐺫' => 230, + '𐺬' => 230, + '𐽆' => 220, + '𐽇' => 220, + '𐽈' => 230, + '𐽉' => 230, + '𐽊' => 230, + '𐽋' => 220, + '𐽌' => 230, + '𐽍' => 220, + '𐽎' => 220, + '𐽏' => 220, + '𐽐' => 220, + '𑁆' => 9, + '𑁿' => 9, + '𑂹' => 9, + '𑂺' => 7, + '𑄀' => 230, + '𑄁' => 230, + '𑄂' => 230, + '𑄳' => 9, + '𑄴' => 9, + '𑅳' => 7, + '𑇀' => 9, + '𑇊' => 7, + '𑈵' => 9, + '𑈶' => 7, + '𑋩' => 7, + '𑋪' => 9, + '𑌻' => 7, + '𑌼' => 7, + '𑍍' => 9, + '𑍦' => 230, + '𑍧' => 230, + '𑍨' => 230, + '𑍩' => 230, + '𑍪' => 230, + '𑍫' => 230, + '𑍬' => 230, + '𑍰' => 230, + '𑍱' => 230, + '𑍲' => 230, + '𑍳' => 230, + '𑍴' => 230, + '𑑂' => 9, + '𑑆' => 7, + '𑑞' => 230, + '𑓂' => 9, + '𑓃' => 7, + '𑖿' => 9, + '𑗀' => 7, + '𑘿' => 9, + '𑚶' => 9, + '𑚷' => 7, + '𑜫' => 9, + '𑠹' => 9, + '𑠺' => 7, + '𑤽' => 9, + '𑤾' => 9, + '𑥃' => 7, + '𑧠' => 9, + '𑨴' => 9, + '𑩇' => 9, + '𑪙' => 9, + '𑰿' => 9, + '𑵂' => 7, + '𑵄' => 9, + '𑵅' => 9, + '𑶗' => 9, + '𖫰' => 1, + '𖫱' => 1, + '𖫲' => 1, + '𖫳' => 1, + '𖫴' => 1, + '𖬰' => 230, + '𖬱' => 230, + '𖬲' => 230, + '𖬳' => 230, + '𖬴' => 230, + '𖬵' => 230, + '𖬶' => 230, + '𖿰' => 6, + '𖿱' => 6, + '𛲞' => 1, + '𝅥' => 216, + '𝅦' => 216, + '𝅧' => 1, + '𝅨' => 1, + '𝅩' => 1, + '𝅭' => 226, + '𝅮' => 216, + '𝅯' => 216, + '𝅰' => 216, + '𝅱' => 216, + '𝅲' => 216, + '𝅻' => 220, + '𝅼' => 220, + '𝅽' => 220, + '𝅾' => 220, + '𝅿' => 220, + '𝆀' => 220, + '𝆁' => 220, + '𝆂' => 220, + '𝆅' => 230, + '𝆆' => 230, + '𝆇' => 230, + '𝆈' => 230, + '𝆉' => 230, + '𝆊' => 220, + '𝆋' => 220, + '𝆪' => 230, + '𝆫' => 230, + '𝆬' => 230, + '𝆭' => 230, + '𝉂' => 230, + '𝉃' => 230, + '𝉄' => 230, + '𞀀' => 230, + '𞀁' => 230, + '𞀂' => 230, + '𞀃' => 230, + '𞀄' => 230, + '𞀅' => 230, + '𞀆' => 230, + '𞀈' => 230, + '𞀉' => 230, + '𞀊' => 230, + '𞀋' => 230, + '𞀌' => 230, + '𞀍' => 230, + '𞀎' => 230, + '𞀏' => 230, + '𞀐' => 230, + '𞀑' => 230, + '𞀒' => 230, + '𞀓' => 230, + '𞀔' => 230, + '𞀕' => 230, + '𞀖' => 230, + '𞀗' => 230, + '𞀘' => 230, + '𞀛' => 230, + '𞀜' => 230, + '𞀝' => 230, + '𞀞' => 230, + '𞀟' => 230, + '𞀠' => 230, + '𞀡' => 230, + '𞀣' => 230, + '𞀤' => 230, + '𞀦' => 230, + '𞀧' => 230, + '𞀨' => 230, + '𞀩' => 230, + '𞀪' => 230, + '𞄰' => 230, + '𞄱' => 230, + '𞄲' => 230, + '𞄳' => 230, + '𞄴' => 230, + '𞄵' => 230, + '𞄶' => 230, + '𞋬' => 230, + '𞋭' => 230, + '𞋮' => 230, + '𞋯' => 230, + '𞣐' => 220, + '𞣑' => 220, + '𞣒' => 220, + '𞣓' => 220, + '𞣔' => 220, + '𞣕' => 220, + '𞣖' => 220, + '𞥄' => 230, + '𞥅' => 230, + '𞥆' => 230, + '𞥇' => 230, + '𞥈' => 230, + '𞥉' => 230, + '𞥊' => 7, +); diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php new file mode 100644 index 000000000..157490289 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php @@ -0,0 +1,3695 @@ + ' ', + '¨' => ' ̈', + 'ª' => 'a', + '¯' => ' ̄', + '²' => '2', + '³' => '3', + '´' => ' ́', + 'µ' => 'μ', + '¸' => ' ̧', + '¹' => '1', + 'º' => 'o', + '¼' => '1⁄4', + '½' => '1⁄2', + '¾' => '3⁄4', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ŀ' => 'L·', + 'ŀ' => 'l·', + 'ʼn' => 'ʼn', + 'ſ' => 's', + 'DŽ' => 'DŽ', + 'Dž' => 'Dž', + 'dž' => 'dž', + 'LJ' => 'LJ', + 'Lj' => 'Lj', + 'lj' => 'lj', + 'NJ' => 'NJ', + 'Nj' => 'Nj', + 'nj' => 'nj', + 'DZ' => 'DZ', + 'Dz' => 'Dz', + 'dz' => 'dz', + 'ʰ' => 'h', + 'ʱ' => 'ɦ', + 'ʲ' => 'j', + 'ʳ' => 'r', + 'ʴ' => 'ɹ', + 'ʵ' => 'ɻ', + 'ʶ' => 'ʁ', + 'ʷ' => 'w', + 'ʸ' => 'y', + '˘' => ' ̆', + '˙' => ' ̇', + '˚' => ' ̊', + '˛' => ' ̨', + '˜' => ' ̃', + '˝' => ' ̋', + 'ˠ' => 'ɣ', + 'ˡ' => 'l', + 'ˢ' => 's', + 'ˣ' => 'x', + 'ˤ' => 'ʕ', + 'ͺ' => ' ͅ', + '΄' => ' ́', + '΅' => ' ̈́', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϒ' => 'Υ', + 'ϓ' => 'Ύ', + 'ϔ' => 'Ϋ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϲ' => 'ς', + 'ϴ' => 'Θ', + 'ϵ' => 'ε', + 'Ϲ' => 'Σ', + 'և' => 'եւ', + 'ٵ' => 'اٴ', + 'ٶ' => 'وٴ', + 'ٷ' => 'ۇٴ', + 'ٸ' => 'يٴ', + 'ำ' => 'ํา', + 'ຳ' => 'ໍາ', + 'ໜ' => 'ຫນ', + 'ໝ' => 'ຫມ', + '༌' => '་', + 'ཷ' => 'ྲཱྀ', + 'ཹ' => 'ླཱྀ', + 'ჼ' => 'ნ', + 'ᴬ' => 'A', + 'ᴭ' => 'Æ', + 'ᴮ' => 'B', + 'ᴰ' => 'D', + 'ᴱ' => 'E', + 'ᴲ' => 'Ǝ', + 'ᴳ' => 'G', + 'ᴴ' => 'H', + 'ᴵ' => 'I', + 'ᴶ' => 'J', + 'ᴷ' => 'K', + 'ᴸ' => 'L', + 'ᴹ' => 'M', + 'ᴺ' => 'N', + 'ᴼ' => 'O', + 'ᴽ' => 'Ȣ', + 'ᴾ' => 'P', + 'ᴿ' => 'R', + 'ᵀ' => 'T', + 'ᵁ' => 'U', + 'ᵂ' => 'W', + 'ᵃ' => 'a', + 'ᵄ' => 'ɐ', + 'ᵅ' => 'ɑ', + 'ᵆ' => 'ᴂ', + 'ᵇ' => 'b', + 'ᵈ' => 'd', + 'ᵉ' => 'e', + 'ᵊ' => 'ə', + 'ᵋ' => 'ɛ', + 'ᵌ' => 'ɜ', + 'ᵍ' => 'g', + 'ᵏ' => 'k', + 'ᵐ' => 'm', + 'ᵑ' => 'ŋ', + 'ᵒ' => 'o', + 'ᵓ' => 'ɔ', + 'ᵔ' => 'ᴖ', + 'ᵕ' => 'ᴗ', + 'ᵖ' => 'p', + 'ᵗ' => 't', + 'ᵘ' => 'u', + 'ᵙ' => 'ᴝ', + 'ᵚ' => 'ɯ', + 'ᵛ' => 'v', + 'ᵜ' => 'ᴥ', + 'ᵝ' => 'β', + 'ᵞ' => 'γ', + 'ᵟ' => 'δ', + 'ᵠ' => 'φ', + 'ᵡ' => 'χ', + 'ᵢ' => 'i', + 'ᵣ' => 'r', + 'ᵤ' => 'u', + 'ᵥ' => 'v', + 'ᵦ' => 'β', + 'ᵧ' => 'γ', + 'ᵨ' => 'ρ', + 'ᵩ' => 'φ', + 'ᵪ' => 'χ', + 'ᵸ' => 'н', + 'ᶛ' => 'ɒ', + 'ᶜ' => 'c', + 'ᶝ' => 'ɕ', + 'ᶞ' => 'ð', + 'ᶟ' => 'ɜ', + 'ᶠ' => 'f', + 'ᶡ' => 'ɟ', + 'ᶢ' => 'ɡ', + 'ᶣ' => 'ɥ', + 'ᶤ' => 'ɨ', + 'ᶥ' => 'ɩ', + 'ᶦ' => 'ɪ', + 'ᶧ' => 'ᵻ', + 'ᶨ' => 'ʝ', + 'ᶩ' => 'ɭ', + 'ᶪ' => 'ᶅ', + 'ᶫ' => 'ʟ', + 'ᶬ' => 'ɱ', + 'ᶭ' => 'ɰ', + 'ᶮ' => 'ɲ', + 'ᶯ' => 'ɳ', + 'ᶰ' => 'ɴ', + 'ᶱ' => 'ɵ', + 'ᶲ' => 'ɸ', + 'ᶳ' => 'ʂ', + 'ᶴ' => 'ʃ', + 'ᶵ' => 'ƫ', + 'ᶶ' => 'ʉ', + 'ᶷ' => 'ʊ', + 'ᶸ' => 'ᴜ', + 'ᶹ' => 'ʋ', + 'ᶺ' => 'ʌ', + 'ᶻ' => 'z', + 'ᶼ' => 'ʐ', + 'ᶽ' => 'ʑ', + 'ᶾ' => 'ʒ', + 'ᶿ' => 'θ', + 'ẚ' => 'aʾ', + 'ẛ' => 'ṡ', + '᾽' => ' ̓', + '᾿' => ' ̓', + '῀' => ' ͂', + '῁' => ' ̈͂', + '῍' => ' ̓̀', + '῎' => ' ̓́', + '῏' => ' ̓͂', + '῝' => ' ̔̀', + '῞' => ' ̔́', + '῟' => ' ̔͂', + '῭' => ' ̈̀', + '΅' => ' ̈́', + '´' => ' ́', + '῾' => ' ̔', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '‑' => '‐', + '‗' => ' ̳', + '․' => '.', + '‥' => '..', + '…' => '...', + ' ' => ' ', + '″' => '′′', + '‴' => '′′′', + '‶' => '‵‵', + '‷' => '‵‵‵', + '‼' => '!!', + '‾' => ' ̅', + '⁇' => '??', + '⁈' => '?!', + '⁉' => '!?', + '⁗' => '′′′′', + ' ' => ' ', + '⁰' => '0', + 'ⁱ' => 'i', + '⁴' => '4', + '⁵' => '5', + '⁶' => '6', + '⁷' => '7', + '⁸' => '8', + '⁹' => '9', + '⁺' => '+', + '⁻' => '−', + '⁼' => '=', + '⁽' => '(', + '⁾' => ')', + 'ⁿ' => 'n', + '₀' => '0', + '₁' => '1', + '₂' => '2', + '₃' => '3', + '₄' => '4', + '₅' => '5', + '₆' => '6', + '₇' => '7', + '₈' => '8', + '₉' => '9', + '₊' => '+', + '₋' => '−', + '₌' => '=', + '₍' => '(', + '₎' => ')', + 'ₐ' => 'a', + 'ₑ' => 'e', + 'ₒ' => 'o', + 'ₓ' => 'x', + 'ₔ' => 'ə', + 'ₕ' => 'h', + 'ₖ' => 'k', + 'ₗ' => 'l', + 'ₘ' => 'm', + 'ₙ' => 'n', + 'ₚ' => 'p', + 'ₛ' => 's', + 'ₜ' => 't', + '₨' => 'Rs', + '℀' => 'a/c', + '℁' => 'a/s', + 'ℂ' => 'C', + '℃' => '°C', + '℅' => 'c/o', + '℆' => 'c/u', + 'ℇ' => 'Ɛ', + '℉' => '°F', + 'ℊ' => 'g', + 'ℋ' => 'H', + 'ℌ' => 'H', + 'ℍ' => 'H', + 'ℎ' => 'h', + 'ℏ' => 'ħ', + 'ℐ' => 'I', + 'ℑ' => 'I', + 'ℒ' => 'L', + 'ℓ' => 'l', + 'ℕ' => 'N', + '№' => 'No', + 'ℙ' => 'P', + 'ℚ' => 'Q', + 'ℛ' => 'R', + 'ℜ' => 'R', + 'ℝ' => 'R', + '℠' => 'SM', + '℡' => 'TEL', + '™' => 'TM', + 'ℤ' => 'Z', + 'ℨ' => 'Z', + 'ℬ' => 'B', + 'ℭ' => 'C', + 'ℯ' => 'e', + 'ℰ' => 'E', + 'ℱ' => 'F', + 'ℳ' => 'M', + 'ℴ' => 'o', + 'ℵ' => 'א', + 'ℶ' => 'ב', + 'ℷ' => 'ג', + 'ℸ' => 'ד', + 'ℹ' => 'i', + '℻' => 'FAX', + 'ℼ' => 'π', + 'ℽ' => 'γ', + 'ℾ' => 'Γ', + 'ℿ' => 'Π', + '⅀' => '∑', + 'ⅅ' => 'D', + 'ⅆ' => 'd', + 'ⅇ' => 'e', + 'ⅈ' => 'i', + 'ⅉ' => 'j', + '⅐' => '1⁄7', + '⅑' => '1⁄9', + '⅒' => '1⁄10', + '⅓' => '1⁄3', + '⅔' => '2⁄3', + '⅕' => '1⁄5', + '⅖' => '2⁄5', + '⅗' => '3⁄5', + '⅘' => '4⁄5', + '⅙' => '1⁄6', + '⅚' => '5⁄6', + '⅛' => '1⁄8', + '⅜' => '3⁄8', + '⅝' => '5⁄8', + '⅞' => '7⁄8', + '⅟' => '1⁄', + 'Ⅰ' => 'I', + 'Ⅱ' => 'II', + 'Ⅲ' => 'III', + 'Ⅳ' => 'IV', + 'Ⅴ' => 'V', + 'Ⅵ' => 'VI', + 'Ⅶ' => 'VII', + 'Ⅷ' => 'VIII', + 'Ⅸ' => 'IX', + 'Ⅹ' => 'X', + 'Ⅺ' => 'XI', + 'Ⅻ' => 'XII', + 'Ⅼ' => 'L', + 'Ⅽ' => 'C', + 'Ⅾ' => 'D', + 'Ⅿ' => 'M', + 'ⅰ' => 'i', + 'ⅱ' => 'ii', + 'ⅲ' => 'iii', + 'ⅳ' => 'iv', + 'ⅴ' => 'v', + 'ⅵ' => 'vi', + 'ⅶ' => 'vii', + 'ⅷ' => 'viii', + 'ⅸ' => 'ix', + 'ⅹ' => 'x', + 'ⅺ' => 'xi', + 'ⅻ' => 'xii', + 'ⅼ' => 'l', + 'ⅽ' => 'c', + 'ⅾ' => 'd', + 'ⅿ' => 'm', + '↉' => '0⁄3', + '∬' => '∫∫', + '∭' => '∫∫∫', + '∯' => '∮∮', + '∰' => '∮∮∮', + '①' => '1', + '②' => '2', + '③' => '3', + '④' => '4', + '⑤' => '5', + '⑥' => '6', + '⑦' => '7', + '⑧' => '8', + '⑨' => '9', + '⑩' => '10', + '⑪' => '11', + '⑫' => '12', + '⑬' => '13', + '⑭' => '14', + '⑮' => '15', + '⑯' => '16', + '⑰' => '17', + '⑱' => '18', + '⑲' => '19', + '⑳' => '20', + '⑴' => '(1)', + '⑵' => '(2)', + '⑶' => '(3)', + '⑷' => '(4)', + '⑸' => '(5)', + '⑹' => '(6)', + '⑺' => '(7)', + '⑻' => '(8)', + '⑼' => '(9)', + '⑽' => '(10)', + '⑾' => '(11)', + '⑿' => '(12)', + '⒀' => '(13)', + '⒁' => '(14)', + '⒂' => '(15)', + '⒃' => '(16)', + '⒄' => '(17)', + '⒅' => '(18)', + '⒆' => '(19)', + '⒇' => '(20)', + '⒈' => '1.', + '⒉' => '2.', + '⒊' => '3.', + '⒋' => '4.', + '⒌' => '5.', + '⒍' => '6.', + '⒎' => '7.', + '⒏' => '8.', + '⒐' => '9.', + '⒑' => '10.', + '⒒' => '11.', + '⒓' => '12.', + '⒔' => '13.', + '⒕' => '14.', + '⒖' => '15.', + '⒗' => '16.', + '⒘' => '17.', + '⒙' => '18.', + '⒚' => '19.', + '⒛' => '20.', + '⒜' => '(a)', + '⒝' => '(b)', + '⒞' => '(c)', + '⒟' => '(d)', + '⒠' => '(e)', + '⒡' => '(f)', + '⒢' => '(g)', + '⒣' => '(h)', + '⒤' => '(i)', + '⒥' => '(j)', + '⒦' => '(k)', + '⒧' => '(l)', + '⒨' => '(m)', + '⒩' => '(n)', + '⒪' => '(o)', + '⒫' => '(p)', + '⒬' => '(q)', + '⒭' => '(r)', + '⒮' => '(s)', + '⒯' => '(t)', + '⒰' => '(u)', + '⒱' => '(v)', + '⒲' => '(w)', + '⒳' => '(x)', + '⒴' => '(y)', + '⒵' => '(z)', + 'Ⓐ' => 'A', + 'Ⓑ' => 'B', + 'Ⓒ' => 'C', + 'Ⓓ' => 'D', + 'Ⓔ' => 'E', + 'Ⓕ' => 'F', + 'Ⓖ' => 'G', + 'Ⓗ' => 'H', + 'Ⓘ' => 'I', + 'Ⓙ' => 'J', + 'Ⓚ' => 'K', + 'Ⓛ' => 'L', + 'Ⓜ' => 'M', + 'Ⓝ' => 'N', + 'Ⓞ' => 'O', + 'Ⓟ' => 'P', + 'Ⓠ' => 'Q', + 'Ⓡ' => 'R', + 'Ⓢ' => 'S', + 'Ⓣ' => 'T', + 'Ⓤ' => 'U', + 'Ⓥ' => 'V', + 'Ⓦ' => 'W', + 'Ⓧ' => 'X', + 'Ⓨ' => 'Y', + 'Ⓩ' => 'Z', + 'ⓐ' => 'a', + 'ⓑ' => 'b', + 'ⓒ' => 'c', + 'ⓓ' => 'd', + 'ⓔ' => 'e', + 'ⓕ' => 'f', + 'ⓖ' => 'g', + 'ⓗ' => 'h', + 'ⓘ' => 'i', + 'ⓙ' => 'j', + 'ⓚ' => 'k', + 'ⓛ' => 'l', + 'ⓜ' => 'm', + 'ⓝ' => 'n', + 'ⓞ' => 'o', + 'ⓟ' => 'p', + 'ⓠ' => 'q', + 'ⓡ' => 'r', + 'ⓢ' => 's', + 'ⓣ' => 't', + 'ⓤ' => 'u', + 'ⓥ' => 'v', + 'ⓦ' => 'w', + 'ⓧ' => 'x', + 'ⓨ' => 'y', + 'ⓩ' => 'z', + '⓪' => '0', + '⨌' => '∫∫∫∫', + '⩴' => '::=', + '⩵' => '==', + '⩶' => '===', + 'ⱼ' => 'j', + 'ⱽ' => 'V', + 'ⵯ' => 'ⵡ', + '⺟' => '母', + '⻳' => '龟', + '⼀' => '一', + '⼁' => '丨', + '⼂' => '丶', + '⼃' => '丿', + '⼄' => '乙', + '⼅' => '亅', + '⼆' => '二', + '⼇' => '亠', + '⼈' => '人', + '⼉' => '儿', + '⼊' => '入', + '⼋' => '八', + '⼌' => '冂', + '⼍' => '冖', + '⼎' => '冫', + '⼏' => '几', + '⼐' => '凵', + '⼑' => '刀', + '⼒' => '力', + '⼓' => '勹', + '⼔' => '匕', + '⼕' => '匚', + '⼖' => '匸', + '⼗' => '十', + '⼘' => '卜', + '⼙' => '卩', + '⼚' => '厂', + '⼛' => '厶', + '⼜' => '又', + '⼝' => '口', + '⼞' => '囗', + '⼟' => '土', + '⼠' => '士', + '⼡' => '夂', + '⼢' => '夊', + '⼣' => '夕', + '⼤' => '大', + '⼥' => '女', + '⼦' => '子', + '⼧' => '宀', + '⼨' => '寸', + '⼩' => '小', + '⼪' => '尢', + '⼫' => '尸', + '⼬' => '屮', + '⼭' => '山', + '⼮' => '巛', + '⼯' => '工', + '⼰' => '己', + '⼱' => '巾', + '⼲' => '干', + '⼳' => '幺', + '⼴' => '广', + '⼵' => '廴', + '⼶' => '廾', + '⼷' => '弋', + '⼸' => '弓', + '⼹' => '彐', + '⼺' => '彡', + '⼻' => '彳', + '⼼' => '心', + '⼽' => '戈', + '⼾' => '戶', + '⼿' => '手', + '⽀' => '支', + '⽁' => '攴', + '⽂' => '文', + '⽃' => '斗', + '⽄' => '斤', + '⽅' => '方', + '⽆' => '无', + '⽇' => '日', + '⽈' => '曰', + '⽉' => '月', + '⽊' => '木', + '⽋' => '欠', + '⽌' => '止', + '⽍' => '歹', + '⽎' => '殳', + '⽏' => '毋', + '⽐' => '比', + '⽑' => '毛', + '⽒' => '氏', + '⽓' => '气', + '⽔' => '水', + '⽕' => '火', + '⽖' => '爪', + '⽗' => '父', + '⽘' => '爻', + '⽙' => '爿', + '⽚' => '片', + '⽛' => '牙', + '⽜' => '牛', + '⽝' => '犬', + '⽞' => '玄', + '⽟' => '玉', + '⽠' => '瓜', + '⽡' => '瓦', + '⽢' => '甘', + '⽣' => '生', + '⽤' => '用', + '⽥' => '田', + '⽦' => '疋', + '⽧' => '疒', + '⽨' => '癶', + '⽩' => '白', + '⽪' => '皮', + '⽫' => '皿', + '⽬' => '目', + '⽭' => '矛', + '⽮' => '矢', + '⽯' => '石', + '⽰' => '示', + '⽱' => '禸', + '⽲' => '禾', + '⽳' => '穴', + '⽴' => '立', + '⽵' => '竹', + '⽶' => '米', + '⽷' => '糸', + '⽸' => '缶', + '⽹' => '网', + '⽺' => '羊', + '⽻' => '羽', + '⽼' => '老', + '⽽' => '而', + '⽾' => '耒', + '⽿' => '耳', + '⾀' => '聿', + '⾁' => '肉', + '⾂' => '臣', + '⾃' => '自', + '⾄' => '至', + '⾅' => '臼', + '⾆' => '舌', + '⾇' => '舛', + '⾈' => '舟', + '⾉' => '艮', + '⾊' => '色', + '⾋' => '艸', + '⾌' => '虍', + '⾍' => '虫', + '⾎' => '血', + '⾏' => '行', + '⾐' => '衣', + '⾑' => '襾', + '⾒' => '見', + '⾓' => '角', + '⾔' => '言', + '⾕' => '谷', + '⾖' => '豆', + '⾗' => '豕', + '⾘' => '豸', + '⾙' => '貝', + '⾚' => '赤', + '⾛' => '走', + '⾜' => '足', + '⾝' => '身', + '⾞' => '車', + '⾟' => '辛', + '⾠' => '辰', + '⾡' => '辵', + '⾢' => '邑', + '⾣' => '酉', + '⾤' => '釆', + '⾥' => '里', + '⾦' => '金', + '⾧' => '長', + '⾨' => '門', + '⾩' => '阜', + '⾪' => '隶', + '⾫' => '隹', + '⾬' => '雨', + '⾭' => '靑', + '⾮' => '非', + '⾯' => '面', + '⾰' => '革', + '⾱' => '韋', + '⾲' => '韭', + '⾳' => '音', + '⾴' => '頁', + '⾵' => '風', + '⾶' => '飛', + '⾷' => '食', + '⾸' => '首', + '⾹' => '香', + '⾺' => '馬', + '⾻' => '骨', + '⾼' => '高', + '⾽' => '髟', + '⾾' => '鬥', + '⾿' => '鬯', + '⿀' => '鬲', + '⿁' => '鬼', + '⿂' => '魚', + '⿃' => '鳥', + '⿄' => '鹵', + '⿅' => '鹿', + '⿆' => '麥', + '⿇' => '麻', + '⿈' => '黃', + '⿉' => '黍', + '⿊' => '黑', + '⿋' => '黹', + '⿌' => '黽', + '⿍' => '鼎', + '⿎' => '鼓', + '⿏' => '鼠', + '⿐' => '鼻', + '⿑' => '齊', + '⿒' => '齒', + '⿓' => '龍', + '⿔' => '龜', + '⿕' => '龠', + ' ' => ' ', + '〶' => '〒', + '〸' => '十', + '〹' => '卄', + '〺' => '卅', + '゛' => ' ゙', + '゜' => ' ゚', + 'ゟ' => 'より', + 'ヿ' => 'コト', + 'ㄱ' => 'ᄀ', + 'ㄲ' => 'ᄁ', + 'ㄳ' => 'ᆪ', + 'ㄴ' => 'ᄂ', + 'ㄵ' => 'ᆬ', + 'ㄶ' => 'ᆭ', + 'ㄷ' => 'ᄃ', + 'ㄸ' => 'ᄄ', + 'ㄹ' => 'ᄅ', + 'ㄺ' => 'ᆰ', + 'ㄻ' => 'ᆱ', + 'ㄼ' => 'ᆲ', + 'ㄽ' => 'ᆳ', + 'ㄾ' => 'ᆴ', + 'ㄿ' => 'ᆵ', + 'ㅀ' => 'ᄚ', + 'ㅁ' => 'ᄆ', + 'ㅂ' => 'ᄇ', + 'ㅃ' => 'ᄈ', + 'ㅄ' => 'ᄡ', + 'ㅅ' => 'ᄉ', + 'ㅆ' => 'ᄊ', + 'ㅇ' => 'ᄋ', + 'ㅈ' => 'ᄌ', + 'ㅉ' => 'ᄍ', + 'ㅊ' => 'ᄎ', + 'ㅋ' => 'ᄏ', + 'ㅌ' => 'ᄐ', + 'ㅍ' => 'ᄑ', + 'ㅎ' => 'ᄒ', + 'ㅏ' => 'ᅡ', + 'ㅐ' => 'ᅢ', + 'ㅑ' => 'ᅣ', + 'ㅒ' => 'ᅤ', + 'ㅓ' => 'ᅥ', + 'ㅔ' => 'ᅦ', + 'ㅕ' => 'ᅧ', + 'ㅖ' => 'ᅨ', + 'ㅗ' => 'ᅩ', + 'ㅘ' => 'ᅪ', + 'ㅙ' => 'ᅫ', + 'ㅚ' => 'ᅬ', + 'ㅛ' => 'ᅭ', + 'ㅜ' => 'ᅮ', + 'ㅝ' => 'ᅯ', + 'ㅞ' => 'ᅰ', + 'ㅟ' => 'ᅱ', + 'ㅠ' => 'ᅲ', + 'ㅡ' => 'ᅳ', + 'ㅢ' => 'ᅴ', + 'ㅣ' => 'ᅵ', + 'ㅤ' => 'ᅠ', + 'ㅥ' => 'ᄔ', + 'ㅦ' => 'ᄕ', + 'ㅧ' => 'ᇇ', + 'ㅨ' => 'ᇈ', + 'ㅩ' => 'ᇌ', + 'ㅪ' => 'ᇎ', + 'ㅫ' => 'ᇓ', + 'ㅬ' => 'ᇗ', + 'ㅭ' => 'ᇙ', + 'ㅮ' => 'ᄜ', + 'ㅯ' => 'ᇝ', + 'ㅰ' => 'ᇟ', + 'ㅱ' => 'ᄝ', + 'ㅲ' => 'ᄞ', + 'ㅳ' => 'ᄠ', + 'ㅴ' => 'ᄢ', + 'ㅵ' => 'ᄣ', + 'ㅶ' => 'ᄧ', + 'ㅷ' => 'ᄩ', + 'ㅸ' => 'ᄫ', + 'ㅹ' => 'ᄬ', + 'ㅺ' => 'ᄭ', + 'ㅻ' => 'ᄮ', + 'ㅼ' => 'ᄯ', + 'ㅽ' => 'ᄲ', + 'ㅾ' => 'ᄶ', + 'ㅿ' => 'ᅀ', + 'ㆀ' => 'ᅇ', + 'ㆁ' => 'ᅌ', + 'ㆂ' => 'ᇱ', + 'ㆃ' => 'ᇲ', + 'ㆄ' => 'ᅗ', + 'ㆅ' => 'ᅘ', + 'ㆆ' => 'ᅙ', + 'ㆇ' => 'ᆄ', + 'ㆈ' => 'ᆅ', + 'ㆉ' => 'ᆈ', + 'ㆊ' => 'ᆑ', + 'ㆋ' => 'ᆒ', + 'ㆌ' => 'ᆔ', + 'ㆍ' => 'ᆞ', + 'ㆎ' => 'ᆡ', + '㆒' => '一', + '㆓' => '二', + '㆔' => '三', + '㆕' => '四', + '㆖' => '上', + '㆗' => '中', + '㆘' => '下', + '㆙' => '甲', + '㆚' => '乙', + '㆛' => '丙', + '㆜' => '丁', + '㆝' => '天', + '㆞' => '地', + '㆟' => '人', + '㈀' => '(ᄀ)', + '㈁' => '(ᄂ)', + '㈂' => '(ᄃ)', + '㈃' => '(ᄅ)', + '㈄' => '(ᄆ)', + '㈅' => '(ᄇ)', + '㈆' => '(ᄉ)', + '㈇' => '(ᄋ)', + '㈈' => '(ᄌ)', + '㈉' => '(ᄎ)', + '㈊' => '(ᄏ)', + '㈋' => '(ᄐ)', + '㈌' => '(ᄑ)', + '㈍' => '(ᄒ)', + '㈎' => '(가)', + '㈏' => '(나)', + '㈐' => '(다)', + '㈑' => '(라)', + '㈒' => '(마)', + '㈓' => '(바)', + '㈔' => '(사)', + '㈕' => '(아)', + '㈖' => '(자)', + '㈗' => '(차)', + '㈘' => '(카)', + '㈙' => '(타)', + '㈚' => '(파)', + '㈛' => '(하)', + '㈜' => '(주)', + '㈝' => '(오전)', + '㈞' => '(오후)', + '㈠' => '(一)', + '㈡' => '(二)', + '㈢' => '(三)', + '㈣' => '(四)', + '㈤' => '(五)', + '㈥' => '(六)', + '㈦' => '(七)', + '㈧' => '(八)', + '㈨' => '(九)', + '㈩' => '(十)', + '㈪' => '(月)', + '㈫' => '(火)', + '㈬' => '(水)', + '㈭' => '(木)', + '㈮' => '(金)', + '㈯' => '(土)', + '㈰' => '(日)', + '㈱' => '(株)', + '㈲' => '(有)', + '㈳' => '(社)', + '㈴' => '(名)', + '㈵' => '(特)', + '㈶' => '(財)', + '㈷' => '(祝)', + '㈸' => '(労)', + '㈹' => '(代)', + '㈺' => '(呼)', + '㈻' => '(学)', + '㈼' => '(監)', + '㈽' => '(企)', + '㈾' => '(資)', + '㈿' => '(協)', + '㉀' => '(祭)', + '㉁' => '(休)', + '㉂' => '(自)', + '㉃' => '(至)', + '㉄' => '問', + '㉅' => '幼', + '㉆' => '文', + '㉇' => '箏', + '㉐' => 'PTE', + '㉑' => '21', + '㉒' => '22', + '㉓' => '23', + '㉔' => '24', + '㉕' => '25', + '㉖' => '26', + '㉗' => '27', + '㉘' => '28', + '㉙' => '29', + '㉚' => '30', + '㉛' => '31', + '㉜' => '32', + '㉝' => '33', + '㉞' => '34', + '㉟' => '35', + '㉠' => 'ᄀ', + '㉡' => 'ᄂ', + '㉢' => 'ᄃ', + '㉣' => 'ᄅ', + '㉤' => 'ᄆ', + '㉥' => 'ᄇ', + '㉦' => 'ᄉ', + '㉧' => 'ᄋ', + '㉨' => 'ᄌ', + '㉩' => 'ᄎ', + '㉪' => 'ᄏ', + '㉫' => 'ᄐ', + '㉬' => 'ᄑ', + '㉭' => 'ᄒ', + '㉮' => '가', + '㉯' => '나', + '㉰' => '다', + '㉱' => '라', + '㉲' => '마', + '㉳' => '바', + '㉴' => '사', + '㉵' => '아', + '㉶' => '자', + '㉷' => '차', + '㉸' => '카', + '㉹' => '타', + '㉺' => '파', + '㉻' => '하', + '㉼' => '참고', + '㉽' => '주의', + '㉾' => '우', + '㊀' => '一', + '㊁' => '二', + '㊂' => '三', + '㊃' => '四', + '㊄' => '五', + '㊅' => '六', + '㊆' => '七', + '㊇' => '八', + '㊈' => '九', + '㊉' => '十', + '㊊' => '月', + '㊋' => '火', + '㊌' => '水', + '㊍' => '木', + '㊎' => '金', + '㊏' => '土', + '㊐' => '日', + '㊑' => '株', + '㊒' => '有', + '㊓' => '社', + '㊔' => '名', + '㊕' => '特', + '㊖' => '財', + '㊗' => '祝', + '㊘' => '労', + '㊙' => '秘', + '㊚' => '男', + '㊛' => '女', + '㊜' => '適', + '㊝' => '優', + '㊞' => '印', + '㊟' => '注', + '㊠' => '項', + '㊡' => '休', + '㊢' => '写', + '㊣' => '正', + '㊤' => '上', + '㊥' => '中', + '㊦' => '下', + '㊧' => '左', + '㊨' => '右', + '㊩' => '医', + '㊪' => '宗', + '㊫' => '学', + '㊬' => '監', + '㊭' => '企', + '㊮' => '資', + '㊯' => '協', + '㊰' => '夜', + '㊱' => '36', + '㊲' => '37', + '㊳' => '38', + '㊴' => '39', + '㊵' => '40', + '㊶' => '41', + '㊷' => '42', + '㊸' => '43', + '㊹' => '44', + '㊺' => '45', + '㊻' => '46', + '㊼' => '47', + '㊽' => '48', + '㊾' => '49', + '㊿' => '50', + '㋀' => '1月', + '㋁' => '2月', + '㋂' => '3月', + '㋃' => '4月', + '㋄' => '5月', + '㋅' => '6月', + '㋆' => '7月', + '㋇' => '8月', + '㋈' => '9月', + '㋉' => '10月', + '㋊' => '11月', + '㋋' => '12月', + '㋌' => 'Hg', + '㋍' => 'erg', + '㋎' => 'eV', + '㋏' => 'LTD', + '㋐' => 'ア', + '㋑' => 'イ', + '㋒' => 'ウ', + '㋓' => 'エ', + '㋔' => 'オ', + '㋕' => 'カ', + '㋖' => 'キ', + '㋗' => 'ク', + '㋘' => 'ケ', + '㋙' => 'コ', + '㋚' => 'サ', + '㋛' => 'シ', + '㋜' => 'ス', + '㋝' => 'セ', + '㋞' => 'ソ', + '㋟' => 'タ', + '㋠' => 'チ', + '㋡' => 'ツ', + '㋢' => 'テ', + '㋣' => 'ト', + '㋤' => 'ナ', + '㋥' => 'ニ', + '㋦' => 'ヌ', + '㋧' => 'ネ', + '㋨' => 'ノ', + '㋩' => 'ハ', + '㋪' => 'ヒ', + '㋫' => 'フ', + '㋬' => 'ヘ', + '㋭' => 'ホ', + '㋮' => 'マ', + '㋯' => 'ミ', + '㋰' => 'ム', + '㋱' => 'メ', + '㋲' => 'モ', + '㋳' => 'ヤ', + '㋴' => 'ユ', + '㋵' => 'ヨ', + '㋶' => 'ラ', + '㋷' => 'リ', + '㋸' => 'ル', + '㋹' => 'レ', + '㋺' => 'ロ', + '㋻' => 'ワ', + '㋼' => 'ヰ', + '㋽' => 'ヱ', + '㋾' => 'ヲ', + '㋿' => '令和', + '㌀' => 'アパート', + '㌁' => 'アルファ', + '㌂' => 'アンペア', + '㌃' => 'アール', + '㌄' => 'イニング', + '㌅' => 'インチ', + '㌆' => 'ウォン', + '㌇' => 'エスクード', + '㌈' => 'エーカー', + '㌉' => 'オンス', + '㌊' => 'オーム', + '㌋' => 'カイリ', + '㌌' => 'カラット', + '㌍' => 'カロリー', + '㌎' => 'ガロン', + '㌏' => 'ガンマ', + '㌐' => 'ギガ', + '㌑' => 'ギニー', + '㌒' => 'キュリー', + '㌓' => 'ギルダー', + '㌔' => 'キロ', + '㌕' => 'キログラム', + '㌖' => 'キロメートル', + '㌗' => 'キロワット', + '㌘' => 'グラム', + '㌙' => 'グラムトン', + '㌚' => 'クルゼイロ', + '㌛' => 'クローネ', + '㌜' => 'ケース', + '㌝' => 'コルナ', + '㌞' => 'コーポ', + '㌟' => 'サイクル', + '㌠' => 'サンチーム', + '㌡' => 'シリング', + '㌢' => 'センチ', + '㌣' => 'セント', + '㌤' => 'ダース', + '㌥' => 'デシ', + '㌦' => 'ドル', + '㌧' => 'トン', + '㌨' => 'ナノ', + '㌩' => 'ノット', + '㌪' => 'ハイツ', + '㌫' => 'パーセント', + '㌬' => 'パーツ', + '㌭' => 'バーレル', + '㌮' => 'ピアストル', + '㌯' => 'ピクル', + '㌰' => 'ピコ', + '㌱' => 'ビル', + '㌲' => 'ファラッド', + '㌳' => 'フィート', + '㌴' => 'ブッシェル', + '㌵' => 'フラン', + '㌶' => 'ヘクタール', + '㌷' => 'ペソ', + '㌸' => 'ペニヒ', + '㌹' => 'ヘルツ', + '㌺' => 'ペンス', + '㌻' => 'ページ', + '㌼' => 'ベータ', + '㌽' => 'ポイント', + '㌾' => 'ボルト', + '㌿' => 'ホン', + '㍀' => 'ポンド', + '㍁' => 'ホール', + '㍂' => 'ホーン', + '㍃' => 'マイクロ', + '㍄' => 'マイル', + '㍅' => 'マッハ', + '㍆' => 'マルク', + '㍇' => 'マンション', + '㍈' => 'ミクロン', + '㍉' => 'ミリ', + '㍊' => 'ミリバール', + '㍋' => 'メガ', + '㍌' => 'メガトン', + '㍍' => 'メートル', + '㍎' => 'ヤード', + '㍏' => 'ヤール', + '㍐' => 'ユアン', + '㍑' => 'リットル', + '㍒' => 'リラ', + '㍓' => 'ルピー', + '㍔' => 'ルーブル', + '㍕' => 'レム', + '㍖' => 'レントゲン', + '㍗' => 'ワット', + '㍘' => '0点', + '㍙' => '1点', + '㍚' => '2点', + '㍛' => '3点', + '㍜' => '4点', + '㍝' => '5点', + '㍞' => '6点', + '㍟' => '7点', + '㍠' => '8点', + '㍡' => '9点', + '㍢' => '10点', + '㍣' => '11点', + '㍤' => '12点', + '㍥' => '13点', + '㍦' => '14点', + '㍧' => '15点', + '㍨' => '16点', + '㍩' => '17点', + '㍪' => '18点', + '㍫' => '19点', + '㍬' => '20点', + '㍭' => '21点', + '㍮' => '22点', + '㍯' => '23点', + '㍰' => '24点', + '㍱' => 'hPa', + '㍲' => 'da', + '㍳' => 'AU', + '㍴' => 'bar', + '㍵' => 'oV', + '㍶' => 'pc', + '㍷' => 'dm', + '㍸' => 'dm2', + '㍹' => 'dm3', + '㍺' => 'IU', + '㍻' => '平成', + '㍼' => '昭和', + '㍽' => '大正', + '㍾' => '明治', + '㍿' => '株式会社', + '㎀' => 'pA', + '㎁' => 'nA', + '㎂' => 'μA', + '㎃' => 'mA', + '㎄' => 'kA', + '㎅' => 'KB', + '㎆' => 'MB', + '㎇' => 'GB', + '㎈' => 'cal', + '㎉' => 'kcal', + '㎊' => 'pF', + '㎋' => 'nF', + '㎌' => 'μF', + '㎍' => 'μg', + '㎎' => 'mg', + '㎏' => 'kg', + '㎐' => 'Hz', + '㎑' => 'kHz', + '㎒' => 'MHz', + '㎓' => 'GHz', + '㎔' => 'THz', + '㎕' => 'μl', + '㎖' => 'ml', + '㎗' => 'dl', + '㎘' => 'kl', + '㎙' => 'fm', + '㎚' => 'nm', + '㎛' => 'μm', + '㎜' => 'mm', + '㎝' => 'cm', + '㎞' => 'km', + '㎟' => 'mm2', + '㎠' => 'cm2', + '㎡' => 'm2', + '㎢' => 'km2', + '㎣' => 'mm3', + '㎤' => 'cm3', + '㎥' => 'm3', + '㎦' => 'km3', + '㎧' => 'm∕s', + '㎨' => 'm∕s2', + '㎩' => 'Pa', + '㎪' => 'kPa', + '㎫' => 'MPa', + '㎬' => 'GPa', + '㎭' => 'rad', + '㎮' => 'rad∕s', + '㎯' => 'rad∕s2', + '㎰' => 'ps', + '㎱' => 'ns', + '㎲' => 'μs', + '㎳' => 'ms', + '㎴' => 'pV', + '㎵' => 'nV', + '㎶' => 'μV', + '㎷' => 'mV', + '㎸' => 'kV', + '㎹' => 'MV', + '㎺' => 'pW', + '㎻' => 'nW', + '㎼' => 'μW', + '㎽' => 'mW', + '㎾' => 'kW', + '㎿' => 'MW', + '㏀' => 'kΩ', + '㏁' => 'MΩ', + '㏂' => 'a.m.', + '㏃' => 'Bq', + '㏄' => 'cc', + '㏅' => 'cd', + '㏆' => 'C∕kg', + '㏇' => 'Co.', + '㏈' => 'dB', + '㏉' => 'Gy', + '㏊' => 'ha', + '㏋' => 'HP', + '㏌' => 'in', + '㏍' => 'KK', + '㏎' => 'KM', + '㏏' => 'kt', + '㏐' => 'lm', + '㏑' => 'ln', + '㏒' => 'log', + '㏓' => 'lx', + '㏔' => 'mb', + '㏕' => 'mil', + '㏖' => 'mol', + '㏗' => 'PH', + '㏘' => 'p.m.', + '㏙' => 'PPM', + '㏚' => 'PR', + '㏛' => 'sr', + '㏜' => 'Sv', + '㏝' => 'Wb', + '㏞' => 'V∕m', + '㏟' => 'A∕m', + '㏠' => '1日', + '㏡' => '2日', + '㏢' => '3日', + '㏣' => '4日', + '㏤' => '5日', + '㏥' => '6日', + '㏦' => '7日', + '㏧' => '8日', + '㏨' => '9日', + '㏩' => '10日', + '㏪' => '11日', + '㏫' => '12日', + '㏬' => '13日', + '㏭' => '14日', + '㏮' => '15日', + '㏯' => '16日', + '㏰' => '17日', + '㏱' => '18日', + '㏲' => '19日', + '㏳' => '20日', + '㏴' => '21日', + '㏵' => '22日', + '㏶' => '23日', + '㏷' => '24日', + '㏸' => '25日', + '㏹' => '26日', + '㏺' => '27日', + '㏻' => '28日', + '㏼' => '29日', + '㏽' => '30日', + '㏾' => '31日', + '㏿' => 'gal', + 'ꚜ' => 'ъ', + 'ꚝ' => 'ь', + 'ꝰ' => 'ꝯ', + 'ꟸ' => 'Ħ', + 'ꟹ' => 'œ', + 'ꭜ' => 'ꜧ', + 'ꭝ' => 'ꬷ', + 'ꭞ' => 'ɫ', + 'ꭟ' => 'ꭒ', + 'ꭩ' => 'ʍ', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', + 'ﬠ' => 'ע', + 'ﬡ' => 'א', + 'ﬢ' => 'ד', + 'ﬣ' => 'ה', + 'ﬤ' => 'כ', + 'ﬥ' => 'ל', + 'ﬦ' => 'ם', + 'ﬧ' => 'ר', + 'ﬨ' => 'ת', + '﬩' => '+', + 'ﭏ' => 'אל', + 'ﭐ' => 'ٱ', + 'ﭑ' => 'ٱ', + 'ﭒ' => 'ٻ', + 'ﭓ' => 'ٻ', + 'ﭔ' => 'ٻ', + 'ﭕ' => 'ٻ', + 'ﭖ' => 'پ', + 'ﭗ' => 'پ', + 'ﭘ' => 'پ', + 'ﭙ' => 'پ', + 'ﭚ' => 'ڀ', + 'ﭛ' => 'ڀ', + 'ﭜ' => 'ڀ', + 'ﭝ' => 'ڀ', + 'ﭞ' => 'ٺ', + 'ﭟ' => 'ٺ', + 'ﭠ' => 'ٺ', + 'ﭡ' => 'ٺ', + 'ﭢ' => 'ٿ', + 'ﭣ' => 'ٿ', + 'ﭤ' => 'ٿ', + 'ﭥ' => 'ٿ', + 'ﭦ' => 'ٹ', + 'ﭧ' => 'ٹ', + 'ﭨ' => 'ٹ', + 'ﭩ' => 'ٹ', + 'ﭪ' => 'ڤ', + 'ﭫ' => 'ڤ', + 'ﭬ' => 'ڤ', + 'ﭭ' => 'ڤ', + 'ﭮ' => 'ڦ', + 'ﭯ' => 'ڦ', + 'ﭰ' => 'ڦ', + 'ﭱ' => 'ڦ', + 'ﭲ' => 'ڄ', + 'ﭳ' => 'ڄ', + 'ﭴ' => 'ڄ', + 'ﭵ' => 'ڄ', + 'ﭶ' => 'ڃ', + 'ﭷ' => 'ڃ', + 'ﭸ' => 'ڃ', + 'ﭹ' => 'ڃ', + 'ﭺ' => 'چ', + 'ﭻ' => 'چ', + 'ﭼ' => 'چ', + 'ﭽ' => 'چ', + 'ﭾ' => 'ڇ', + 'ﭿ' => 'ڇ', + 'ﮀ' => 'ڇ', + 'ﮁ' => 'ڇ', + 'ﮂ' => 'ڍ', + 'ﮃ' => 'ڍ', + 'ﮄ' => 'ڌ', + 'ﮅ' => 'ڌ', + 'ﮆ' => 'ڎ', + 'ﮇ' => 'ڎ', + 'ﮈ' => 'ڈ', + 'ﮉ' => 'ڈ', + 'ﮊ' => 'ژ', + 'ﮋ' => 'ژ', + 'ﮌ' => 'ڑ', + 'ﮍ' => 'ڑ', + 'ﮎ' => 'ک', + 'ﮏ' => 'ک', + 'ﮐ' => 'ک', + 'ﮑ' => 'ک', + 'ﮒ' => 'گ', + 'ﮓ' => 'گ', + 'ﮔ' => 'گ', + 'ﮕ' => 'گ', + 'ﮖ' => 'ڳ', + 'ﮗ' => 'ڳ', + 'ﮘ' => 'ڳ', + 'ﮙ' => 'ڳ', + 'ﮚ' => 'ڱ', + 'ﮛ' => 'ڱ', + 'ﮜ' => 'ڱ', + 'ﮝ' => 'ڱ', + 'ﮞ' => 'ں', + 'ﮟ' => 'ں', + 'ﮠ' => 'ڻ', + 'ﮡ' => 'ڻ', + 'ﮢ' => 'ڻ', + 'ﮣ' => 'ڻ', + 'ﮤ' => 'ۀ', + 'ﮥ' => 'ۀ', + 'ﮦ' => 'ہ', + 'ﮧ' => 'ہ', + 'ﮨ' => 'ہ', + 'ﮩ' => 'ہ', + 'ﮪ' => 'ھ', + 'ﮫ' => 'ھ', + 'ﮬ' => 'ھ', + 'ﮭ' => 'ھ', + 'ﮮ' => 'ے', + 'ﮯ' => 'ے', + 'ﮰ' => 'ۓ', + 'ﮱ' => 'ۓ', + 'ﯓ' => 'ڭ', + 'ﯔ' => 'ڭ', + 'ﯕ' => 'ڭ', + 'ﯖ' => 'ڭ', + 'ﯗ' => 'ۇ', + 'ﯘ' => 'ۇ', + 'ﯙ' => 'ۆ', + 'ﯚ' => 'ۆ', + 'ﯛ' => 'ۈ', + 'ﯜ' => 'ۈ', + 'ﯝ' => 'ۇٴ', + 'ﯞ' => 'ۋ', + 'ﯟ' => 'ۋ', + 'ﯠ' => 'ۅ', + 'ﯡ' => 'ۅ', + 'ﯢ' => 'ۉ', + 'ﯣ' => 'ۉ', + 'ﯤ' => 'ې', + 'ﯥ' => 'ې', + 'ﯦ' => 'ې', + 'ﯧ' => 'ې', + 'ﯨ' => 'ى', + 'ﯩ' => 'ى', + 'ﯪ' => 'ئا', + 'ﯫ' => 'ئا', + 'ﯬ' => 'ئە', + 'ﯭ' => 'ئە', + 'ﯮ' => 'ئو', + 'ﯯ' => 'ئو', + 'ﯰ' => 'ئۇ', + 'ﯱ' => 'ئۇ', + 'ﯲ' => 'ئۆ', + 'ﯳ' => 'ئۆ', + 'ﯴ' => 'ئۈ', + 'ﯵ' => 'ئۈ', + 'ﯶ' => 'ئې', + 'ﯷ' => 'ئې', + 'ﯸ' => 'ئې', + 'ﯹ' => 'ئى', + 'ﯺ' => 'ئى', + 'ﯻ' => 'ئى', + 'ﯼ' => 'ی', + 'ﯽ' => 'ی', + 'ﯾ' => 'ی', + 'ﯿ' => 'ی', + 'ﰀ' => 'ئج', + 'ﰁ' => 'ئح', + 'ﰂ' => 'ئم', + 'ﰃ' => 'ئى', + 'ﰄ' => 'ئي', + 'ﰅ' => 'بج', + 'ﰆ' => 'بح', + 'ﰇ' => 'بخ', + 'ﰈ' => 'بم', + 'ﰉ' => 'بى', + 'ﰊ' => 'بي', + 'ﰋ' => 'تج', + 'ﰌ' => 'تح', + 'ﰍ' => 'تخ', + 'ﰎ' => 'تم', + 'ﰏ' => 'تى', + 'ﰐ' => 'تي', + 'ﰑ' => 'ثج', + 'ﰒ' => 'ثم', + 'ﰓ' => 'ثى', + 'ﰔ' => 'ثي', + 'ﰕ' => 'جح', + 'ﰖ' => 'جم', + 'ﰗ' => 'حج', + 'ﰘ' => 'حم', + 'ﰙ' => 'خج', + 'ﰚ' => 'خح', + 'ﰛ' => 'خم', + 'ﰜ' => 'سج', + 'ﰝ' => 'سح', + 'ﰞ' => 'سخ', + 'ﰟ' => 'سم', + 'ﰠ' => 'صح', + 'ﰡ' => 'صم', + 'ﰢ' => 'ضج', + 'ﰣ' => 'ضح', + 'ﰤ' => 'ضخ', + 'ﰥ' => 'ضم', + 'ﰦ' => 'طح', + 'ﰧ' => 'طم', + 'ﰨ' => 'ظم', + 'ﰩ' => 'عج', + 'ﰪ' => 'عم', + 'ﰫ' => 'غج', + 'ﰬ' => 'غم', + 'ﰭ' => 'فج', + 'ﰮ' => 'فح', + 'ﰯ' => 'فخ', + 'ﰰ' => 'فم', + 'ﰱ' => 'فى', + 'ﰲ' => 'في', + 'ﰳ' => 'قح', + 'ﰴ' => 'قم', + 'ﰵ' => 'قى', + 'ﰶ' => 'قي', + 'ﰷ' => 'كا', + 'ﰸ' => 'كج', + 'ﰹ' => 'كح', + 'ﰺ' => 'كخ', + 'ﰻ' => 'كل', + 'ﰼ' => 'كم', + 'ﰽ' => 'كى', + 'ﰾ' => 'كي', + 'ﰿ' => 'لج', + 'ﱀ' => 'لح', + 'ﱁ' => 'لخ', + 'ﱂ' => 'لم', + 'ﱃ' => 'لى', + 'ﱄ' => 'لي', + 'ﱅ' => 'مج', + 'ﱆ' => 'مح', + 'ﱇ' => 'مخ', + 'ﱈ' => 'مم', + 'ﱉ' => 'مى', + 'ﱊ' => 'مي', + 'ﱋ' => 'نج', + 'ﱌ' => 'نح', + 'ﱍ' => 'نخ', + 'ﱎ' => 'نم', + 'ﱏ' => 'نى', + 'ﱐ' => 'ني', + 'ﱑ' => 'هج', + 'ﱒ' => 'هم', + 'ﱓ' => 'هى', + 'ﱔ' => 'هي', + 'ﱕ' => 'يج', + 'ﱖ' => 'يح', + 'ﱗ' => 'يخ', + 'ﱘ' => 'يم', + 'ﱙ' => 'يى', + 'ﱚ' => 'يي', + 'ﱛ' => 'ذٰ', + 'ﱜ' => 'رٰ', + 'ﱝ' => 'ىٰ', + 'ﱞ' => ' ٌّ', + 'ﱟ' => ' ٍّ', + 'ﱠ' => ' َّ', + 'ﱡ' => ' ُّ', + 'ﱢ' => ' ِّ', + 'ﱣ' => ' ّٰ', + 'ﱤ' => 'ئر', + 'ﱥ' => 'ئز', + 'ﱦ' => 'ئم', + 'ﱧ' => 'ئن', + 'ﱨ' => 'ئى', + 'ﱩ' => 'ئي', + 'ﱪ' => 'بر', + 'ﱫ' => 'بز', + 'ﱬ' => 'بم', + 'ﱭ' => 'بن', + 'ﱮ' => 'بى', + 'ﱯ' => 'بي', + 'ﱰ' => 'تر', + 'ﱱ' => 'تز', + 'ﱲ' => 'تم', + 'ﱳ' => 'تن', + 'ﱴ' => 'تى', + 'ﱵ' => 'تي', + 'ﱶ' => 'ثر', + 'ﱷ' => 'ثز', + 'ﱸ' => 'ثم', + 'ﱹ' => 'ثن', + 'ﱺ' => 'ثى', + 'ﱻ' => 'ثي', + 'ﱼ' => 'فى', + 'ﱽ' => 'في', + 'ﱾ' => 'قى', + 'ﱿ' => 'قي', + 'ﲀ' => 'كا', + 'ﲁ' => 'كل', + 'ﲂ' => 'كم', + 'ﲃ' => 'كى', + 'ﲄ' => 'كي', + 'ﲅ' => 'لم', + 'ﲆ' => 'لى', + 'ﲇ' => 'لي', + 'ﲈ' => 'ما', + 'ﲉ' => 'مم', + 'ﲊ' => 'نر', + 'ﲋ' => 'نز', + 'ﲌ' => 'نم', + 'ﲍ' => 'نن', + 'ﲎ' => 'نى', + 'ﲏ' => 'ني', + 'ﲐ' => 'ىٰ', + 'ﲑ' => 'ير', + 'ﲒ' => 'يز', + 'ﲓ' => 'يم', + 'ﲔ' => 'ين', + 'ﲕ' => 'يى', + 'ﲖ' => 'يي', + 'ﲗ' => 'ئج', + 'ﲘ' => 'ئح', + 'ﲙ' => 'ئخ', + 'ﲚ' => 'ئم', + 'ﲛ' => 'ئه', + 'ﲜ' => 'بج', + 'ﲝ' => 'بح', + 'ﲞ' => 'بخ', + 'ﲟ' => 'بم', + 'ﲠ' => 'به', + 'ﲡ' => 'تج', + 'ﲢ' => 'تح', + 'ﲣ' => 'تخ', + 'ﲤ' => 'تم', + 'ﲥ' => 'ته', + 'ﲦ' => 'ثم', + 'ﲧ' => 'جح', + 'ﲨ' => 'جم', + 'ﲩ' => 'حج', + 'ﲪ' => 'حم', + 'ﲫ' => 'خج', + 'ﲬ' => 'خم', + 'ﲭ' => 'سج', + 'ﲮ' => 'سح', + 'ﲯ' => 'سخ', + 'ﲰ' => 'سم', + 'ﲱ' => 'صح', + 'ﲲ' => 'صخ', + 'ﲳ' => 'صم', + 'ﲴ' => 'ضج', + 'ﲵ' => 'ضح', + 'ﲶ' => 'ضخ', + 'ﲷ' => 'ضم', + 'ﲸ' => 'طح', + 'ﲹ' => 'ظم', + 'ﲺ' => 'عج', + 'ﲻ' => 'عم', + 'ﲼ' => 'غج', + 'ﲽ' => 'غم', + 'ﲾ' => 'فج', + 'ﲿ' => 'فح', + 'ﳀ' => 'فخ', + 'ﳁ' => 'فم', + 'ﳂ' => 'قح', + 'ﳃ' => 'قم', + 'ﳄ' => 'كج', + 'ﳅ' => 'كح', + 'ﳆ' => 'كخ', + 'ﳇ' => 'كل', + 'ﳈ' => 'كم', + 'ﳉ' => 'لج', + 'ﳊ' => 'لح', + 'ﳋ' => 'لخ', + 'ﳌ' => 'لم', + 'ﳍ' => 'له', + 'ﳎ' => 'مج', + 'ﳏ' => 'مح', + 'ﳐ' => 'مخ', + 'ﳑ' => 'مم', + 'ﳒ' => 'نج', + 'ﳓ' => 'نح', + 'ﳔ' => 'نخ', + 'ﳕ' => 'نم', + 'ﳖ' => 'نه', + 'ﳗ' => 'هج', + 'ﳘ' => 'هم', + 'ﳙ' => 'هٰ', + 'ﳚ' => 'يج', + 'ﳛ' => 'يح', + 'ﳜ' => 'يخ', + 'ﳝ' => 'يم', + 'ﳞ' => 'يه', + 'ﳟ' => 'ئم', + 'ﳠ' => 'ئه', + 'ﳡ' => 'بم', + 'ﳢ' => 'به', + 'ﳣ' => 'تم', + 'ﳤ' => 'ته', + 'ﳥ' => 'ثم', + 'ﳦ' => 'ثه', + 'ﳧ' => 'سم', + 'ﳨ' => 'سه', + 'ﳩ' => 'شم', + 'ﳪ' => 'شه', + 'ﳫ' => 'كل', + 'ﳬ' => 'كم', + 'ﳭ' => 'لم', + 'ﳮ' => 'نم', + 'ﳯ' => 'نه', + 'ﳰ' => 'يم', + 'ﳱ' => 'يه', + 'ﳲ' => 'ـَّ', + 'ﳳ' => 'ـُّ', + 'ﳴ' => 'ـِّ', + 'ﳵ' => 'طى', + 'ﳶ' => 'طي', + 'ﳷ' => 'عى', + 'ﳸ' => 'عي', + 'ﳹ' => 'غى', + 'ﳺ' => 'غي', + 'ﳻ' => 'سى', + 'ﳼ' => 'سي', + 'ﳽ' => 'شى', + 'ﳾ' => 'شي', + 'ﳿ' => 'حى', + 'ﴀ' => 'حي', + 'ﴁ' => 'جى', + 'ﴂ' => 'جي', + 'ﴃ' => 'خى', + 'ﴄ' => 'خي', + 'ﴅ' => 'صى', + 'ﴆ' => 'صي', + 'ﴇ' => 'ضى', + 'ﴈ' => 'ضي', + 'ﴉ' => 'شج', + 'ﴊ' => 'شح', + 'ﴋ' => 'شخ', + 'ﴌ' => 'شم', + 'ﴍ' => 'شر', + 'ﴎ' => 'سر', + 'ﴏ' => 'صر', + 'ﴐ' => 'ضر', + 'ﴑ' => 'طى', + 'ﴒ' => 'طي', + 'ﴓ' => 'عى', + 'ﴔ' => 'عي', + 'ﴕ' => 'غى', + 'ﴖ' => 'غي', + 'ﴗ' => 'سى', + 'ﴘ' => 'سي', + 'ﴙ' => 'شى', + 'ﴚ' => 'شي', + 'ﴛ' => 'حى', + 'ﴜ' => 'حي', + 'ﴝ' => 'جى', + 'ﴞ' => 'جي', + 'ﴟ' => 'خى', + 'ﴠ' => 'خي', + 'ﴡ' => 'صى', + 'ﴢ' => 'صي', + 'ﴣ' => 'ضى', + 'ﴤ' => 'ضي', + 'ﴥ' => 'شج', + 'ﴦ' => 'شح', + 'ﴧ' => 'شخ', + 'ﴨ' => 'شم', + 'ﴩ' => 'شر', + 'ﴪ' => 'سر', + 'ﴫ' => 'صر', + 'ﴬ' => 'ضر', + 'ﴭ' => 'شج', + 'ﴮ' => 'شح', + 'ﴯ' => 'شخ', + 'ﴰ' => 'شم', + 'ﴱ' => 'سه', + 'ﴲ' => 'شه', + 'ﴳ' => 'طم', + 'ﴴ' => 'سج', + 'ﴵ' => 'سح', + 'ﴶ' => 'سخ', + 'ﴷ' => 'شج', + 'ﴸ' => 'شح', + 'ﴹ' => 'شخ', + 'ﴺ' => 'طم', + 'ﴻ' => 'ظم', + 'ﴼ' => 'اً', + 'ﴽ' => 'اً', + 'ﵐ' => 'تجم', + 'ﵑ' => 'تحج', + 'ﵒ' => 'تحج', + 'ﵓ' => 'تحم', + 'ﵔ' => 'تخم', + 'ﵕ' => 'تمج', + 'ﵖ' => 'تمح', + 'ﵗ' => 'تمخ', + 'ﵘ' => 'جمح', + 'ﵙ' => 'جمح', + 'ﵚ' => 'حمي', + 'ﵛ' => 'حمى', + 'ﵜ' => 'سحج', + 'ﵝ' => 'سجح', + 'ﵞ' => 'سجى', + 'ﵟ' => 'سمح', + 'ﵠ' => 'سمح', + 'ﵡ' => 'سمج', + 'ﵢ' => 'سمم', + 'ﵣ' => 'سمم', + 'ﵤ' => 'صحح', + 'ﵥ' => 'صحح', + 'ﵦ' => 'صمم', + 'ﵧ' => 'شحم', + 'ﵨ' => 'شحم', + 'ﵩ' => 'شجي', + 'ﵪ' => 'شمخ', + 'ﵫ' => 'شمخ', + 'ﵬ' => 'شمم', + 'ﵭ' => 'شمم', + 'ﵮ' => 'ضحى', + 'ﵯ' => 'ضخم', + 'ﵰ' => 'ضخم', + 'ﵱ' => 'طمح', + 'ﵲ' => 'طمح', + 'ﵳ' => 'طمم', + 'ﵴ' => 'طمي', + 'ﵵ' => 'عجم', + 'ﵶ' => 'عمم', + 'ﵷ' => 'عمم', + 'ﵸ' => 'عمى', + 'ﵹ' => 'غمم', + 'ﵺ' => 'غمي', + 'ﵻ' => 'غمى', + 'ﵼ' => 'فخم', + 'ﵽ' => 'فخم', + 'ﵾ' => 'قمح', + 'ﵿ' => 'قمم', + 'ﶀ' => 'لحم', + 'ﶁ' => 'لحي', + 'ﶂ' => 'لحى', + 'ﶃ' => 'لجج', + 'ﶄ' => 'لجج', + 'ﶅ' => 'لخم', + 'ﶆ' => 'لخم', + 'ﶇ' => 'لمح', + 'ﶈ' => 'لمح', + 'ﶉ' => 'محج', + 'ﶊ' => 'محم', + 'ﶋ' => 'محي', + 'ﶌ' => 'مجح', + 'ﶍ' => 'مجم', + 'ﶎ' => 'مخج', + 'ﶏ' => 'مخم', + 'ﶒ' => 'مجخ', + 'ﶓ' => 'همج', + 'ﶔ' => 'همم', + 'ﶕ' => 'نحم', + 'ﶖ' => 'نحى', + 'ﶗ' => 'نجم', + 'ﶘ' => 'نجم', + 'ﶙ' => 'نجى', + 'ﶚ' => 'نمي', + 'ﶛ' => 'نمى', + 'ﶜ' => 'يمم', + 'ﶝ' => 'يمم', + 'ﶞ' => 'بخي', + 'ﶟ' => 'تجي', + 'ﶠ' => 'تجى', + 'ﶡ' => 'تخي', + 'ﶢ' => 'تخى', + 'ﶣ' => 'تمي', + 'ﶤ' => 'تمى', + 'ﶥ' => 'جمي', + 'ﶦ' => 'جحى', + 'ﶧ' => 'جمى', + 'ﶨ' => 'سخى', + 'ﶩ' => 'صحي', + 'ﶪ' => 'شحي', + 'ﶫ' => 'ضحي', + 'ﶬ' => 'لجي', + 'ﶭ' => 'لمي', + 'ﶮ' => 'يحي', + 'ﶯ' => 'يجي', + 'ﶰ' => 'يمي', + 'ﶱ' => 'ممي', + 'ﶲ' => 'قمي', + 'ﶳ' => 'نحي', + 'ﶴ' => 'قمح', + 'ﶵ' => 'لحم', + 'ﶶ' => 'عمي', + 'ﶷ' => 'كمي', + 'ﶸ' => 'نجح', + 'ﶹ' => 'مخي', + 'ﶺ' => 'لجم', + 'ﶻ' => 'كمم', + 'ﶼ' => 'لجم', + 'ﶽ' => 'نجح', + 'ﶾ' => 'جحي', + 'ﶿ' => 'حجي', + 'ﷀ' => 'مجي', + 'ﷁ' => 'فمي', + 'ﷂ' => 'بحي', + 'ﷃ' => 'كمم', + 'ﷄ' => 'عجم', + 'ﷅ' => 'صمم', + 'ﷆ' => 'سخي', + 'ﷇ' => 'نجي', + 'ﷰ' => 'صلے', + 'ﷱ' => 'قلے', + 'ﷲ' => 'الله', + 'ﷳ' => 'اكبر', + 'ﷴ' => 'محمد', + 'ﷵ' => 'صلعم', + 'ﷶ' => 'رسول', + 'ﷷ' => 'عليه', + 'ﷸ' => 'وسلم', + 'ﷹ' => 'صلى', + 'ﷺ' => 'صلى الله عليه وسلم', + 'ﷻ' => 'جل جلاله', + '﷼' => 'ریال', + '︐' => ',', + '︑' => '、', + '︒' => '。', + '︓' => ':', + '︔' => ';', + '︕' => '!', + '︖' => '?', + '︗' => '〖', + '︘' => '〗', + '︙' => '...', + '︰' => '..', + '︱' => '—', + '︲' => '–', + '︳' => '_', + '︴' => '_', + '︵' => '(', + '︶' => ')', + '︷' => '{', + '︸' => '}', + '︹' => '〔', + '︺' => '〕', + '︻' => '【', + '︼' => '】', + '︽' => '《', + '︾' => '》', + '︿' => '〈', + '﹀' => '〉', + '﹁' => '「', + '﹂' => '」', + '﹃' => '『', + '﹄' => '』', + '﹇' => '[', + '﹈' => ']', + '﹉' => ' ̅', + '﹊' => ' ̅', + '﹋' => ' ̅', + '﹌' => ' ̅', + '﹍' => '_', + '﹎' => '_', + '﹏' => '_', + '﹐' => ',', + '﹑' => '、', + '﹒' => '.', + '﹔' => ';', + '﹕' => ':', + '﹖' => '?', + '﹗' => '!', + '﹘' => '—', + '﹙' => '(', + '﹚' => ')', + '﹛' => '{', + '﹜' => '}', + '﹝' => '〔', + '﹞' => '〕', + '﹟' => '#', + '﹠' => '&', + '﹡' => '*', + '﹢' => '+', + '﹣' => '-', + '﹤' => '<', + '﹥' => '>', + '﹦' => '=', + '﹨' => '\\', + '﹩' => '$', + '﹪' => '%', + '﹫' => '@', + 'ﹰ' => ' ً', + 'ﹱ' => 'ـً', + 'ﹲ' => ' ٌ', + 'ﹴ' => ' ٍ', + 'ﹶ' => ' َ', + 'ﹷ' => 'ـَ', + 'ﹸ' => ' ُ', + 'ﹹ' => 'ـُ', + 'ﹺ' => ' ِ', + 'ﹻ' => 'ـِ', + 'ﹼ' => ' ّ', + 'ﹽ' => 'ـّ', + 'ﹾ' => ' ْ', + 'ﹿ' => 'ـْ', + 'ﺀ' => 'ء', + 'ﺁ' => 'آ', + 'ﺂ' => 'آ', + 'ﺃ' => 'أ', + 'ﺄ' => 'أ', + 'ﺅ' => 'ؤ', + 'ﺆ' => 'ؤ', + 'ﺇ' => 'إ', + 'ﺈ' => 'إ', + 'ﺉ' => 'ئ', + 'ﺊ' => 'ئ', + 'ﺋ' => 'ئ', + 'ﺌ' => 'ئ', + 'ﺍ' => 'ا', + 'ﺎ' => 'ا', + 'ﺏ' => 'ب', + 'ﺐ' => 'ب', + 'ﺑ' => 'ب', + 'ﺒ' => 'ب', + 'ﺓ' => 'ة', + 'ﺔ' => 'ة', + 'ﺕ' => 'ت', + 'ﺖ' => 'ت', + 'ﺗ' => 'ت', + 'ﺘ' => 'ت', + 'ﺙ' => 'ث', + 'ﺚ' => 'ث', + 'ﺛ' => 'ث', + 'ﺜ' => 'ث', + 'ﺝ' => 'ج', + 'ﺞ' => 'ج', + 'ﺟ' => 'ج', + 'ﺠ' => 'ج', + 'ﺡ' => 'ح', + 'ﺢ' => 'ح', + 'ﺣ' => 'ح', + 'ﺤ' => 'ح', + 'ﺥ' => 'خ', + 'ﺦ' => 'خ', + 'ﺧ' => 'خ', + 'ﺨ' => 'خ', + 'ﺩ' => 'د', + 'ﺪ' => 'د', + 'ﺫ' => 'ذ', + 'ﺬ' => 'ذ', + 'ﺭ' => 'ر', + 'ﺮ' => 'ر', + 'ﺯ' => 'ز', + 'ﺰ' => 'ز', + 'ﺱ' => 'س', + 'ﺲ' => 'س', + 'ﺳ' => 'س', + 'ﺴ' => 'س', + 'ﺵ' => 'ش', + 'ﺶ' => 'ش', + 'ﺷ' => 'ش', + 'ﺸ' => 'ش', + 'ﺹ' => 'ص', + 'ﺺ' => 'ص', + 'ﺻ' => 'ص', + 'ﺼ' => 'ص', + 'ﺽ' => 'ض', + 'ﺾ' => 'ض', + 'ﺿ' => 'ض', + 'ﻀ' => 'ض', + 'ﻁ' => 'ط', + 'ﻂ' => 'ط', + 'ﻃ' => 'ط', + 'ﻄ' => 'ط', + 'ﻅ' => 'ظ', + 'ﻆ' => 'ظ', + 'ﻇ' => 'ظ', + 'ﻈ' => 'ظ', + 'ﻉ' => 'ع', + 'ﻊ' => 'ع', + 'ﻋ' => 'ع', + 'ﻌ' => 'ع', + 'ﻍ' => 'غ', + 'ﻎ' => 'غ', + 'ﻏ' => 'غ', + 'ﻐ' => 'غ', + 'ﻑ' => 'ف', + 'ﻒ' => 'ف', + 'ﻓ' => 'ف', + 'ﻔ' => 'ف', + 'ﻕ' => 'ق', + 'ﻖ' => 'ق', + 'ﻗ' => 'ق', + 'ﻘ' => 'ق', + 'ﻙ' => 'ك', + 'ﻚ' => 'ك', + 'ﻛ' => 'ك', + 'ﻜ' => 'ك', + 'ﻝ' => 'ل', + 'ﻞ' => 'ل', + 'ﻟ' => 'ل', + 'ﻠ' => 'ل', + 'ﻡ' => 'م', + 'ﻢ' => 'م', + 'ﻣ' => 'م', + 'ﻤ' => 'م', + 'ﻥ' => 'ن', + 'ﻦ' => 'ن', + 'ﻧ' => 'ن', + 'ﻨ' => 'ن', + 'ﻩ' => 'ه', + 'ﻪ' => 'ه', + 'ﻫ' => 'ه', + 'ﻬ' => 'ه', + 'ﻭ' => 'و', + 'ﻮ' => 'و', + 'ﻯ' => 'ى', + 'ﻰ' => 'ى', + 'ﻱ' => 'ي', + 'ﻲ' => 'ي', + 'ﻳ' => 'ي', + 'ﻴ' => 'ي', + 'ﻵ' => 'لآ', + 'ﻶ' => 'لآ', + 'ﻷ' => 'لأ', + 'ﻸ' => 'لأ', + 'ﻹ' => 'لإ', + 'ﻺ' => 'لإ', + 'ﻻ' => 'لا', + 'ﻼ' => 'لا', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + ''' => '\'', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '-' => '-', + '.' => '.', + '/' => '/', + '0' => '0', + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + '7' => '7', + '8' => '8', + '9' => '9', + ':' => ':', + ';' => ';', + '<' => '<', + '=' => '=', + '>' => '>', + '?' => '?', + '@' => '@', + 'A' => 'A', + 'B' => 'B', + 'C' => 'C', + 'D' => 'D', + 'E' => 'E', + 'F' => 'F', + 'G' => 'G', + 'H' => 'H', + 'I' => 'I', + 'J' => 'J', + 'K' => 'K', + 'L' => 'L', + 'M' => 'M', + 'N' => 'N', + 'O' => 'O', + 'P' => 'P', + 'Q' => 'Q', + 'R' => 'R', + 'S' => 'S', + 'T' => 'T', + 'U' => 'U', + 'V' => 'V', + 'W' => 'W', + 'X' => 'X', + 'Y' => 'Y', + 'Z' => 'Z', + '[' => '[', + '\' => '\\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'a' => 'a', + 'b' => 'b', + 'c' => 'c', + 'd' => 'd', + 'e' => 'e', + 'f' => 'f', + 'g' => 'g', + 'h' => 'h', + 'i' => 'i', + 'j' => 'j', + 'k' => 'k', + 'l' => 'l', + 'm' => 'm', + 'n' => 'n', + 'o' => 'o', + 'p' => 'p', + 'q' => 'q', + 'r' => 'r', + 's' => 's', + 't' => 't', + 'u' => 'u', + 'v' => 'v', + 'w' => 'w', + 'x' => 'x', + 'y' => 'y', + 'z' => 'z', + '{' => '{', + '|' => '|', + '}' => '}', + '~' => '~', + '⦅' => '⦅', + '⦆' => '⦆', + '。' => '。', + '「' => '「', + '」' => '」', + '、' => '、', + '・' => '・', + 'ヲ' => 'ヲ', + 'ァ' => 'ァ', + 'ィ' => 'ィ', + 'ゥ' => 'ゥ', + 'ェ' => 'ェ', + 'ォ' => 'ォ', + 'ャ' => 'ャ', + 'ュ' => 'ュ', + 'ョ' => 'ョ', + 'ッ' => 'ッ', + 'ー' => 'ー', + 'ア' => 'ア', + 'イ' => 'イ', + 'ウ' => 'ウ', + 'エ' => 'エ', + 'オ' => 'オ', + 'カ' => 'カ', + 'キ' => 'キ', + 'ク' => 'ク', + 'ケ' => 'ケ', + 'コ' => 'コ', + 'サ' => 'サ', + 'シ' => 'シ', + 'ス' => 'ス', + 'セ' => 'セ', + 'ソ' => 'ソ', + 'タ' => 'タ', + 'チ' => 'チ', + 'ツ' => 'ツ', + 'テ' => 'テ', + 'ト' => 'ト', + 'ナ' => 'ナ', + 'ニ' => 'ニ', + 'ヌ' => 'ヌ', + 'ネ' => 'ネ', + 'ノ' => 'ノ', + 'ハ' => 'ハ', + 'ヒ' => 'ヒ', + 'フ' => 'フ', + 'ヘ' => 'ヘ', + 'ホ' => 'ホ', + 'マ' => 'マ', + 'ミ' => 'ミ', + 'ム' => 'ム', + 'メ' => 'メ', + 'モ' => 'モ', + 'ヤ' => 'ヤ', + 'ユ' => 'ユ', + 'ヨ' => 'ヨ', + 'ラ' => 'ラ', + 'リ' => 'リ', + 'ル' => 'ル', + 'レ' => 'レ', + 'ロ' => 'ロ', + 'ワ' => 'ワ', + 'ン' => 'ン', + '゙' => '゙', + '゚' => '゚', + 'ᅠ' => 'ᅠ', + 'ᄀ' => 'ᄀ', + 'ᄁ' => 'ᄁ', + 'ᆪ' => 'ᆪ', + 'ᄂ' => 'ᄂ', + 'ᆬ' => 'ᆬ', + 'ᆭ' => 'ᆭ', + 'ᄃ' => 'ᄃ', + 'ᄄ' => 'ᄄ', + 'ᄅ' => 'ᄅ', + 'ᆰ' => 'ᆰ', + 'ᆱ' => 'ᆱ', + 'ᆲ' => 'ᆲ', + 'ᆳ' => 'ᆳ', + 'ᆴ' => 'ᆴ', + 'ᆵ' => 'ᆵ', + 'ᄚ' => 'ᄚ', + 'ᄆ' => 'ᄆ', + 'ᄇ' => 'ᄇ', + 'ᄈ' => 'ᄈ', + 'ᄡ' => 'ᄡ', + 'ᄉ' => 'ᄉ', + 'ᄊ' => 'ᄊ', + 'ᄋ' => 'ᄋ', + 'ᄌ' => 'ᄌ', + 'ᄍ' => 'ᄍ', + 'ᄎ' => 'ᄎ', + 'ᄏ' => 'ᄏ', + 'ᄐ' => 'ᄐ', + 'ᄑ' => 'ᄑ', + 'ᄒ' => 'ᄒ', + 'ᅡ' => 'ᅡ', + 'ᅢ' => 'ᅢ', + 'ᅣ' => 'ᅣ', + 'ᅤ' => 'ᅤ', + 'ᅥ' => 'ᅥ', + 'ᅦ' => 'ᅦ', + 'ᅧ' => 'ᅧ', + 'ᅨ' => 'ᅨ', + 'ᅩ' => 'ᅩ', + 'ᅪ' => 'ᅪ', + 'ᅫ' => 'ᅫ', + 'ᅬ' => 'ᅬ', + 'ᅭ' => 'ᅭ', + 'ᅮ' => 'ᅮ', + 'ᅯ' => 'ᅯ', + 'ᅰ' => 'ᅰ', + 'ᅱ' => 'ᅱ', + 'ᅲ' => 'ᅲ', + 'ᅳ' => 'ᅳ', + 'ᅴ' => 'ᅴ', + 'ᅵ' => 'ᅵ', + '¢' => '¢', + '£' => '£', + '¬' => '¬', + ' ̄' => ' ̄', + '¦' => '¦', + '¥' => '¥', + '₩' => '₩', + '│' => '│', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '■' => '■', + '○' => '○', + '𝐀' => 'A', + '𝐁' => 'B', + '𝐂' => 'C', + '𝐃' => 'D', + '𝐄' => 'E', + '𝐅' => 'F', + '𝐆' => 'G', + '𝐇' => 'H', + '𝐈' => 'I', + '𝐉' => 'J', + '𝐊' => 'K', + '𝐋' => 'L', + '𝐌' => 'M', + '𝐍' => 'N', + '𝐎' => 'O', + '𝐏' => 'P', + '𝐐' => 'Q', + '𝐑' => 'R', + '𝐒' => 'S', + '𝐓' => 'T', + '𝐔' => 'U', + '𝐕' => 'V', + '𝐖' => 'W', + '𝐗' => 'X', + '𝐘' => 'Y', + '𝐙' => 'Z', + '𝐚' => 'a', + '𝐛' => 'b', + '𝐜' => 'c', + '𝐝' => 'd', + '𝐞' => 'e', + '𝐟' => 'f', + '𝐠' => 'g', + '𝐡' => 'h', + '𝐢' => 'i', + '𝐣' => 'j', + '𝐤' => 'k', + '𝐥' => 'l', + '𝐦' => 'm', + '𝐧' => 'n', + '𝐨' => 'o', + '𝐩' => 'p', + '𝐪' => 'q', + '𝐫' => 'r', + '𝐬' => 's', + '𝐭' => 't', + '𝐮' => 'u', + '𝐯' => 'v', + '𝐰' => 'w', + '𝐱' => 'x', + '𝐲' => 'y', + '𝐳' => 'z', + '𝐴' => 'A', + '𝐵' => 'B', + '𝐶' => 'C', + '𝐷' => 'D', + '𝐸' => 'E', + '𝐹' => 'F', + '𝐺' => 'G', + '𝐻' => 'H', + '𝐼' => 'I', + '𝐽' => 'J', + '𝐾' => 'K', + '𝐿' => 'L', + '𝑀' => 'M', + '𝑁' => 'N', + '𝑂' => 'O', + '𝑃' => 'P', + '𝑄' => 'Q', + '𝑅' => 'R', + '𝑆' => 'S', + '𝑇' => 'T', + '𝑈' => 'U', + '𝑉' => 'V', + '𝑊' => 'W', + '𝑋' => 'X', + '𝑌' => 'Y', + '𝑍' => 'Z', + '𝑎' => 'a', + '𝑏' => 'b', + '𝑐' => 'c', + '𝑑' => 'd', + '𝑒' => 'e', + '𝑓' => 'f', + '𝑔' => 'g', + '𝑖' => 'i', + '𝑗' => 'j', + '𝑘' => 'k', + '𝑙' => 'l', + '𝑚' => 'm', + '𝑛' => 'n', + '𝑜' => 'o', + '𝑝' => 'p', + '𝑞' => 'q', + '𝑟' => 'r', + '𝑠' => 's', + '𝑡' => 't', + '𝑢' => 'u', + '𝑣' => 'v', + '𝑤' => 'w', + '𝑥' => 'x', + '𝑦' => 'y', + '𝑧' => 'z', + '𝑨' => 'A', + '𝑩' => 'B', + '𝑪' => 'C', + '𝑫' => 'D', + '𝑬' => 'E', + '𝑭' => 'F', + '𝑮' => 'G', + '𝑯' => 'H', + '𝑰' => 'I', + '𝑱' => 'J', + '𝑲' => 'K', + '𝑳' => 'L', + '𝑴' => 'M', + '𝑵' => 'N', + '𝑶' => 'O', + '𝑷' => 'P', + '𝑸' => 'Q', + '𝑹' => 'R', + '𝑺' => 'S', + '𝑻' => 'T', + '𝑼' => 'U', + '𝑽' => 'V', + '𝑾' => 'W', + '𝑿' => 'X', + '𝒀' => 'Y', + '𝒁' => 'Z', + '𝒂' => 'a', + '𝒃' => 'b', + '𝒄' => 'c', + '𝒅' => 'd', + '𝒆' => 'e', + '𝒇' => 'f', + '𝒈' => 'g', + '𝒉' => 'h', + '𝒊' => 'i', + '𝒋' => 'j', + '𝒌' => 'k', + '𝒍' => 'l', + '𝒎' => 'm', + '𝒏' => 'n', + '𝒐' => 'o', + '𝒑' => 'p', + '𝒒' => 'q', + '𝒓' => 'r', + '𝒔' => 's', + '𝒕' => 't', + '𝒖' => 'u', + '𝒗' => 'v', + '𝒘' => 'w', + '𝒙' => 'x', + '𝒚' => 'y', + '𝒛' => 'z', + '𝒜' => 'A', + '𝒞' => 'C', + '𝒟' => 'D', + '𝒢' => 'G', + '𝒥' => 'J', + '𝒦' => 'K', + '𝒩' => 'N', + '𝒪' => 'O', + '𝒫' => 'P', + '𝒬' => 'Q', + '𝒮' => 'S', + '𝒯' => 'T', + '𝒰' => 'U', + '𝒱' => 'V', + '𝒲' => 'W', + '𝒳' => 'X', + '𝒴' => 'Y', + '𝒵' => 'Z', + '𝒶' => 'a', + '𝒷' => 'b', + '𝒸' => 'c', + '𝒹' => 'd', + '𝒻' => 'f', + '𝒽' => 'h', + '𝒾' => 'i', + '𝒿' => 'j', + '𝓀' => 'k', + '𝓁' => 'l', + '𝓂' => 'm', + '𝓃' => 'n', + '𝓅' => 'p', + '𝓆' => 'q', + '𝓇' => 'r', + '𝓈' => 's', + '𝓉' => 't', + '𝓊' => 'u', + '𝓋' => 'v', + '𝓌' => 'w', + '𝓍' => 'x', + '𝓎' => 'y', + '𝓏' => 'z', + '𝓐' => 'A', + '𝓑' => 'B', + '𝓒' => 'C', + '𝓓' => 'D', + '𝓔' => 'E', + '𝓕' => 'F', + '𝓖' => 'G', + '𝓗' => 'H', + '𝓘' => 'I', + '𝓙' => 'J', + '𝓚' => 'K', + '𝓛' => 'L', + '𝓜' => 'M', + '𝓝' => 'N', + '𝓞' => 'O', + '𝓟' => 'P', + '𝓠' => 'Q', + '𝓡' => 'R', + '𝓢' => 'S', + '𝓣' => 'T', + '𝓤' => 'U', + '𝓥' => 'V', + '𝓦' => 'W', + '𝓧' => 'X', + '𝓨' => 'Y', + '𝓩' => 'Z', + '𝓪' => 'a', + '𝓫' => 'b', + '𝓬' => 'c', + '𝓭' => 'd', + '𝓮' => 'e', + '𝓯' => 'f', + '𝓰' => 'g', + '𝓱' => 'h', + '𝓲' => 'i', + '𝓳' => 'j', + '𝓴' => 'k', + '𝓵' => 'l', + '𝓶' => 'm', + '𝓷' => 'n', + '𝓸' => 'o', + '𝓹' => 'p', + '𝓺' => 'q', + '𝓻' => 'r', + '𝓼' => 's', + '𝓽' => 't', + '𝓾' => 'u', + '𝓿' => 'v', + '𝔀' => 'w', + '𝔁' => 'x', + '𝔂' => 'y', + '𝔃' => 'z', + '𝔄' => 'A', + '𝔅' => 'B', + '𝔇' => 'D', + '𝔈' => 'E', + '𝔉' => 'F', + '𝔊' => 'G', + '𝔍' => 'J', + '𝔎' => 'K', + '𝔏' => 'L', + '𝔐' => 'M', + '𝔑' => 'N', + '𝔒' => 'O', + '𝔓' => 'P', + '𝔔' => 'Q', + '𝔖' => 'S', + '𝔗' => 'T', + '𝔘' => 'U', + '𝔙' => 'V', + '𝔚' => 'W', + '𝔛' => 'X', + '𝔜' => 'Y', + '𝔞' => 'a', + '𝔟' => 'b', + '𝔠' => 'c', + '𝔡' => 'd', + '𝔢' => 'e', + '𝔣' => 'f', + '𝔤' => 'g', + '𝔥' => 'h', + '𝔦' => 'i', + '𝔧' => 'j', + '𝔨' => 'k', + '𝔩' => 'l', + '𝔪' => 'm', + '𝔫' => 'n', + '𝔬' => 'o', + '𝔭' => 'p', + '𝔮' => 'q', + '𝔯' => 'r', + '𝔰' => 's', + '𝔱' => 't', + '𝔲' => 'u', + '𝔳' => 'v', + '𝔴' => 'w', + '𝔵' => 'x', + '𝔶' => 'y', + '𝔷' => 'z', + '𝔸' => 'A', + '𝔹' => 'B', + '𝔻' => 'D', + '𝔼' => 'E', + '𝔽' => 'F', + '𝔾' => 'G', + '𝕀' => 'I', + '𝕁' => 'J', + '𝕂' => 'K', + '𝕃' => 'L', + '𝕄' => 'M', + '𝕆' => 'O', + '𝕊' => 'S', + '𝕋' => 'T', + '𝕌' => 'U', + '𝕍' => 'V', + '𝕎' => 'W', + '𝕏' => 'X', + '𝕐' => 'Y', + '𝕒' => 'a', + '𝕓' => 'b', + '𝕔' => 'c', + '𝕕' => 'd', + '𝕖' => 'e', + '𝕗' => 'f', + '𝕘' => 'g', + '𝕙' => 'h', + '𝕚' => 'i', + '𝕛' => 'j', + '𝕜' => 'k', + '𝕝' => 'l', + '𝕞' => 'm', + '𝕟' => 'n', + '𝕠' => 'o', + '𝕡' => 'p', + '𝕢' => 'q', + '𝕣' => 'r', + '𝕤' => 's', + '𝕥' => 't', + '𝕦' => 'u', + '𝕧' => 'v', + '𝕨' => 'w', + '𝕩' => 'x', + '𝕪' => 'y', + '𝕫' => 'z', + '𝕬' => 'A', + '𝕭' => 'B', + '𝕮' => 'C', + '𝕯' => 'D', + '𝕰' => 'E', + '𝕱' => 'F', + '𝕲' => 'G', + '𝕳' => 'H', + '𝕴' => 'I', + '𝕵' => 'J', + '𝕶' => 'K', + '𝕷' => 'L', + '𝕸' => 'M', + '𝕹' => 'N', + '𝕺' => 'O', + '𝕻' => 'P', + '𝕼' => 'Q', + '𝕽' => 'R', + '𝕾' => 'S', + '𝕿' => 'T', + '𝖀' => 'U', + '𝖁' => 'V', + '𝖂' => 'W', + '𝖃' => 'X', + '𝖄' => 'Y', + '𝖅' => 'Z', + '𝖆' => 'a', + '𝖇' => 'b', + '𝖈' => 'c', + '𝖉' => 'd', + '𝖊' => 'e', + '𝖋' => 'f', + '𝖌' => 'g', + '𝖍' => 'h', + '𝖎' => 'i', + '𝖏' => 'j', + '𝖐' => 'k', + '𝖑' => 'l', + '𝖒' => 'm', + '𝖓' => 'n', + '𝖔' => 'o', + '𝖕' => 'p', + '𝖖' => 'q', + '𝖗' => 'r', + '𝖘' => 's', + '𝖙' => 't', + '𝖚' => 'u', + '𝖛' => 'v', + '𝖜' => 'w', + '𝖝' => 'x', + '𝖞' => 'y', + '𝖟' => 'z', + '𝖠' => 'A', + '𝖡' => 'B', + '𝖢' => 'C', + '𝖣' => 'D', + '𝖤' => 'E', + '𝖥' => 'F', + '𝖦' => 'G', + '𝖧' => 'H', + '𝖨' => 'I', + '𝖩' => 'J', + '𝖪' => 'K', + '𝖫' => 'L', + '𝖬' => 'M', + '𝖭' => 'N', + '𝖮' => 'O', + '𝖯' => 'P', + '𝖰' => 'Q', + '𝖱' => 'R', + '𝖲' => 'S', + '𝖳' => 'T', + '𝖴' => 'U', + '𝖵' => 'V', + '𝖶' => 'W', + '𝖷' => 'X', + '𝖸' => 'Y', + '𝖹' => 'Z', + '𝖺' => 'a', + '𝖻' => 'b', + '𝖼' => 'c', + '𝖽' => 'd', + '𝖾' => 'e', + '𝖿' => 'f', + '𝗀' => 'g', + '𝗁' => 'h', + '𝗂' => 'i', + '𝗃' => 'j', + '𝗄' => 'k', + '𝗅' => 'l', + '𝗆' => 'm', + '𝗇' => 'n', + '𝗈' => 'o', + '𝗉' => 'p', + '𝗊' => 'q', + '𝗋' => 'r', + '𝗌' => 's', + '𝗍' => 't', + '𝗎' => 'u', + '𝗏' => 'v', + '𝗐' => 'w', + '𝗑' => 'x', + '𝗒' => 'y', + '𝗓' => 'z', + '𝗔' => 'A', + '𝗕' => 'B', + '𝗖' => 'C', + '𝗗' => 'D', + '𝗘' => 'E', + '𝗙' => 'F', + '𝗚' => 'G', + '𝗛' => 'H', + '𝗜' => 'I', + '𝗝' => 'J', + '𝗞' => 'K', + '𝗟' => 'L', + '𝗠' => 'M', + '𝗡' => 'N', + '𝗢' => 'O', + '𝗣' => 'P', + '𝗤' => 'Q', + '𝗥' => 'R', + '𝗦' => 'S', + '𝗧' => 'T', + '𝗨' => 'U', + '𝗩' => 'V', + '𝗪' => 'W', + '𝗫' => 'X', + '𝗬' => 'Y', + '𝗭' => 'Z', + '𝗮' => 'a', + '𝗯' => 'b', + '𝗰' => 'c', + '𝗱' => 'd', + '𝗲' => 'e', + '𝗳' => 'f', + '𝗴' => 'g', + '𝗵' => 'h', + '𝗶' => 'i', + '𝗷' => 'j', + '𝗸' => 'k', + '𝗹' => 'l', + '𝗺' => 'm', + '𝗻' => 'n', + '𝗼' => 'o', + '𝗽' => 'p', + '𝗾' => 'q', + '𝗿' => 'r', + '𝘀' => 's', + '𝘁' => 't', + '𝘂' => 'u', + '𝘃' => 'v', + '𝘄' => 'w', + '𝘅' => 'x', + '𝘆' => 'y', + '𝘇' => 'z', + '𝘈' => 'A', + '𝘉' => 'B', + '𝘊' => 'C', + '𝘋' => 'D', + '𝘌' => 'E', + '𝘍' => 'F', + '𝘎' => 'G', + '𝘏' => 'H', + '𝘐' => 'I', + '𝘑' => 'J', + '𝘒' => 'K', + '𝘓' => 'L', + '𝘔' => 'M', + '𝘕' => 'N', + '𝘖' => 'O', + '𝘗' => 'P', + '𝘘' => 'Q', + '𝘙' => 'R', + '𝘚' => 'S', + '𝘛' => 'T', + '𝘜' => 'U', + '𝘝' => 'V', + '𝘞' => 'W', + '𝘟' => 'X', + '𝘠' => 'Y', + '𝘡' => 'Z', + '𝘢' => 'a', + '𝘣' => 'b', + '𝘤' => 'c', + '𝘥' => 'd', + '𝘦' => 'e', + '𝘧' => 'f', + '𝘨' => 'g', + '𝘩' => 'h', + '𝘪' => 'i', + '𝘫' => 'j', + '𝘬' => 'k', + '𝘭' => 'l', + '𝘮' => 'm', + '𝘯' => 'n', + '𝘰' => 'o', + '𝘱' => 'p', + '𝘲' => 'q', + '𝘳' => 'r', + '𝘴' => 's', + '𝘵' => 't', + '𝘶' => 'u', + '𝘷' => 'v', + '𝘸' => 'w', + '𝘹' => 'x', + '𝘺' => 'y', + '𝘻' => 'z', + '𝘼' => 'A', + '𝘽' => 'B', + '𝘾' => 'C', + '𝘿' => 'D', + '𝙀' => 'E', + '𝙁' => 'F', + '𝙂' => 'G', + '𝙃' => 'H', + '𝙄' => 'I', + '𝙅' => 'J', + '𝙆' => 'K', + '𝙇' => 'L', + '𝙈' => 'M', + '𝙉' => 'N', + '𝙊' => 'O', + '𝙋' => 'P', + '𝙌' => 'Q', + '𝙍' => 'R', + '𝙎' => 'S', + '𝙏' => 'T', + '𝙐' => 'U', + '𝙑' => 'V', + '𝙒' => 'W', + '𝙓' => 'X', + '𝙔' => 'Y', + '𝙕' => 'Z', + '𝙖' => 'a', + '𝙗' => 'b', + '𝙘' => 'c', + '𝙙' => 'd', + '𝙚' => 'e', + '𝙛' => 'f', + '𝙜' => 'g', + '𝙝' => 'h', + '𝙞' => 'i', + '𝙟' => 'j', + '𝙠' => 'k', + '𝙡' => 'l', + '𝙢' => 'm', + '𝙣' => 'n', + '𝙤' => 'o', + '𝙥' => 'p', + '𝙦' => 'q', + '𝙧' => 'r', + '𝙨' => 's', + '𝙩' => 't', + '𝙪' => 'u', + '𝙫' => 'v', + '𝙬' => 'w', + '𝙭' => 'x', + '𝙮' => 'y', + '𝙯' => 'z', + '𝙰' => 'A', + '𝙱' => 'B', + '𝙲' => 'C', + '𝙳' => 'D', + '𝙴' => 'E', + '𝙵' => 'F', + '𝙶' => 'G', + '𝙷' => 'H', + '𝙸' => 'I', + '𝙹' => 'J', + '𝙺' => 'K', + '𝙻' => 'L', + '𝙼' => 'M', + '𝙽' => 'N', + '𝙾' => 'O', + '𝙿' => 'P', + '𝚀' => 'Q', + '𝚁' => 'R', + '𝚂' => 'S', + '𝚃' => 'T', + '𝚄' => 'U', + '𝚅' => 'V', + '𝚆' => 'W', + '𝚇' => 'X', + '𝚈' => 'Y', + '𝚉' => 'Z', + '𝚊' => 'a', + '𝚋' => 'b', + '𝚌' => 'c', + '𝚍' => 'd', + '𝚎' => 'e', + '𝚏' => 'f', + '𝚐' => 'g', + '𝚑' => 'h', + '𝚒' => 'i', + '𝚓' => 'j', + '𝚔' => 'k', + '𝚕' => 'l', + '𝚖' => 'm', + '𝚗' => 'n', + '𝚘' => 'o', + '𝚙' => 'p', + '𝚚' => 'q', + '𝚛' => 'r', + '𝚜' => 's', + '𝚝' => 't', + '𝚞' => 'u', + '𝚟' => 'v', + '𝚠' => 'w', + '𝚡' => 'x', + '𝚢' => 'y', + '𝚣' => 'z', + '𝚤' => 'ı', + '𝚥' => 'ȷ', + '𝚨' => 'Α', + '𝚩' => 'Β', + '𝚪' => 'Γ', + '𝚫' => 'Δ', + '𝚬' => 'Ε', + '𝚭' => 'Ζ', + '𝚮' => 'Η', + '𝚯' => 'Θ', + '𝚰' => 'Ι', + '𝚱' => 'Κ', + '𝚲' => 'Λ', + '𝚳' => 'Μ', + '𝚴' => 'Ν', + '𝚵' => 'Ξ', + '𝚶' => 'Ο', + '𝚷' => 'Π', + '𝚸' => 'Ρ', + '𝚹' => 'Θ', + '𝚺' => 'Σ', + '𝚻' => 'Τ', + '𝚼' => 'Υ', + '𝚽' => 'Φ', + '𝚾' => 'Χ', + '𝚿' => 'Ψ', + '𝛀' => 'Ω', + '𝛁' => '∇', + '𝛂' => 'α', + '𝛃' => 'β', + '𝛄' => 'γ', + '𝛅' => 'δ', + '𝛆' => 'ε', + '𝛇' => 'ζ', + '𝛈' => 'η', + '𝛉' => 'θ', + '𝛊' => 'ι', + '𝛋' => 'κ', + '𝛌' => 'λ', + '𝛍' => 'μ', + '𝛎' => 'ν', + '𝛏' => 'ξ', + '𝛐' => 'ο', + '𝛑' => 'π', + '𝛒' => 'ρ', + '𝛓' => 'ς', + '𝛔' => 'σ', + '𝛕' => 'τ', + '𝛖' => 'υ', + '𝛗' => 'φ', + '𝛘' => 'χ', + '𝛙' => 'ψ', + '𝛚' => 'ω', + '𝛛' => '∂', + '𝛜' => 'ε', + '𝛝' => 'θ', + '𝛞' => 'κ', + '𝛟' => 'φ', + '𝛠' => 'ρ', + '𝛡' => 'π', + '𝛢' => 'Α', + '𝛣' => 'Β', + '𝛤' => 'Γ', + '𝛥' => 'Δ', + '𝛦' => 'Ε', + '𝛧' => 'Ζ', + '𝛨' => 'Η', + '𝛩' => 'Θ', + '𝛪' => 'Ι', + '𝛫' => 'Κ', + '𝛬' => 'Λ', + '𝛭' => 'Μ', + '𝛮' => 'Ν', + '𝛯' => 'Ξ', + '𝛰' => 'Ο', + '𝛱' => 'Π', + '𝛲' => 'Ρ', + '𝛳' => 'Θ', + '𝛴' => 'Σ', + '𝛵' => 'Τ', + '𝛶' => 'Υ', + '𝛷' => 'Φ', + '𝛸' => 'Χ', + '𝛹' => 'Ψ', + '𝛺' => 'Ω', + '𝛻' => '∇', + '𝛼' => 'α', + '𝛽' => 'β', + '𝛾' => 'γ', + '𝛿' => 'δ', + '𝜀' => 'ε', + '𝜁' => 'ζ', + '𝜂' => 'η', + '𝜃' => 'θ', + '𝜄' => 'ι', + '𝜅' => 'κ', + '𝜆' => 'λ', + '𝜇' => 'μ', + '𝜈' => 'ν', + '𝜉' => 'ξ', + '𝜊' => 'ο', + '𝜋' => 'π', + '𝜌' => 'ρ', + '𝜍' => 'ς', + '𝜎' => 'σ', + '𝜏' => 'τ', + '𝜐' => 'υ', + '𝜑' => 'φ', + '𝜒' => 'χ', + '𝜓' => 'ψ', + '𝜔' => 'ω', + '𝜕' => '∂', + '𝜖' => 'ε', + '𝜗' => 'θ', + '𝜘' => 'κ', + '𝜙' => 'φ', + '𝜚' => 'ρ', + '𝜛' => 'π', + '𝜜' => 'Α', + '𝜝' => 'Β', + '𝜞' => 'Γ', + '𝜟' => 'Δ', + '𝜠' => 'Ε', + '𝜡' => 'Ζ', + '𝜢' => 'Η', + '𝜣' => 'Θ', + '𝜤' => 'Ι', + '𝜥' => 'Κ', + '𝜦' => 'Λ', + '𝜧' => 'Μ', + '𝜨' => 'Ν', + '𝜩' => 'Ξ', + '𝜪' => 'Ο', + '𝜫' => 'Π', + '𝜬' => 'Ρ', + '𝜭' => 'Θ', + '𝜮' => 'Σ', + '𝜯' => 'Τ', + '𝜰' => 'Υ', + '𝜱' => 'Φ', + '𝜲' => 'Χ', + '𝜳' => 'Ψ', + '𝜴' => 'Ω', + '𝜵' => '∇', + '𝜶' => 'α', + '𝜷' => 'β', + '𝜸' => 'γ', + '𝜹' => 'δ', + '𝜺' => 'ε', + '𝜻' => 'ζ', + '𝜼' => 'η', + '𝜽' => 'θ', + '𝜾' => 'ι', + '𝜿' => 'κ', + '𝝀' => 'λ', + '𝝁' => 'μ', + '𝝂' => 'ν', + '𝝃' => 'ξ', + '𝝄' => 'ο', + '𝝅' => 'π', + '𝝆' => 'ρ', + '𝝇' => 'ς', + '𝝈' => 'σ', + '𝝉' => 'τ', + '𝝊' => 'υ', + '𝝋' => 'φ', + '𝝌' => 'χ', + '𝝍' => 'ψ', + '𝝎' => 'ω', + '𝝏' => '∂', + '𝝐' => 'ε', + '𝝑' => 'θ', + '𝝒' => 'κ', + '𝝓' => 'φ', + '𝝔' => 'ρ', + '𝝕' => 'π', + '𝝖' => 'Α', + '𝝗' => 'Β', + '𝝘' => 'Γ', + '𝝙' => 'Δ', + '𝝚' => 'Ε', + '𝝛' => 'Ζ', + '𝝜' => 'Η', + '𝝝' => 'Θ', + '𝝞' => 'Ι', + '𝝟' => 'Κ', + '𝝠' => 'Λ', + '𝝡' => 'Μ', + '𝝢' => 'Ν', + '𝝣' => 'Ξ', + '𝝤' => 'Ο', + '𝝥' => 'Π', + '𝝦' => 'Ρ', + '𝝧' => 'Θ', + '𝝨' => 'Σ', + '𝝩' => 'Τ', + '𝝪' => 'Υ', + '𝝫' => 'Φ', + '𝝬' => 'Χ', + '𝝭' => 'Ψ', + '𝝮' => 'Ω', + '𝝯' => '∇', + '𝝰' => 'α', + '𝝱' => 'β', + '𝝲' => 'γ', + '𝝳' => 'δ', + '𝝴' => 'ε', + '𝝵' => 'ζ', + '𝝶' => 'η', + '𝝷' => 'θ', + '𝝸' => 'ι', + '𝝹' => 'κ', + '𝝺' => 'λ', + '𝝻' => 'μ', + '𝝼' => 'ν', + '𝝽' => 'ξ', + '𝝾' => 'ο', + '𝝿' => 'π', + '𝞀' => 'ρ', + '𝞁' => 'ς', + '𝞂' => 'σ', + '𝞃' => 'τ', + '𝞄' => 'υ', + '𝞅' => 'φ', + '𝞆' => 'χ', + '𝞇' => 'ψ', + '𝞈' => 'ω', + '𝞉' => '∂', + '𝞊' => 'ε', + '𝞋' => 'θ', + '𝞌' => 'κ', + '𝞍' => 'φ', + '𝞎' => 'ρ', + '𝞏' => 'π', + '𝞐' => 'Α', + '𝞑' => 'Β', + '𝞒' => 'Γ', + '𝞓' => 'Δ', + '𝞔' => 'Ε', + '𝞕' => 'Ζ', + '𝞖' => 'Η', + '𝞗' => 'Θ', + '𝞘' => 'Ι', + '𝞙' => 'Κ', + '𝞚' => 'Λ', + '𝞛' => 'Μ', + '𝞜' => 'Ν', + '𝞝' => 'Ξ', + '𝞞' => 'Ο', + '𝞟' => 'Π', + '𝞠' => 'Ρ', + '𝞡' => 'Θ', + '𝞢' => 'Σ', + '𝞣' => 'Τ', + '𝞤' => 'Υ', + '𝞥' => 'Φ', + '𝞦' => 'Χ', + '𝞧' => 'Ψ', + '𝞨' => 'Ω', + '𝞩' => '∇', + '𝞪' => 'α', + '𝞫' => 'β', + '𝞬' => 'γ', + '𝞭' => 'δ', + '𝞮' => 'ε', + '𝞯' => 'ζ', + '𝞰' => 'η', + '𝞱' => 'θ', + '𝞲' => 'ι', + '𝞳' => 'κ', + '𝞴' => 'λ', + '𝞵' => 'μ', + '𝞶' => 'ν', + '𝞷' => 'ξ', + '𝞸' => 'ο', + '𝞹' => 'π', + '𝞺' => 'ρ', + '𝞻' => 'ς', + '𝞼' => 'σ', + '𝞽' => 'τ', + '𝞾' => 'υ', + '𝞿' => 'φ', + '𝟀' => 'χ', + '𝟁' => 'ψ', + '𝟂' => 'ω', + '𝟃' => '∂', + '𝟄' => 'ε', + '𝟅' => 'θ', + '𝟆' => 'κ', + '𝟇' => 'φ', + '𝟈' => 'ρ', + '𝟉' => 'π', + '𝟊' => 'Ϝ', + '𝟋' => 'ϝ', + '𝟎' => '0', + '𝟏' => '1', + '𝟐' => '2', + '𝟑' => '3', + '𝟒' => '4', + '𝟓' => '5', + '𝟔' => '6', + '𝟕' => '7', + '𝟖' => '8', + '𝟗' => '9', + '𝟘' => '0', + '𝟙' => '1', + '𝟚' => '2', + '𝟛' => '3', + '𝟜' => '4', + '𝟝' => '5', + '𝟞' => '6', + '𝟟' => '7', + '𝟠' => '8', + '𝟡' => '9', + '𝟢' => '0', + '𝟣' => '1', + '𝟤' => '2', + '𝟥' => '3', + '𝟦' => '4', + '𝟧' => '5', + '𝟨' => '6', + '𝟩' => '7', + '𝟪' => '8', + '𝟫' => '9', + '𝟬' => '0', + '𝟭' => '1', + '𝟮' => '2', + '𝟯' => '3', + '𝟰' => '4', + '𝟱' => '5', + '𝟲' => '6', + '𝟳' => '7', + '𝟴' => '8', + '𝟵' => '9', + '𝟶' => '0', + '𝟷' => '1', + '𝟸' => '2', + '𝟹' => '3', + '𝟺' => '4', + '𝟻' => '5', + '𝟼' => '6', + '𝟽' => '7', + '𝟾' => '8', + '𝟿' => '9', + '𞸀' => 'ا', + '𞸁' => 'ب', + '𞸂' => 'ج', + '𞸃' => 'د', + '𞸅' => 'و', + '𞸆' => 'ز', + '𞸇' => 'ح', + '𞸈' => 'ط', + '𞸉' => 'ي', + '𞸊' => 'ك', + '𞸋' => 'ل', + '𞸌' => 'م', + '𞸍' => 'ن', + '𞸎' => 'س', + '𞸏' => 'ع', + '𞸐' => 'ف', + '𞸑' => 'ص', + '𞸒' => 'ق', + '𞸓' => 'ر', + '𞸔' => 'ش', + '𞸕' => 'ت', + '𞸖' => 'ث', + '𞸗' => 'خ', + '𞸘' => 'ذ', + '𞸙' => 'ض', + '𞸚' => 'ظ', + '𞸛' => 'غ', + '𞸜' => 'ٮ', + '𞸝' => 'ں', + '𞸞' => 'ڡ', + '𞸟' => 'ٯ', + '𞸡' => 'ب', + '𞸢' => 'ج', + '𞸤' => 'ه', + '𞸧' => 'ح', + '𞸩' => 'ي', + '𞸪' => 'ك', + '𞸫' => 'ل', + '𞸬' => 'م', + '𞸭' => 'ن', + '𞸮' => 'س', + '𞸯' => 'ع', + '𞸰' => 'ف', + '𞸱' => 'ص', + '𞸲' => 'ق', + '𞸴' => 'ش', + '𞸵' => 'ت', + '𞸶' => 'ث', + '𞸷' => 'خ', + '𞸹' => 'ض', + '𞸻' => 'غ', + '𞹂' => 'ج', + '𞹇' => 'ح', + '𞹉' => 'ي', + '𞹋' => 'ل', + '𞹍' => 'ن', + '𞹎' => 'س', + '𞹏' => 'ع', + '𞹑' => 'ص', + '𞹒' => 'ق', + '𞹔' => 'ش', + '𞹗' => 'خ', + '𞹙' => 'ض', + '𞹛' => 'غ', + '𞹝' => 'ں', + '𞹟' => 'ٯ', + '𞹡' => 'ب', + '𞹢' => 'ج', + '𞹤' => 'ه', + '𞹧' => 'ح', + '𞹨' => 'ط', + '𞹩' => 'ي', + '𞹪' => 'ك', + '𞹬' => 'م', + '𞹭' => 'ن', + '𞹮' => 'س', + '𞹯' => 'ع', + '𞹰' => 'ف', + '𞹱' => 'ص', + '𞹲' => 'ق', + '𞹴' => 'ش', + '𞹵' => 'ت', + '𞹶' => 'ث', + '𞹷' => 'خ', + '𞹹' => 'ض', + '𞹺' => 'ظ', + '𞹻' => 'غ', + '𞹼' => 'ٮ', + '𞹾' => 'ڡ', + '𞺀' => 'ا', + '𞺁' => 'ب', + '𞺂' => 'ج', + '𞺃' => 'د', + '𞺄' => 'ه', + '𞺅' => 'و', + '𞺆' => 'ز', + '𞺇' => 'ح', + '𞺈' => 'ط', + '𞺉' => 'ي', + '𞺋' => 'ل', + '𞺌' => 'م', + '𞺍' => 'ن', + '𞺎' => 'س', + '𞺏' => 'ع', + '𞺐' => 'ف', + '𞺑' => 'ص', + '𞺒' => 'ق', + '𞺓' => 'ر', + '𞺔' => 'ش', + '𞺕' => 'ت', + '𞺖' => 'ث', + '𞺗' => 'خ', + '𞺘' => 'ذ', + '𞺙' => 'ض', + '𞺚' => 'ظ', + '𞺛' => 'غ', + '𞺡' => 'ب', + '𞺢' => 'ج', + '𞺣' => 'د', + '𞺥' => 'و', + '𞺦' => 'ز', + '𞺧' => 'ح', + '𞺨' => 'ط', + '𞺩' => 'ي', + '𞺫' => 'ل', + '𞺬' => 'م', + '𞺭' => 'ن', + '𞺮' => 'س', + '𞺯' => 'ع', + '𞺰' => 'ف', + '𞺱' => 'ص', + '𞺲' => 'ق', + '𞺳' => 'ر', + '𞺴' => 'ش', + '𞺵' => 'ت', + '𞺶' => 'ث', + '𞺷' => 'خ', + '𞺸' => 'ذ', + '𞺹' => 'ض', + '𞺺' => 'ظ', + '𞺻' => 'غ', + '🄀' => '0.', + '🄁' => '0,', + '🄂' => '1,', + '🄃' => '2,', + '🄄' => '3,', + '🄅' => '4,', + '🄆' => '5,', + '🄇' => '6,', + '🄈' => '7,', + '🄉' => '8,', + '🄊' => '9,', + '🄐' => '(A)', + '🄑' => '(B)', + '🄒' => '(C)', + '🄓' => '(D)', + '🄔' => '(E)', + '🄕' => '(F)', + '🄖' => '(G)', + '🄗' => '(H)', + '🄘' => '(I)', + '🄙' => '(J)', + '🄚' => '(K)', + '🄛' => '(L)', + '🄜' => '(M)', + '🄝' => '(N)', + '🄞' => '(O)', + '🄟' => '(P)', + '🄠' => '(Q)', + '🄡' => '(R)', + '🄢' => '(S)', + '🄣' => '(T)', + '🄤' => '(U)', + '🄥' => '(V)', + '🄦' => '(W)', + '🄧' => '(X)', + '🄨' => '(Y)', + '🄩' => '(Z)', + '🄪' => '〔S〕', + '🄫' => 'C', + '🄬' => 'R', + '🄭' => 'CD', + '🄮' => 'WZ', + '🄰' => 'A', + '🄱' => 'B', + '🄲' => 'C', + '🄳' => 'D', + '🄴' => 'E', + '🄵' => 'F', + '🄶' => 'G', + '🄷' => 'H', + '🄸' => 'I', + '🄹' => 'J', + '🄺' => 'K', + '🄻' => 'L', + '🄼' => 'M', + '🄽' => 'N', + '🄾' => 'O', + '🄿' => 'P', + '🅀' => 'Q', + '🅁' => 'R', + '🅂' => 'S', + '🅃' => 'T', + '🅄' => 'U', + '🅅' => 'V', + '🅆' => 'W', + '🅇' => 'X', + '🅈' => 'Y', + '🅉' => 'Z', + '🅊' => 'HV', + '🅋' => 'MV', + '🅌' => 'SD', + '🅍' => 'SS', + '🅎' => 'PPV', + '🅏' => 'WC', + '🅪' => 'MC', + '🅫' => 'MD', + '🅬' => 'MR', + '🆐' => 'DJ', + '🈀' => 'ほか', + '🈁' => 'ココ', + '🈂' => 'サ', + '🈐' => '手', + '🈑' => '字', + '🈒' => '双', + '🈓' => 'デ', + '🈔' => '二', + '🈕' => '多', + '🈖' => '解', + '🈗' => '天', + '🈘' => '交', + '🈙' => '映', + '🈚' => '無', + '🈛' => '料', + '🈜' => '前', + '🈝' => '後', + '🈞' => '再', + '🈟' => '新', + '🈠' => '初', + '🈡' => '終', + '🈢' => '生', + '🈣' => '販', + '🈤' => '声', + '🈥' => '吹', + '🈦' => '演', + '🈧' => '投', + '🈨' => '捕', + '🈩' => '一', + '🈪' => '三', + '🈫' => '遊', + '🈬' => '左', + '🈭' => '中', + '🈮' => '右', + '🈯' => '指', + '🈰' => '走', + '🈱' => '打', + '🈲' => '禁', + '🈳' => '空', + '🈴' => '合', + '🈵' => '満', + '🈶' => '有', + '🈷' => '月', + '🈸' => '申', + '🈹' => '割', + '🈺' => '営', + '🈻' => '配', + '🉀' => '〔本〕', + '🉁' => '〔三〕', + '🉂' => '〔二〕', + '🉃' => '〔安〕', + '🉄' => '〔点〕', + '🉅' => '〔打〕', + '🉆' => '〔盗〕', + '🉇' => '〔勝〕', + '🉈' => '〔敗〕', + '🉐' => '得', + '🉑' => '可', + '🯰' => '0', + '🯱' => '1', + '🯲' => '2', + '🯳' => '3', + '🯴' => '4', + '🯵' => '5', + '🯶' => '6', + '🯷' => '7', + '🯸' => '8', + '🯹' => '9', +); diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap.php new file mode 100644 index 000000000..3608e5c05 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap80.php b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap80.php new file mode 100644 index 000000000..e36d1a947 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/bootstrap80.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/composer.json b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/composer.json new file mode 100644 index 000000000..9bd04e887 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-intl-normalizer/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-intl-normalizer", + "type": "library", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/Mbstring.php b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/Mbstring.php index 3d45c9d9a..31e36a368 100644 --- a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/Mbstring.php +++ b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/Mbstring.php @@ -983,7 +983,7 @@ final class Mbstring public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/bootstrap80.php b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/bootstrap80.php index 5be7d2018..5236e6dcc 100644 --- a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/bootstrap80.php +++ b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/bootstrap80.php @@ -133,11 +133,11 @@ if (!function_exists('mb_str_pad')) { } if (!function_exists('mb_ucfirst')) { - function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } } if (!function_exists('mb_lcfirst')) { - function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } } if (!function_exists('mb_trim')) { diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/composer.json b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/composer.json index 4ed241a33..daa07f86b 100644 --- a/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/composer.json +++ b/lam/lib/3rdParty/composer/symfony/polyfill-mbstring/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=7.2" + "php": ">=7.2", + "ext-iconv": "*" }, "provide": { "ext-mbstring": "*" diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/LICENSE b/lam/lib/3rdParty/composer/symfony/polyfill-php80/LICENSE deleted file mode 100644 index 0ed3a2465..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2020-present Fabien Potencier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Php80.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Php80.php deleted file mode 100644 index 362dd1a95..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Php80.php +++ /dev/null @@ -1,115 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Php80; - -/** - * @author Ion Bazan - * @author Nico Oelgart - * @author Nicolas Grekas - * - * @internal - */ -final class Php80 -{ - public static function fdiv(float $dividend, float $divisor): float - { - return @($dividend / $divisor); - } - - public static function get_debug_type($value): string - { - switch (true) { - case null === $value: return 'null'; - case \is_bool($value): return 'bool'; - case \is_string($value): return 'string'; - case \is_array($value): return 'array'; - case \is_int($value): return 'int'; - case \is_float($value): return 'float'; - case \is_object($value): break; - case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; - default: - if (null === $type = @get_resource_type($value)) { - return 'unknown'; - } - - if ('Unknown' === $type) { - $type = 'closed'; - } - - return "resource ($type)"; - } - - $class = \get_class($value); - - if (false === strpos($class, '@')) { - return $class; - } - - return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; - } - - public static function get_resource_id($res): int - { - if (!\is_resource($res) && null === @get_resource_type($res)) { - throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); - } - - return (int) $res; - } - - public static function preg_last_error_msg(): string - { - switch (preg_last_error()) { - case \PREG_INTERNAL_ERROR: - return 'Internal error'; - case \PREG_BAD_UTF8_ERROR: - return 'Malformed UTF-8 characters, possibly incorrectly encoded'; - case \PREG_BAD_UTF8_OFFSET_ERROR: - return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; - case \PREG_BACKTRACK_LIMIT_ERROR: - return 'Backtrack limit exhausted'; - case \PREG_RECURSION_LIMIT_ERROR: - return 'Recursion limit exhausted'; - case \PREG_JIT_STACKLIMIT_ERROR: - return 'JIT stack limit exhausted'; - case \PREG_NO_ERROR: - return 'No error'; - default: - return 'Unknown error'; - } - } - - public static function str_contains(string $haystack, string $needle): bool - { - return '' === $needle || false !== strpos($haystack, $needle); - } - - public static function str_starts_with(string $haystack, string $needle): bool - { - return 0 === strncmp($haystack, $needle, \strlen($needle)); - } - - public static function str_ends_with(string $haystack, string $needle): bool - { - if ('' === $needle || $needle === $haystack) { - return true; - } - - if ('' === $haystack) { - return false; - } - - $needleLength = \strlen($needle); - - return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/PhpToken.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/PhpToken.php deleted file mode 100644 index fe6e69105..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/PhpToken.php +++ /dev/null @@ -1,103 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Php80; - -/** - * @author Fedonyuk Anton - * - * @internal - */ -class PhpToken implements \Stringable -{ - /** - * @var int - */ - public $id; - - /** - * @var string - */ - public $text; - - /** - * @var int - */ - public $line; - - /** - * @var int - */ - public $pos; - - public function __construct(int $id, string $text, int $line = -1, int $position = -1) - { - $this->id = $id; - $this->text = $text; - $this->line = $line; - $this->pos = $position; - } - - public function getTokenName(): ?string - { - if ('UNKNOWN' === $name = token_name($this->id)) { - $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; - } - - return $name; - } - - /** - * @param int|string|array $kind - */ - public function is($kind): bool - { - foreach ((array) $kind as $value) { - if (\in_array($value, [$this->id, $this->text], true)) { - return true; - } - } - - return false; - } - - public function isIgnorable(): bool - { - return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); - } - - public function __toString(): string - { - return (string) $this->text; - } - - /** - * @return static[] - */ - public static function tokenize(string $code, int $flags = 0): array - { - $line = 1; - $position = 0; - $tokens = token_get_all($code, $flags); - foreach ($tokens as $index => $token) { - if (\is_string($token)) { - $id = \ord($token); - $text = $token; - } else { - [$id, $text, $line] = $token; - } - $tokens[$index] = new static($id, $text, $line, $position); - $position += \strlen($text); - } - - return $tokens; - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/README.md b/lam/lib/3rdParty/composer/symfony/polyfill-php80/README.md deleted file mode 100644 index 3816c559d..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/README.md +++ /dev/null @@ -1,25 +0,0 @@ -Symfony Polyfill / Php80 -======================== - -This component provides features added to PHP 8.0 core: - -- [`Stringable`](https://php.net/stringable) interface -- [`fdiv`](https://php.net/fdiv) -- [`ValueError`](https://php.net/valueerror) class -- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class -- `FILTER_VALIDATE_BOOL` constant -- [`get_debug_type`](https://php.net/get_debug_type) -- [`PhpToken`](https://php.net/phptoken) class -- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) -- [`str_contains`](https://php.net/str_contains) -- [`str_starts_with`](https://php.net/str_starts_with) -- [`str_ends_with`](https://php.net/str_ends_with) -- [`get_resource_id`](https://php.net/get_resource_id) - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Attribute.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Attribute.php deleted file mode 100644 index 2b955423f..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Attribute.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#[Attribute(Attribute::TARGET_CLASS)] -final class Attribute -{ - public const TARGET_CLASS = 1; - public const TARGET_FUNCTION = 2; - public const TARGET_METHOD = 4; - public const TARGET_PROPERTY = 8; - public const TARGET_CLASS_CONSTANT = 16; - public const TARGET_PARAMETER = 32; - public const TARGET_ALL = 63; - public const IS_REPEATABLE = 64; - - /** @var int */ - public $flags; - - public function __construct(int $flags = self::TARGET_ALL) - { - $this->flags = $flags; - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/PhpToken.php deleted file mode 100644 index bd1212f6e..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/PhpToken.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { - class PhpToken extends Symfony\Polyfill\Php80\PhpToken - { - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Stringable.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Stringable.php deleted file mode 100644 index 7c62d7508..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/Stringable.php +++ /dev/null @@ -1,20 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -if (\PHP_VERSION_ID < 80000) { - interface Stringable - { - /** - * @return string - */ - public function __toString(); - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php deleted file mode 100644 index 01c6c6c8a..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -if (\PHP_VERSION_ID < 80000) { - class UnhandledMatchError extends Error - { - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/ValueError.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/ValueError.php deleted file mode 100644 index 783dbc28c..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/Resources/stubs/ValueError.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -if (\PHP_VERSION_ID < 80000) { - class ValueError extends Error - { - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/bootstrap.php b/lam/lib/3rdParty/composer/symfony/polyfill-php80/bootstrap.php deleted file mode 100644 index e5f7dbc1a..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/bootstrap.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Php80 as p; - -if (\PHP_VERSION_ID >= 80000) { - return; -} - -if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { - define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); -} - -if (!function_exists('fdiv')) { - function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } -} -if (!function_exists('preg_last_error_msg')) { - function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } -} -if (!function_exists('str_contains')) { - function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } -} -if (!function_exists('str_starts_with')) { - function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } -} -if (!function_exists('str_ends_with')) { - function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } -} -if (!function_exists('get_debug_type')) { - function get_debug_type($value): string { return p\Php80::get_debug_type($value); } -} -if (!function_exists('get_resource_id')) { - function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php80/composer.json b/lam/lib/3rdParty/composer/symfony/polyfill-php80/composer.json deleted file mode 100644 index a503b039a..000000000 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php80/composer.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "symfony/polyfill-php80", - "type": "library", - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=7.2" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, - "files": [ "bootstrap.php" ], - "classmap": [ "Resources/stubs" ] - }, - "minimum-stability": "dev", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - } -} diff --git a/lam/lib/3rdParty/composer/symfony/polyfill-php83/Php83.php b/lam/lib/3rdParty/composer/symfony/polyfill-php83/Php83.php index 3d94b6c32..8b7ee4c70 100644 --- a/lam/lib/3rdParty/composer/symfony/polyfill-php83/Php83.php +++ b/lam/lib/3rdParty/composer/symfony/polyfill-php83/Php83.php @@ -35,7 +35,7 @@ final class Php83 throw new \ValueError(sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH)); } - json_decode($json, null, $depth, $flags); + json_decode($json, true, $depth, $flags); return \JSON_ERROR_NONE === json_last_error(); } diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php index 7c824fd44..a4a07ad8e 100644 --- a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php @@ -50,7 +50,7 @@ class PsrHttpFactory implements HttpMessageFactoryInterface $psr17Factory = match (true) { class_exists(DiscoveryPsr17Factory::class) => new DiscoveryPsr17Factory(), class_exists(NyholmPsr17Factory::class) => new NyholmPsr17Factory(), - default => throw new \LogicException(sprintf('You cannot use the "%s" as no PSR-17 factories have been provided. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', self::class)), + default => throw new \LogicException(\sprintf('You cannot use the "%s" as no PSR-17 factories have been provided. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', self::class)), }; $serverRequestFactory ??= $psr17Factory; diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php index f680dd5ab..34d405856 100644 --- a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php @@ -59,7 +59,7 @@ class UploadedFile extends BaseUploadedFile try { $this->psrUploadedFile->moveTo((string) $target); } catch (\RuntimeException $e) { - throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, $e->getMessage()), 0, $e); + throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, $e->getMessage()), 0, $e); } @chmod($target, 0666 & ~umask()); diff --git a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceLocatorTrait.php b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceLocatorTrait.php index b62ec3e53..bbe454843 100644 --- a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceLocatorTrait.php +++ b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceLocatorTrait.php @@ -26,16 +26,15 @@ class_exists(NotFoundExceptionInterface::class); */ trait ServiceLocatorTrait { - private array $factories; private array $loading = []; private array $providedTypes; /** * @param array $factories */ - public function __construct(array $factories) - { - $this->factories = $factories; + public function __construct( + private array $factories, + ) { } public function has(string $id): bool @@ -91,16 +90,16 @@ trait ServiceLocatorTrait } else { $last = array_pop($alternatives); if ($alternatives) { - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); } else { - $message = sprintf('only knows about the "%s" service.', $last); + $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); } else { - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { @@ -109,7 +108,7 @@ trait ServiceLocatorTrait private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface { - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } diff --git a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php index 0d89d9f25..844be8907 100644 --- a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php +++ b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -42,18 +42,18 @@ trait ServiceMethodsSubscriberTrait } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceSubscriberTrait.php b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceSubscriberTrait.php index cc3bc321a..ed4cec044 100644 --- a/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceSubscriberTrait.php +++ b/lam/lib/3rdParty/composer/symfony/service-contracts/ServiceSubscriberTrait.php @@ -46,18 +46,18 @@ trait ServiceSubscriberTrait } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/lam/lib/3rdParty/composer/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/lam/lib/3rdParty/composer/symfony/service-contracts/Test/ServiceLocatorTestCase.php index 65a3fe337..fdd5b2793 100644 --- a/lam/lib/3rdParty/composer/symfony/service-contracts/Test/ServiceLocatorTestCase.php +++ b/lam/lib/3rdParty/composer/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -19,6 +19,9 @@ use Symfony\Contracts\Service\ServiceLocatorTrait; abstract class ServiceLocatorTestCase extends TestCase { + /** + * @param array $factories + */ protected function getServiceLocator(array $factories): ContainerInterface { return new class($factories) implements ContainerInterface { @@ -72,10 +75,8 @@ abstract class ServiceLocatorTestCase extends TestCase 'foo' => function () use (&$locator) { return $locator->get('bar'); }, ]); - if (!$this->getExpectedException()) { - $this->expectException(NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); $locator->get('foo'); } diff --git a/lam/lib/3rdParty/composer/symfony/service-contracts/composer.json b/lam/lib/3rdParty/composer/symfony/service-contracts/composer.json index fc8674a72..bc2e99a8f 100644 --- a/lam/lib/3rdParty/composer/symfony/service-contracts/composer.json +++ b/lam/lib/3rdParty/composer/symfony/service-contracts/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/lam/lib/3rdParty/composer/symfony/string/AbstractString.php b/lam/lib/3rdParty/composer/symfony/string/AbstractString.php new file mode 100644 index 000000000..45bcf0c03 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/AbstractString.php @@ -0,0 +1,702 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +use Symfony\Component\String\Exception\ExceptionInterface; +use Symfony\Component\String\Exception\InvalidArgumentException; +use Symfony\Component\String\Exception\RuntimeException; + +/** + * Represents a string of abstract characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement doesn't care about the exact variant it deals with. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +abstract class AbstractString implements \Stringable, \JsonSerializable +{ + public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; + public const PREG_SET_ORDER = \PREG_SET_ORDER; + public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; + public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; + + public const PREG_SPLIT = 0; + public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; + public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; + public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; + + protected $string = ''; + protected $ignoreCase = false; + + abstract public function __construct(string $string = ''); + + /** + * Unwraps instances of AbstractString back to strings. + * + * @return string[]|array + */ + public static function unwrap(array $values): array + { + foreach ($values as $k => $v) { + if ($v instanceof self) { + $values[$k] = $v->__toString(); + } elseif (\is_array($v) && $values[$k] !== $v = static::unwrap($v)) { + $values[$k] = $v; + } + } + + return $values; + } + + /** + * Wraps (and normalizes) strings in instances of AbstractString. + * + * @return static[]|array + */ + public static function wrap(array $values): array + { + $i = 0; + $keys = null; + + foreach ($values as $k => $v) { + if (\is_string($k) && '' !== $k && $k !== $j = (string) new static($k)) { + $keys ??= array_keys($values); + $keys[$i] = $j; + } + + if (\is_string($v)) { + $values[$k] = new static($v); + } elseif (\is_array($v) && $values[$k] !== $v = static::wrap($v)) { + $values[$k] = $v; + } + + ++$i; + } + + return null !== $keys ? array_combine($keys, $values) : $values; + } + + /** + * @param string|string[] $needle + */ + public function after(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static + { + $str = clone $this; + $i = \PHP_INT_MAX; + + if (\is_string($needle)) { + $needle = [$needle]; + } + + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + + if (\PHP_INT_MAX === $i) { + return $str; + } + + if (!$includeNeedle) { + $i += $str->length(); + } + + return $this->slice($i); + } + + /** + * @param string|string[] $needle + */ + public function afterLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static + { + $str = clone $this; + $i = null; + + if (\is_string($needle)) { + $needle = [$needle]; + } + + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + + if (null === $i) { + return $str; + } + + if (!$includeNeedle) { + $i += $str->length(); + } + + return $this->slice($i); + } + + abstract public function append(string ...$suffix): static; + + /** + * @param string|string[] $needle + */ + public function before(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static + { + $str = clone $this; + $i = \PHP_INT_MAX; + + if (\is_string($needle)) { + $needle = [$needle]; + } + + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + + if (\PHP_INT_MAX === $i) { + return $str; + } + + if ($includeNeedle) { + $i += $str->length(); + } + + return $this->slice(0, $i); + } + + /** + * @param string|string[] $needle + */ + public function beforeLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static + { + $str = clone $this; + $i = null; + + if (\is_string($needle)) { + $needle = [$needle]; + } + + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + + if (null === $i) { + return $str; + } + + if ($includeNeedle) { + $i += $str->length(); + } + + return $this->slice(0, $i); + } + + /** + * @return int[] + */ + public function bytesAt(int $offset): array + { + $str = $this->slice($offset, 1); + + return '' === $str->string ? [] : array_values(unpack('C*', $str->string)); + } + + abstract public function camel(): static; + + /** + * @return static[] + */ + abstract public function chunk(int $length = 1): array; + + public function collapseWhitespace(): static + { + $str = clone $this; + $str->string = trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $str->string), " \n\r\t\x0C"); + + return $str; + } + + /** + * @param string|string[] $needle + */ + public function containsAny(string|iterable $needle): bool + { + return null !== $this->indexOf($needle); + } + + /** + * @param string|string[] $suffix + */ + public function endsWith(string|iterable $suffix): bool + { + if (\is_string($suffix)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + + foreach ($suffix as $s) { + if ($this->endsWith((string) $s)) { + return true; + } + } + + return false; + } + + public function ensureEnd(string $suffix): static + { + if (!$this->endsWith($suffix)) { + return $this->append($suffix); + } + + $suffix = preg_quote($suffix); + $regex = '{('.$suffix.')(?:'.$suffix.')++$}D'; + + return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1'); + } + + public function ensureStart(string $prefix): static + { + $prefix = new static($prefix); + + if (!$this->startsWith($prefix)) { + return $this->prepend($prefix); + } + + $str = clone $this; + $i = $prefixLen = $prefix->length(); + + while ($this->indexOf($prefix, $i) === $i) { + $str = $str->slice($prefixLen); + $i += $prefixLen; + } + + return $str; + } + + /** + * @param string|string[] $string + */ + public function equalsTo(string|iterable $string): bool + { + if (\is_string($string)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + + foreach ($string as $s) { + if ($this->equalsTo((string) $s)) { + return true; + } + } + + return false; + } + + abstract public function folded(): static; + + public function ignoreCase(): static + { + $str = clone $this; + $str->ignoreCase = true; + + return $str; + } + + /** + * @param string|string[] $needle + */ + public function indexOf(string|iterable $needle, int $offset = 0): ?int + { + if (\is_string($needle)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + + $i = \PHP_INT_MAX; + + foreach ($needle as $n) { + $j = $this->indexOf((string) $n, $offset); + + if (null !== $j && $j < $i) { + $i = $j; + } + } + + return \PHP_INT_MAX === $i ? null : $i; + } + + /** + * @param string|string[] $needle + */ + public function indexOfLast(string|iterable $needle, int $offset = 0): ?int + { + if (\is_string($needle)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + + $i = null; + + foreach ($needle as $n) { + $j = $this->indexOfLast((string) $n, $offset); + + if (null !== $j && $j >= $i) { + $i = $offset = $j; + } + } + + return $i; + } + + public function isEmpty(): bool + { + return '' === $this->string; + } + + abstract public function join(array $strings, ?string $lastGlue = null): static; + + public function jsonSerialize(): string + { + return $this->string; + } + + abstract public function length(): int; + + abstract public function lower(): static; + + /** + * Matches the string using a regular expression. + * + * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression. + * + * @return array All matches in a multi-dimensional array ordered according to flags + */ + abstract public function match(string $regexp, int $flags = 0, int $offset = 0): array; + + abstract public function padBoth(int $length, string $padStr = ' '): static; + + abstract public function padEnd(int $length, string $padStr = ' '): static; + + abstract public function padStart(int $length, string $padStr = ' '): static; + + abstract public function prepend(string ...$prefix): static; + + public function repeat(int $multiplier): static + { + if (0 > $multiplier) { + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); + } + + $str = clone $this; + $str->string = str_repeat($str->string, $multiplier); + + return $str; + } + + abstract public function replace(string $from, string $to): static; + + abstract public function replaceMatches(string $fromRegexp, string|callable $to): static; + + abstract public function reverse(): static; + + abstract public function slice(int $start = 0, ?int $length = null): static; + + abstract public function snake(): static; + + abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static; + + /** + * @return static[] + */ + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array + { + if (null === $flags) { + throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); + } + + if ($this->ignoreCase) { + $delimiter .= 'i'; + } + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) { + throw new RuntimeException('Splitting failed with error: '.preg_last_error_msg()); + } + } finally { + restore_error_handler(); + } + + $str = clone $this; + + if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) { + foreach ($chunks as &$chunk) { + $str->string = $chunk[0]; + $chunk[0] = clone $str; + } + } else { + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + } + + return $chunks; + } + + /** + * @param string|string[] $prefix + */ + public function startsWith(string|iterable $prefix): bool + { + if (\is_string($prefix)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + + foreach ($prefix as $prefix) { + if ($this->startsWith((string) $prefix)) { + return true; + } + } + + return false; + } + + abstract public function title(bool $allWords = false): static; + + public function toByteString(?string $toEncoding = null): ByteString + { + $b = new ByteString(); + + $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], true) ? 'UTF-8' : $toEncoding; + + if (null === $toEncoding || $toEncoding === $fromEncoding = $this instanceof AbstractUnicodeString || preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252') { + $b->string = $this->string; + + return $b; + } + + try { + $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); + } catch (\ValueError $e) { + if (!\function_exists('iconv')) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + + $b->string = iconv('UTF-8', $toEncoding, $this->string); + } + + return $b; + } + + public function toCodePointString(): CodePointString + { + return new CodePointString($this->string); + } + + public function toString(): string + { + return $this->string; + } + + public function toUnicodeString(): UnicodeString + { + return new UnicodeString($this->string); + } + + abstract public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; + + abstract public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; + + /** + * @param string|string[] $prefix + */ + public function trimPrefix($prefix): static + { + if (\is_array($prefix) || $prefix instanceof \Traversable) { // don't use is_iterable(), it's slow + foreach ($prefix as $s) { + $t = $this->trimPrefix($s); + + if ($t->string !== $this->string) { + return $t; + } + } + + return clone $this; + } + + $str = clone $this; + + if ($prefix instanceof self) { + $prefix = $prefix->string; + } else { + $prefix = (string) $prefix; + } + + if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) { + $str->string = substr($this->string, \strlen($prefix)); + } + + return $str; + } + + abstract public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; + + /** + * @param string|string[] $suffix + */ + public function trimSuffix($suffix): static + { + if (\is_array($suffix) || $suffix instanceof \Traversable) { // don't use is_iterable(), it's slow + foreach ($suffix as $s) { + $t = $this->trimSuffix($s); + + if ($t->string !== $this->string) { + return $t; + } + } + + return clone $this; + } + + $str = clone $this; + + if ($suffix instanceof self) { + $suffix = $suffix->string; + } else { + $suffix = (string) $suffix; + } + + if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) { + $str->string = substr($this->string, 0, -\strlen($suffix)); + } + + return $str; + } + + public function truncate(int $length, string $ellipsis = '', bool $cut = true): static + { + $stringLength = $this->length(); + + if ($stringLength <= $length) { + return clone $this; + } + + $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; + + if ($length < $ellipsisLength) { + $ellipsisLength = 0; + } + + if (!$cut) { + if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { + return clone $this; + } + + $length += $ellipsisLength; + } + + $str = $this->slice(0, $length - $ellipsisLength); + + return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; + } + + abstract public function upper(): static; + + /** + * Returns the printable length on a terminal. + */ + abstract public function width(bool $ignoreAnsiDecoration = true): int; + + public function wordwrap(int $width = 75, string $break = "\n", bool $cut = false): static + { + $lines = '' !== $break ? $this->split($break) : [clone $this]; + $chars = []; + $mask = ''; + + if (1 === \count($lines) && '' === $lines[0]->string) { + return $lines[0]; + } + + foreach ($lines as $i => $line) { + if ($i) { + $chars[] = $break; + $mask .= '#'; + } + + foreach ($line->chunk() as $char) { + $chars[] = $char->string; + $mask .= ' ' === $char->string ? ' ' : '?'; + } + } + + $string = ''; + $j = 0; + $b = $i = -1; + $mask = wordwrap($mask, $width, '#', $cut); + + while (false !== $b = strpos($mask, '#', $b + 1)) { + for (++$i; $i < $b; ++$i) { + $string .= $chars[$j]; + unset($chars[$j++]); + } + + if ($break === $chars[$j] || ' ' === $chars[$j]) { + unset($chars[$j++]); + } + + $string .= $break; + } + + $str = clone $this; + $str->string = $string.implode('', $chars); + + return $str; + } + + public function __sleep(): array + { + return ['string']; + } + + public function __clone() + { + $this->ignoreCase = false; + } + + public function __toString(): string + { + return $this->string; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/AbstractUnicodeString.php b/lam/lib/3rdParty/composer/symfony/string/AbstractUnicodeString.php new file mode 100644 index 000000000..6ea79938f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/AbstractUnicodeString.php @@ -0,0 +1,596 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +use Symfony\Component\String\Exception\ExceptionInterface; +use Symfony\Component\String\Exception\InvalidArgumentException; +use Symfony\Component\String\Exception\RuntimeException; + +/** + * Represents a string of abstract Unicode characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. + * + * @author Nicolas Grekas + * + * @throws ExceptionInterface + */ +abstract class AbstractUnicodeString extends AbstractString +{ + public const NFC = \Normalizer::NFC; + public const NFD = \Normalizer::NFD; + public const NFKC = \Normalizer::NFKC; + public const NFKD = \Normalizer::NFKD; + + // all ASCII letters sorted by typical frequency of occurrence + private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + + // the subset of folded case mappings that is not in lower case mappings + private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ']; + private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ']; + + // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD + private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; + private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; + + private static array $transliterators = []; + private static array $tableZero; + private static array $tableWide; + + public static function fromCodePoints(int ...$codes): static + { + $string = ''; + + foreach ($codes as $code) { + if (0x80 > $code %= 0x200000) { + $string .= \chr($code); + } elseif (0x800 > $code) { + $string .= \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $string .= \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $string .= \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + } + + return new static($string); + } + + /** + * Generic UTF-8 to ASCII transliteration. + * + * Install the intl extension for best results. + * + * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() + */ + public function ascii(array $rules = []): self + { + $str = clone $this; + $s = $str->string; + $str->string = ''; + + array_unshift($rules, 'nfd'); + $rules[] = 'latin-ascii'; + + if (\function_exists('transliterator_transliterate')) { + $rules[] = 'any-latin/bgn'; + } + + $rules[] = 'nfkd'; + $rules[] = '[:nonspacing mark:] remove'; + + while (\strlen($s) - 1 > $i = strspn($s, self::ASCII)) { + if (0 < --$i) { + $str->string .= substr($s, 0, $i); + $s = substr($s, $i); + } + + if (!$rule = array_shift($rules)) { + $rules = []; // An empty rule interrupts the next ones + } + + if ($rule instanceof \Transliterator) { + $s = $rule->transliterate($s); + } elseif ($rule instanceof \Closure) { + $s = $rule($s); + } elseif ($rule) { + if ('nfd' === $rule = strtolower($rule)) { + normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD); + } elseif ('nfkd' === $rule) { + normalizer_is_normalized($s, self::NFKD) ?: $s = normalizer_normalize($s, self::NFKD); + } elseif ('[:nonspacing mark:] remove' === $rule) { + $s = preg_replace('/\p{Mn}++/u', '', $s); + } elseif ('latin-ascii' === $rule) { + $s = str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s); + } elseif ('de-ascii' === $rule) { + $s = preg_replace("/([AUO])\u{0308}(?=\p{Ll})/u", '$1e', $s); + $s = str_replace(["a\u{0308}", "o\u{0308}", "u\u{0308}", "A\u{0308}", "O\u{0308}", "U\u{0308}"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s); + } elseif (\function_exists('transliterator_transliterate')) { + if (null === $transliterator = self::$transliterators[$rule] ??= \Transliterator::create($rule)) { + if ('any-latin/bgn' === $rule) { + $rule = 'any-latin'; + $transliterator = self::$transliterators[$rule] ??= \Transliterator::create($rule); + } + + if (null === $transliterator) { + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); + } + + self::$transliterators['any-latin/bgn'] = $transliterator; + } + + $s = $transliterator->transliterate($s); + } + } elseif (!\function_exists('iconv')) { + $s = preg_replace('/[^\x00-\x7F]/u', '?', $s); + } else { + $previousLocale = setlocale(\LC_CTYPE, 0); + try { + setlocale(\LC_CTYPE, 'C'); + $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { + $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + + if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } + + return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } finally { + setlocale(\LC_CTYPE, $previousLocale); + } + } + } + + $str->string .= $s; + + return $str; + } + + public function camel(): static + { + $str = clone $this; + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?!\p{Lu})/u', static function ($m) { + static $i = 0; + + return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); + }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string))); + + return $str; + } + + /** + * @return int[] + */ + public function codePointsAt(int $offset): array + { + $str = $this->slice($offset, 1); + + if ('' === $str->string) { + return []; + } + + $codePoints = []; + + foreach (preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoints[] = mb_ord($c, 'UTF-8'); + } + + return $codePoints; + } + + public function folded(bool $compat = true): static + { + $str = clone $this; + + if (!$compat || !\defined('Normalizer::NFKC_CF')) { + $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); + $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8'); + } else { + $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF); + } + + return $str; + } + + public function join(array $strings, ?string $lastGlue = null): static + { + $str = clone $this; + + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : ''; + $str->string = implode($this->string, $strings).$tail; + + if (!preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + return $str; + } + + public function lower(): static + { + $str = clone $this; + $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8'); + + return $str; + } + + public function match(string $regexp, int $flags = 0, int $offset = 0): array + { + $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; + + if ($this->ignoreCase) { + $regexp .= 'i'; + } + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + throw new RuntimeException('Matching failed with error: '.preg_last_error_msg()); + } + } finally { + restore_error_handler(); + } + + return $matches; + } + + public function normalize(int $form = self::NFC): static + { + if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } + + $str = clone $this; + normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form); + + return $str; + } + + public function padBoth(int $length, string $padStr = ' '): static + { + if ('' === $padStr || !preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $pad = clone $this; + $pad->string = $padStr; + + return $this->pad($length, $pad, \STR_PAD_BOTH); + } + + public function padEnd(int $length, string $padStr = ' '): static + { + if ('' === $padStr || !preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $pad = clone $this; + $pad->string = $padStr; + + return $this->pad($length, $pad, \STR_PAD_RIGHT); + } + + public function padStart(int $length, string $padStr = ' '): static + { + if ('' === $padStr || !preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $pad = clone $this; + $pad->string = $padStr; + + return $this->pad($length, $pad, \STR_PAD_LEFT); + } + + public function replaceMatches(string $fromRegexp, string|callable $to): static + { + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + + if (\is_array($to) || $to instanceof \Closure) { + $replace = 'preg_replace_callback'; + $to = static function (array $m) use ($to): string { + $to = $to($m); + + if ('' !== $to && (!\is_string($to) || !preg_match('//u', $to))) { + throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.'); + } + + return $to; + }; + } elseif ('' !== $to && !preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } else { + $replace = 'preg_replace'; + } + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) { + $lastError = preg_last_error(); + + foreach (get_defined_constants(true)['pcre'] as $k => $v) { + if ($lastError === $v && str_ends_with($k, '_ERROR')) { + throw new RuntimeException('Matching failed with '.$k.'.'); + } + } + + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + restore_error_handler(); + } + + $str = clone $this; + $str->string = $string; + + return $str; + } + + public function reverse(): static + { + $str = clone $this; + $str->string = implode('', array_reverse(preg_split('/(\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY))); + + return $str; + } + + public function snake(): static + { + $str = $this->camel(); + $str->string = mb_strtolower(preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1_\2', $str->string), 'UTF-8'); + + return $str; + } + + public function title(bool $allWords = false): static + { + $str = clone $this; + + $limit = $allWords ? -1 : 1; + + $str->string = preg_replace_callback('/\b./u', static fn (array $m): string => mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'), $str->string, $limit); + + return $str; + } + + public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static + { + if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = preg_quote($chars); + + $str = clone $this; + $str->string = preg_replace("{^[$chars]++|[$chars]++$}uD", '', $str->string); + + return $str; + } + + public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static + { + if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = preg_quote($chars); + + $str = clone $this; + $str->string = preg_replace("{[$chars]++$}uD", '', $str->string); + + return $str; + } + + public function trimPrefix($prefix): static + { + if (!$this->ignoreCase) { + return parent::trimPrefix($prefix); + } + + $str = clone $this; + + if ($prefix instanceof \Traversable) { + $prefix = iterator_to_array($prefix, false); + } elseif ($prefix instanceof parent) { + $prefix = $prefix->string; + } + + $prefix = implode('|', array_map('preg_quote', (array) $prefix)); + $str->string = preg_replace("{^(?:$prefix)}iuD", '', $this->string); + + return $str; + } + + public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static + { + if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = preg_quote($chars); + + $str = clone $this; + $str->string = preg_replace("{^[$chars]++}uD", '', $str->string); + + return $str; + } + + public function trimSuffix($suffix): static + { + if (!$this->ignoreCase) { + return parent::trimSuffix($suffix); + } + + $str = clone $this; + + if ($suffix instanceof \Traversable) { + $suffix = iterator_to_array($suffix, false); + } elseif ($suffix instanceof parent) { + $suffix = $suffix->string; + } + + $suffix = implode('|', array_map('preg_quote', (array) $suffix)); + $str->string = preg_replace("{(?:$suffix)$}iuD", '', $this->string); + + return $str; + } + + public function upper(): static + { + $str = clone $this; + $str->string = mb_strtoupper($str->string, 'UTF-8'); + + return $str; + } + + public function width(bool $ignoreAnsiDecoration = true): int + { + $width = 0; + $s = str_replace(["\x00", "\x05", "\x07"], '', $this->string); + + if (str_contains($s, "\r")) { + $s = str_replace(["\r\n", "\r"], "\n", $s); + } + + if (!$ignoreAnsiDecoration) { + $s = preg_replace('/[\p{Cc}\x7F]++/u', '', $s); + } + + foreach (explode("\n", $s) as $s) { + if ($ignoreAnsiDecoration) { + $s = preg_replace('/(?:\x1B(?: + \[ [\x30-\x3F]*+ [\x20-\x2F]*+ [\x40-\x7E] + | [P\]X^_] .*? \x1B\\\\ + | [\x41-\x7E] + )|[\p{Cc}\x7F]++)/xu', '', $s); + } + + $lineWidth = $this->wcswidth($s); + + if ($lineWidth > $width) { + $width = $lineWidth; + } + } + + return $width; + } + + private function pad(int $len, self $pad, int $type): static + { + $sLen = $this->length(); + + if ($len <= $sLen) { + return clone $this; + } + + $padLen = $pad->length(); + $freeLen = $len - $sLen; + $len = $freeLen % $padLen; + + switch ($type) { + case \STR_PAD_RIGHT: + return $this->append(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : '')); + + case \STR_PAD_LEFT: + return $this->prepend(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : '')); + + case \STR_PAD_BOTH: + $freeLen /= 2; + + $rightLen = ceil($freeLen); + $len = $rightLen % $padLen; + $str = $this->append(str_repeat($pad->string, intdiv($rightLen, $padLen)).($len ? $pad->slice(0, $len) : '')); + + $leftLen = floor($freeLen); + $len = $leftLen % $padLen; + + return $str->prepend(str_repeat($pad->string, intdiv($leftLen, $padLen)).($len ? $pad->slice(0, $len) : '')); + + default: + throw new InvalidArgumentException('Invalid padding type.'); + } + } + + /** + * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c. + */ + private function wcswidth(string $string): int + { + $width = 0; + + foreach (preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoint = mb_ord($c, 'UTF-8'); + + if (0 === $codePoint // NULL + || 0x034F === $codePoint // COMBINING GRAPHEME JOINER + || (0x200B <= $codePoint && 0x200F >= $codePoint) // ZERO WIDTH SPACE to RIGHT-TO-LEFT MARK + || 0x2028 === $codePoint // LINE SEPARATOR + || 0x2029 === $codePoint // PARAGRAPH SEPARATOR + || (0x202A <= $codePoint && 0x202E >= $codePoint) // LEFT-TO-RIGHT EMBEDDING to RIGHT-TO-LEFT OVERRIDE + || (0x2060 <= $codePoint && 0x2063 >= $codePoint) // WORD JOINER to INVISIBLE SEPARATOR + ) { + continue; + } + + // Non printable characters + if (32 > $codePoint // C0 control characters + || (0x07F <= $codePoint && 0x0A0 > $codePoint) // C1 control characters and DEL + ) { + return -1; + } + + self::$tableZero ??= require __DIR__.'/Resources/data/wcswidth_table_zero.php'; + + if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = floor(($lbound + $ubound) / 2); + + if ($codePoint > self::$tableZero[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < self::$tableZero[$mid][0]) { + $ubound = $mid - 1; + } else { + continue 2; + } + } + } + + self::$tableWide ??= require __DIR__.'/Resources/data/wcswidth_table_wide.php'; + + if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = floor(($lbound + $ubound) / 2); + + if ($codePoint > self::$tableWide[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < self::$tableWide[$mid][0]) { + $ubound = $mid - 1; + } else { + $width += 2; + + continue 2; + } + } + } + + ++$width; + } + + return $width; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/ByteString.php b/lam/lib/3rdParty/composer/symfony/string/ByteString.php new file mode 100644 index 000000000..e96a184ca --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/ByteString.php @@ -0,0 +1,485 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +use Symfony\Component\String\Exception\ExceptionInterface; +use Symfony\Component\String\Exception\InvalidArgumentException; +use Symfony\Component\String\Exception\RuntimeException; + +/** + * Represents a binary-safe string of bytes. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class ByteString extends AbstractString +{ + private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + + public function __construct(string $string = '') + { + $this->string = $string; + } + + /* + * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) + * + * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 + * + * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). + * + * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) + */ + + public static function fromRandom(int $length = 16, ?string $alphabet = null): self + { + if ($length <= 0) { + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); + } + + $alphabet ??= self::ALPHABET_ALPHANUMERIC; + $alphabetSize = \strlen($alphabet); + $bits = (int) ceil(log($alphabetSize, 2.0)); + if ($bits <= 0 || $bits > 56) { + throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); + } + + $ret = ''; + while ($length > 0) { + $urandomLength = (int) ceil(2 * $length * $bits / 8.0); + $data = random_bytes($urandomLength); + $unpackedData = 0; + $unpackedBits = 0; + for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { + // Unpack 8 bits + $unpackedData = ($unpackedData << 8) | \ord($data[$i]); + $unpackedBits += 8; + + // While we have enough bits to select a character from the alphabet, keep + // consuming the random data + for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { + $index = ($unpackedData & ((1 << $bits) - 1)); + $unpackedData >>= $bits; + // Unfortunately, the alphabet size is not necessarily a power of two. + // Worst case, it is 2^k + 1, which means we need (k+1) bits and we + // have around a 50% chance of missing as k gets larger + if ($index < $alphabetSize) { + $ret .= $alphabet[$index]; + --$length; + } + } + } + } + + return new static($ret); + } + + public function bytesAt(int $offset): array + { + $str = $this->string[$offset] ?? ''; + + return '' === $str ? [] : [\ord($str)]; + } + + public function append(string ...$suffix): static + { + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix); + + return $str; + } + + public function camel(): static + { + $str = clone $this; + + $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string)))); + $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]); + $str->string = implode('', $parts); + + return $str; + } + + public function chunk(int $length = 1): array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + + if ('' === $this->string) { + return []; + } + + $str = clone $this; + $chunks = []; + + foreach (str_split($this->string, $length) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + + return $chunks; + } + + public function endsWith(string|iterable|AbstractString $suffix): bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + + return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase); + } + + public function equalsTo(string|iterable|AbstractString $string): bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + + if ('' !== $string && $this->ignoreCase) { + return 0 === strcasecmp($string, $this->string); + } + + return $string === $this->string; + } + + public function folded(): static + { + $str = clone $this; + $str->string = strtolower($str->string); + + return $str; + } + + public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + + if ('' === $needle) { + return null; + } + + $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset); + + return false === $i ? null : $i; + } + + public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + + if ('' === $needle) { + return null; + } + + $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset); + + return false === $i ? null : $i; + } + + public function isUtf8(): bool + { + return '' === $this->string || preg_match('//u', $this->string); + } + + public function join(array $strings, ?string $lastGlue = null): static + { + $str = clone $this; + + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : ''; + $str->string = implode($this->string, $strings).$tail; + + return $str; + } + + public function length(): int + { + return \strlen($this->string); + } + + public function lower(): static + { + $str = clone $this; + $str->string = strtolower($str->string); + + return $str; + } + + public function match(string $regexp, int $flags = 0, int $offset = 0): array + { + $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; + + if ($this->ignoreCase) { + $regexp .= 'i'; + } + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + throw new RuntimeException('Matching failed with error: '.preg_last_error_msg()); + } + } finally { + restore_error_handler(); + } + + return $matches; + } + + public function padBoth(int $length, string $padStr = ' '): static + { + $str = clone $this; + $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH); + + return $str; + } + + public function padEnd(int $length, string $padStr = ' '): static + { + $str = clone $this; + $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT); + + return $str; + } + + public function padStart(int $length, string $padStr = ' '): static + { + $str = clone $this; + $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT); + + return $str; + } + + public function prepend(string ...$prefix): static + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string; + + return $str; + } + + public function replace(string $from, string $to): static + { + $str = clone $this; + + if ('' !== $from) { + $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string); + } + + return $str; + } + + public function replaceMatches(string $fromRegexp, string|callable $to): static + { + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + + $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + if (null === $string = $replace($fromRegexp, $to, $this->string)) { + $lastError = preg_last_error(); + + foreach (get_defined_constants(true)['pcre'] as $k => $v) { + if ($lastError === $v && str_ends_with($k, '_ERROR')) { + throw new RuntimeException('Matching failed with '.$k.'.'); + } + } + + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + restore_error_handler(); + } + + $str = clone $this; + $str->string = $string; + + return $str; + } + + public function reverse(): static + { + $str = clone $this; + $str->string = strrev($str->string); + + return $str; + } + + public function slice(int $start = 0, ?int $length = null): static + { + $str = clone $this; + $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX); + + return $str; + } + + public function snake(): static + { + $str = $this->camel(); + $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string)); + + return $str; + } + + public function splice(string $replacement, int $start = 0, ?int $length = null): static + { + $str = clone $this; + $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); + + return $str; + } + + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array + { + if (1 > $limit ??= \PHP_INT_MAX) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + + if (null !== $flags) { + return parent::split($delimiter, $limit, $flags); + } + + $str = clone $this; + $chunks = $this->ignoreCase + ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit) + : explode($delimiter, $this->string, $limit); + + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + + return $chunks; + } + + public function startsWith(string|iterable|AbstractString $prefix): bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + + return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \strlen($prefix)) : strncmp($this->string, $prefix, \strlen($prefix))); + } + + public function title(bool $allWords = false): static + { + $str = clone $this; + $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string); + + return $str; + } + + public function toUnicodeString(?string $fromEncoding = null): UnicodeString + { + return new UnicodeString($this->toCodePointString($fromEncoding)->string); + } + + public function toCodePointString(?string $fromEncoding = null): CodePointString + { + $u = new CodePointString(); + + if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) { + $u->string = $this->string; + + return $u; + } + + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); + + try { + try { + $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true); + } catch (InvalidArgumentException $e) { + if (!\function_exists('iconv')) { + throw $e; + } + + $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string); + + return $u; + } + } finally { + restore_error_handler(); + } + + if (!$validEncoding) { + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); + } + + $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); + + return $u; + } + + public function trim(string $chars = " \t\n\r\0\x0B\x0C"): static + { + $str = clone $this; + $str->string = trim($str->string, $chars); + + return $str; + } + + public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): static + { + $str = clone $this; + $str->string = rtrim($str->string, $chars); + + return $str; + } + + public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): static + { + $str = clone $this; + $str->string = ltrim($str->string, $chars); + + return $str; + } + + public function upper(): static + { + $str = clone $this; + $str->string = strtoupper($str->string); + + return $str; + } + + public function width(bool $ignoreAnsiDecoration = true): int + { + $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\x80-\xFF]/', '?', $this->string); + + return (new CodePointString($string))->width($ignoreAnsiDecoration); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/CHANGELOG.md b/lam/lib/3rdParty/composer/symfony/string/CHANGELOG.md new file mode 100644 index 000000000..31a3b54db --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/CHANGELOG.md @@ -0,0 +1,40 @@ +CHANGELOG +========= + +6.2 +--- + + * Add support for emoji in `AsciiSlugger` + +5.4 +--- + + * Add `trimSuffix()` and `trimPrefix()` methods + +5.3 +--- + + * Made `AsciiSlugger` fallback to parent locale's symbolsMap + +5.2.0 +----- + + * added a `FrenchInflector` class + +5.1.0 +----- + + * added the `AbstractString::reverse()` method + * made `AbstractString::width()` follow POSIX.1-2001 + * added `LazyString` which provides memoizing stringable objects + * The component is not marked as `@experimental` anymore + * added the `s()` helper method to get either an `UnicodeString` or `ByteString` instance, + depending of the input string UTF-8 compliancy + * added `$cut` parameter to `Symfony\Component\String\AbstractString::truncate()` + * added `AbstractString::containsAny()` + * allow passing a string of custom characters to `ByteString::fromRandom()` + +5.0.0 +----- + + * added the component as experimental diff --git a/lam/lib/3rdParty/composer/symfony/string/CodePointString.php b/lam/lib/3rdParty/composer/symfony/string/CodePointString.php new file mode 100644 index 000000000..337bfc12a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/CodePointString.php @@ -0,0 +1,260 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +use Symfony\Component\String\Exception\ExceptionInterface; +use Symfony\Component\String\Exception\InvalidArgumentException; + +/** + * Represents a string of Unicode code points encoded as UTF-8. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class CodePointString extends AbstractUnicodeString +{ + public function __construct(string $string = '') + { + if ('' !== $string && !preg_match('//u', $string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $this->string = $string; + } + + public function append(string ...$suffix): static + { + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix); + + if (!preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + return $str; + } + + public function chunk(int $length = 1): array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + + if ('' === $this->string) { + return []; + } + + $rx = '/('; + while (65535 < $length) { + $rx .= '.{65535}'; + $length -= 65535; + } + $rx .= '.{'.$length.'})/us'; + + $str = clone $this; + $chunks = []; + + foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + + return $chunks; + } + + public function codePointsAt(int $offset): array + { + $str = $offset ? $this->slice($offset, 1) : $this; + + return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')]; + } + + public function endsWith(string|iterable|AbstractString $suffix): bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + + if ('' === $suffix || !preg_match('//u', $suffix)) { + return false; + } + + if ($this->ignoreCase) { + return preg_match('{'.preg_quote($suffix).'$}iuD', $this->string); + } + + return \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix)); + } + + public function equalsTo(string|iterable|AbstractString $string): bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + + if ('' !== $string && $this->ignoreCase) { + return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8'); + } + + return $string === $this->string; + } + + public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + + if ('' === $needle) { + return null; + } + + $i = $this->ignoreCase ? mb_stripos($this->string, $needle, $offset, 'UTF-8') : mb_strpos($this->string, $needle, $offset, 'UTF-8'); + + return false === $i ? null : $i; + } + + public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + + if ('' === $needle) { + return null; + } + + $i = $this->ignoreCase ? mb_strripos($this->string, $needle, $offset, 'UTF-8') : mb_strrpos($this->string, $needle, $offset, 'UTF-8'); + + return false === $i ? null : $i; + } + + public function length(): int + { + return mb_strlen($this->string, 'UTF-8'); + } + + public function prepend(string ...$prefix): static + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; + + if (!preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + return $str; + } + + public function replace(string $from, string $to): static + { + $str = clone $this; + + if ('' === $from || !preg_match('//u', $from)) { + return $str; + } + + if ('' !== $to && !preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + if ($this->ignoreCase) { + $str->string = implode($to, preg_split('{'.preg_quote($from).'}iuD', $this->string)); + } else { + $str->string = str_replace($from, $to, $this->string); + } + + return $str; + } + + public function slice(int $start = 0, ?int $length = null): static + { + $str = clone $this; + $str->string = mb_substr($this->string, $start, $length, 'UTF-8'); + + return $str; + } + + public function splice(string $replacement, int $start = 0, ?int $length = null): static + { + if (!preg_match('//u', $replacement)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $str = clone $this; + $start = $start ? \strlen(mb_substr($this->string, 0, $start, 'UTF-8')) : 0; + $length = $length ? \strlen(mb_substr($this->string, $start, $length, 'UTF-8')) : $length; + $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); + + return $str; + } + + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array + { + if (1 > $limit ??= \PHP_INT_MAX) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + + if (null !== $flags) { + return parent::split($delimiter.'u', $limit, $flags); + } + + if (!preg_match('//u', $delimiter)) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + + $str = clone $this; + $chunks = $this->ignoreCase + ? preg_split('{'.preg_quote($delimiter).'}iuD', $this->string, $limit) + : explode($delimiter, $this->string, $limit); + + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + + return $chunks; + } + + public function startsWith(string|iterable|AbstractString $prefix): bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + + if ('' === $prefix || !preg_match('//u', $prefix)) { + return false; + } + + if ($this->ignoreCase) { + return 0 === mb_stripos($this->string, $prefix, 0, 'UTF-8'); + } + + return 0 === strncmp($this->string, $prefix, \strlen($prefix)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Exception/ExceptionInterface.php b/lam/lib/3rdParty/composer/symfony/string/Exception/ExceptionInterface.php new file mode 100644 index 000000000..361978656 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Exception/ExceptionInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Exception/InvalidArgumentException.php b/lam/lib/3rdParty/composer/symfony/string/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..6aa586bcf --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Exception/InvalidArgumentException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Exception; + +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Exception/RuntimeException.php b/lam/lib/3rdParty/composer/symfony/string/Exception/RuntimeException.php new file mode 100644 index 000000000..77cb091f9 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Exception/RuntimeException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Exception; + +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Inflector/EnglishInflector.php b/lam/lib/3rdParty/composer/symfony/string/Inflector/EnglishInflector.php new file mode 100644 index 000000000..b9d74c004 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Inflector/EnglishInflector.php @@ -0,0 +1,601 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +final class EnglishInflector implements InflectorInterface +{ + /** + * Map English plural to singular suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + private const PLURAL_MAP = [ + // First entry: plural suffix, reversed + // Second entry: length of plural suffix + // Third entry: Whether the suffix may succeed a vowel + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: singular suffix, normal + + // nodes (node) + ['sedon', 5, true, true, 'node'], + + // bacteria (bacterium) + ['airetcab', 8, true, true, 'bacterium'], + + // issues (issue) + ['seussi', 6, true, true, 'issue'], + + // corpora (corpus) + ['aroproc', 7, true, true, 'corpus'], + + // criteria (criterion) + ['airetirc', 8, true, true, 'criterion'], + + // curricula (curriculum) + ['alucirruc', 9, true, true, 'curriculum'], + + // quora (quorum) + ['arouq', 5, true, true, 'quorum'], + + // genera (genus) + ['areneg', 6, true, true, 'genus'], + + // media (medium) + ['aidem', 5, true, true, 'medium'], + + // memoranda (memorandum) + ['adnaromem', 9, true, true, 'memorandum'], + + // phenomena (phenomenon) + ['anemonehp', 9, true, true, 'phenomenon'], + + // strata (stratum) + ['atarts', 6, true, true, 'stratum'], + + // nebulae (nebula) + ['ea', 2, true, true, 'a'], + + // services (service) + ['secivres', 8, true, true, 'service'], + + // mice (mouse), lice (louse) + ['eci', 3, false, true, 'ouse'], + + // geese (goose) + ['esee', 4, false, true, 'oose'], + + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['i', 1, true, true, 'us'], + + // men (man), women (woman) + ['nem', 3, true, true, 'man'], + + // children (child) + ['nerdlihc', 8, true, true, 'child'], + + // oxen (ox) + ['nexo', 4, false, false, 'ox'], + + // indices (index), appendices (appendix), prices (price) + ['seci', 4, false, true, ['ex', 'ix', 'ice']], + + // codes (code) + ['sedoc', 5, false, true, 'code'], + + // selfies (selfie) + ['seifles', 7, true, true, 'selfie'], + + // zombies (zombie) + ['seibmoz', 7, true, true, 'zombie'], + + // movies (movie) + ['seivom', 6, true, true, 'movie'], + + // names (name) + ['seman', 5, true, false, 'name'], + + // conspectuses (conspectus), prospectuses (prospectus) + ['sesutcep', 8, true, true, 'pectus'], + + // feet (foot) + ['teef', 4, true, true, 'foot'], + + // geese (goose) + ['eseeg', 5, true, true, 'goose'], + + // teeth (tooth) + ['hteet', 5, true, true, 'tooth'], + + // news (news) + ['swen', 4, true, true, 'news'], + + // series (series) + ['seires', 6, true, true, 'series'], + + // babies (baby) + ['sei', 3, false, true, 'y'], + + // accesses (access), addresses (address), kisses (kiss) + ['sess', 4, true, false, 'ss'], + + // statuses (status) + ['sesutats', 8, true, true, 'status'], + + // article (articles), ancle (ancles) + ['sel', 3, true, true, 'le'], + + // analyses (analysis), ellipses (ellipsis), fungi (fungus), + // neuroses (neurosis), theses (thesis), emphases (emphasis), + // oases (oasis), crises (crisis), houses (house), bases (base), + // atlases (atlas) + ['ses', 3, true, true, ['s', 'se', 'sis']], + + // objectives (objective), alternative (alternatives) + ['sevit', 5, true, true, 'tive'], + + // drives (drive) + ['sevird', 6, false, true, 'drive'], + + // lives (life), wives (wife) + ['sevi', 4, false, true, 'ife'], + + // moves (move) + ['sevom', 5, true, true, 'move'], + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) + ['sev', 3, true, true, ['f', 've', 'ff']], + + // axes (axis), axes (ax), axes (axe) + ['sexa', 4, false, false, ['ax', 'axe', 'axis']], + + // indexes (index), matrixes (matrix) + ['sex', 3, true, false, 'x'], + + // quizzes (quiz) + ['sezz', 4, true, false, 'z'], + + // bureaus (bureau) + ['suae', 4, false, true, 'eau'], + + // fees (fee), trees (tree), employees (employee) + ['see', 3, true, true, 'ee'], + + // edges (edge) + ['segd', 4, true, true, 'dge'], + + // outages (outage) - specific fix to avoid 'outag' + ['segatuo', 7, true, true, 'outage'], + + // roses (rose), garages (garage), cassettes (cassette), + // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), + // shoes (shoe) + ['se', 2, true, true, ['', 'e']], + + // status (status) + ['sutats', 6, true, true, 'status'], + + // tags (tag) + ['s', 1, true, true, ''], + + // chateaux (chateau) + ['xuae', 4, false, true, 'eau'], + + // people (person) + ['elpoep', 6, true, true, 'person'], + ]; + + /** + * Map English singular to plural suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + private const SINGULAR_MAP = [ + // First entry: singular suffix, reversed + // Second entry: length of singular suffix + // Third entry: Whether the suffix may succeed a vowel + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: plural suffix, normal + + // nodes (node) + ['edon', 4, true, true, 'nodes'], + + // axes (axis) + ['sixa', 4, false, false, 'axes'], + + // criterion (criteria) + ['airetirc', 8, false, false, 'criterion'], + + // nebulae (nebula) + ['aluben', 6, false, false, 'nebulae'], + + // children (child) + ['dlihc', 5, true, true, 'children'], + + // prices (price) + ['eci', 3, false, true, 'ices'], + + // services (service) + ['ecivres', 7, true, true, 'services'], + + // lives (life), wives (wife) + ['efi', 3, false, true, 'ives'], + + // selfies (selfie) + ['eifles', 6, true, true, 'selfies'], + + // movies (movie) + ['eivom', 5, true, true, 'movies'], + + // lice (louse) + ['esuol', 5, false, true, 'lice'], + + // mice (mouse) + ['esuom', 5, false, true, 'mice'], + + // geese (goose) + ['esoo', 4, false, true, 'eese'], + + // houses (house), bases (base) + ['es', 2, true, true, 'ses'], + + // geese (goose) + ['esoog', 5, true, true, 'geese'], + + // caves (cave) + ['ev', 2, true, true, 'ves'], + + // drives (drive) + ['evird', 5, false, true, 'drives'], + + // objectives (objective), alternative (alternatives) + ['evit', 4, true, true, 'tives'], + + // moves (move) + ['evom', 4, true, true, 'moves'], + + // staves (staff) + ['ffats', 5, true, true, 'staves'], + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['ff', 2, true, true, 'ffs'], + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['f', 1, true, true, ['fs', 'ves']], + + // arches (arch) + ['hc', 2, true, true, 'ches'], + + // bushes (bush) + ['hs', 2, true, true, 'shes'], + + // teeth (tooth) + ['htoot', 5, true, true, 'teeth'], + + // albums (album) + ['mubla', 5, true, true, 'albums'], + + // quorums (quorum) + ['murouq', 6, true, true, ['quora', 'quorums']], + + // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum) + ['mu', 2, true, true, 'a'], + + // men (man), women (woman) + ['nam', 3, true, true, 'men'], + + // people (person) + ['nosrep', 6, true, true, ['persons', 'people']], + + // criteria (criterion) + ['noiretirc', 9, true, true, 'criteria'], + + // phenomena (phenomenon) + ['nonemonehp', 10, true, true, 'phenomena'], + + // echoes (echo) + ['ohce', 4, true, true, 'echoes'], + + // heroes (hero) + ['oreh', 4, true, true, 'heroes'], + + // atlases (atlas) + ['salta', 5, true, true, 'atlases'], + + // aliases (alias) + ['saila', 5, true, true, 'aliases'], + + // irises (iris) + ['siri', 4, true, true, 'irises'], + + // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) + // theses (thesis), emphases (emphasis), oases (oasis), + // crises (crisis) + ['sis', 3, true, true, 'ses'], + + // accesses (access), addresses (address), kisses (kiss) + ['ss', 2, true, false, 'sses'], + + // syllabi (syllabus) + ['suballys', 8, true, true, 'syllabi'], + + // buses (bus) + ['sub', 3, true, true, 'buses'], + + // circuses (circus) + ['suc', 3, true, true, 'cuses'], + + // hippocampi (hippocampus) + ['supmacoppih', 11, false, false, 'hippocampi'], + + // campuses (campus) + ['sup', 3, true, true, 'puses'], + + // status (status) + ['sutats', 6, true, true, ['status', 'statuses']], + + // conspectuses (conspectus), prospectuses (prospectus) + ['sutcep', 6, true, true, 'pectuses'], + + // nexuses (nexus) + ['suxen', 5, false, false, 'nexuses'], + + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['su', 2, true, true, 'i'], + + // news (news) + ['swen', 4, true, true, 'news'], + + // feet (foot) + ['toof', 4, true, true, 'feet'], + + // chateaux (chateau), bureaus (bureau) + ['uae', 3, false, true, ['eaus', 'eaux']], + + // oxen (ox) + ['xo', 2, false, false, 'oxen'], + + // hoaxes (hoax) + ['xaoh', 4, true, false, 'hoaxes'], + + // indices (index) + ['xedni', 5, false, true, ['indicies', 'indexes']], + + // fax (faxes, faxxes) + ['xaf', 3, true, true, ['faxes', 'faxxes']], + + // boxes (box) + ['xo', 2, false, true, 'oxes'], + + // indexes (index), matrixes (matrix), appendices (appendix) + ['x', 1, true, false, ['ces', 'xes']], + + // babies (baby) + ['y', 1, false, true, 'ies'], + + // quizzes (quiz) + ['ziuq', 4, true, false, 'quizzes'], + + // waltzes (waltz) + ['z', 1, true, true, 'zes'], + ]; + + /** + * A list of words which should not be inflected, reversed. + */ + private const UNINFLECTED = [ + '', + + // data + 'atad', + + // deer + 'reed', + + // equipment + 'tnempiuqe', + + // feedback + 'kcabdeef', + + // fish + 'hsif', + + // health + 'htlaeh', + + // history + 'yrotsih', + + // info + 'ofni', + + // information + 'noitamrofni', + + // money + 'yenom', + + // moose + 'esoom', + + // series + 'seires', + + // sheep + 'peehs', + + // species + 'seiceps', + + // traffic + 'ciffart', + + // aircraft + 'tfarcria', + + // hardware + 'erawdrah', + ]; + + public function singularize(string $plural): array + { + $pluralRev = strrev($plural); + $lowerPluralRev = strtolower($pluralRev); + $pluralLength = \strlen($lowerPluralRev); + + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerPluralRev, self::UNINFLECTED, true)) { + return [$plural]; + } + + // The outer loop iterates over the entries of the plural table + // The inner loop $j iterates over the characters of the plural suffix + // in the plural table to compare them with the characters of the actual + // given plural suffix + foreach (self::PLURAL_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + + // Compare characters in the plural table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerPluralRev[$j]) { + // Let $j point to the next character + ++$j; + + // Successfully compared the last character + // Add an entry with the singular suffix to the singular array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $pluralLength) { + $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]); + + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one + break; + } + + if (!$map[3] && !$nextIsVowel) { + // suffix may not succeed a consonant but next char is one + break; + } + } + + $newBase = substr($plural, 0, $pluralLength - $suffixLength); + $newSuffix = $map[4]; + + // Check whether the first character in the plural suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = ctype_upper($pluralRev[$j - 1]); + + if (\is_array($newSuffix)) { + $singulars = []; + + foreach ($newSuffix as $newSuffixEntry) { + $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); + } + + return $singulars; + } + + return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)]; + } + + // Suffix is longer than word + if ($j === $pluralLength) { + break; + } + } + } + + // Assume that plural and singular is identical + return [$plural]; + } + + public function pluralize(string $singular): array + { + $singularRev = strrev($singular); + $lowerSingularRev = strtolower($singularRev); + $singularLength = \strlen($lowerSingularRev); + + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerSingularRev, self::UNINFLECTED, true)) { + return [$singular]; + } + + // The outer loop iterates over the entries of the singular table + // The inner loop $j iterates over the characters of the singular suffix + // in the singular table to compare them with the characters of the actual + // given singular suffix + foreach (self::SINGULAR_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + + // Compare characters in the singular table and of the suffix of the + // given plural one by one + + while ($suffix[$j] === $lowerSingularRev[$j]) { + // Let $j point to the next character + ++$j; + + // Successfully compared the last character + // Add an entry with the plural suffix to the plural array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $singularLength) { + $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]); + + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one + break; + } + + if (!$map[3] && !$nextIsVowel) { + // suffix may not succeed a consonant but next char is one + break; + } + } + + $newBase = substr($singular, 0, $singularLength - $suffixLength); + $newSuffix = $map[4]; + + // Check whether the first character in the singular suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = ctype_upper($singularRev[$j - 1]); + + if (\is_array($newSuffix)) { + $plurals = []; + + foreach ($newSuffix as $newSuffixEntry) { + $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); + } + + return $plurals; + } + + return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)]; + } + + // Suffix is longer than word + if ($j === $singularLength) { + break; + } + } + } + + // Assume that plural is singular with a trailing `s` + return [$singular.'s']; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Inflector/FrenchInflector.php b/lam/lib/3rdParty/composer/symfony/string/Inflector/FrenchInflector.php new file mode 100644 index 000000000..955abbf46 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Inflector/FrenchInflector.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +/** + * French inflector. + * + * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix". + */ +final class FrenchInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php + */ + private const PLURALIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + + // Words finishing with "s", "x" or "z" are invariables + // Les mots finissant par "s", "x" ou "z" sont invariables + ['/(s|x|z)$/i', '\1'], + + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)$/i', '\1x'], + + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/^(landau)$/i', '\1s'], + ['/(au)$/i', '\1x'], + + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/^(pneu|bleu|émeu)$/i', '\1s'], + ['/(eu)$/i', '\1x'], + + // Words finishing with "al" are pluralized with a "aux" excepted + // Les mots finissant en "al" se terminent en "aux" sauf + ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\1s'], + ['/al$/i', '\1aux'], + + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\1aux'], + + // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel + ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\1oux'], + + // Invariable words + ['/^(cinquante|soixante|mille)$/i', '\1'], + + // French titles + ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'mes\2s'], + ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Mes\2s'], + ]; + + /** + * A list of all rules for singularize. + */ + private const SINGULARIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\1ail'], + + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)x$/i', '\1'], + + // Words finishing with "al" are pluralized with a "aux" expected + // Les mots finissant en "al" se terminent en "aux" sauf + ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\1al'], + + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/(au)x$/i', '\1'], + + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/(eu)x$/i', '\1'], + + // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou + // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou + ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\1ou'], + + // French titles + ['/^mes(dame|demoiselle)s$/', 'ma\1'], + ['/^Mes(dame|demoiselle)s$/', 'Ma\1'], + ['/^mes(sieur|seigneur)s$/', 'mon\1'], + ['/^Mes(sieur|seigneur)s$/', 'Mon\1'], + + // Default rule + ['/s$/i', ''], + ]; + + /** + * A list of words which should not be inflected. + * This list is only used by singularize. + */ + private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; + + public function singularize(string $plural): array + { + if ($this->isInflectedWord($plural)) { + return [$plural]; + } + + foreach (self::SINGULARIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $plural)) { + return [preg_replace($regexp, $replace, $plural)]; + } + } + + return [$plural]; + } + + public function pluralize(string $singular): array + { + if ($this->isInflectedWord($singular)) { + return [$singular]; + } + + foreach (self::PLURALIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $singular)) { + return [preg_replace($regexp, $replace, $singular)]; + } + } + + return [$singular.'s']; + } + + private function isInflectedWord(string $word): bool + { + return 1 === preg_match(self::UNINFLECTED, $word); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Inflector/InflectorInterface.php b/lam/lib/3rdParty/composer/symfony/string/Inflector/InflectorInterface.php new file mode 100644 index 000000000..67f283404 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Inflector/InflectorInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +interface InflectorInterface +{ + /** + * Returns the singular forms of a string. + * + * If the method can't determine the form with certainty, several possible singulars are returned. + * + * @return string[] + */ + public function singularize(string $plural): array; + + /** + * Returns the plural forms of a string. + * + * If the method can't determine the form with certainty, several possible plurals are returned. + * + * @return string[] + */ + public function pluralize(string $singular): array; +} diff --git a/lam/lib/3rdParty/composer/symfony/string/LICENSE b/lam/lib/3rdParty/composer/symfony/string/LICENSE new file mode 100644 index 000000000..f37c76b59 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lam/lib/3rdParty/composer/symfony/string/LazyString.php b/lam/lib/3rdParty/composer/symfony/string/LazyString.php new file mode 100644 index 000000000..b89ec4df1 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/LazyString.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +/** + * A string whose value is computed lazily by a callback. + * + * @author Nicolas Grekas + */ +class LazyString implements \Stringable, \JsonSerializable +{ + private \Closure|string $value; + + /** + * @param callable|array $callback A callable or a [Closure, method] lazy-callable + */ + public static function fromCallable(callable|array $callback, mixed ...$arguments): static + { + if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); + } + + $lazyString = new static(); + $lazyString->value = static function () use (&$callback, &$arguments): string { + static $value; + + if (null !== $arguments) { + if (!\is_callable($callback)) { + $callback[0] = $callback[0](); + $callback[1] ??= '__invoke'; + } + $value = $callback(...$arguments); + $callback = !\is_scalar($value) && !$value instanceof \Stringable ? self::getPrettyName($callback) : 'callable'; + $arguments = null; + } + + return $value ?? ''; + }; + + return $lazyString; + } + + public static function fromStringable(string|int|float|bool|\Stringable $value): static + { + if (\is_object($value)) { + return static::fromCallable($value->__toString(...)); + } + + $lazyString = new static(); + $lazyString->value = (string) $value; + + return $lazyString; + } + + /** + * Tells whether the provided value can be cast to string. + */ + final public static function isStringable(mixed $value): bool + { + return \is_string($value) || $value instanceof \Stringable || \is_scalar($value); + } + + /** + * Casts scalars and stringable objects to strings. + * + * @throws \TypeError When the provided value is not stringable + */ + final public static function resolve(\Stringable|string|int|float|bool $value): string + { + return $value; + } + + public function __toString(): string + { + if (\is_string($this->value)) { + return $this->value; + } + + try { + return $this->value = ($this->value)(); + } catch (\Throwable $e) { + if (\TypeError::class === $e::class && __FILE__ === $e->getFile()) { + $type = explode(', ', $e->getMessage()); + $type = substr(array_pop($type), 0, -\strlen(' returned')); + $r = new \ReflectionFunction($this->value); + $callback = $r->getStaticVariables()['callback']; + + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + } + + throw $e; + } + } + + public function __sleep(): array + { + $this->__toString(); + + return ['value']; + } + + public function jsonSerialize(): string + { + return $this->__toString(); + } + + private function __construct() + { + } + + private static function getPrettyName(callable $callback): string + { + if (\is_string($callback)) { + return $callback; + } + + if (\is_array($callback)) { + $class = \is_object($callback[0]) ? get_debug_type($callback[0]) : $callback[0]; + $method = $callback[1]; + } elseif ($callback instanceof \Closure) { + $r = new \ReflectionFunction($callback); + + if (str_contains($r->name, '{closure') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { + return $r->name; + } + + $class = $class->name; + $method = $r->name; + } else { + $class = get_debug_type($callback); + $method = '__invoke'; + } + + return $class.'::'.$method; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/README.md b/lam/lib/3rdParty/composer/symfony/string/README.md new file mode 100644 index 000000000..9c7e1e190 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/README.md @@ -0,0 +1,14 @@ +String Component +================ + +The String component provides an object-oriented API to strings and deals +with bytes, UTF-8 code points and grapheme clusters in a unified way. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/string.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/lam/lib/3rdParty/composer/symfony/string/Resources/data/wcswidth_table_wide.php b/lam/lib/3rdParty/composer/symfony/string/Resources/data/wcswidth_table_wide.php new file mode 100644 index 000000000..6a7509421 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Resources/data/wcswidth_table_wide.php @@ -0,0 +1,1175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +if (!\function_exists(u::class)) { + function u(?string $string = ''): UnicodeString + { + return new UnicodeString($string ?? ''); + } +} + +if (!\function_exists(b::class)) { + function b(?string $string = ''): ByteString + { + return new ByteString($string ?? ''); + } +} + +if (!\function_exists(s::class)) { + /** + * @return UnicodeString|ByteString + */ + function s(?string $string = ''): AbstractString + { + $string ??= ''; + + return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Slugger/AsciiSlugger.php b/lam/lib/3rdParty/composer/symfony/string/Slugger/AsciiSlugger.php new file mode 100644 index 000000000..d0c338682 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Slugger/AsciiSlugger.php @@ -0,0 +1,210 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Slugger; + +use Symfony\Component\Intl\Transliterator\EmojiTransliterator; +use Symfony\Component\String\AbstractUnicodeString; +use Symfony\Component\String\UnicodeString; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +if (!interface_exists(LocaleAwareInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".'); +} + +/** + * @author Titouan Galopin + */ +class AsciiSlugger implements SluggerInterface, LocaleAwareInterface +{ + private const LOCALE_TO_TRANSLITERATOR_ID = [ + 'am' => 'Amharic-Latin', + 'ar' => 'Arabic-Latin', + 'az' => 'Azerbaijani-Latin', + 'be' => 'Belarusian-Latin', + 'bg' => 'Bulgarian-Latin', + 'bn' => 'Bengali-Latin', + 'de' => 'de-ASCII', + 'el' => 'Greek-Latin', + 'fa' => 'Persian-Latin', + 'he' => 'Hebrew-Latin', + 'hy' => 'Armenian-Latin', + 'ka' => 'Georgian-Latin', + 'kk' => 'Kazakh-Latin', + 'ky' => 'Kirghiz-Latin', + 'ko' => 'Korean-Latin', + 'mk' => 'Macedonian-Latin', + 'mn' => 'Mongolian-Latin', + 'or' => 'Oriya-Latin', + 'ps' => 'Pashto-Latin', + 'ru' => 'Russian-Latin', + 'sr' => 'Serbian-Latin', + 'sr_Cyrl' => 'Serbian-Latin', + 'th' => 'Thai-Latin', + 'tk' => 'Turkmen-Latin', + 'uk' => 'Ukrainian-Latin', + 'uz' => 'Uzbek-Latin', + 'zh' => 'Han-Latin', + ]; + + private ?string $defaultLocale; + private \Closure|array $symbolsMap = [ + 'en' => ['@' => 'at', '&' => 'and'], + ]; + private bool|string $emoji = false; + + /** + * Cache of transliterators per locale. + * + * @var \Transliterator[] + */ + private array $transliterators = []; + + public function __construct(?string $defaultLocale = null, array|\Closure|null $symbolsMap = null) + { + $this->defaultLocale = $defaultLocale; + $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; + } + + /** + * @return void + */ + public function setLocale(string $locale) + { + $this->defaultLocale = $locale; + } + + public function getLocale(): string + { + return $this->defaultLocale; + } + + /** + * @param bool|string $emoji true will use the same locale, + * false will disable emoji, + * and a string to use a specific locale + */ + public function withEmoji(bool|string $emoji = true): static + { + if (false !== $emoji && !class_exists(EmojiTransliterator::class)) { + throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); + } + + $new = clone $this; + $new->emoji = $emoji; + + return $new; + } + + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString + { + $locale ??= $this->defaultLocale; + + $transliterator = []; + if ($locale && ('de' === $locale || str_starts_with($locale, 'de_'))) { + // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) + $transliterator = ['de-ASCII']; + } elseif (\function_exists('transliterator_transliterate') && $locale) { + $transliterator = (array) $this->createTransliterator($locale); + } + + if ($emojiTransliterator = $this->createEmojiTransliterator($locale)) { + $transliterator[] = $emojiTransliterator; + } + + if ($this->symbolsMap instanceof \Closure) { + // If the symbols map is passed as a closure, there is no need to fallback to the parent locale + // as the closure can just provide substitutions for all locales of interest. + $symbolsMap = $this->symbolsMap; + array_unshift($transliterator, static fn ($s) => $symbolsMap($s, $locale)); + } + + $unicodeString = (new UnicodeString($string))->ascii($transliterator); + + if (\is_array($this->symbolsMap)) { + $map = null; + if (isset($this->symbolsMap[$locale])) { + $map = $this->symbolsMap[$locale]; + } else { + $parent = self::getParentLocale($locale); + if ($parent && isset($this->symbolsMap[$parent])) { + $map = $this->symbolsMap[$parent]; + } + } + if ($map) { + foreach ($map as $char => $replace) { + $unicodeString = $unicodeString->replace($char, ' '.$replace.' '); + } + } + } + + return $unicodeString + ->replaceMatches('/[^A-Za-z0-9]++/', $separator) + ->trim($separator) + ; + } + + private function createTransliterator(string $locale): ?\Transliterator + { + if (\array_key_exists($locale, $this->transliterators)) { + return $this->transliterators[$locale]; + } + + // Exact locale supported, cache and return + if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) { + return $this->transliterators[$locale] = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id); + } + + // Locale not supported and no parent, fallback to any-latin + if (!$parent = self::getParentLocale($locale)) { + return $this->transliterators[$locale] = null; + } + + // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales + if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) { + $transliterator = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id); + } + + return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null; + } + + private function createEmojiTransliterator(?string $locale): ?EmojiTransliterator + { + if (\is_string($this->emoji)) { + $locale = $this->emoji; + } elseif (!$this->emoji) { + return null; + } + + while (null !== $locale) { + try { + return EmojiTransliterator::create("emoji-$locale"); + } catch (\IntlException) { + $locale = self::getParentLocale($locale); + } + } + + return null; + } + + private static function getParentLocale(?string $locale): ?string + { + if (!$locale) { + return null; + } + if (false === $str = strrchr($locale, '_')) { + // no parent locale + return null; + } + + return substr($locale, 0, -\strlen($str)); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/Slugger/SluggerInterface.php b/lam/lib/3rdParty/composer/symfony/string/Slugger/SluggerInterface.php new file mode 100644 index 000000000..dd0d58102 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/Slugger/SluggerInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Slugger; + +use Symfony\Component\String\AbstractUnicodeString; + +/** + * Creates a URL-friendly slug from a given string. + * + * @author Titouan Galopin + */ +interface SluggerInterface +{ + /** + * Creates a slug for the given string and locale, using appropriate transliteration when needed. + */ + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString; +} diff --git a/lam/lib/3rdParty/composer/symfony/string/UnicodeString.php b/lam/lib/3rdParty/composer/symfony/string/UnicodeString.php new file mode 100644 index 000000000..75af2da42 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/UnicodeString.php @@ -0,0 +1,385 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +use Symfony\Component\String\Exception\ExceptionInterface; +use Symfony\Component\String\Exception\InvalidArgumentException; + +/** + * Represents a string of Unicode grapheme clusters encoded as UTF-8. + * + * A letter followed by combining characters (accents typically) form what Unicode defines + * as a grapheme cluster: a character as humans mean it in written texts. This class knows + * about the concept and won't split a letter apart from its combining accents. It also + * ensures all string comparisons happen on their canonically-composed representation, + * ignoring e.g. the order in which accents are listed when a letter has many of them. + * + * @see https://unicode.org/reports/tr15/ + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class UnicodeString extends AbstractUnicodeString +{ + public function __construct(string $string = '') + { + if ('' === $string || normalizer_is_normalized($this->string = $string)) { + return; + } + + if (false === $string = normalizer_normalize($string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $this->string = $string; + } + + public function append(string ...$suffix): static + { + $str = clone $this; + $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix)); + + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $str->string = $string; + + return $str; + } + + public function chunk(int $length = 1): array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + + if ('' === $this->string) { + return []; + } + + $rx = '/('; + while (65535 < $length) { + $rx .= '\X{65535}'; + $length -= 65535; + } + $rx .= '\X{'.$length.'})/u'; + + $str = clone $this; + $chunks = []; + + foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + + return $chunks; + } + + public function endsWith(string|iterable|AbstractString $suffix): bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + normalizer_is_normalized($suffix, $form) ?: $suffix = normalizer_normalize($suffix, $form); + + if ('' === $suffix || false === $suffix) { + return false; + } + + if ($this->ignoreCase) { + return 0 === mb_stripos(grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8'); + } + + return $suffix === grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)); + } + + public function equalsTo(string|iterable|AbstractString $string): bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + normalizer_is_normalized($string, $form) ?: $string = normalizer_normalize($string, $form); + + if ('' !== $string && false !== $string && $this->ignoreCase) { + return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8'); + } + + return $string === $this->string; + } + + public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form); + + if ('' === $needle || false === $needle) { + return null; + } + + try { + $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset); + } catch (\ValueError) { + return null; + } + + return false === $i ? null : $i; + } + + public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form); + + if ('' === $needle || false === $needle) { + return null; + } + + $string = $this->string; + + if (0 > $offset) { + // workaround https://bugs.php.net/74264 + if (0 > $offset += grapheme_strlen($needle)) { + $string = grapheme_substr($string, 0, $offset); + } + $offset = 0; + } + + $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset); + + return false === $i ? null : $i; + } + + public function join(array $strings, ?string $lastGlue = null): static + { + $str = parent::join($strings, $lastGlue); + normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); + + return $str; + } + + public function length(): int + { + return grapheme_strlen($this->string); + } + + public function normalize(int $form = self::NFC): static + { + $str = clone $this; + + if (\in_array($form, [self::NFC, self::NFKC], true)) { + normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form); + } elseif (!\in_array($form, [self::NFD, self::NFKD], true)) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } elseif (!normalizer_is_normalized($str->string, $form)) { + $str->string = normalizer_normalize($str->string, $form); + $str->ignoreCase = null; + } + + return $str; + } + + public function prepend(string ...$prefix): static + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; + + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $str->string = $string; + + return $str; + } + + public function replace(string $from, string $to): static + { + $str = clone $this; + normalizer_is_normalized($from) ?: $from = normalizer_normalize($from); + + if ('' !== $from && false !== $from) { + $tail = $str->string; + $result = ''; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + + while ('' !== $tail && false !== $i = $indexOf($tail, $from)) { + $slice = grapheme_substr($tail, 0, $i); + $result .= $slice.$to; + $tail = substr($tail, \strlen($slice) + \strlen($from)); + } + + $str->string = $result.$tail; + + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $str->string = $string; + } + + return $str; + } + + public function replaceMatches(string $fromRegexp, string|callable $to): static + { + $str = parent::replaceMatches($fromRegexp, $to); + normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); + + return $str; + } + + public function slice(int $start = 0, ?int $length = null): static + { + $str = clone $this; + + $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647); + + return $str; + } + + public function splice(string $replacement, int $start = 0, ?int $length = null): static + { + $str = clone $this; + + $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; + $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; + $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); + + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + + $str->string = $string; + + return $str; + } + + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array + { + if (1 > $limit ??= 2147483647) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + + if (null !== $flags) { + return parent::split($delimiter.'u', $limit, $flags); + } + + normalizer_is_normalized($delimiter) ?: $delimiter = normalizer_normalize($delimiter); + + if (false === $delimiter) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + + $str = clone $this; + $tail = $this->string; + $chunks = []; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + + while (1 < $limit && false !== $i = $indexOf($tail, $delimiter)) { + $str->string = grapheme_substr($tail, 0, $i); + $chunks[] = clone $str; + $tail = substr($tail, \strlen($str->string) + \strlen($delimiter)); + --$limit; + } + + $str->string = $tail; + $chunks[] = clone $str; + + return $chunks; + } + + public function startsWith(string|iterable|AbstractString $prefix): bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + normalizer_is_normalized($prefix, $form) ?: $prefix = normalizer_normalize($prefix, $form); + + if ('' === $prefix || false === $prefix) { + return false; + } + + if ($this->ignoreCase) { + return 0 === mb_stripos(grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8'); + } + + return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); + } + + /** + * @return void + */ + public function __wakeup() + { + if (!\is_string($this->string)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string); + } + + public function __clone() + { + if (null === $this->ignoreCase) { + normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string); + } + + $this->ignoreCase = false; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/string/composer.json b/lam/lib/3rdParty/composer/symfony/string/composer.json new file mode 100644 index 000000000..56c136882 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/string/composer.json @@ -0,0 +1,43 @@ +{ + "name": "symfony/string", + "type": "library", + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "keywords": ["string", "utf8", "utf-8", "grapheme", "i18n", "unicode"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\String\\": "" }, + "files": [ "Resources/functions.php" ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/lam/lib/3rdParty/composer/symfony/translation-contracts/Test/TranslatorTest.php b/lam/lib/3rdParty/composer/symfony/translation-contracts/Test/TranslatorTest.php index 756228af5..da19d09bd 100644 --- a/lam/lib/3rdParty/composer/symfony/translation-contracts/Test/TranslatorTest.php +++ b/lam/lib/3rdParty/composer/symfony/translation-contracts/Test/TranslatorTest.php @@ -11,6 +11,8 @@ namespace Symfony\Contracts\Translation\Test; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorTrait; @@ -45,7 +47,7 @@ class TranslatorTest extends TestCase public function getTranslator(): TranslatorInterface { - return new class() implements TranslatorInterface { + return new class implements TranslatorInterface { use TranslatorTrait; }; } @@ -53,6 +55,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getTransTests */ + #[DataProvider('getTransTests')] public function testTrans($expected, $id, $parameters) { $translator = $this->getTranslator(); @@ -63,6 +66,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] public function testTransChoiceWithExplicitLocale($expected, $id, $number) { $translator = $this->getTranslator(); @@ -75,6 +79,8 @@ class TranslatorTest extends TestCase * * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] + #[RequiresPhpExtension('intl')] public function testTransChoiceWithDefaultLocale($expected, $id, $number) { $translator = $this->getTranslator(); @@ -85,6 +91,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getTransChoiceTests */ + #[DataProvider('getTransChoiceTests')] public function testTransChoiceWithEnUsPosix($expected, $id, $number) { $translator = $this->getTranslator(); @@ -103,6 +110,7 @@ class TranslatorTest extends TestCase /** * @requires extension intl */ + #[RequiresPhpExtension('intl')] public function testGetLocaleReturnsDefaultLocaleIfNotSet() { $translator = $this->getTranslator(); @@ -139,6 +147,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getInterval */ + #[DataProvider('getInterval')] public function testInterval($expected, $number, $interval) { $translator = $this->getTranslator(); @@ -164,6 +173,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getChooseTests */ + #[DataProvider('getChooseTests')] public function testChoose($expected, $id, $number, $locale = null) { $translator = $this->getTranslator(); @@ -181,6 +191,7 @@ class TranslatorTest extends TestCase /** * @dataProvider getNonMatchingMessages */ + #[DataProvider('getNonMatchingMessages')] public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) { $translator = $this->getTranslator(); @@ -296,6 +307,7 @@ class TranslatorTest extends TestCase /** * @dataProvider failingLangcodes */ + #[DataProvider('failingLangcodes')] public function testFailedLangcodes($nplural, $langCodes) { $matrix = $this->generateTestData($langCodes); @@ -305,6 +317,7 @@ class TranslatorTest extends TestCase /** * @dataProvider successLangcodes */ + #[DataProvider('successLangcodes')] public function testLangcodes($nplural, $langCodes) { $matrix = $this->generateTestData($langCodes); @@ -359,14 +372,14 @@ class TranslatorTest extends TestCase if ($expectSuccess) { $this->assertCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms."); } else { - $this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); + $this->assertNotCount($nplural, $indexes, "Langcode '$langCode' has '$nplural' plural forms."); } } } protected function generateTestData($langCodes) { - $translator = new class() { + $translator = new class { use TranslatorTrait { getPluralizationRule as public; } diff --git a/lam/lib/3rdParty/composer/symfony/translation-contracts/TranslatorTrait.php b/lam/lib/3rdParty/composer/symfony/translation-contracts/TranslatorTrait.php index 63f6fb333..06210b0ed 100644 --- a/lam/lib/3rdParty/composer/symfony/translation-contracts/TranslatorTrait.php +++ b/lam/lib/3rdParty/composer/symfony/translation-contracts/TranslatorTrait.php @@ -111,7 +111,7 @@ EOF; return strtr($standardRules[0], $parameters); } - $message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); + $message = \sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); if (class_exists(InvalidArgumentException::class)) { throw new InvalidArgumentException($message); diff --git a/lam/lib/3rdParty/composer/symfony/translation-contracts/composer.json b/lam/lib/3rdParty/composer/symfony/translation-contracts/composer.json index 181651e0d..b7220b84c 100644 --- a/lam/lib/3rdParty/composer/symfony/translation-contracts/composer.json +++ b/lam/lib/3rdParty/composer/symfony/translation-contracts/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/lam/lib/3rdParty/composer/symfony/translation/Catalogue/AbstractOperation.php b/lam/lib/3rdParty/composer/symfony/translation/Catalogue/AbstractOperation.php index 7dff58ff4..32fc5813c 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Catalogue/AbstractOperation.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Catalogue/AbstractOperation.php @@ -97,7 +97,7 @@ abstract class AbstractOperation implements OperationInterface public function getMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::ALL_BATCH])) { @@ -110,7 +110,7 @@ abstract class AbstractOperation implements OperationInterface public function getNewMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::NEW_BATCH])) { @@ -123,7 +123,7 @@ abstract class AbstractOperation implements OperationInterface public function getObsoleteMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) { @@ -160,7 +160,7 @@ abstract class AbstractOperation implements OperationInterface self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain), self::NEW_BATCH => $this->getNewMessages($domain), self::ALL_BATCH => $this->getMessages($domain), - default => throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)), + default => throw new \InvalidArgumentException(\sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)), }; if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) { diff --git a/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPullCommand.php b/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPullCommand.php index 5d9c092c3..2394b3efe 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPullCommand.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPullCommand.php @@ -92,10 +92,10 @@ final class TranslationPullCommand extends Command new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to pull translations from.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with provider ones (it will delete not synchronized messages).'), new InputOption('intl-icu', null, InputOption::VALUE_NONE, 'Associated to --force option, it will write messages in "%domain%+intl-icu.%locale%.xlf" files.'), - new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), - new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), - new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format.', 'xlf12'), - new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'), + new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), + new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format.', 'xlf12'), + new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'), ]) ->setHelp(<<<'EOF' The %command.name% command pulls translations from the given provider. Only @@ -163,7 +163,7 @@ EOF $this->writer->write($operation->getResult(), $format, $writeOptions); } - $io->success(sprintf('Local translations has been updated from "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('Local translations has been updated from "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } @@ -177,7 +177,7 @@ EOF $this->writer->write($catalogue, $format, $writeOptions); } - $io->success(sprintf('New translations from "%s" has been written locally (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('New translations from "%s" has been written locally (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPushCommand.php b/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPushCommand.php index 1d04adbc9..e0be0f447 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPushCommand.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Command/TranslationPushCommand.php @@ -83,8 +83,8 @@ final class TranslationPushCommand extends Command new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'), new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'), - new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'), - new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales), + new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'), + new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales), ]) ->setHelp(<<<'EOF' The %command.name% command pushes translations to the given provider. Only new @@ -115,7 +115,7 @@ EOF $provider = $this->providers->get($input->getArgument('provider')); if (!$this->enabledLocales) { - throw new InvalidArgumentException(sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME))); + throw new InvalidArgumentException(\sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME))); } $io = new SymfonyStyle($input, $output); @@ -139,7 +139,7 @@ EOF if (!$deleteMissing && $force) { $provider->write($localTranslations); - $io->success(sprintf('All local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('All local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } @@ -149,7 +149,7 @@ EOF if ($deleteMissing) { $provider->delete($providerTranslations->diff($localTranslations)); - $io->success(sprintf('Missing translations on "%s" has been deleted (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('Missing translations on "%s" has been deleted (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); // Read provider translations again, after missing translations deletion, // to avoid push freshly deleted translations. @@ -164,7 +164,7 @@ EOF $provider->write($translationsToWrite); - $io->success(sprintf('%s local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('%s local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Command/XliffLintCommand.php b/lam/lib/3rdParty/composer/symfony/translation/Command/XliffLintCommand.php index ba946389e..7220e24a9 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Command/XliffLintCommand.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Command/XliffLintCommand.php @@ -57,7 +57,7 @@ class XliffLintCommand extends Command { $this ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') - ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) + ->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) ->setHelp(<<%command.name% command lints an XLIFF file and outputs to STDOUT the first encountered syntax error. @@ -98,7 +98,7 @@ EOF $filesInfo = []; foreach ($filenames as $filename) { if (!$this->isReadable($filename)) { - throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename)); + throw new RuntimeException(\sprintf('File or directory "%s" is not readable.', $filename)); } foreach ($this->getFiles($filename) as $file) { @@ -124,18 +124,18 @@ EOF $document->loadXML($content); if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) { - $normalizedLocalePattern = sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/')); + $normalizedLocalePattern = \sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/')); // strict file names require translation files to be named '____.locale.xlf' // otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed // also, the regexp matching must be case-insensitive, as defined for 'target-language' values // http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language - $expectedFilenamePattern = $this->requireStrictFileNames ? sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern); + $expectedFilenamePattern = $this->requireStrictFileNames ? \sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : \sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern); if (0 === preg_match($expectedFilenamePattern, basename($file))) { $errors[] = [ 'line' => -1, 'column' => -1, - 'message' => sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage), + 'message' => \sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage), ]; } } @@ -160,7 +160,7 @@ EOF 'txt' => $this->displayTxt($io, $files), 'json' => $this->displayJson($io, $files), 'github' => $this->displayTxt($io, $files, true), - default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), + default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), }; } @@ -172,25 +172,25 @@ EOF foreach ($filesInfo as $info) { if ($info['valid'] && $this->displayCorrectFiles) { - $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); + $io->comment('OK'.($info['file'] ? \sprintf(' in %s', $info['file']) : '')); } elseif (!$info['valid']) { ++$erroredFiles; - $io->text(' ERROR '.($info['file'] ? sprintf(' in %s', $info['file']) : '')); + $io->text(' ERROR '.($info['file'] ? \sprintf(' in %s', $info['file']) : '')); $io->listing(array_map(function ($error) use ($info, $githubReporter) { // general document errors have a '-1' line number $line = -1 === $error['line'] ? null : $error['line']; $githubReporter?->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null); - return null === $line ? $error['message'] : sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']); + return null === $line ? $error['message'] : \sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']); }, $info['messages'])); } } if (0 === $erroredFiles) { - $io->success(sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); + $io->success(\sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); } else { - $io->warning(sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); + $io->warning(\sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); } return min($erroredFiles, 1); diff --git a/lam/lib/3rdParty/composer/symfony/translation/DataCollectorTranslator.php b/lam/lib/3rdParty/composer/symfony/translation/DataCollectorTranslator.php index a2832ee8e..7ab3b047b 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/DataCollectorTranslator.php +++ b/lam/lib/3rdParty/composer/symfony/translation/DataCollectorTranslator.php @@ -34,7 +34,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter public function __construct(TranslatorInterface $translator) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { - throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); + throw new InvalidArgumentException(\sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; diff --git a/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/LoggingTranslatorPass.php b/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/LoggingTranslatorPass.php index c21552f97..fba86981c 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/LoggingTranslatorPass.php +++ b/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/LoggingTranslatorPass.php @@ -37,7 +37,7 @@ class LoggingTranslatorPass implements CompilerPassInterface $class = $container->getParameterBag()->resolveValue($definition->getClass()); if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias)); } if (!$r->isSubclassOf(TranslatorInterface::class) || !$r->isSubclassOf(TranslatorBagInterface::class)) { diff --git a/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/TranslationExtractorPass.php b/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/TranslationExtractorPass.php index 1baf9341e..5e9b5af34 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/TranslationExtractorPass.php +++ b/lam/lib/3rdParty/composer/symfony/translation/DependencyInjection/TranslationExtractorPass.php @@ -34,7 +34,7 @@ class TranslationExtractorPass implements CompilerPassInterface foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) { if (!isset($attributes[0]['alias'])) { - throw new RuntimeException(sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id)); + throw new RuntimeException(\sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id)); } $definition->addMethodCall('addExtractor', [$attributes[0]['alias'], new Reference($id)]); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Dumper/FileDumper.php b/lam/lib/3rdParty/composer/symfony/translation/Dumper/FileDumper.php index e30d4770e..8f3a953e3 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Dumper/FileDumper.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Dumper/FileDumper.php @@ -57,7 +57,7 @@ abstract class FileDumper implements DumperInterface if (!file_exists($fullpath)) { $directory = \dirname($fullpath); if (!file_exists($directory) && !@mkdir($directory, 0777, true)) { - throw new RuntimeException(sprintf('Unable to create directory "%s".', $directory)); + throw new RuntimeException(\sprintf('Unable to create directory "%s".', $directory)); } } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Dumper/PoFileDumper.php b/lam/lib/3rdParty/composer/symfony/translation/Dumper/PoFileDumper.php index a2d0deb78..acf046c14 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Dumper/PoFileDumper.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Dumper/PoFileDumper.php @@ -51,14 +51,14 @@ class PoFileDumper extends FileDumper $sourceRules = $this->getStandardRules($source); $targetRules = $this->getStandardRules($target); if (2 == \count($sourceRules) && [] !== $targetRules) { - $output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); - $output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); + $output .= \sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); + $output .= \sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); foreach ($targetRules as $i => $targetRule) { - $output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); + $output .= \sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); } } else { - $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); - $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); + $output .= \sprintf('msgid "%s"'."\n", $this->escape($source)); + $output .= \sprintf('msgstr "%s"'."\n", $this->escape($target)); } } @@ -123,7 +123,7 @@ EOF; $output = null; foreach ((array) $comments as $comment) { - $output .= sprintf('#%s %s'."\n", $prefix, $comment); + $output .= \sprintf('#%s %s'."\n", $prefix, $comment); } return $output; diff --git a/lam/lib/3rdParty/composer/symfony/translation/Dumper/XliffFileDumper.php b/lam/lib/3rdParty/composer/symfony/translation/Dumper/XliffFileDumper.php index d0f016b23..a2dfcd16d 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Dumper/XliffFileDumper.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Dumper/XliffFileDumper.php @@ -46,7 +46,7 @@ class XliffFileDumper extends FileDumper return $this->dumpXliff2($defaultLocale, $messages, $domain); } - throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); + throw new InvalidArgumentException(\sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); } protected function getExtension(): string @@ -176,7 +176,7 @@ class XliffFileDumper extends FileDumper $metadata = $messages->getMetadata($source, $domain); // Add notes section - if ($this->hasMetadataArrayInfo('notes', $metadata)) { + if ($this->hasMetadataArrayInfo('notes', $metadata) && $metadata['notes']) { $notesElement = $dom->createElement('notes'); foreach ($metadata['notes'] as $note) { $n = $dom->createElement('note'); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Exception/IncompleteDsnException.php b/lam/lib/3rdParty/composer/symfony/translation/Exception/IncompleteDsnException.php index b304bde01..6c9247f89 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Exception/IncompleteDsnException.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Exception/IncompleteDsnException.php @@ -16,7 +16,7 @@ class IncompleteDsnException extends InvalidArgumentException public function __construct(string $message, ?string $dsn = null, ?\Throwable $previous = null) { if ($dsn) { - $message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message; + $message = \sprintf('Invalid "%s" provider DSN: ', $dsn).$message; } parent::__construct($message, 0, $previous); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Exception/MissingRequiredOptionException.php b/lam/lib/3rdParty/composer/symfony/translation/Exception/MissingRequiredOptionException.php index 46152e254..8cef03a81 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Exception/MissingRequiredOptionException.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Exception/MissingRequiredOptionException.php @@ -18,7 +18,7 @@ class MissingRequiredOptionException extends IncompleteDsnException { public function __construct(string $option, ?string $dsn = null, ?\Throwable $previous = null) { - $message = sprintf('The option "%s" is required but missing.', $option); + $message = \sprintf('The option "%s" is required but missing.', $option); parent::__construct($message, $dsn, $previous); } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Exception/UnsupportedSchemeException.php b/lam/lib/3rdParty/composer/symfony/translation/Exception/UnsupportedSchemeException.php index 8d3295184..ca18444e4 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Exception/UnsupportedSchemeException.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Exception/UnsupportedSchemeException.php @@ -43,14 +43,14 @@ class UnsupportedSchemeException extends LogicException } $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; if ($package && !class_exists($package['class'])) { - parent::__construct(sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package'])); + parent::__construct(\sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package'])); return; } - $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); + $message = \sprintf('The "%s" scheme is not supported', $dsn->getScheme()); if ($name && $supported) { - $message .= sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported)); + $message .= \sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported)); } parent::__construct($message.'.'); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Extractor/AbstractFileExtractor.php b/lam/lib/3rdParty/composer/symfony/translation/Extractor/AbstractFileExtractor.php index 4c088b94f..8af022402 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Extractor/AbstractFileExtractor.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Extractor/AbstractFileExtractor.php @@ -49,7 +49,7 @@ abstract class AbstractFileExtractor protected function isFile(string $file): bool { if (!is_file($file)) { - throw new InvalidArgumentException(sprintf('The "%s" file does not exist.', $file)); + throw new InvalidArgumentException(\sprintf('The "%s" file does not exist.', $file)); } return true; diff --git a/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpAstExtractor.php b/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpAstExtractor.php index 06fc77de3..a5375f480 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpAstExtractor.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpAstExtractor.php @@ -36,7 +36,7 @@ final class PhpAstExtractor extends AbstractFileExtractor implements ExtractorIn private string $prefix = '', ) { if (!class_exists(ParserFactory::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class)); } $this->parser = (new ParserFactory())->createForHostVersion(); @@ -77,7 +77,7 @@ final class PhpAstExtractor extends AbstractFileExtractor implements ExtractorIn protected function extractFromDirectory(array|string $resource): iterable|Finder { if (!class_exists(Finder::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } return (new Finder())->files()->name('*.php')->in($resource); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpExtractor.php b/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpExtractor.php index 7ff27f7c8..72afe4777 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpExtractor.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Extractor/PhpExtractor.php @@ -323,7 +323,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface protected function extractFromDirectory(string|array $directory): iterable { if (!class_exists(Finder::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } $finder = new Finder(); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Extractor/Visitor/ConstraintVisitor.php b/lam/lib/3rdParty/composer/symfony/translation/Extractor/Visitor/ConstraintVisitor.php index 00fb9eedc..45cae3536 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Extractor/Visitor/ConstraintVisitor.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Extractor/Visitor/ConstraintVisitor.php @@ -22,7 +22,7 @@ use PhpParser\NodeVisitor; final class ConstraintVisitor extends AbstractVisitor implements NodeVisitor { public function __construct( - private readonly array $constraintClassNames = [] + private readonly array $constraintClassNames = [], ) { } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Formatter/IntlFormatter.php b/lam/lib/3rdParty/composer/symfony/translation/Formatter/IntlFormatter.php index e62de253f..87cb00733 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Formatter/IntlFormatter.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Formatter/IntlFormatter.php @@ -37,7 +37,7 @@ class IntlFormatter implements IntlFormatterInterface try { $this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message); } catch (\IntlException $e) { - throw new InvalidArgumentException(sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e); + throw new InvalidArgumentException(\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e); } } @@ -49,7 +49,7 @@ class IntlFormatter implements IntlFormatterInterface } if (false === $message = $formatter->format($parameters)) { - throw new InvalidArgumentException(sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage()); + throw new InvalidArgumentException(\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage()); } return $message; diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/CsvFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/CsvFileLoader.php index 93bee730b..9d26611e5 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/CsvFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/CsvFileLoader.php @@ -31,7 +31,7 @@ class CsvFileLoader extends FileLoader try { $file = new \SplFileObject($resource, 'rb'); } catch (\RuntimeException $e) { - throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e); + throw new NotFoundResourceException(\sprintf('Error opening file "%s".', $resource), 0, $e); } $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/FileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/FileLoader.php index 877c3bbc7..94f6e2022 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/FileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/FileLoader.php @@ -24,11 +24,11 @@ abstract class FileLoader extends ArrayLoader public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } $messages = $this->loadResource($resource); @@ -38,7 +38,7 @@ abstract class FileLoader extends ArrayLoader // not an array if (!\is_array($messages)) { - throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource)); } $catalogue = parent::load($messages, $locale, $domain); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuDatFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuDatFileLoader.php index 76e4e7f02..1af864303 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuDatFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuDatFileLoader.php @@ -26,11 +26,11 @@ class IcuDatFileLoader extends IcuResFileLoader public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource.'.dat')) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource.'.dat')) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { @@ -40,7 +40,7 @@ class IcuDatFileLoader extends IcuResFileLoader } if (!$rb) { - throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuResFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuResFileLoader.php index 949dd9792..8ada43dca 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuResFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/IcuResFileLoader.php @@ -26,11 +26,11 @@ class IcuResFileLoader implements LoaderInterface public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!is_dir($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { @@ -40,7 +40,7 @@ class IcuResFileLoader implements LoaderInterface } if (!$rb) { - throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/QtFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/QtFileLoader.php index 235f85ee9..1b167bd6d 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/QtFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/QtFileLoader.php @@ -32,17 +32,17 @@ class QtFileLoader implements LoaderInterface } if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { $dom = XmlUtils::loadFile($resource); } catch (\InvalidArgumentException $e) { - throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e); + throw new InvalidResourceException(\sprintf('Unable to load "%s".', $resource), $e->getCode(), $e); } $internalErrors = libxml_use_internal_errors(true); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/XliffFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/XliffFileLoader.php index ffe4bbbd8..98c759fae 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/XliffFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/XliffFileLoader.php @@ -36,15 +36,15 @@ class XliffFileLoader implements LoaderInterface if (!$this->isXmlString($resource)) { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } if (!is_file($resource)) { - throw new InvalidResourceException(sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); } } @@ -55,11 +55,11 @@ class XliffFileLoader implements LoaderInterface $dom = XmlUtils::loadFile($resource); } } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) { - throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); + throw new InvalidResourceException(\sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); } if ($errors = XliffUtils::validateSchema($dom)) { - throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); + throw new InvalidResourceException(\sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); } $catalogue = new MessageCatalogue($locale); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Loader/YamlFileLoader.php b/lam/lib/3rdParty/composer/symfony/translation/Loader/YamlFileLoader.php index 48e735d16..39d5a0e99 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Loader/YamlFileLoader.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Loader/YamlFileLoader.php @@ -29,7 +29,7 @@ class YamlFileLoader extends FileLoader protected function loadResource(string $resource): array { if (!isset($this->yamlParser)) { - if (!class_exists(\Symfony\Component\Yaml\Parser::class)) { + if (!class_exists(YamlParser::class)) { throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.'); } @@ -39,11 +39,11 @@ class YamlFileLoader extends FileLoader try { $messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT); } catch (ParseException $e) { - throw new InvalidResourceException(sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e); + throw new InvalidResourceException(\sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e); } if (null !== $messages && !\is_array($messages)) { - throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource)); } return $messages ?: []; diff --git a/lam/lib/3rdParty/composer/symfony/translation/LoggingTranslator.php b/lam/lib/3rdParty/composer/symfony/translation/LoggingTranslator.php index 4a560bd6a..629f3f7ad 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/LoggingTranslator.php +++ b/lam/lib/3rdParty/composer/symfony/translation/LoggingTranslator.php @@ -30,7 +30,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, public function __construct(TranslatorInterface $translator, LoggerInterface $logger) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { - throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); + throw new InvalidArgumentException(\sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; @@ -56,7 +56,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, return; } - $this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); + $this->logger->debug(\sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); } public function getLocale(): string diff --git a/lam/lib/3rdParty/composer/symfony/translation/MessageCatalogue.php b/lam/lib/3rdParty/composer/symfony/translation/MessageCatalogue.php index d56f04393..9098619e8 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/MessageCatalogue.php +++ b/lam/lib/3rdParty/composer/symfony/translation/MessageCatalogue.php @@ -155,7 +155,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf public function addCatalogue(MessageCatalogueInterface $catalogue) { if ($catalogue->getLocale() !== $this->locale) { - throw new LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s".', $catalogue->getLocale(), $this->locale)); + throw new LogicException(\sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s".', $catalogue->getLocale(), $this->locale)); } foreach ($catalogue->all() as $domain => $messages) { @@ -190,14 +190,14 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf $c = $catalogue; while ($c = $c->getFallbackCatalogue()) { if ($c->getLocale() === $this->getLocale()) { - throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); + throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } } $c = $this; do { if ($c->getLocale() === $catalogue->getLocale()) { - throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); + throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } foreach ($catalogue->getResources() as $resource) { @@ -237,6 +237,16 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf return $this->metadata; } + if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX])) { + if ('' === $key) { + return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX]; + } + + if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key])) { + return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key]; + } + } + if (isset($this->metadata[$domain])) { if ('' == $key) { return $this->metadata[$domain]; diff --git a/lam/lib/3rdParty/composer/symfony/translation/Provider/TranslationProviderCollection.php b/lam/lib/3rdParty/composer/symfony/translation/Provider/TranslationProviderCollection.php index b917415ba..878998fec 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Provider/TranslationProviderCollection.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Provider/TranslationProviderCollection.php @@ -44,7 +44,7 @@ final class TranslationProviderCollection public function get(string $name): ProviderInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('Provider "%s" not found. Available: "%s".', $name, (string) $this)); + throw new InvalidArgumentException(\sprintf('Provider "%s" not found. Available: "%s".', $name, (string) $this)); } return $this->providers[$name]; diff --git a/lam/lib/3rdParty/composer/symfony/translation/Resources/data/parents.json b/lam/lib/3rdParty/composer/symfony/translation/Resources/data/parents.json index 24d4d119e..c9e52fd98 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Resources/data/parents.json +++ b/lam/lib/3rdParty/composer/symfony/translation/Resources/data/parents.json @@ -18,29 +18,35 @@ "en_CM": "en_001", "en_CX": "en_001", "en_CY": "en_001", + "en_CZ": "en_150", "en_DE": "en_150", "en_DG": "en_001", "en_DK": "en_150", "en_DM": "en_001", "en_ER": "en_001", + "en_ES": "en_150", "en_FI": "en_150", "en_FJ": "en_001", "en_FK": "en_001", "en_FM": "en_001", + "en_FR": "en_150", "en_GB": "en_001", "en_GD": "en_001", "en_GG": "en_001", "en_GH": "en_001", "en_GI": "en_001", "en_GM": "en_001", + "en_GS": "en_001", "en_GY": "en_001", "en_HK": "en_001", + "en_HU": "en_150", "en_ID": "en_001", "en_IE": "en_001", "en_IL": "en_001", "en_IM": "en_001", "en_IN": "en_001", "en_IO": "en_001", + "en_IT": "en_150", "en_JE": "en_001", "en_JM": "en_001", "en_KE": "en_001", @@ -62,13 +68,17 @@ "en_NF": "en_001", "en_NG": "en_001", "en_NL": "en_150", + "en_NO": "en_150", "en_NR": "en_001", "en_NU": "en_001", "en_NZ": "en_001", "en_PG": "en_001", "en_PK": "en_001", + "en_PL": "en_150", "en_PN": "en_001", + "en_PT": "en_150", "en_PW": "en_001", + "en_RO": "en_150", "en_RW": "en_001", "en_SB": "en_001", "en_SC": "en_001", @@ -77,6 +87,7 @@ "en_SG": "en_001", "en_SH": "en_001", "en_SI": "en_150", + "en_SK": "en_150", "en_SL": "en_001", "en_SS": "en_001", "en_SX": "en_001", diff --git a/lam/lib/3rdParty/composer/symfony/translation/TranslatableMessage.php b/lam/lib/3rdParty/composer/symfony/translation/TranslatableMessage.php index c591e68c2..8f6063c50 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/TranslatableMessage.php +++ b/lam/lib/3rdParty/composer/symfony/translation/TranslatableMessage.php @@ -52,9 +52,13 @@ class TranslatableMessage implements TranslatableInterface public function trans(TranslatorInterface $translator, ?string $locale = null): string { - return $translator->trans($this->getMessage(), array_map( - static fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter, - $this->getParameters() - ), $this->getDomain(), $locale); + $parameters = $this->getParameters(); + foreach ($parameters as $k => $v) { + if ($v instanceof TranslatableInterface) { + $parameters[$k] = $v->trans($translator, $locale); + } + } + + return $translator->trans($this->getMessage(), $parameters, $this->getDomain(), $locale); } } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Translator.php b/lam/lib/3rdParty/composer/symfony/translation/Translator.php index 1973d079f..d3396c515 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Translator.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Translator.php @@ -290,7 +290,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA $this->initializeCatalogue($locale); $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]); - $content = sprintf(<<addFallbackCatalogue($catalogue%s); @@ -356,10 +356,10 @@ EOF foreach ($this->resources[$locale] as $resource) { if (!isset($this->loaders[$resource[0]])) { if (\is_string($resource[1])) { - throw new RuntimeException(sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1])); + throw new RuntimeException(\sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1])); } - throw new RuntimeException(sprintf('No loader is registered for the "%s" format.', $resource[0])); + throw new RuntimeException(\sprintf('No loader is registered for the "%s" format.', $resource[0])); } $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2])); } @@ -438,7 +438,7 @@ EOF protected function assertValidLocale(string $locale) { if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) { - throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale)); + throw new InvalidArgumentException(\sprintf('Invalid "%s" locale.', $locale)); } } diff --git a/lam/lib/3rdParty/composer/symfony/translation/Util/XliffUtils.php b/lam/lib/3rdParty/composer/symfony/translation/Util/XliffUtils.php index 335c34beb..e76e12284 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Util/XliffUtils.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Util/XliffUtils.php @@ -41,7 +41,7 @@ class XliffUtils $namespace = $xliff->attributes->getNamedItem('xmlns'); if ($namespace) { if (0 !== substr_compare('urn:oasis:names:tc:xliff:document:', $namespace->nodeValue, 0, 34)) { - throw new InvalidArgumentException(sprintf('Not a valid XLIFF namespace "%s".', $namespace)); + throw new InvalidArgumentException(\sprintf('Not a valid XLIFF namespace "%s".', $namespace)); } return substr($namespace, 34); @@ -113,7 +113,7 @@ class XliffUtils $errorsAsString = ''; foreach ($xmlErrors as $error) { - $errorsAsString .= sprintf("[%s %s] %s (in %s - line %d, column %d)\n", + $errorsAsString .= \sprintf("[%s %s] %s (in %s - line %d, column %d)\n", \LIBXML_ERR_WARNING === $error['level'] ? 'WARNING' : 'ERROR', $error['code'], $error['message'], @@ -135,7 +135,7 @@ class XliffUtils $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.0.xsd'); $xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd'; } else { - throw new InvalidArgumentException(sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion)); + throw new InvalidArgumentException(\sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion)); } return self::fixXmlLocation($schemaSource, $xmlUri); diff --git a/lam/lib/3rdParty/composer/symfony/translation/Writer/TranslationWriter.php b/lam/lib/3rdParty/composer/symfony/translation/Writer/TranslationWriter.php index 61e03cb0e..464a83c5b 100644 --- a/lam/lib/3rdParty/composer/symfony/translation/Writer/TranslationWriter.php +++ b/lam/lib/3rdParty/composer/symfony/translation/Writer/TranslationWriter.php @@ -59,14 +59,14 @@ class TranslationWriter implements TranslationWriterInterface public function write(MessageCatalogue $catalogue, string $format, array $options = []) { if (!isset($this->dumpers[$format])) { - throw new InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format)); + throw new InvalidArgumentException(\sprintf('There is no dumper associated with format "%s".', $format)); } // get the right dumper $dumper = $this->dumpers[$format]; if (isset($options['path']) && !is_dir($options['path']) && !@mkdir($options['path'], 0777, true) && !is_dir($options['path'])) { - throw new RuntimeException(sprintf('Translation Writer was not able to create directory "%s".', $options['path'])); + throw new RuntimeException(\sprintf('Translation Writer was not able to create directory "%s".', $options['path'])); } // save diff --git a/lam/lib/3rdParty/composer/symfony/uid/AbstractUid.php b/lam/lib/3rdParty/composer/symfony/uid/AbstractUid.php index d556bb732..7eb7f1468 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/AbstractUid.php +++ b/lam/lib/3rdParty/composer/symfony/uid/AbstractUid.php @@ -95,7 +95,7 @@ abstract class AbstractUid implements \JsonSerializable, \Stringable */ public function toBase58(): string { - return strtr(sprintf('%022s', BinaryUtil::toBase($this->toBinary(), BinaryUtil::BASE58)), '0', '1'); + return strtr(\sprintf('%022s', BinaryUtil::toBase($this->toBinary(), BinaryUtil::BASE58)), '0', '1'); } /** @@ -108,7 +108,7 @@ abstract class AbstractUid implements \JsonSerializable, \Stringable public function toBase32(): string { $uid = bin2hex($this->toBinary()); - $uid = sprintf('%02s%04s%04s%04s%04s%04s%04s', + $uid = \sprintf('%02s%04s%04s%04s%04s%04s%04s', base_convert(substr($uid, 0, 2), 16, 32), base_convert(substr($uid, 2, 5), 16, 32), base_convert(substr($uid, 7, 5), 16, 32), diff --git a/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUlidCommand.php b/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUlidCommand.php index 6c8d16387..a41cf2840 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUlidCommand.php +++ b/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUlidCommand.php @@ -40,7 +40,7 @@ class GenerateUlidCommand extends Command ->setDefinition([ new InputOption('time', null, InputOption::VALUE_REQUIRED, 'The ULID timestamp: a parsable date/time string'), new InputOption('count', 'c', InputOption::VALUE_REQUIRED, 'The number of ULID to generate', 1), - new InputOption('format', 'f', InputOption::VALUE_REQUIRED, sprintf('The ULID output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'base32'), + new InputOption('format', 'f', InputOption::VALUE_REQUIRED, \sprintf('The ULID output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'base32'), ]) ->setHelp(<<<'EOF' The %command.name% command generates a ULID. @@ -71,7 +71,7 @@ EOF try { $time = new \DateTimeImmutable($time); } catch (\Exception $e) { - $io->error(sprintf('Invalid timestamp "%s": %s', $time, str_replace('DateTimeImmutable::__construct(): ', '', $e->getMessage()))); + $io->error(\sprintf('Invalid timestamp "%s": %s', $time, str_replace('DateTimeImmutable::__construct(): ', '', $e->getMessage()))); return 1; } @@ -82,7 +82,7 @@ EOF if (\in_array($formatOption, $this->getAvailableFormatOptions())) { $format = 'to'.ucfirst($formatOption); } else { - $io->error(sprintf('Invalid format "%s", supported formats are "%s".', $formatOption, implode('", "', $this->getAvailableFormatOptions()))); + $io->error(\sprintf('Invalid format "%s", supported formats are "%s".', $formatOption, implode('", "', $this->getAvailableFormatOptions()))); return 1; } diff --git a/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUuidCommand.php b/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUuidCommand.php index 6dad923c4..858f44990 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUuidCommand.php +++ b/lam/lib/3rdParty/composer/symfony/uid/Command/GenerateUuidCommand.php @@ -45,7 +45,7 @@ class GenerateUuidCommand extends Command new InputOption('namespace', null, InputOption::VALUE_REQUIRED, 'The UUID to use at the namespace for named-based UUIDs, predefined namespaces keywords "dns", "url", "oid" and "x500" are accepted'), new InputOption('random-based', null, InputOption::VALUE_NONE, 'To generate a random-based UUID'), new InputOption('count', 'c', InputOption::VALUE_REQUIRED, 'The number of UUID to generate', 1), - new InputOption('format', 'f', InputOption::VALUE_REQUIRED, sprintf('The UUID output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'rfc4122'), + new InputOption('format', 'f', InputOption::VALUE_REQUIRED, \sprintf('The UUID output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'rfc4122'), ]) ->setHelp(<<<'EOF' The %command.name% generates a UUID. @@ -118,7 +118,7 @@ EOF try { $node = Uuid::fromString($node); } catch (\InvalidArgumentException $e) { - $io->error(sprintf('Invalid node "%s": %s', $node, $e->getMessage())); + $io->error(\sprintf('Invalid node "%s": %s', $node, $e->getMessage())); return 1; } @@ -127,7 +127,7 @@ EOF try { new \DateTimeImmutable($time); } catch (\Exception $e) { - $io->error(sprintf('Invalid timestamp "%s": %s', $time, str_replace('DateTimeImmutable::__construct(): ', '', $e->getMessage()))); + $io->error(\sprintf('Invalid timestamp "%s": %s', $time, str_replace('DateTimeImmutable::__construct(): ', '', $e->getMessage()))); return 1; } @@ -140,7 +140,7 @@ EOF try { $namespace = Uuid::fromString($namespace); } catch (\InvalidArgumentException $e) { - $io->error(sprintf('Invalid namespace "%s": %s', $namespace, $e->getMessage())); + $io->error(\sprintf('Invalid namespace "%s": %s', $namespace, $e->getMessage())); return 1; } @@ -171,7 +171,7 @@ EOF if (\in_array($formatOption, $this->getAvailableFormatOptions())) { $format = 'to'.ucfirst($formatOption); } else { - $io->error(sprintf('Invalid format "%s", supported formats are "%s".', $formatOption, implode('", "', $this->getAvailableFormatOptions()))); + $io->error(\sprintf('Invalid format "%s", supported formats are "%s".', $formatOption, implode('", "', $this->getAvailableFormatOptions()))); return 1; } diff --git a/lam/lib/3rdParty/composer/symfony/uid/Factory/UuidFactory.php b/lam/lib/3rdParty/composer/symfony/uid/Factory/UuidFactory.php index d1935c4ba..f95082d2c 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/Factory/UuidFactory.php +++ b/lam/lib/3rdParty/composer/symfony/uid/Factory/UuidFactory.php @@ -72,7 +72,7 @@ class UuidFactory $namespace ??= $this->nameBasedNamespace; if (null === $namespace) { - throw new \LogicException(sprintf('A namespace should be defined when using "%s()".', __METHOD__)); + throw new \LogicException(\sprintf('A namespace should be defined when using "%s()".', __METHOD__)); } return new NameBasedUuidFactory($this->nameBasedClass, $this->getNamespace($namespace)); diff --git a/lam/lib/3rdParty/composer/symfony/uid/Ulid.php b/lam/lib/3rdParty/composer/symfony/uid/Ulid.php index 5359067af..87f604a11 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/Ulid.php +++ b/lam/lib/3rdParty/composer/symfony/uid/Ulid.php @@ -36,7 +36,7 @@ class Ulid extends AbstractUid implements TimeBasedUidInterface $this->uid = $ulid; } else { if (!self::isValid($ulid)) { - throw new \InvalidArgumentException(sprintf('Invalid ULID: "%s".', $ulid)); + throw new \InvalidArgumentException(\sprintf('Invalid ULID: "%s".', $ulid)); } $this->uid = strtoupper($ulid); @@ -73,7 +73,7 @@ class Ulid extends AbstractUid implements TimeBasedUidInterface } $ulid = bin2hex($ulid); - $ulid = sprintf('%02s%04s%04s%04s%04s%04s%04s', + $ulid = \sprintf('%02s%04s%04s%04s%04s%04s%04s', base_convert(substr($ulid, 0, 2), 16, 32), base_convert(substr($ulid, 2, 5), 16, 32), base_convert(substr($ulid, 7, 5), 16, 32), @@ -101,7 +101,7 @@ class Ulid extends AbstractUid implements TimeBasedUidInterface { $ulid = strtr($this->uid, 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'); - $ulid = sprintf('%02s%05s%05s%05s%05s%05s%05s', + $ulid = \sprintf('%02s%05s%05s%05s%05s%05s%05s', base_convert(substr($ulid, 0, 2), 32, 16), base_convert(substr($ulid, 2, 4), 32, 16), base_convert(substr($ulid, 6, 4), 32, 16), @@ -133,7 +133,7 @@ class Ulid extends AbstractUid implements TimeBasedUidInterface if (\PHP_INT_SIZE >= 8) { $time = (string) hexdec(base_convert($time, 32, 16)); } else { - $time = sprintf('%02s%05s%05s', + $time = \sprintf('%02s%05s%05s', base_convert(substr($time, 0, 2), 32, 16), base_convert(substr($time, 2, 4), 32, 16), base_convert(substr($time, 6, 4), 32, 16) @@ -190,14 +190,14 @@ class Ulid extends AbstractUid implements TimeBasedUidInterface $time = base_convert($time, 10, 32); } else { $time = str_pad(bin2hex(BinaryUtil::fromBase($time, BinaryUtil::BASE10)), 12, '0', \STR_PAD_LEFT); - $time = sprintf('%s%04s%04s', + $time = \sprintf('%s%04s%04s', base_convert(substr($time, 0, 2), 16, 32), base_convert(substr($time, 2, 5), 16, 32), base_convert(substr($time, 7, 5), 16, 32) ); } - return strtr(sprintf('%010s%04s%04s%04s%04s', + return strtr(\sprintf('%010s%04s%04s%04s%04s', $time, base_convert(self::$rand[1], 10, 32), base_convert(self::$rand[2], 10, 32), diff --git a/lam/lib/3rdParty/composer/symfony/uid/Uuid.php b/lam/lib/3rdParty/composer/symfony/uid/Uuid.php index 0c4cdf8c1..85968993d 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/Uuid.php +++ b/lam/lib/3rdParty/composer/symfony/uid/Uuid.php @@ -32,13 +32,13 @@ class Uuid extends AbstractUid $type = preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid) ? (int) $uuid[14] : false; if (false === $type || (static::TYPE ?: $type) !== $type) { - throw new \InvalidArgumentException(sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); + throw new \InvalidArgumentException(\sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); } $this->uid = strtolower($uuid); if ($checkVariant && !\in_array($this->uid[19], ['8', '9', 'a', 'b'], true)) { - throw new \InvalidArgumentException(sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); + throw new \InvalidArgumentException(\sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); } } diff --git a/lam/lib/3rdParty/composer/symfony/uid/UuidV1.php b/lam/lib/3rdParty/composer/symfony/uid/UuidV1.php index 1e6873708..ae21f92bf 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/UuidV1.php +++ b/lam/lib/3rdParty/composer/symfony/uid/UuidV1.php @@ -54,7 +54,7 @@ class UuidV1 extends Uuid implements TimeBasedUidInterface $seq = substr($uuid, 19, 4); do { - self::$clockSeq = sprintf('%04x', random_int(0, 0x3FFF) | 0x8000); + self::$clockSeq = \sprintf('%04x', random_int(0, 0x3FFF) | 0x8000); } while ($seq === self::$clockSeq); $seq = self::$clockSeq; diff --git a/lam/lib/3rdParty/composer/symfony/uid/UuidV6.php b/lam/lib/3rdParty/composer/symfony/uid/UuidV6.php index b3492083c..cd30082e2 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/UuidV6.php +++ b/lam/lib/3rdParty/composer/symfony/uid/UuidV6.php @@ -58,7 +58,7 @@ class UuidV6 extends Uuid implements TimeBasedUidInterface if (!isset(self::$node)) { $seed = [random_int(0, 0xFFFFFF), random_int(0, 0xFFFFFF)]; $node = unpack('N2', hex2bin('00'.substr($uuidV1, 24, 6)).hex2bin('00'.substr($uuidV1, 30))); - self::$node = sprintf('%06x%06x', ($seed[0] ^ $node[1]) | 0x010000, $seed[1] ^ $node[2]); + self::$node = \sprintf('%06x%06x', ($seed[0] ^ $node[1]) | 0x010000, $seed[1] ^ $node[2]); } return $uuid.self::$node; diff --git a/lam/lib/3rdParty/composer/symfony/uid/UuidV7.php b/lam/lib/3rdParty/composer/symfony/uid/UuidV7.php index 43740b67e..12c752095 100644 --- a/lam/lib/3rdParty/composer/symfony/uid/UuidV7.php +++ b/lam/lib/3rdParty/composer/symfony/uid/UuidV7.php @@ -60,7 +60,7 @@ class UuidV7 extends Uuid implements TimeBasedUidInterface if ($time > self::$time || (null !== $mtime && $time !== self::$time)) { randomize: - self::$rand = unpack('n*', isset(self::$seed) ? random_bytes(10) : self::$seed = random_bytes(16)); + self::$rand = unpack('S*', isset(self::$seed) ? random_bytes(10) : self::$seed = random_bytes(16)); self::$rand[1] &= 0x03FF; self::$time = $time; } else { @@ -76,7 +76,7 @@ class UuidV7 extends Uuid implements TimeBasedUidInterface // 24-bit number in the self::$seedParts list and decrement self::$seedIndex. if (!self::$seedIndex) { - $s = unpack('l*', self::$seed = hash('sha512', self::$seed, true)); + $s = unpack(\PHP_INT_SIZE >= 8 ? 'L*' : 'l*', self::$seed = hash('sha512', self::$seed, true)); $s[] = ($s[1] >> 8 & 0xFF0000) | ($s[2] >> 16 & 0xFF00) | ($s[3] >> 24 & 0xFF); $s[] = ($s[4] >> 8 & 0xFF0000) | ($s[5] >> 16 & 0xFF00) | ($s[6] >> 24 & 0xFF); $s[] = ($s[7] >> 8 & 0xFF0000) | ($s[8] >> 16 & 0xFF00) | ($s[9] >> 24 & 0xFF); @@ -113,7 +113,7 @@ class UuidV7 extends Uuid implements TimeBasedUidInterface $time = bin2hex(BinaryUtil::fromBase($time, BinaryUtil::BASE10)); } - return substr_replace(sprintf('%012s-%04x-%04x-%04x%04x%04x', + return substr_replace(\sprintf('%012s-%04x-%04x-%04x%04x%04x', $time, 0x7000 | (self::$rand[1] << 2) | (self::$rand[2] >> 14), 0x8000 | (self::$rand[2] & 0x3FFF), diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/LICENSE b/lam/lib/3rdParty/composer/thecodingmachine/safe/LICENSE deleted file mode 100644 index 4188a9bbd..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 TheCodingMachine - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/README.md b/lam/lib/3rdParty/composer/thecodingmachine/safe/README.md deleted file mode 100644 index 4b63d155f..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/README.md +++ /dev/null @@ -1,176 +0,0 @@ -[![Latest Stable Version](https://poser.pugx.org/thecodingmachine/safe/v/stable.svg)](https://packagist.org/packages/thecodingmachine/safe) -[![Total Downloads](https://poser.pugx.org/thecodingmachine/safe/downloads.svg)](https://packagist.org/packages/thecodingmachine/safe) -[![Latest Unstable Version](https://poser.pugx.org/thecodingmachine/safe/v/unstable.svg)](https://packagist.org/packages/thecodingmachine/safe) -[![License](https://poser.pugx.org/thecodingmachine/safe/license.svg)](https://packagist.org/packages/thecodingmachine/safe) -[![Build Status](https://travis-ci.org/thecodingmachine/safe.svg?branch=master)](https://travis-ci.org/thecodingmachine/safe) -[![Continuous Integration](https://github.com/thecodingmachine/safe/workflows/Continuous%20Integration/badge.svg)](https://github.com/thecodingmachine/safe/actions) -[![codecov](https://codecov.io/gh/thecodingmachine/safe/branch/master/graph/badge.svg)](https://codecov.io/gh/thecodingmachine/safe) - -Safe PHP -======== - -A set of core PHP functions rewritten to throw exceptions instead of returning `false` when an error is encountered. - -## The problem - -Most PHP core functions were written before exception handling was added to the language. Therefore, most PHP functions -do not throw exceptions. Instead, they return `false` in case of error. - -But most of us are too lazy to check explicitly for every single return of every core PHP function. - -```php -// This code is incorrect. Twice. -// "file_get_contents" can return false if the file does not exist -// "json_decode" can return false if the file content is not valid JSON -$content = file_get_contents('foobar.json'); -$foobar = json_decode($content); -``` - -The correct version of this code would be: - -```php -$content = file_get_contents('foobar.json'); -if ($content === false) { - throw new FileLoadingException('Could not load file foobar.json'); -} -$foobar = json_decode($content); -if (json_last_error() !== JSON_ERROR_NONE) { - throw new FileLoadingException('foobar.json does not contain valid JSON: '.json_last_error_msg()); -} -``` - -Obviously, while this snippet is correct, it is less easy to read. - -## The solution - -Enter *thecodingmachine/safe* aka Safe-PHP. - -Safe-PHP redeclares all core PHP functions. The new PHP functions act exactly as the old ones, except they -throw exceptions properly when an error is encountered. The "safe" functions have the same name as the core PHP -functions, except they are in the `Safe` namespace. - -```php -use function Safe\file_get_contents; -use function Safe\json_decode; - -// This code is both safe and simple! -$content = file_get_contents('foobar.json'); -$foobar = json_decode($content); -``` - -All PHP functions that can return `false` on error are part of Safe. -In addition, Safe also provide 2 'Safe' classes: `Safe\DateTime` and `Safe\DateTimeImmutable` whose methods will throw exceptions instead of returning false. - -## PHPStan integration - -> Yeah... but I must explicitly think about importing the "safe" variant of the function, for each and every file of my application. -> I'm sure I will forget some "use function" statements! - -Fear not! thecodingmachine/safe comes with a PHPStan rule. - -Never heard of [PHPStan](https://github.com/phpstan/phpstan) before? -Check it out, it's an amazing code analyzer for PHP. - -Simply install the Safe rule in your PHPStan setup (explained in the "Installation" section) and PHPStan will let you know each time you are using an "unsafe" function. - -The code below will trigger this warning: - -```php -$content = file_get_contents('foobar.json'); -``` - -> Function file_get_contents is unsafe to use. It can return FALSE instead of throwing an exception. Please add 'use function Safe\\file_get_contents;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library. - -## Installation - -Use composer to install Safe-PHP: - -```bash -$ composer require thecodingmachine/safe -``` - -*Highly recommended*: install PHPStan and PHPStan extension: - -```bash -$ composer require --dev thecodingmachine/phpstan-safe-rule -``` - -Now, edit your `phpstan.neon` file and add these rules: - -```yml -includes: - - vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon -``` - -## Automated refactoring - -You have a large legacy codebase and want to use "Safe-PHP" functions throughout your project? PHPStan will help you -find these functions but changing the namespace of the functions one function at a time might be a tedious task. - -Fortunately, Safe comes bundled with a "Rector" configuration file. [Rector](https://github.com/rectorphp/rector) is a command-line -tool that performs instant refactoring of your application. - -Run - -```bash -$ composer require --dev rector/rector -``` - -to install `rector/rector`. - -Run - -```bash -vendor/bin/rector process src/ --config vendor/thecodingmachine/safe/rector-migrate.php -``` - -to run `rector/rector`. - -*Note:* do not forget to replace "src/" with the path to your source directory. - -**Important:** the refactoring only performs a "dumb" replacement of functions. It will not modify the way -"false" return values are handled. So if your code was already performing error handling, you will have to deal -with it manually. - -Especially, you should look for error handling that was already performed, like: - -```php -if (!mkdir($dirPath)) { - // Do something on error -} -``` - -This code will be refactored by Rector to: - -```php -if (!\Safe\mkdir($dirPath)) { - // Do something on error -} -``` - -You should then (manually) refactor it to: - -```php -try { - \Safe\mkdir($dirPath)); -} catch (\Safe\FilesystemException $e) { - // Do something on error -} -``` - -## Performance impact - -Safe is loading 1000+ functions from ~85 files on each request. Yet, the performance impact of this loading is quite low. - -In case you worry, using Safe will "cost" you ~700µs on each request. The [performance section](performance/README.md) -contains more information regarding the way we tested the performance impact of Safe. - -## Learn more - -Read [the release article on TheCodingMachine's blog](https://thecodingmachine.io/introducing-safe-php) if you want to -learn more about what triggered the development of Safe-PHP. - -## Contributing - -The files that contain all the functions are auto-generated from the PHP doc. -Read the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn how to regenerate these files and to contribute to this library. diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/composer.json b/lam/lib/3rdParty/composer/thecodingmachine/safe/composer.json deleted file mode 100644 index e85a6593e..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/composer.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "name": "thecodingmachine/safe", - "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "license": "MIT", - "autoload": { - "classmap": [ - "lib/DateTime.php", - "lib/DateTimeImmutable.php", - "lib/Exceptions/", - "deprecated/Exceptions/", - "generated/Exceptions/" - ], - "files": [ - "deprecated/apc.php", - "deprecated/array.php", - "deprecated/datetime.php", - "deprecated/libevent.php", - "deprecated/misc.php", - "deprecated/password.php", - "deprecated/mssql.php", - "deprecated/stats.php", - "deprecated/strings.php", - "lib/special_cases.php", - "deprecated/mysqli.php", - "generated/apache.php", - "generated/apcu.php", - "generated/array.php", - "generated/bzip2.php", - "generated/calendar.php", - "generated/classobj.php", - "generated/com.php", - "generated/cubrid.php", - "generated/curl.php", - "generated/datetime.php", - "generated/dir.php", - "generated/eio.php", - "generated/errorfunc.php", - "generated/exec.php", - "generated/fileinfo.php", - "generated/filesystem.php", - "generated/filter.php", - "generated/fpm.php", - "generated/ftp.php", - "generated/funchand.php", - "generated/gettext.php", - "generated/gmp.php", - "generated/gnupg.php", - "generated/hash.php", - "generated/ibase.php", - "generated/ibmDb2.php", - "generated/iconv.php", - "generated/image.php", - "generated/imap.php", - "generated/info.php", - "generated/inotify.php", - "generated/json.php", - "generated/ldap.php", - "generated/libxml.php", - "generated/lzf.php", - "generated/mailparse.php", - "generated/mbstring.php", - "generated/misc.php", - "generated/mysql.php", - "generated/network.php", - "generated/oci8.php", - "generated/opcache.php", - "generated/openssl.php", - "generated/outcontrol.php", - "generated/pcntl.php", - "generated/pcre.php", - "generated/pgsql.php", - "generated/posix.php", - "generated/ps.php", - "generated/pspell.php", - "generated/readline.php", - "generated/rpminfo.php", - "generated/rrd.php", - "generated/sem.php", - "generated/session.php", - "generated/shmop.php", - "generated/sockets.php", - "generated/sodium.php", - "generated/solr.php", - "generated/spl.php", - "generated/sqlsrv.php", - "generated/ssdeep.php", - "generated/ssh2.php", - "generated/stream.php", - "generated/strings.php", - "generated/swoole.php", - "generated/uodbc.php", - "generated/uopz.php", - "generated/url.php", - "generated/var.php", - "generated/xdiff.php", - "generated/xml.php", - "generated/xmlrpc.php", - "generated/yaml.php", - "generated/yaz.php", - "generated/zip.php", - "generated/zlib.php" - ] - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.5", - "thecodingmachine/phpstan-strict-rules": "^1.0", - "squizlabs/php_codesniffer": "^3.2", - "phpunit/phpunit": "^9.5" - }, - "scripts": { - "phpstan": "phpstan analyse lib -c phpstan.neon --level=max --no-progress -vvv", - "cs-fix": "phpcbf", - "cs-check": "phpcs" - }, - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - } -} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/deprecated/Exceptions/ApcException.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/deprecated/Exceptions/ApcException.php deleted file mode 100644 index f344490d8..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/deprecated/Exceptions/ApcException.php +++ /dev/null @@ -1,11 +0,0 @@ - - * - * - * @param int $length If length is given and is positive, the string - * returned will contain at most length characters - * beginning from start (depending on the length of - * string). - * - * If length is given and is negative, then that many - * characters will be omitted from the end of string - * (after the start position has been calculated when a - * start is negative). If - * start denotes the position of this truncation or - * beyond, FALSE will be returned. - * - * If length is given and is 0, - * FALSE or NULL, an empty string will be returned. - * - * If length is omitted, the substring starting from - * start until the end of the string will be - * returned. - * @return string Returns the extracted part of string;, or - * an empty string. - * @throws StringsException - * @deprecated The Safe version of this function is no longer needed in PHP 8.0+ - * - */ -function substr(string $string, int $start, int $length = null): string -{ - error_clear_last(); - if ($length !== null) { - $result = \substr($string, $start, $length); - } else { - $result = \substr($string, $start); - } - if ($result === false) { - throw StringsException::createFromPhpError(); - } - return $result; -} - -/** - * Operates as sprintf but accepts an array of - * arguments, rather than a variable number of arguments. - * - * @param string $format The format string is composed of zero or more directives: - * ordinary characters (excluding %) that are - * copied directly to the result and conversion - * specifications, each of which results in fetching its - * own parameter. - * - * A conversion specification follows this prototype: - * %[argnum$][flags][width][.precision]specifier. - * - * An integer followed by a dollar sign $, - * to specify which number argument to treat in the conversion. - * - * - * Flags - * - * - * - * Flag - * Description - * - * - * - * - * - - * - * Left-justify within the given field width; - * Right justification is the default - * - * - * - * + - * - * Prefix positive numbers with a plus sign - * +; Default only negative - * are prefixed with a negative sign. - * - * - * - * (space) - * - * Pads the result with spaces. - * This is the default. - * - * - * - * 0 - * - * Only left-pads numbers with zeros. - * With s specifiers this can - * also right-pad with zeros. - * - * - * - * '(char) - * - * Pads the result with the character (char). - * - * - * - * - * - * - * An integer that says how many characters (minimum) - * this conversion should result in. - * - * A period . followed by an integer - * who's meaning depends on the specifier: - * - * - * - * For e, E, - * f and F - * specifiers: this is the number of digits to be printed - * after the decimal point (by default, this is 6). - * - * - * - * - * For g and G - * specifiers: this is the maximum number of significant - * digits to be printed. - * - * - * - * - * For s specifier: it acts as a cutoff point, - * setting a maximum character limit to the string. - * - * - * - * - * - * If the period is specified without an explicit value for precision, - * 0 is assumed. - * - * - * - * - * Specifiers - * - * - * - * Specifier - * Description - * - * - * - * - * % - * - * A literal percent character. No argument is required. - * - * - * - * b - * - * The argument is treated as an integer and presented - * as a binary number. - * - * - * - * c - * - * The argument is treated as an integer and presented - * as the character with that ASCII. - * - * - * - * d - * - * The argument is treated as an integer and presented - * as a (signed) decimal number. - * - * - * - * e - * - * The argument is treated as scientific notation (e.g. 1.2e+2). - * The precision specifier stands for the number of digits after the - * decimal point since PHP 5.2.1. In earlier versions, it was taken as - * number of significant digits (one less). - * - * - * - * E - * - * Like the e specifier but uses - * uppercase letter (e.g. 1.2E+2). - * - * - * - * f - * - * The argument is treated as a float and presented - * as a floating-point number (locale aware). - * - * - * - * F - * - * The argument is treated as a float and presented - * as a floating-point number (non-locale aware). - * Available as of PHP 5.0.3. - * - * - * - * g - * - * - * General format. - * - * - * Let P equal the precision if nonzero, 6 if the precision is omitted, - * or 1 if the precision is zero. - * Then, if a conversion with style E would have an exponent of X: - * - * - * If P > X ≥ −4, the conversion is with style f and precision P − (X + 1). - * Otherwise, the conversion is with style e and precision P − 1. - * - * - * - * - * G - * - * Like the g specifier but uses - * E and f. - * - * - * - * o - * - * The argument is treated as an integer and presented - * as an octal number. - * - * - * - * s - * - * The argument is treated and presented as a string. - * - * - * - * u - * - * The argument is treated as an integer and presented - * as an unsigned decimal number. - * - * - * - * x - * - * The argument is treated as an integer and presented - * as a hexadecimal number (with lowercase letters). - * - * - * - * X - * - * The argument is treated as an integer and presented - * as a hexadecimal number (with uppercase letters). - * - * - * - * - * - * - * General format. - * - * Let P equal the precision if nonzero, 6 if the precision is omitted, - * or 1 if the precision is zero. - * Then, if a conversion with style E would have an exponent of X: - * - * If P > X ≥ −4, the conversion is with style f and precision P − (X + 1). - * Otherwise, the conversion is with style e and precision P − 1. - * - * The c type specifier ignores padding and width - * - * Attempting to use a combination of the string and width specifiers with character sets that require more than one byte per character may result in unexpected results - * - * Variables will be co-erced to a suitable type for the specifier: - * - * Type Handling - * - * - * - * Type - * Specifiers - * - * - * - * - * string - * s - * - * - * integer - * - * d, - * u, - * c, - * o, - * x, - * X, - * b - * - * - * - * double - * - * g, - * G, - * e, - * E, - * f, - * F - * - * - * - * - * - * @param array $args - * @return string Return array values as a formatted string according to - * format. - * @throws StringsException - * @deprecated The Safe version of this function is no longer needed in PHP 8.0+ - */ -function vsprintf(string $format, array $args): string -{ - error_clear_last(); - $result = \vsprintf($format, $args); - if ($result === false) { - throw StringsException::createFromPhpError(); - } - return $result; -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/Exceptions/.gitkeep b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/Exceptions/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/Exceptions/ApacheException.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/Exceptions/ApacheException.php deleted file mode 100644 index 5d69236fa..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/Exceptions/ApacheException.php +++ /dev/null @@ -1,11 +0,0 @@ - - * - * - * - * The permissions parameter consists of three octal - * number components specifying access restrictions for the owner, - * the user group in which the owner is in, and to everybody else in - * this order. One component can be computed by adding up the needed - * permissions for that target user base. Number 1 means that you - * grant execute rights, number 2 means that you make the file - * writeable, number 4 means that you make the file readable. Add - * up these numbers to specify needed rights. You can also read more - * about modes on Unix systems with 'man 1 chmod' - * and 'man 2 chmod'. - * - * - * - * - */ -function chmod(string $filename, int $permissions): void -{ - error_clear_last(); - $safeResult = \chmod($filename, $permissions); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Attempts to change the owner of the file filename - * to user user. Only the superuser may change the - * owner of a file. - * - * @param string $filename Path to the file. - * @param string|int $user A user name or number. - * @throws FilesystemException - * - */ -function chown(string $filename, $user): void -{ - error_clear_last(); - $safeResult = \chown($filename, $user); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Makes a copy of the file from to - * to. - * - * If you wish to move a file, use the rename function. - * - * @param string $from Path to the source file. - * @param string $to The destination path. If to is a URL, the - * copy operation may fail if the wrapper does not support overwriting of - * existing files. - * - * If the destination file already exists, it will be overwritten. - * @param resource $context A valid context resource created with - * stream_context_create. - * @throws FilesystemException - * - */ -function copy(string $from, string $to, $context = null): void -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \copy($from, $to, $context); - } else { - $safeResult = \copy($from, $to); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Given a string containing a directory, this function will return the - * number of bytes available on the corresponding filesystem or disk - * partition. - * - * @param string $directory A directory of the filesystem or disk partition. - * - * Given a file name instead of a directory, the behaviour of the - * function is unspecified and may differ between operating systems and - * PHP versions. - * @return float Returns the number of available bytes as a float. - * @throws FilesystemException - * - */ -function disk_free_space(string $directory): float -{ - error_clear_last(); - $safeResult = \disk_free_space($directory); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Given a string containing a directory, this function will return the total - * number of bytes on the corresponding filesystem or disk partition. - * - * @param string $directory A directory of the filesystem or disk partition. - * @return float Returns the total number of bytes as a float. - * @throws FilesystemException - * - */ -function disk_total_space(string $directory): float -{ - error_clear_last(); - $safeResult = \disk_total_space($directory); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * The file pointed to by stream is closed. - * - * @param resource $stream The file pointer must be valid, and must point to a file successfully - * opened by fopen or fsockopen. - * @throws FilesystemException - * - */ -function fclose($stream): void -{ - error_clear_last(); - $safeResult = \fclose($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * This function synchronizes stream contents to storage media, just like fsync does, - * but it does not synchronize file meta-data. - * Note that this function is only effectively different in POSIX systems. - * In Windows, this function is aliased to fsync. - * - * @param resource $stream The file pointer must be valid, and must point to - * a file successfully opened by fopen or - * fsockopen (and not yet closed by - * fclose). - * @throws FilesystemException - * - */ -function fdatasync($stream): void -{ - error_clear_last(); - $safeResult = \fdatasync($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * This function forces a write of all buffered output to the resource - * pointed to by the file stream. - * - * @param resource $stream The file pointer must be valid, and must point to - * a file successfully opened by fopen or - * fsockopen (and not yet closed by - * fclose). - * @throws FilesystemException - * - */ -function fflush($stream): void -{ - error_clear_last(); - $safeResult = \fflush($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * This function is similar to file, except that - * file_get_contents returns the file in a - * string, starting at the specified offset - * up to length bytes. On failure, - * file_get_contents will return FALSE. - * - * file_get_contents is the preferred way to read the - * contents of a file into a string. It will use memory mapping techniques if - * supported by your OS to enhance performance. - * - * @param string $filename Name of the file to read. - * @param bool $use_include_path The FILE_USE_INCLUDE_PATH constant can be used - * to trigger include path - * search. - * This is not possible if strict typing - * is enabled, since FILE_USE_INCLUDE_PATH is an - * int. Use TRUE instead. - * @param resource|null $context A valid context resource created with - * stream_context_create. If you don't need to use a - * custom context, you can skip this parameter by NULL. - * @param int $offset The offset where the reading starts on the original stream. - * Negative offsets count from the end of the stream. - * - * Seeking (offset) is not supported with remote files. - * Attempting to seek on non-local files may work with small offsets, but this - * is unpredictable because it works on the buffered stream. - * @param int $length Maximum length of data read. The default is to read until end - * of file is reached. Note that this parameter is applied to the - * stream processed by the filters. - * @return string The function returns the read data. - * @throws FilesystemException - * - */ -function file_get_contents(string $filename, bool $use_include_path = false, $context = null, int $offset = 0, int $length = null): string -{ - error_clear_last(); - if ($length !== null) { - $safeResult = \file_get_contents($filename, $use_include_path, $context, $offset, $length); - } elseif ($offset !== 0) { - $safeResult = \file_get_contents($filename, $use_include_path, $context, $offset); - } elseif ($context !== null) { - $safeResult = \file_get_contents($filename, $use_include_path, $context); - } else { - $safeResult = \file_get_contents($filename, $use_include_path); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * This function is identical to calling fopen, - * fwrite and fclose successively - * to write data to a file. - * - * If filename does not exist, the file is created. - * Otherwise, the existing file is overwritten, unless the - * FILE_APPEND flag is set. - * - * @param string $filename Path to the file where to write the data. - * @param mixed $data The data to write. Can be either a string, an - * array or a stream resource. - * - * If data is a stream resource, the - * remaining buffer of that stream will be copied to the specified file. - * This is similar with using stream_copy_to_stream. - * - * You can also specify the data parameter as a single - * dimension array. This is equivalent to - * file_put_contents($filename, implode('', $array)). - * @param int $flags The value of flags can be any combination of - * the following flags, joined with the binary OR (|) - * operator. - * - * - * Available flags - * - * - * - * Flag - * Description - * - * - * - * - * - * FILE_USE_INCLUDE_PATH - * - * - * Search for filename in the include directory. - * See include_path for more - * information. - * - * - * - * - * FILE_APPEND - * - * - * If file filename already exists, append - * the data to the file instead of overwriting it. - * - * - * - * - * LOCK_EX - * - * - * Acquire an exclusive lock on the file while proceeding to the - * writing. In other words, a flock call happens - * between the fopen call and the - * fwrite call. This is not identical to an - * fopen call with mode "x". - * - * - * - * - * - * @param resource|null $context A valid context resource created with - * stream_context_create. - * @return int This function returns the number of bytes that were written to the file. - * @throws FilesystemException - * - */ -function file_put_contents(string $filename, $data, int $flags = 0, $context = null): int -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \file_put_contents($filename, $data, $flags, $context); - } else { - $safeResult = \file_put_contents($filename, $data, $flags); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Reads an entire file into an array. - * - * @param string $filename Path to the file. - * @param int $flags The optional parameter flags can be one, or - * more, of the following constants: - * - * - * - * FILE_USE_INCLUDE_PATH - * - * - * - * Search for the file in the include_path. - * - * - * - * - * - * FILE_IGNORE_NEW_LINES - * - * - * - * Omit newline at the end of each array element - * - * - * - * - * - * FILE_SKIP_EMPTY_LINES - * - * - * - * Skip empty lines - * - * - * - * - * @param resource $context - * @return array Returns the file in an array. Each element of the array corresponds to a - * line in the file, with the newline still attached. Upon failure, - * file returns FALSE. - * @throws FilesystemException - * - */ -function file(string $filename, int $flags = 0, $context = null): array -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \file($filename, $flags, $context); - } else { - $safeResult = \file($filename, $flags); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * - * - * @param string $filename Path to the file. - * @return int Returns the time the file was last accessed. - * The time is returned as a Unix timestamp. - * @throws FilesystemException - * - */ -function fileatime(string $filename): int -{ - error_clear_last(); - $safeResult = \fileatime($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets the inode change time of a file. - * - * @param string $filename Path to the file. - * @return int Returns the time the file was last changed. - * The time is returned as a Unix timestamp. - * @throws FilesystemException - * - */ -function filectime(string $filename): int -{ - error_clear_last(); - $safeResult = \filectime($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets the file inode. - * - * @param string $filename Path to the file. - * @return int Returns the inode number of the file. - * @throws FilesystemException - * - */ -function fileinode(string $filename): int -{ - error_clear_last(); - $safeResult = \fileinode($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * This function returns the time when the data blocks of a file were being - * written to, that is, the time when the content of the file was changed. - * - * @param string $filename Path to the file. - * @return int Returns the time the file was last modified. - * The time is returned as a Unix timestamp, which is - * suitable for the date function. - * @throws FilesystemException - * - */ -function filemtime(string $filename): int -{ - error_clear_last(); - $safeResult = \filemtime($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets the file owner. - * - * @param string $filename Path to the file. - * @return int Returns the user ID of the owner of the file. - * The user ID is returned in numerical format, use - * posix_getpwuid to resolve it to a username. - * @throws FilesystemException - * - */ -function fileowner(string $filename): int -{ - error_clear_last(); - $safeResult = \fileowner($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets permissions for the given file. - * - * @param string $filename Path to the file. - * @return int Returns the file's permissions as a numeric mode. Lower bits of this mode - * are the same as the permissions expected by chmod, - * however on most platforms the return value will also include information on - * the type of file given as filename. The examples - * below demonstrate how to test the return value for specific permissions and - * file types on POSIX systems, including Linux and macOS. - * - * For local files, the specific return value is that of the - * st_mode member of the structure returned by the C - * library's stat function. Exactly which bits are set - * can vary from platform to platform, and looking up your specific platform's - * documentation is recommended if parsing the non-permission bits of the - * return value is required. - * - * Returns FALSE on failure. - * @throws FilesystemException - * - */ -function fileperms(string $filename): int -{ - error_clear_last(); - $safeResult = \fileperms($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets the size for the given file. - * - * @param string $filename Path to the file. - * @return int Returns the size of the file in bytes, or FALSE (and generates an error - * of level E_WARNING) in case of an error. - * @throws FilesystemException - * - */ -function filesize(string $filename): int -{ - error_clear_last(); - $safeResult = \filesize($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * flock allows you to perform a simple reader/writer - * model which can be used on virtually every platform (including most Unix - * derivatives and even Windows). - * - * The lock is released also by fclose, - * or when stream is garbage collected. - * - * PHP supports a portable way of locking complete files in an advisory way - * (which means all accessing programs have to use the same way of locking - * or it will not work). By default, this function will block until the - * requested lock is acquired; this may be controlled with the LOCK_NB option documented below. - * - * @param resource $stream A file system pointer resource - * that is typically created using fopen. - * @param int $operation operation is one of the following: - * - * - * - * LOCK_SH to acquire a shared lock (reader). - * - * - * - * - * LOCK_EX to acquire an exclusive lock (writer). - * - * - * - * - * LOCK_UN to release a lock (shared or exclusive). - * - * - * - * - * It is also possible to add LOCK_NB as a bitmask to one - * of the above operations, if flock should not - * block during the locking attempt. - * @param int|null $would_block The optional third argument is set to 1 if the lock would block - * (EWOULDBLOCK errno condition). - * @throws FilesystemException - * - */ -function flock($stream, int $operation, ?int &$would_block = null): void -{ - error_clear_last(); - $safeResult = \flock($stream, $operation, $would_block); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * fopen binds a named resource, specified by - * filename, to a stream. - * - * @param string $filename If filename is of the form "scheme://...", it - * is assumed to be a URL and PHP will search for a protocol handler - * (also known as a wrapper) for that scheme. If no wrappers for that - * protocol are registered, PHP will emit a notice to help you track - * potential problems in your script and then continue as though - * filename specifies a regular file. - * - * If PHP has decided that filename specifies - * a local file, then it will try to open a stream on that file. - * The file must be accessible to PHP, so you need to ensure that - * the file access permissions allow this access. - * If you have enabled - * open_basedir further - * restrictions may apply. - * - * If PHP has decided that filename specifies - * a registered protocol, and that protocol is registered as a - * network URL, PHP will check to make sure that - * allow_url_fopen is - * enabled. If it is switched off, PHP will emit a warning and - * the fopen call will fail. - * - * The list of supported protocols can be found in . Some protocols (also referred to as - * wrappers) support context - * and/or php.ini options. Refer to the specific page for the - * protocol in use for a list of options which can be set. (e.g. - * php.ini value user_agent used by the - * http wrapper). - * - * On the Windows platform, be careful to escape any backslashes - * used in the path to the file, or use forward slashes. - * - * - * - * ]]> - * - * - * @param string $mode The mode parameter specifies the type of access - * you require to the stream. It may be any of the following: - * - * - * A list of possible modes for fopen - * using mode - * - * - * - * - * mode - * Description - * - * - * - * - * 'r' - * - * Open for reading only; place the file pointer at the - * beginning of the file. - * - * - * - * 'r+' - * - * Open for reading and writing; place the file pointer at - * the beginning of the file. - * - * - * - * 'w' - * - * Open for writing only; place the file pointer at the - * beginning of the file and truncate the file to zero length. - * If the file does not exist, attempt to create it. - * - * - * - * 'w+' - * - * Open for reading and writing; otherwise it has the - * same behavior as 'w'. - * - * - * - * 'a' - * - * Open for writing only; place the file pointer at the end of - * the file. If the file does not exist, attempt to create it. - * In this mode, fseek has no effect, writes are always appended. - * - * - * - * 'a+' - * - * Open for reading and writing; place the file pointer at - * the end of the file. If the file does not exist, attempt to - * create it. In this mode, fseek only affects - * the reading position, writes are always appended. - * - * - * - * 'x' - * - * Create and open for writing only; place the file pointer at the - * beginning of the file. If the file already exists, the - * fopen call will fail by returning FALSE and - * generating an error of level E_WARNING. If - * the file does not exist, attempt to create it. This is equivalent - * to specifying O_EXCL|O_CREAT flags for the - * underlying open(2) system call. - * - * - * - * 'x+' - * - * Create and open for reading and writing; otherwise it has the - * same behavior as 'x'. - * - * - * - * 'c' - * - * Open the file for writing only. If the file does not exist, it is - * created. If it exists, it is neither truncated (as opposed to - * 'w'), nor the call to this function fails (as is - * the case with 'x'). The file pointer is - * positioned on the beginning of the file. This may be useful if it's - * desired to get an advisory lock (see flock) - * before attempting to modify the file, as using - * 'w' could truncate the file before the lock - * was obtained (if truncation is desired, - * ftruncate can be used after the lock is - * requested). - * - * - * - * 'c+' - * - * Open the file for reading and writing; otherwise it has the same - * behavior as 'c'. - * - * - * - * 'e' - * - * Set close-on-exec flag on the opened file descriptor. Only - * available in PHP compiled on POSIX.1-2008 conform systems. - * - * - * - * - * - * - * Different operating system families have different line-ending - * conventions. When you write a text file and want to insert a line - * break, you need to use the correct line-ending character(s) for your - * operating system. Unix based systems use \n as the - * line ending character, Windows based systems use \r\n - * as the line ending characters and Macintosh based systems (Mac OS Classic) used - * \r as the line ending character. - * - * If you use the wrong line ending characters when writing your files, you - * might find that other applications that open those files will "look - * funny". - * - * Windows offers a text-mode translation flag ('t') - * which will transparently translate \n to - * \r\n when working with the file. In contrast, you - * can also use 'b' to force binary mode, which will not - * translate your data. To use these flags, specify either - * 'b' or 't' as the last character - * of the mode parameter. - * - * The default translation mode is 'b'. - * You can use the 't' - * mode if you are working with plain-text files and you use - * \n to delimit your line endings in your script, but - * expect your files to be readable with applications such as old versions of notepad. You - * should use the 'b' in all other cases. - * - * If you specify the 't' flag when working with binary files, you - * may experience strange problems with your data, including broken image - * files and strange problems with \r\n characters. - * - * For portability, it is also strongly recommended that - * you re-write code that uses or relies upon the 't' - * mode so that it uses the correct line endings and - * 'b' mode instead. - * @param bool $use_include_path The optional third use_include_path parameter - * can be set to '1' or TRUE if you want to search for the file in the - * include_path, too. - * @param resource|null $context A context stream - * resource. - * @return resource Returns a file pointer resource on success - * @throws FilesystemException - * - */ -function fopen(string $filename, string $mode, bool $use_include_path = false, $context = null) -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \fopen($filename, $mode, $use_include_path, $context); - } else { - $safeResult = \fopen($filename, $mode, $use_include_path); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * fread reads up to - * length bytes from the file pointer - * referenced by stream. Reading stops as soon as one - * of the following conditions is met: - * - * - * - * length bytes have been read - * - * - * - * - * EOF (end of file) is reached - * - * - * - * - * a packet becomes available or the - * socket timeout occurs (for network streams) - * - * - * - * - * if the stream is read buffered and it does not represent a plain file, at - * most one read of up to a number of bytes equal to the chunk size (usually - * 8192) is made; depending on the previously buffered data, the size of the - * returned data may be larger than the chunk size. - * - * - * - * - * @param resource $stream A file system pointer resource - * that is typically created using fopen. - * @param int $length Up to length number of bytes read. - * @return string Returns the read string. - * @throws FilesystemException - * - */ -function fread($stream, int $length): string -{ - error_clear_last(); - $safeResult = \fread($stream, $length); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gathers the statistics of the file opened by the file - * pointer stream. This function is similar to the - * stat function except that it operates - * on an open file pointer instead of a filename. - * - * @param resource $stream A file system pointer resource - * that is typically created using fopen. - * @return array Returns an array with the statistics of the file; the format of the array - * is described in detail on the stat manual page. - * Returns FALSE on failure. - * @throws FilesystemException - * - */ -function fstat($stream): array -{ - error_clear_last(); - $safeResult = \fstat($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * This function synchronizes changes to the file, including its meta-data. This is similar to fflush, - * but it also instructs the operating system to write to the storage media. - * - * @param resource $stream The file pointer must be valid, and must point to - * a file successfully opened by fopen or - * fsockopen (and not yet closed by - * fclose). - * @throws FilesystemException - * - */ -function fsync($stream): void -{ - error_clear_last(); - $safeResult = \fsync($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Takes the filepointer, stream, and truncates the file to - * length, size. - * - * @param resource $stream The file pointer. - * - * The stream must be open for writing. - * @param int $size The size to truncate to. - * - * If size is larger than the file then the file - * is extended with null bytes. - * - * If size is smaller than the file then the file - * is truncated to that size. - * @throws FilesystemException - * - */ -function ftruncate($stream, int $size): void -{ - error_clear_last(); - $safeResult = \ftruncate($stream, $size); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * - * - * @param resource $stream A file system pointer resource - * that is typically created using fopen. - * @param string $data The string that is to be written. - * @param int $length If length is an integer, writing will stop - * after length bytes have been written or the - * end of data is reached, whichever comes first. - * @return int - * @throws FilesystemException - * - */ -function fwrite($stream, string $data, int $length = null): int -{ - error_clear_last(); - if ($length !== null) { - $safeResult = \fwrite($stream, $data, $length); - } else { - $safeResult = \fwrite($stream, $data); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * The glob function searches for all the pathnames - * matching pattern according to the rules used by - * the libc glob() function, which is similar to the rules used by common - * shells. - * - * @param string $pattern The pattern. No tilde expansion or parameter substitution is done. - * - * Special characters: - * - * - * - * * - Matches zero or more characters. - * - * - * - * - * ? - Matches exactly one character (any character). - * - * - * - * - * [...] - Matches one character from a group of - * characters. If the first character is !, - * matches any character not in the group. - * - * - * - * - * \ - Escapes the following character, - * except when the GLOB_NOESCAPE flag is used. - * - * - * - * @param int $flags Valid flags: - * - * - * - * GLOB_MARK - Adds a slash (a backslash on Windows) to each directory returned - * - * - * - * - * GLOB_NOSORT - Return files as they appear in the - * directory (no sorting). When this flag is not used, the pathnames are - * sorted alphabetically - * - * - * - * - * GLOB_NOCHECK - Return the search pattern if no - * files matching it were found - * - * - * - * - * GLOB_NOESCAPE - Backslashes do not quote - * metacharacters - * - * - * - * - * GLOB_BRACE - Expands {a,b,c} to match 'a', 'b', - * or 'c' - * - * - * - * - * GLOB_ONLYDIR - Return only directory entries - * which match the pattern - * - * - * - * - * GLOB_ERR - Stop on read errors (like unreadable - * directories), by default errors are ignored. - * - * - * - * - * - * The GLOB_BRACE flag is not available on some non GNU - * systems, like Solaris or Alpine Linux. - * - * - * @return array Returns an array containing the matched files/directories, an empty array - * if no file matched. - * @throws FilesystemException - * - */ -function glob(string $pattern, int $flags = 0): array -{ - error_clear_last(); - $safeResult = \glob($pattern, $flags); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Attempts to change the group of the symlink filename - * to group. - * - * Only the superuser may change the group of a symlink arbitrarily; other - * users may change the group of a symlink to any group of which that user is - * a member. - * - * @param string $filename Path to the symlink. - * @param string|int $group The group specified by name or number. - * @throws FilesystemException - * - */ -function lchgrp(string $filename, $group): void -{ - error_clear_last(); - $safeResult = \lchgrp($filename, $group); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Attempts to change the owner of the symlink filename - * to user user. - * - * Only the superuser may change the owner of a symlink. - * - * @param string $filename Path to the file. - * @param string|int $user User name or number. - * @throws FilesystemException - * - */ -function lchown(string $filename, $user): void -{ - error_clear_last(); - $safeResult = \lchown($filename, $user); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * link creates a hard link. - * - * @param string $target Target of the link. - * @param string $link The link name. - * @throws FilesystemException - * - */ -function link(string $target, string $link): void -{ - error_clear_last(); - $safeResult = \link($target, $link); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Gathers the statistics of the file or symbolic link named by - * filename. - * - * @param string $filename Path to a file or a symbolic link. - * @return array See the manual page for stat for information on - * the structure of the array that lstat returns. - * This function is identical to the stat function - * except that if the filename parameter is a symbolic - * link, the status of the symbolic link is returned, not the status of the - * file pointed to by the symbolic link. - * - * On failure, FALSE is returned. - * @throws FilesystemException - * - */ -function lstat(string $filename): array -{ - error_clear_last(); - $safeResult = \lstat($filename); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Attempts to create the directory specified by directory. - * - * @param string $directory The directory path. - * A URL can be used as a - * filename with this function if the fopen wrappers have been enabled. - * See fopen for more details on how to specify the - * filename. See the for links to information - * about what abilities the various wrappers have, notes on their usage, - * and information on any predefined variables they may - * provide. - * @param int $permissions The permissions are 0777 by default, which means the widest possible - * access. For more information on permissions, read the details - * on the chmod page. - * - * permissions is ignored on Windows. - * - * Note that you probably want to specify the permissions as an octal number, - * which means it should have a leading zero. The permissions is also modified - * by the current umask, which you can change using - * umask. - * @param bool $recursive If TRUE, then any parent directories to the directory specified will - * also be created, with the same permissions. - * @param resource $context A context stream - * resource. - * @throws FilesystemException - * - */ -function mkdir(string $directory, int $permissions = 0777, bool $recursive = false, $context = null): void -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \mkdir($directory, $permissions, $recursive, $context); - } else { - $safeResult = \mkdir($directory, $permissions, $recursive); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * parse_ini_file loads in the - * ini file specified in filename, - * and returns the settings in it in an associative array. - * - * The structure of the ini file is the same as the php.ini's. - * - * @param string $filename The filename of the ini file being parsed. If a relative path is used, - * it is evaluated relative to the current working directory, then the - * include_path. - * @param bool $process_sections By setting the process_sections - * parameter to TRUE, you get a multidimensional array, with - * the section names and settings included. The default - * for process_sections is FALSE - * @param int $scanner_mode Can either be INI_SCANNER_NORMAL (default) or - * INI_SCANNER_RAW. If INI_SCANNER_RAW - * is supplied, then option values will not be parsed. - * - * - * As of PHP 5.6.1 can also be specified as INI_SCANNER_TYPED. - * In this mode boolean, null and integer types are preserved when possible. - * String values "true", "on" and "yes" - * are converted to TRUE. "false", "off", "no" - * and "none" are considered FALSE. "null" is converted to NULL - * in typed mode. Also, all numeric strings are converted to integer type if it is possible. - * @return array The settings are returned as an associative array on success. - * @throws FilesystemException - * - */ -function parse_ini_file(string $filename, bool $process_sections = false, int $scanner_mode = INI_SCANNER_NORMAL): array -{ - error_clear_last(); - $safeResult = \parse_ini_file($filename, $process_sections, $scanner_mode); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * parse_ini_string returns the settings in string - * ini_string in an associative array. - * - * The structure of the ini string is the same as the php.ini's. - * - * @param string $ini_string The contents of the ini file being parsed. - * @param bool $process_sections By setting the process_sections - * parameter to TRUE, you get a multidimensional array, with - * the section names and settings included. The default - * for process_sections is FALSE - * @param int $scanner_mode Can either be INI_SCANNER_NORMAL (default) or - * INI_SCANNER_RAW. If INI_SCANNER_RAW - * is supplied, then option values will not be parsed. - * - * - * As of PHP 5.6.1 can also be specified as INI_SCANNER_TYPED. - * In this mode boolean, null and integer types are preserved when possible. - * String values "true", "on" and "yes" - * are converted to TRUE. "false", "off", "no" - * and "none" are considered FALSE. "null" is converted to NULL - * in typed mode. Also, all numeric strings are converted to integer type if it is possible. - * @return array The settings are returned as an associative array on success. - * @throws FilesystemException - * - */ -function parse_ini_string(string $ini_string, bool $process_sections = false, int $scanner_mode = INI_SCANNER_NORMAL): array -{ - error_clear_last(); - $safeResult = \parse_ini_string($ini_string, $process_sections, $scanner_mode); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Reads a file and writes it to the output buffer. - * - * @param string $filename The filename being read. - * @param bool $use_include_path You can use the optional second parameter and set it to TRUE, if - * you want to search for the file in the include_path, too. - * @param resource $context A context stream - * resource. - * @return int Returns the number of bytes read from the file on success - * @throws FilesystemException - * - */ -function readfile(string $filename, bool $use_include_path = false, $context = null): int -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \readfile($filename, $use_include_path, $context); - } else { - $safeResult = \readfile($filename, $use_include_path); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * readlink does the same as the readlink C function. - * - * @param string $path The symbolic link path. - * @return string Returns the contents of the symbolic link path. - * @throws FilesystemException - * - */ -function readlink(string $path): string -{ - error_clear_last(); - $safeResult = \readlink($path); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * realpath expands all symbolic links and - * resolves references to /./, /../ and extra / characters in - * the input path and returns the canonicalized - * absolute pathname. - * - * @param string $path The path being checked. - * - * - * Whilst a path must be supplied, the value can be an empty string. - * In this case, the value is interpreted as the current directory. - * - * - * - * Whilst a path must be supplied, the value can be an empty string. - * In this case, the value is interpreted as the current directory. - * @return string Returns the canonicalized absolute pathname on success. The resulting path - * will have no symbolic link, /./ or /../ components. Trailing delimiters, - * such as \ and /, are also removed. - * - * realpath returns FALSE on failure, e.g. if - * the file does not exist. - * @throws FilesystemException - * - */ -function realpath(string $path): string -{ - error_clear_last(); - $safeResult = \realpath($path); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Attempts to rename from to - * to, moving it between directories if necessary. - * If renaming a file and to exists, - * it will be overwritten. If renaming a directory and - * to exists, - * this function will emit a warning. - * - * @param string $from The old name. - * - * The wrapper used in from - * must match the wrapper used in - * to. - * @param string $to The new name. - * - * - * On Windows, if to already exists, it must be writable. - * Otherwise rename fails and issues E_WARNING. - * - * - * @param resource $context A context stream - * resource. - * @throws FilesystemException - * - */ -function rename(string $from, string $to, $context = null): void -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \rename($from, $to, $context); - } else { - $safeResult = \rename($from, $to); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Sets the file position indicator for stream - * to the beginning of the file stream. - * - * @param resource $stream The file pointer must be valid, and must point to a file - * successfully opened by fopen. - * @throws FilesystemException - * - */ -function rewind($stream): void -{ - error_clear_last(); - $safeResult = \rewind($stream); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Attempts to remove the directory named by directory. - * The directory must be empty, and the relevant permissions must permit this. - * A E_WARNING level error will be generated on failure. - * - * @param string $directory Path to the directory. - * @param resource $context A context stream - * resource. - * @throws FilesystemException - * - */ -function rmdir(string $directory, $context = null): void -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \rmdir($directory, $context); - } else { - $safeResult = \rmdir($directory); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * symlink creates a symbolic link to the existing - * target with the specified name - * link. - * - * @param string $target Target of the link. - * @param string $link The link name. - * @throws FilesystemException - * - */ -function symlink(string $target, string $link): void -{ - error_clear_last(); - $safeResult = \symlink($target, $link); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Creates a file with a unique filename, with access permission set to 0600, in the specified directory. - * If the directory does not exist or is not writable, tempnam may - * generate a file in the system's temporary directory, and return - * the full path to that file, including its name. - * - * @param string $directory The directory where the temporary filename will be created. - * @param string $prefix The prefix of the generated temporary filename. - * @return string Returns the new temporary filename (with path). - * @throws FilesystemException - * - */ -function tempnam(string $directory, string $prefix): string -{ - error_clear_last(); - $safeResult = \tempnam($directory, $prefix); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Creates a temporary file with a unique name in read-write (w+) mode and - * returns a file handle. - * - * The file is automatically removed when closed (for example, by calling - * fclose, or when there are no remaining references to - * the file handle returned by tmpfile), or when the - * script ends. - * - * @return resource Returns a file handle, similar to the one returned by - * fopen, for the new file. - * @throws FilesystemException - * - */ -function tmpfile() -{ - error_clear_last(); - $safeResult = \tmpfile(); - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Attempts to set the access and modification times of the file named in the - * filename parameter to the value given in - * mtime. - * Note that the access time is always modified, regardless of the number - * of parameters. - * - * If the file does not exist, it will be created. - * - * @param string $filename The name of the file being touched. - * @param int $mtime The touch time. If mtime is NULL, - * the current system time is used. - * @param int $atime If not NULL, the access time of the given filename is set to - * the value of atime. Otherwise, it is set to - * the value passed to the mtime parameter. - * If both are NULL, the current system time is used. - * @throws FilesystemException - * - */ -function touch(string $filename, int $mtime = null, int $atime = null): void -{ - error_clear_last(); - if ($atime !== null) { - $safeResult = \touch($filename, $mtime, $atime); - } elseif ($mtime !== null) { - $safeResult = \touch($filename, $mtime); - } else { - $safeResult = \touch($filename); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} - - -/** - * Deletes filename. Similar to the Unix C unlink() - * function. An E_WARNING level error will be generated on - * failure. - * - * @param string $filename Path to the file. - * - * If the file is a symlink, the symlink will be deleted. On Windows, to delete - * a symlink to a directory, rmdir has to be used instead. - * @param resource $context A context stream - * resource. - * @throws FilesystemException - * - */ -function unlink(string $filename, $context = null): void -{ - error_clear_last(); - if ($context !== null) { - $safeResult = \unlink($filename, $context); - } else { - $safeResult = \unlink($filename); - } - if ($safeResult === false) { - throw FilesystemException::createFromPhpError(); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/filter.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/filter.php deleted file mode 100644 index 0508f8e72..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/filter.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * - * - * channels will be 3 for RGB pictures and 4 for CMYK - * pictures. - * - * bits is the number of bits for each color. - * - * For some image types, the presence of channels and - * bits values can be a bit - * confusing. As an example, GIF always uses 3 channels - * per pixel, but the number of bits per pixel cannot be calculated for an - * animated GIF with a global color table. - * - * On failure, FALSE is returned. - * @throws ImageException - * - */ -function getimagesize(string $filename, ?array &$image_info = null): array -{ - error_clear_last(); - $safeResult = \getimagesize($filename, $image_info); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Returns the extension for the given IMAGETYPE_XXX - * constant. - * - * @param int $image_type One of the IMAGETYPE_XXX constant. - * @param bool $include_dot Whether to prepend a dot to the extension or not. Default to TRUE. - * @return string A string with the extension corresponding to the given image type. - * @throws ImageException - * - */ -function image_type_to_extension(int $image_type, bool $include_dot = true): string -{ - error_clear_last(); - $safeResult = \image_type_to_extension($image_type, $include_dot); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * image2wbmp outputs or save a WBMP - * version of the given image. - * - * @param resource $image An image resource, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|null $filename Path to the saved file. If not given, the raw image stream will be - * output directly. - * @param int $foreground You can set the foreground color with this parameter by setting an - * identifier obtained from imagecolorallocate. - * The default foreground color is black. - * @throws ImageException - * - */ -function image2wbmp($image, ?string $filename = null, int $foreground = null): void -{ - error_clear_last(); - if ($foreground !== null) { - $safeResult = \image2wbmp($image, $filename, $foreground); - } elseif ($filename !== null) { - $safeResult = \image2wbmp($image, $filename); - } else { - $safeResult = \image2wbmp($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param array $affine Array with keys 0 to 5. - * @param array $clip Array with keys "x", "y", "width" and "height"; or NULL. - * @return resource Return affined image object on success. - * @throws ImageException - * - */ -function imageaffine($image, array $affine, array $clip = null) -{ - error_clear_last(); - if ($clip !== null) { - $safeResult = \imageaffine($image, $affine, $clip); - } else { - $safeResult = \imageaffine($image, $affine); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Returns the concatenation of two affine transformation matrices, - * what is useful if multiple transformations should be applied to the same - * image in one go. - * - * @param array $matrix1 An affine transformation matrix (an array with keys - * 0 to 5 and float values). - * @param array $matrix2 An affine transformation matrix (an array with keys - * 0 to 5 and float values). - * @return array{0:float,1:float,2:float,3:float,4:float,5:float} An affine transformation matrix (an array with keys - * 0 to 5 and float values). - * @throws ImageException - * - */ -function imageaffinematrixconcat(array $matrix1, array $matrix2): array -{ - error_clear_last(); - $safeResult = \imageaffinematrixconcat($matrix1, $matrix2); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Returns an affine transformation matrix. - * - * @param int $type One of the IMG_AFFINE_* constants. - * @param array|float $options If type is IMG_AFFINE_TRANSLATE - * or IMG_AFFINE_SCALE, - * options has to be an array with keys x - * and y, both having float values. - * - * If type is IMG_AFFINE_ROTATE, - * IMG_AFFINE_SHEAR_HORIZONTAL or IMG_AFFINE_SHEAR_VERTICAL, - * options has to be a float specifying the angle. - * @return array{0:float,1:float,2:float,3:float,4:float,5:float} An affine transformation matrix (an array with keys - * 0 to 5 and float values). - * @throws ImageException - * - */ -function imageaffinematrixget(int $type, $options): array -{ - error_clear_last(); - $safeResult = \imageaffinematrixget($type, $options); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagealphablending allows for two different - * modes of drawing on truecolor images. In blending mode, the - * alpha channel component of the color supplied to all drawing function, - * such as imagesetpixel determines how much of the - * underlying color should be allowed to shine through. As a result, gd - * automatically blends the existing color at that point with the drawing color, - * and stores the result in the image. The resulting pixel is opaque. In - * non-blending mode, the drawing color is copied literally with its alpha channel - * information, replacing the destination pixel. Blending mode is not available - * when drawing on palette images. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param bool $enable Whether to enable the blending mode or not. On true color images - * the default value is TRUE otherwise the default value is FALSE - * @throws ImageException - * - */ -function imagealphablending($image, bool $enable): void -{ - error_clear_last(); - $safeResult = \imagealphablending($image, $enable); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Activate the fast drawing antialiased methods for lines and wired polygons. - * It does not support alpha components. It works using a direct blend - * operation. It works only with truecolor images. - * - * Thickness and styled are not supported. - * - * Using antialiased primitives with transparent background color can end with - * some unexpected results. The blend method uses the background color as any - * other colors. The lack of alpha component support does not allow an alpha - * based antialiasing method. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param bool $enable Whether to enable antialiasing or not. - * @throws ImageException - * - */ -function imageantialias($image, bool $enable): void -{ - error_clear_last(); - $safeResult = \imageantialias($image, $enable); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagearc draws an arc of circle centered at the given - * coordinates. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $center_x x-coordinate of the center. - * @param int $center_y y-coordinate of the center. - * @param int $width The arc width. - * @param int $height The arc height. - * @param int $start_angle The arc start angle, in degrees. - * @param int $end_angle The arc end angle, in degrees. - * 0° is located at the three-o'clock position, and the arc is drawn - * clockwise. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagearc($image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color): void -{ - error_clear_last(); - $safeResult = \imagearc($image, $center_x, $center_y, $width, $height, $start_angle, $end_angle, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs or saves a AVIF Raster image from the given image. - * - * @param \GdImage $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @param int $quality quality is optional, and ranges from 0 (worst quality, smaller file) - * to 100 (best quality, larger file). - * If -1 is provided, the default value 30 is used. - * @param int $speed speed is optional, and ranges from 0 (slow, smaller file) - * to 10 (fast, larger file). - * If -1 is provided, the default value 6 is used. - * @throws ImageException - * - */ -function imageavif(\GdImage $image, $file = null, int $quality = -1, int $speed = -1): void -{ - error_clear_last(); - if ($speed !== -1) { - $safeResult = \imageavif($image, $file, $quality, $speed); - } elseif ($quality !== -1) { - $safeResult = \imageavif($image, $file, $quality); - } elseif ($file !== null) { - $safeResult = \imageavif($image, $file); - } else { - $safeResult = \imageavif($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs or saves a BMP version of the given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * - * NULL is invalid if the compressed arguments is - * not used. - * @param bool $compressed Whether the BMP should be compressed with run-length encoding (RLE), or not. - * @throws ImageException - * - */ -function imagebmp($image, $file = null, bool $compressed = true): void -{ - error_clear_last(); - if ($compressed !== true) { - $safeResult = \imagebmp($image, $file, $compressed); - } elseif ($file !== null) { - $safeResult = \imagebmp($image, $file); - } else { - $safeResult = \imagebmp($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagechar draws the first character of - * char in the image identified by - * image with its upper-left at - * x,y (top left is 0, - * 0) with the color color. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $font Can be 1, 2, 3, 4, 5 for built-in - * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or GdFont instance, - * returned by imageloadfont. - * @param int $x x-coordinate of the start. - * @param int $y y-coordinate of the start. - * @param string $char The character to draw. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagechar($image, int $font, int $x, int $y, string $char, int $color): void -{ - error_clear_last(); - $safeResult = \imagechar($image, $font, $x, $y, $char, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws the character char vertically at the specified - * coordinate on the given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $font Can be 1, 2, 3, 4, 5 for built-in - * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or GdFont instance, - * returned by imageloadfont. - * @param int $x x-coordinate of the start. - * @param int $y y-coordinate of the start. - * @param string $char The character to draw. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagecharup($image, int $font, int $x, int $y, string $char, int $color): void -{ - error_clear_last(); - $safeResult = \imagecharup($image, $font, $x, $y, $char, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Returns the index of the color of the pixel at the - * specified location in the image specified by image. - * - * If the image is a - * truecolor image, this function returns the RGB value of that pixel as - * integer. Use bitshifting and masking to access the distinct red, green and blue - * component values: - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x x-coordinate of the point. - * @param int $y y-coordinate of the point. - * @return int Returns the index of the color. - * @throws ImageException - * - */ -function imagecolorat($image, int $x, int $y): int -{ - error_clear_last(); - $safeResult = \imagecolorat($image, $x, $y); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * De-allocates a color previously allocated with - * imagecolorallocate or - * imagecolorallocatealpha. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $color The color identifier. - * @throws ImageException - * - */ -function imagecolordeallocate($image, int $color): void -{ - error_clear_last(); - $safeResult = \imagecolordeallocate($image, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Makes the colors of the palette version of an image more closely match the true color version. - * - * @param resource $image1 A truecolor image object. - * @param resource $image2 A palette image object pointing to an image that has the same - * size as image1. - * @throws ImageException - * - */ -function imagecolormatch($image1, $image2): void -{ - error_clear_last(); - $safeResult = \imagecolormatch($image1, $image2); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * This sets the specified index in the palette to the specified - * color. This is useful for creating flood-fill-like effects in - * palleted images without the overhead of performing the actual - * flood-fill. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $color An index in the palette. - * @param int $red Value of red component. - * @param int $green Value of green component. - * @param int $blue Value of blue component. - * @param int $alpha Value of alpha component. - * @throws ImageException - * - */ -function imagecolorset($image, int $color, int $red, int $green, int $blue, int $alpha = 0): void -{ - error_clear_last(); - $safeResult = \imagecolorset($image, $color, $red, $green, $blue, $alpha); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Applies a convolution matrix on the image, using the given coefficient and - * offset. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param array $matrix A 3x3 matrix: an array of three arrays of three floats. - * @param float $divisor The divisor of the result of the convolution, used for normalization. - * @param float $offset Color offset. - * @throws ImageException - * - */ -function imageconvolution($image, array $matrix, float $divisor, float $offset): void -{ - error_clear_last(); - $safeResult = \imageconvolution($image, $matrix, $divisor, $offset); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Copy a part of src_image onto - * dst_image starting at the x,y coordinates - * src_x, src_y with - * a width of src_width and a height of - * src_height. The portion defined will be copied - * onto the x,y coordinates, dst_x and - * dst_y. - * - * @param resource $dst_image Destination image resource. - * @param resource $src_image Source image resource. - * @param int $dst_x x-coordinate of destination point. - * @param int $dst_y y-coordinate of destination point. - * @param int $src_x x-coordinate of source point. - * @param int $src_y y-coordinate of source point. - * @param int $src_width Source width. - * @param int $src_height Source height. - * @throws ImageException - * - */ -function imagecopy($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height): void -{ - error_clear_last(); - $safeResult = \imagecopy($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Copy a part of src_image onto - * dst_image starting at the x,y coordinates - * src_x, src_y with - * a width of src_width and a height of - * src_height. The portion defined will be copied - * onto the x,y coordinates, dst_x and - * dst_y. - * - * @param resource $dst_image Destination image resource. - * @param resource $src_image Source image resource. - * @param int $dst_x x-coordinate of destination point. - * @param int $dst_y y-coordinate of destination point. - * @param int $src_x x-coordinate of source point. - * @param int $src_y y-coordinate of source point. - * @param int $src_width Source width. - * @param int $src_height Source height. - * @param int $pct The two images will be merged according to pct - * which can range from 0 to 100. When pct = 0, - * no action is taken, when 100 this function behaves identically - * to imagecopy for pallete images, except for - * ignoring alpha components, while it implements alpha transparency - * for true colour images. - * @throws ImageException - * - */ -function imagecopymerge($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): void -{ - error_clear_last(); - $safeResult = \imagecopymerge($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height, $pct); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagecopymergegray copy a part of src_image onto - * dst_image starting at the x,y coordinates - * src_x, src_y with - * a width of src_width and a height of - * src_height. The portion defined will be copied - * onto the x,y coordinates, dst_x and - * dst_y. - * - * This function is identical to imagecopymerge except - * that when merging it preserves the hue of the source by converting - * the destination pixels to gray scale before the copy operation. - * - * @param resource $dst_image Destination image resource. - * @param resource $src_image Source image resource. - * @param int $dst_x x-coordinate of destination point. - * @param int $dst_y y-coordinate of destination point. - * @param int $src_x x-coordinate of source point. - * @param int $src_y y-coordinate of source point. - * @param int $src_width Source width. - * @param int $src_height Source height. - * @param int $pct The src_image will be changed to grayscale according - * to pct where 0 is fully grayscale and 100 is - * unchanged. When pct = 100 this function behaves - * identically to imagecopy for pallete images, except for - * ignoring alpha components, while - * it implements alpha transparency for true colour images. - * @throws ImageException - * - */ -function imagecopymergegray($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_width, int $src_height, int $pct): void -{ - error_clear_last(); - $safeResult = \imagecopymergegray($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height, $pct); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagecopyresampled copies a rectangular - * portion of one image to another image, smoothly interpolating pixel - * values so that, in particular, reducing the size of an image still - * retains a great deal of clarity. - * - * In other words, imagecopyresampled will take a - * rectangular area from src_image of width - * src_width and height src_height at - * position (src_x,src_y) - * and place it in a rectangular area of dst_image - * of width dst_width and height dst_height - * at position (dst_x,dst_y). - * - * If the source and destination coordinates and width and heights - * differ, appropriate stretching or shrinking of the image fragment - * will be performed. The coordinates refer to the upper left - * corner. This function can be used to copy regions within the - * same image (if dst_image is the same as - * src_image) but if the regions overlap the - * results will be unpredictable. - * - * @param resource $dst_image Destination image resource. - * @param resource $src_image Source image resource. - * @param int $dst_x x-coordinate of destination point. - * @param int $dst_y y-coordinate of destination point. - * @param int $src_x x-coordinate of source point. - * @param int $src_y y-coordinate of source point. - * @param int $dst_width Destination width. - * @param int $dst_height Destination height. - * @param int $src_width Source width. - * @param int $src_height Source height. - * @throws ImageException - * - */ -function imagecopyresampled($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): void -{ - error_clear_last(); - $safeResult = \imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagecopyresized copies a rectangular - * portion of one image to another image. - * dst_image is the destination image, - * src_image is the source image identifier. - * - * In other words, imagecopyresized will take a - * rectangular area from src_image of width - * src_width and height src_height at - * position (src_x,src_y) - * and place it in a rectangular area of dst_image - * of width dst_width and height dst_height - * at position (dst_x,dst_y). - * - * If the source and destination coordinates and width and heights - * differ, appropriate stretching or shrinking of the image fragment - * will be performed. The coordinates refer to the upper left - * corner. This function can be used to copy regions within the - * same image (if dst_image is the same as - * src_image) but if the regions overlap the - * results will be unpredictable. - * - * @param resource $dst_image Destination image resource. - * @param resource $src_image Source image resource. - * @param int $dst_x x-coordinate of destination point. - * @param int $dst_y y-coordinate of destination point. - * @param int $src_x x-coordinate of source point. - * @param int $src_y y-coordinate of source point. - * @param int $dst_width Destination width. - * @param int $dst_height Destination height. - * @param int $src_width Source width. - * @param int $src_height Source height. - * @throws ImageException - * - */ -function imagecopyresized($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_width, int $dst_height, int $src_width, int $src_height): void -{ - error_clear_last(); - $safeResult = \imagecopyresized($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagecreate returns an image identifier - * representing a blank image of specified size. - * - * In general, we recommend the use of - * imagecreatetruecolor instead of - * imagecreate so that image processing occurs on the - * highest quality image possible. If you want to output a palette image, then - * imagetruecolortopalette should be called immediately - * before saving the image with imagepng or - * imagegif. - * - * @param int $width The image width. - * @param int $height The image height. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreate(int $width, int $height) -{ - error_clear_last(); - $safeResult = \imagecreate($width, $height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromavif returns an image object - * representing the image obtained from the given filename. - * - * @param string $filename Path to the AVIF raster image. - * @return Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromavif(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromavif($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefrombmp returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the BMP image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefrombmp(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefrombmp($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Create a new image from GD file or URL. - * - * @param string $filename Path to the GD file. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromgd(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromgd($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Create a new image from GD2 file or URL. - * - * @param string $filename Path to the GD2 image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromgd2(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromgd2($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Create a new image from a given part of GD2 file or URL. - * - * @param string $filename Path to the GD2 image. - * @param int $x x-coordinate of source point. - * @param int $y y-coordinate of source point. - * @param int $width Source width. - * @param int $height Source height. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromgd2part(string $filename, int $x, int $y, int $width, int $height) -{ - error_clear_last(); - $safeResult = \imagecreatefromgd2part($filename, $x, $y, $width, $height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromgif returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the GIF image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromgif(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromgif($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromjpeg returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the JPEG image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromjpeg(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromjpeg($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefrompng returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the PNG image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefrompng(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefrompng($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromstring returns an image identifier - * representing the image obtained from the given data. - * These types will be automatically detected if your build of PHP supports - * them: JPEG, PNG, GIF, BMP, WBMP, GD2, and WEBP. - * - * @param string $data A string containing the image data. - * @return resource An image object will be returned on success. FALSE is returned if - * the image type is unsupported, the data is not in a recognised format, - * or the image is corrupt and cannot be loaded. - * @throws ImageException - * - */ -function imagecreatefromstring(string $data) -{ - error_clear_last(); - $safeResult = \imagecreatefromstring($data); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromtga returns an image object - * representing the image obtained from the given filename. - * - * @param string $filename Path to the Truevision TGA image. - * @return Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromtga(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromtga($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromwbmp returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the WBMP image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromwbmp(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromwbmp($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromwebp returns an image identifier - * representing the image obtained from the given filename. - * Note that animated WebP files cannot be read. - * - * @param string $filename Path to the WebP image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromwebp(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromwebp($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromxbm returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the XBM image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromxbm(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromxbm($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatefromxpm returns an image identifier - * representing the image obtained from the given filename. - * - * @param string $filename Path to the XPM image. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatefromxpm(string $filename) -{ - error_clear_last(); - $safeResult = \imagecreatefromxpm($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagecreatetruecolor returns an image object - * representing a black image of the specified size. - * - * @param int $width Image width. - * @param int $height Image height. - * @return resource Returns an image object on success, FALSE on errors. - * @throws ImageException - * - */ -function imagecreatetruecolor(int $width, int $height) -{ - error_clear_last(); - $safeResult = \imagecreatetruecolor($width, $height); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Crops an image to the given rectangular area and returns the resulting image. - * The given image is not modified. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param array $rectangle The cropping rectangle as array with keys - * x, y, width and - * height. - * @return resource Return cropped image object on success. - * @throws ImageException - * - */ -function imagecrop($image, array $rectangle) -{ - error_clear_last(); - $safeResult = \imagecrop($image, $rectangle); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Automatically crops an image according to the given - * mode. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $mode One of the following constants: - * @param float $threshold - * @param int $color - * @return resource Returns a cropped image object on success. - * If the complete image was cropped, imagecrop returns FALSE. - * @throws ImageException - * - */ -function imagecropauto($image, int $mode = IMG_CROP_DEFAULT, float $threshold = 0.5, int $color = -1) -{ - error_clear_last(); - $safeResult = \imagecropauto($image, $mode, $threshold, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * This function is deprecated. Use combination of - * imagesetstyle and imageline - * instead. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x1 Upper left x coordinate. - * @param int $y1 Upper left y coordinate 0, 0 is the top left corner of the image. - * @param int $x2 Bottom right x coordinate. - * @param int $y2 Bottom right y coordinate. - * @param int $color The fill color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagedashedline($image, int $x1, int $y1, int $x2, int $y2, int $color): void -{ - error_clear_last(); - $safeResult = \imagedashedline($image, $x1, $y1, $x2, $y2, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Prior to PHP 8.0.0, imagedestroy freed any memory associated - * with image image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @throws ImageException - * - */ -function imagedestroy($image): void -{ - error_clear_last(); - $safeResult = \imagedestroy($image); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws an ellipse centered at the specified coordinates. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $center_x x-coordinate of the center. - * @param int $center_y y-coordinate of the center. - * @param int $width The ellipse width. - * @param int $height The ellipse height. - * @param int $color The color of the ellipse. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imageellipse($image, int $center_x, int $center_y, int $width, int $height, int $color): void -{ - error_clear_last(); - $safeResult = \imageellipse($image, $center_x, $center_y, $width, $height, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Performs a flood fill starting at the given coordinate (top left is 0, 0) - * with the given color in the - * image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x x-coordinate of start point. - * @param int $y y-coordinate of start point. - * @param int $color The fill color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagefill($image, int $x, int $y, int $color): void -{ - error_clear_last(); - $safeResult = \imagefill($image, $x, $y, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws a partial arc centered at the specified coordinate in the - * given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $center_x x-coordinate of the center. - * @param int $center_y y-coordinate of the center. - * @param int $width The arc width. - * @param int $height The arc height. - * @param int $start_angle The arc start angle, in degrees. - * @param int $end_angle The arc end angle, in degrees. - * 0° is located at the three-o'clock position, and the arc is drawn - * clockwise. - * @param int $color A color identifier created with imagecolorallocate. - * @param int $style A bitwise OR of the following possibilities: - * - * IMG_ARC_PIE - * IMG_ARC_CHORD - * IMG_ARC_NOFILL - * IMG_ARC_EDGED - * - * IMG_ARC_PIE and IMG_ARC_CHORD are - * mutually exclusive; IMG_ARC_CHORD just - * connects the starting and ending angles with a straight line, while - * IMG_ARC_PIE produces a rounded edge. - * IMG_ARC_NOFILL indicates that the arc - * or chord should be outlined, not filled. IMG_ARC_EDGED, - * used together with IMG_ARC_NOFILL, indicates that the - * beginning and ending angles should be connected to the center - this is a - * good way to outline (rather than fill) a 'pie slice'. - * @throws ImageException - * - */ -function imagefilledarc($image, int $center_x, int $center_y, int $width, int $height, int $start_angle, int $end_angle, int $color, int $style): void -{ - error_clear_last(); - $safeResult = \imagefilledarc($image, $center_x, $center_y, $width, $height, $start_angle, $end_angle, $color, $style); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws an ellipse centered at the specified coordinate on the given - * image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $center_x x-coordinate of the center. - * @param int $center_y y-coordinate of the center. - * @param int $width The ellipse width. - * @param int $height The ellipse height. - * @param int $color The fill color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagefilledellipse($image, int $center_x, int $center_y, int $width, int $height, int $color): void -{ - error_clear_last(); - $safeResult = \imagefilledellipse($image, $center_x, $center_y, $width, $height, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Creates a rectangle filled with color in the given - * image starting at point 1 and ending at point 2. - * 0, 0 is the top left corner of the image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x1 x-coordinate for point 1. - * @param int $y1 y-coordinate for point 1. - * @param int $x2 x-coordinate for point 2. - * @param int $y2 y-coordinate for point 2. - * @param int $color The fill color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagefilledrectangle($image, int $x1, int $y1, int $x2, int $y2, int $color): void -{ - error_clear_last(); - $safeResult = \imagefilledrectangle($image, $x1, $y1, $x2, $y2, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagefilltoborder performs a flood fill - * whose border color is defined by border_color. - * The starting point for the fill is x, - * y (top left is 0, 0) and the region is - * filled with color color. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x x-coordinate of start. - * @param int $y y-coordinate of start. - * @param int $border_color The border color. A color identifier created with imagecolorallocate. - * @param int $color The fill color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagefilltoborder($image, int $x, int $y, int $border_color, int $color): void -{ - error_clear_last(); - $safeResult = \imagefilltoborder($image, $x, $y, $border_color, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagefilter applies the given filter - * filter on the image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $filter filter can be one of the following: - * - * - * - * IMG_FILTER_NEGATE: Reverses all colors of - * the image. - * - * - * - * - * IMG_FILTER_GRAYSCALE: Converts the image into - * grayscale by changing the red, green and blue components to their - * weighted sum using the same coefficients as the REC.601 luma (Y') - * calculation. The alpha components are retained. For palette images the - * result may differ due to palette limitations. - * - * - * - * - * IMG_FILTER_BRIGHTNESS: Changes the brightness - * of the image. Use args to set the level of - * brightness. The range for the brightness is -255 to 255. - * - * - * - * - * IMG_FILTER_CONTRAST: Changes the contrast of - * the image. Use args to set the level of - * contrast. - * - * - * - * - * IMG_FILTER_COLORIZE: Like - * IMG_FILTER_GRAYSCALE, except you can specify the - * color. Use args, arg2 and - * arg3 in the form of - * red, green, - * blue and arg4 for the - * alpha channel. The range for each color is 0 to 255. - * - * - * - * - * IMG_FILTER_EDGEDETECT: Uses edge detection to - * highlight the edges in the image. - * - * - * - * - * IMG_FILTER_EMBOSS: Embosses the image. - * - * - * - * - * IMG_FILTER_GAUSSIAN_BLUR: Blurs the image using - * the Gaussian method. - * - * - * - * - * IMG_FILTER_SELECTIVE_BLUR: Blurs the image. - * - * - * - * - * IMG_FILTER_MEAN_REMOVAL: Uses mean removal to - * achieve a "sketchy" effect. - * - * - * - * - * IMG_FILTER_SMOOTH: Makes the image smoother. - * Use args to set the level of smoothness. - * - * - * - * - * IMG_FILTER_PIXELATE: Applies pixelation effect - * to the image, use args to set the block size - * and arg2 to set the pixelation effect mode. - * - * - * - * - * IMG_FILTER_SCATTER: Applies scatter effect - * to the image, use args and - * arg2 to define the effect strength and - * additionally arg3 to only apply the - * on select pixel colors. - * - * - * - * @param int $args - * - * - * IMG_FILTER_BRIGHTNESS: Brightness level. - * - * - * - * - * IMG_FILTER_CONTRAST: Contrast level. - * - * - * - * - * IMG_FILTER_COLORIZE: Value of red component. - * - * - * - * - * IMG_FILTER_SMOOTH: Smoothness level. - * - * - * - * - * IMG_FILTER_PIXELATE: Block size in pixels. - * - * - * - * - * IMG_FILTER_SCATTER: Effect substraction level. - * This must not be higher or equal to the addition level set with - * arg2. - * - * - * - * @throws ImageException - * - */ -function imagefilter($image, int $filter, int ...$args): void -{ - error_clear_last(); - if ($args !== []) { - $safeResult = \imagefilter($image, $filter, ...$args); - } else { - $safeResult = \imagefilter($image, $filter); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Flips the image image using the given - * mode. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $mode Flip mode, this can be one of the IMG_FLIP_* constants: - * - * - * - * - * - * Constant - * Meaning - * - * - * - * - * IMG_FLIP_HORIZONTAL - * - * Flips the image horizontally. - * - * - * - * IMG_FLIP_VERTICAL - * - * Flips the image vertically. - * - * - * - * IMG_FLIP_BOTH - * - * Flips the image both horizontally and vertically. - * - * - * - * - * - * @throws ImageException - * - */ -function imageflip($image, int $mode): void -{ - error_clear_last(); - $safeResult = \imageflip($image, $mode); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * This function calculates and returns the bounding box in pixels - * for a FreeType text. - * - * @param float $size The font size in points. - * @param float $angle Angle in degrees in which string will be - * measured. - * @param string $font_filename The name of the TrueType font file (can be a URL). Depending on - * which version of the GD library that PHP is using, it may attempt to - * search for files that do not begin with a leading '/' by appending - * '.ttf' to the filename and searching along a library-defined font path. - * @param string $string The string to be measured. - * @param array $options - * Possible array indexes for options - * - * - * - * Key - * Type - * Meaning - * - * - * - * - * linespacing - * float - * Defines drawing linespacing - * - * - * - * - * @return array imageftbbox returns an array with 8 - * elements representing four points making the bounding box of the - * text: - * - * - * - * - * 0 - * lower left corner, X position - * - * - * 1 - * lower left corner, Y position - * - * - * 2 - * lower right corner, X position - * - * - * 3 - * lower right corner, Y position - * - * - * 4 - * upper right corner, X position - * - * - * 5 - * upper right corner, Y position - * - * - * 6 - * upper left corner, X position - * - * - * 7 - * upper left corner, Y position - * - * - * - * - * - * The points are relative to the text regardless of the - * angle, so "upper left" means in the top left-hand - * corner seeing the text horizontally. - * - * On failure, FALSE is returned. - * @throws ImageException - * - */ -function imageftbbox(float $size, float $angle, string $font_filename, string $string, array $options = []): array -{ - error_clear_last(); - $safeResult = \imageftbbox($size, $angle, $font_filename, $string, $options); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param float $size The font size to use in points. - * @param float $angle The angle in degrees, with 0 degrees being left-to-right reading text. - * Higher values represent a counter-clockwise rotation. For example, a - * value of 90 would result in bottom-to-top reading text. - * @param int $x The coordinates given by x and - * y will define the basepoint of the first - * character (roughly the lower-left corner of the character). This - * is different from the imagestring, where - * x and y define the - * upper-left corner of the first character. For example, "top left" - * is 0, 0. - * @param int $y The y-ordinate. This sets the position of the fonts baseline, not the - * very bottom of the character. - * @param int $color The index of the desired color for the text, see - * imagecolorexact. - * @param string $font_filename The path to the TrueType font you wish to use. - * - * Depending on which version of the GD library PHP is using, when - * font_filename does not begin with a leading - * / then .ttf will be appended - * to the filename and the library will attempt to search for that - * filename along a library-defined font path. - * - * In many cases where a font resides in the same directory as the script using it - * the following trick will alleviate any include problems. - * - * - * ]]> - * - * @param string $text Text to be inserted into image. - * @param array $options - * Possible array indexes for options - * - * - * - * Key - * Type - * Meaning - * - * - * - * - * linespacing - * float - * Defines drawing linespacing - * - * - * - * - * @return array This function returns an array defining the four points of the box, starting in the lower left and moving counter-clockwise: - * - * - * - * - * 0 - * lower left x-coordinate - * - * - * 1 - * lower left y-coordinate - * - * - * 2 - * lower right x-coordinate - * - * - * 3 - * lower right y-coordinate - * - * - * 4 - * upper right x-coordinate - * - * - * 5 - * upper right y-coordinate - * - * - * 6 - * upper left x-coordinate - * - * - * 7 - * upper left y-coordinate - * - * - * - * - * - * On failure, FALSE is returned. - * @throws ImageException - * - */ -function imagefttext($image, float $size, float $angle, int $x, int $y, int $color, string $font_filename, string $text, array $options = []): array -{ - error_clear_last(); - $safeResult = \imagefttext($image, $size, $angle, $x, $y, $color, $font_filename, $text, $options); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Applies gamma correction to the given gd image - * given an input and an output gamma. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param float $input_gamma The input gamma. - * @param float $output_gamma The output gamma. - * @throws ImageException - * - */ -function imagegammacorrect($image, float $input_gamma, float $output_gamma): void -{ - error_clear_last(); - $safeResult = \imagegammacorrect($image, $input_gamma, $output_gamma); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs a GD image to the given file. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @throws ImageException - * - */ -function imagegd($image, $file = null): void -{ - error_clear_last(); - if ($file !== null) { - $safeResult = \imagegd($image, $file); - } else { - $safeResult = \imagegd($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs a GD2 image to the given file. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @param int $chunk_size Chunk size. - * @param int $mode Either IMG_GD2_RAW or - * IMG_GD2_COMPRESSED. Default is - * IMG_GD2_RAW. - * @throws ImageException - * - */ -function imagegd2($image, $file = null, int $chunk_size = 128, int $mode = IMG_GD2_RAW): void -{ - error_clear_last(); - if ($mode !== IMG_GD2_RAW) { - $safeResult = \imagegd2($image, $file, $chunk_size, $mode); - } elseif ($chunk_size !== 128) { - $safeResult = \imagegd2($image, $file, $chunk_size); - } elseif ($file !== null) { - $safeResult = \imagegd2($image, $file); - } else { - $safeResult = \imagegd2($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagegif creates the GIF - * file in file from the image image. The - * image argument is the return from the - * imagecreate or imagecreatefrom* - * function. - * - * The image format will be GIF87a unless the - * image has been made transparent with - * imagecolortransparent, in which case the - * image format will be GIF89a. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @throws ImageException - * - */ -function imagegif($image, $file = null): void -{ - error_clear_last(); - if ($file !== null) { - $safeResult = \imagegif($image, $file); - } else { - $safeResult = \imagegif($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Grabs a screenshot of the whole screen. - * - * @return resource Returns an image object on success, FALSE on failure. - * @throws ImageException - * - */ -function imagegrabscreen() -{ - error_clear_last(); - $safeResult = \imagegrabscreen(); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Grabs a window or its client area using a windows handle (HWND property in COM instance) - * - * @param int $handle The HWND window ID. - * @param bool $client_area Include the client area of the application window. - * @return \GdImage Returns an image object on success, FALSE on failure. - * @throws ImageException - * - */ -function imagegrabwindow(int $handle, bool $client_area = false): \GdImage -{ - error_clear_last(); - $safeResult = \imagegrabwindow($handle, $client_area); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagejpeg creates a JPEG file from - * the given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @param int $quality quality is optional, and ranges from 0 (worst - * quality, smaller file) to 100 (best quality, biggest file). The - * default (-1) uses the default IJG quality value (about 75). - * @throws ImageException - * - */ -function imagejpeg($image, $file = null, int $quality = -1): void -{ - error_clear_last(); - if ($quality !== -1) { - $safeResult = \imagejpeg($image, $file, $quality); - } elseif ($file !== null) { - $safeResult = \imagejpeg($image, $file); - } else { - $safeResult = \imagejpeg($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Set the alpha blending flag to use layering effects. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $effect One of the following constants: - * - * - * IMG_EFFECT_REPLACE - * - * - * Use pixel replacement (equivalent of passing TRUE to - * imagealphablending) - * - * - * - * - * IMG_EFFECT_ALPHABLEND - * - * - * Use normal pixel blending (equivalent of passing FALSE to - * imagealphablending) - * - * - * - * - * IMG_EFFECT_NORMAL - * - * - * Same as IMG_EFFECT_ALPHABLEND. - * - * - * - * - * IMG_EFFECT_OVERLAY - * - * - * Overlay has the effect that black background pixels will remain - * black, white background pixels will remain white, but grey - * background pixels will take the colour of the foreground pixel. - * - * - * - * - * IMG_EFFECT_MULTIPLY - * - * - * Overlays with a multiply effect. - * - * - * - * - * @throws ImageException - * - */ -function imagelayereffect($image, int $effect): void -{ - error_clear_last(); - $safeResult = \imagelayereffect($image, $effect); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws a line between the two given points. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x1 x-coordinate for first point. - * @param int $y1 y-coordinate for first point. - * @param int $x2 x-coordinate for second point. - * @param int $y2 y-coordinate for second point. - * @param int $color The line color. A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imageline($image, int $x1, int $y1, int $x2, int $y2, int $color): void -{ - error_clear_last(); - $safeResult = \imageline($image, $x1, $y1, $x2, $y2, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imageloadfont loads a user-defined bitmap and returns - * its identifier. - * - * @param string $filename The font file format is currently binary and architecture - * dependent. This means you should generate the font files on the - * same type of CPU as the machine you are running PHP on. - * - * - * Font file format - * - * - * - * byte position - * C data type - * description - * - * - * - * - * byte 0-3 - * int - * number of characters in the font - * - * - * byte 4-7 - * int - * - * value of first character in the font (often 32 for space) - * - * - * - * byte 8-11 - * int - * pixel width of each character - * - * - * byte 12-15 - * int - * pixel height of each character - * - * - * byte 16- - * char - * - * array with character data, one byte per pixel in each - * character, for a total of (nchars*width*height) bytes. - * - * - * - * - * - * @return int Returns an GdFont instance. - * @throws ImageException - * - */ -function imageloadfont(string $filename): int -{ - error_clear_last(); - $safeResult = \imageloadfont($filename); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Outputs or saves a PNG image from the given - * image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * - * NULL is invalid if the quality and - * filters arguments are not used. - * @param int $quality Compression level: from 0 (no compression) to 9. - * The default (-1) uses the zlib compression default. - * For more information see the zlib manual. - * @param int $filters Allows reducing the PNG file size. It is a bitmask field which may be - * set to any combination of the PNG_FILTER_XXX - * constants. PNG_NO_FILTER or - * PNG_ALL_FILTERS may also be used to respectively - * disable or activate all filters. - * The default value (-1) disables filtering. - * @throws ImageException - * - */ -function imagepng($image, $file = null, int $quality = -1, int $filters = -1): void -{ - error_clear_last(); - if ($filters !== -1) { - $safeResult = \imagepng($image, $file, $quality, $filters); - } elseif ($quality !== -1) { - $safeResult = \imagepng($image, $file, $quality); - } elseif ($file !== null) { - $safeResult = \imagepng($image, $file); - } else { - $safeResult = \imagepng($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagerectangle creates a rectangle starting at - * the specified coordinates. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x1 Upper left x coordinate. - * @param int $y1 Upper left y coordinate - * 0, 0 is the top left corner of the image. - * @param int $x2 Bottom right x coordinate. - * @param int $y2 Bottom right y coordinate. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagerectangle($image, int $x1, int $y1, int $x2, int $y2, int $color): void -{ - error_clear_last(); - $safeResult = \imagerectangle($image, $x1, $y1, $x2, $y2, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imageresolution allows to set and get the resolution of - * an image in DPI (dots per inch). If the optional parameters are NULL, - * the current resolution is returned as an indexed array. If only - * resolution_x is not NULL, the horizontal and vertical resolution - * are set to this value. If none of the optional parameters are NULL, the horizontal - * and vertical resolution are set to these values, respectively. - * - * The resolution is only used as meta information when images are read from and - * written to formats supporting this kind of information (curently PNG and - * JPEG). It does not affect any drawing operations. The default resolution - * for new images is 96 DPI. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $resolution_x The horizontal resolution in DPI. - * @param int $resolution_y The vertical resolution in DPI. - * @return mixed When used as getter, - * it returns an indexed array of the horizontal and vertical resolution on - * success. - * When used as setter, it returns - * TRUE on success. - * @throws ImageException - * - */ -function imageresolution($image, int $resolution_x = null, int $resolution_y = null) -{ - error_clear_last(); - if ($resolution_y !== null) { - $safeResult = \imageresolution($image, $resolution_x, $resolution_y); - } elseif ($resolution_x !== null) { - $safeResult = \imageresolution($image, $resolution_x); - } else { - $safeResult = \imageresolution($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Rotates the image image using the given - * angle in degrees. - * - * The center of rotation is the center of the image, and the rotated - * image may have different dimensions than the original image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param float $angle Rotation angle, in degrees. The rotation angle is interpreted as the - * number of degrees to rotate the image anticlockwise. - * @param int $background_color Specifies the color of the uncovered zone after the rotation - * @param bool $ignore_transparent This parameter is unused. - * @return resource Returns an image object for the rotated image. - * @throws ImageException - * - */ -function imagerotate($image, float $angle, int $background_color, bool $ignore_transparent = false) -{ - error_clear_last(); - $safeResult = \imagerotate($image, $angle, $background_color, $ignore_transparent); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagesavealpha sets the flag which determines whether to retain - * full alpha channel information (as opposed to single-color transparency) - * when saving PNG images. - * - * Alphablending has to be disabled (imagealphablending($im, false)) - * to retain the alpha-channel in the first place. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param bool $enable Whether to save the alpha channel or not. Defaults to FALSE. - * @throws ImageException - * - */ -function imagesavealpha($image, bool $enable): void -{ - error_clear_last(); - $safeResult = \imagesavealpha($image, $enable); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagescale scales an image using the given - * interpolation algorithm. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $width The width to scale the image to. - * @param int $height The height to scale the image to. If omitted or negative, the aspect - * ratio will be preserved. - * @param int $mode One of IMG_NEAREST_NEIGHBOUR, - * IMG_BILINEAR_FIXED, - * IMG_BICUBIC, - * IMG_BICUBIC_FIXED or anything else (will use two - * pass). - * - * - * IMG_WEIGHTED4 is not yet supported. - * - * - * @return resource Return the scaled image object on success. - * @throws ImageException - * - */ -function imagescale($image, int $width, int $height = -1, int $mode = IMG_BILINEAR_FIXED) -{ - error_clear_last(); - $safeResult = \imagescale($image, $width, $height, $mode); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagesetbrush sets the brush image to be - * used by all line drawing functions (such as imageline - * and imagepolygon) when drawing with the special - * colors IMG_COLOR_BRUSHED or - * IMG_COLOR_STYLEDBRUSHED. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param resource $brush An image object. - * @throws ImageException - * - */ -function imagesetbrush($image, $brush): void -{ - error_clear_last(); - $safeResult = \imagesetbrush($image, $brush); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagesetclip sets the current clipping rectangle, i.e. - * the area beyond which no pixels will be drawn. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x1 The x-coordinate of the upper left corner. - * @param int $y1 The y-coordinate of the upper left corner. - * @param int $x2 The x-coordinate of the lower right corner. - * @param int $y2 The y-coordinate of the lower right corner. - * @throws ImageException - * - */ -function imagesetclip($image, int $x1, int $y1, int $x2, int $y2): void -{ - error_clear_last(); - $safeResult = \imagesetclip($image, $x1, $y1, $x2, $y2); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Sets the interpolation method, setting an interpolation method affects the rendering - * of various functions in GD, such as the imagerotate function. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $method The interpolation method, which can be one of the following: - * - * - * - * IMG_BELL: Bell filter. - * - * - * - * - * IMG_BESSEL: Bessel filter. - * - * - * - * - * IMG_BICUBIC: Bicubic interpolation. - * - * - * - * - * IMG_BICUBIC_FIXED: Fixed point implementation of the bicubic interpolation. - * - * - * - * - * IMG_BILINEAR_FIXED: Fixed point implementation of the bilinear interpolation (default (also on image creation)). - * - * - * - * - * IMG_BLACKMAN: Blackman window function. - * - * - * - * - * IMG_BOX: Box blur filter. - * - * - * - * - * IMG_BSPLINE: Spline interpolation. - * - * - * - * - * IMG_CATMULLROM: Cubic Hermite spline interpolation. - * - * - * - * - * IMG_GAUSSIAN: Gaussian function. - * - * - * - * - * IMG_GENERALIZED_CUBIC: Generalized cubic spline fractal interpolation. - * - * - * - * - * IMG_HERMITE: Hermite interpolation. - * - * - * - * - * IMG_HAMMING: Hamming filter. - * - * - * - * - * IMG_HANNING: Hanning filter. - * - * - * - * - * IMG_MITCHELL: Mitchell filter. - * - * - * - * - * IMG_POWER: Power interpolation. - * - * - * - * - * IMG_QUADRATIC: Inverse quadratic interpolation. - * - * - * - * - * IMG_SINC: Sinc function. - * - * - * - * - * IMG_NEAREST_NEIGHBOUR: Nearest neighbour interpolation. - * - * - * - * - * IMG_WEIGHTED4: Weighting filter. - * - * - * - * - * IMG_TRIANGLE: Triangle interpolation. - * - * - * - * @throws ImageException - * - */ -function imagesetinterpolation($image, int $method = IMG_BILINEAR_FIXED): void -{ - error_clear_last(); - $safeResult = \imagesetinterpolation($image, $method); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagesetpixel draws a pixel at the specified - * coordinate. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $x x-coordinate. - * @param int $y y-coordinate. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagesetpixel($image, int $x, int $y, int $color): void -{ - error_clear_last(); - $safeResult = \imagesetpixel($image, $x, $y, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagesetstyle sets the style to be used by all - * line drawing functions (such as imageline - * and imagepolygon) when drawing with the special - * color IMG_COLOR_STYLED or lines of images with color - * IMG_COLOR_STYLEDBRUSHED. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param array $style An array of pixel colors. You can use the - * IMG_COLOR_TRANSPARENT constant to add a - * transparent pixel. - * Note that style must not be an empty array. - * @throws ImageException - * - */ -function imagesetstyle($image, array $style): void -{ - error_clear_last(); - $safeResult = \imagesetstyle($image, $style); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagesetthickness sets the thickness of the lines - * drawn when drawing rectangles, polygons, arcs etc. to - * thickness pixels. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $thickness Thickness, in pixels. - * @throws ImageException - * - */ -function imagesetthickness($image, int $thickness): void -{ - error_clear_last(); - $safeResult = \imagesetthickness($image, $thickness); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * imagesettile sets the tile image to be - * used by all region filling functions (such as imagefill - * and imagefilledpolygon) when filling with the special - * color IMG_COLOR_TILED. - * - * A tile is an image used to fill an area with a repeated pattern. Any - * GD image can be used as a tile, and by setting the transparent color index of the tile - * image with imagecolortransparent, a tile allows certain parts - * of the underlying area to shine through can be created. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param resource $tile The image object to be used as a tile. - * @throws ImageException - * - */ -function imagesettile($image, $tile): void -{ - error_clear_last(); - $safeResult = \imagesettile($image, $tile); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws a string at the given coordinates. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $font Can be 1, 2, 3, 4, 5 for built-in - * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or GdFont instance, - * returned by imageloadfont. - * @param int $x x-coordinate of the upper left corner. - * @param int $y y-coordinate of the upper left corner. - * @param string $string The string to be written. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagestring($image, int $font, int $x, int $y, string $string, int $color): void -{ - error_clear_last(); - $safeResult = \imagestring($image, $font, $x, $y, $string, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Draws a string vertically at the given - * coordinates. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param int $font Can be 1, 2, 3, 4, 5 for built-in - * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or GdFont instance, - * returned by imageloadfont. - * @param int $x x-coordinate of the bottom left corner. - * @param int $y y-coordinate of the bottom left corner. - * @param string $string The string to be written. - * @param int $color A color identifier created with imagecolorallocate. - * @throws ImageException - * - */ -function imagestringup($image, int $font, int $x, int $y, string $string, int $color): void -{ - error_clear_last(); - $safeResult = \imagestringup($image, $font, $x, $y, $string, $color); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Returns the width of the given image object. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @return int Return the width of the images. - * @throws ImageException - * - */ -function imagesx($image): int -{ - error_clear_last(); - $safeResult = \imagesx($image); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Returns the height of the given image object. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @return int Return the height of the images. - * @throws ImageException - * - */ -function imagesy($image): int -{ - error_clear_last(); - $safeResult = \imagesy($image); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagetruecolortopalette converts a truecolor image - * to a palette image. The code for this function was originally drawn from - * the Independent JPEG Group library code, which is excellent. The code - * has been modified to preserve as much alpha channel information as - * possible in the resulting palette, in addition to preserving colors as - * well as possible. This does not work as well as might be hoped. It is - * usually best to simply produce a truecolor output image instead, which - * guarantees the highest output quality. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param bool $dither Indicates if the image should be dithered - if it is TRUE then - * dithering will be used which will result in a more speckled image but - * with better color approximation. - * @param int $num_colors Sets the maximum number of colors that should be retained in the palette. - * @throws ImageException - * - */ -function imagetruecolortopalette($image, bool $dither, int $num_colors): void -{ - error_clear_last(); - $safeResult = \imagetruecolortopalette($image, $dither, $num_colors); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * This function calculates and returns the bounding box in pixels - * for a TrueType text. - * - * @param float $size The font size in points. - * @param float $angle Angle in degrees in which string will be measured. - * @param string $font_filename The path to the TrueType font you wish to use. - * - * Depending on which version of the GD library PHP is using, when - * fontfile does not begin with a leading - * / then .ttf will be appended - * to the filename and the library will attempt to search for that - * filename along a library-defined font path. - * - * When using versions of the GD library lower than 2.0.18, a space character, - * rather than a semicolon, was used as the 'path separator' for different font files. - * Unintentional use of this feature will result in the warning message: - * Warning: Could not find/open font. For these affected versions, the - * only solution is moving the font to a path which does not contain spaces. - * - * In many cases where a font resides in the same directory as the script using it - * the following trick will alleviate any include problems. - * - * - * ]]> - * - * - * Note that open_basedir does - * not apply to fontfile. - * @param string $string The string to be measured. - * @param array $options - * @return array imagettfbbox returns an array with 8 - * elements representing four points making the bounding box of the - * text on success and FALSE on error. - * - * - * - * - * key - * contents - * - * - * - * - * 0 - * lower left corner, X position - * - * - * 1 - * lower left corner, Y position - * - * - * 2 - * lower right corner, X position - * - * - * 3 - * lower right corner, Y position - * - * - * 4 - * upper right corner, X position - * - * - * 5 - * upper right corner, Y position - * - * - * 6 - * upper left corner, X position - * - * - * 7 - * upper left corner, Y position - * - * - * - * - * - * The points are relative to the text regardless of the - * angle, so "upper left" means in the top left-hand - * corner seeing the text horizontally. - * @throws ImageException - * - */ -function imagettfbbox(float $size, float $angle, string $font_filename, string $string, array $options = []): array -{ - error_clear_last(); - $safeResult = \imagettfbbox($size, $angle, $font_filename, $string, $options); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Writes the given text into the image using TrueType - * fonts. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param float $size The font size in points. - * @param float $angle The angle in degrees, with 0 degrees being left-to-right reading text. - * Higher values represent a counter-clockwise rotation. For example, a - * value of 90 would result in bottom-to-top reading text. - * @param int $x The coordinates given by x and - * y will define the basepoint of the first - * character (roughly the lower-left corner of the character). This - * is different from the imagestring, where - * x and y define the - * upper-left corner of the first character. For example, "top left" - * is 0, 0. - * @param int $y The y-ordinate. This sets the position of the fonts baseline, not the - * very bottom of the character. - * @param int $color The color index. Using the negative of a color index has the effect of - * turning off antialiasing. See imagecolorallocate. - * @param string $font_filename The path to the TrueType font you wish to use. - * - * Depending on which version of the GD library PHP is using, when - * fontfile does not begin with a leading - * / then .ttf will be appended - * to the filename and the library will attempt to search for that - * filename along a library-defined font path. - * - * When using versions of the GD library lower than 2.0.18, a space character, - * rather than a semicolon, was used as the 'path separator' for different font files. - * Unintentional use of this feature will result in the warning message: - * Warning: Could not find/open font. For these affected versions, the - * only solution is moving the font to a path which does not contain spaces. - * - * In many cases where a font resides in the same directory as the script using it - * the following trick will alleviate any include problems. - * - * - * ]]> - * - * - * Note that open_basedir does - * not apply to fontfile. - * @param string $text The text string in UTF-8 encoding. - * - * May include decimal numeric character references (of the form: - * &#8364;) to access characters in a font beyond position 127. - * The hexadecimal format (like &#xA9;) is supported. - * Strings in UTF-8 encoding can be passed directly. - * - * Named entities, such as &copy;, are not supported. Consider using - * html_entity_decode - * to decode these named entities into UTF-8 strings. - * - * If a character is used in the string which is not supported by the - * font, a hollow rectangle will replace the character. - * @param array $options - * @return array Returns an array with 8 elements representing four points making the - * bounding box of the text. The order of the points is lower left, lower - * right, upper right, upper left. The points are relative to the text - * regardless of the angle, so "upper left" means in the top left-hand - * corner when you see the text horizontally. - * @throws ImageException - * - */ -function imagettftext($image, float $size, float $angle, int $x, int $y, int $color, string $font_filename, string $text, array $options = []): array -{ - error_clear_last(); - $safeResult = \imagettftext($image, $size, $angle, $x, $y, $color, $font_filename, $text, $options); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * imagewbmp outputs or save a WBMP - * version of the given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @param int $foreground_color You can set the foreground color with this parameter by setting an - * identifier obtained from imagecolorallocate. - * The default foreground color is black. - * @throws ImageException - * - */ -function imagewbmp($image, $file = null, int $foreground_color = null): void -{ - error_clear_last(); - if ($foreground_color !== null) { - $safeResult = \imagewbmp($image, $file, $foreground_color); - } elseif ($file !== null) { - $safeResult = \imagewbmp($image, $file); - } else { - $safeResult = \imagewbmp($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs or saves a WebP version of the given image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $file The path or an open stream resource (which is automatically closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be output directly. - * @param int $quality quality ranges from 0 (worst - * quality, smaller file) to 100 (best quality, biggest file). - * @throws ImageException - * - */ -function imagewebp($image, $file = null, int $quality = -1): void -{ - error_clear_last(); - if ($quality !== -1) { - $safeResult = \imagewebp($image, $file, $quality); - } elseif ($file !== null) { - $safeResult = \imagewebp($image, $file); - } else { - $safeResult = \imagewebp($image); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Outputs or save an XBM version of the given - * image. - * - * @param resource $image A GdImage object, returned by one of the image creation functions, - * such as imagecreatetruecolor. - * @param string|resource|null $filename The path to save the file to, given as string. If NULL, the raw image stream will be output directly. - * - * The filename (without the .xbm extension) is also - * used for the C identifiers of the XBM, whereby non - * alphanumeric characters of the current locale are substituted by - * underscores. If filename is set to NULL, - * image is used to build the C identifiers. - * @param int $foreground_color You can set the foreground color with this parameter by setting an - * identifier obtained from imagecolorallocate. - * The default foreground color is black. All other colors are treated as - * background. - * @throws ImageException - * - */ -function imagexbm($image, $filename, int $foreground_color = null): void -{ - error_clear_last(); - if ($foreground_color !== null) { - $safeResult = \imagexbm($image, $filename, $foreground_color); - } else { - $safeResult = \imagexbm($image, $filename); - } - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Embeds binary IPTC data into a JPEG image. - * - * @param string $iptc_data The data to be written. - * @param string $filename Path to the JPEG image. - * @param int $spool Spool flag. If the spool flag is less than 2 then the JPEG will be - * returned as a string. Otherwise the JPEG will be printed to STDOUT. - * @return string|bool If spool is less than 2, the JPEG will be returned. Otherwise returns TRUE on success. - * @throws ImageException - * - */ -function iptcembed(string $iptc_data, string $filename, int $spool = 0) -{ - error_clear_last(); - $safeResult = \iptcembed($iptc_data, $filename, $spool); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Parses an IPTC block into its single tags. - * - * @param string $iptc_block A binary IPTC block. - * @return array Returns an array using the tagmarker as an index and the value as the - * value. It returns FALSE on error or if no IPTC data was found. - * @throws ImageException - * - */ -function iptcparse(string $iptc_block): array -{ - error_clear_last(); - $safeResult = \iptcparse($iptc_block); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Converts a JPEG file into a WBMP file. - * - * @param string $jpegname Path to JPEG file. - * @param string $wbmpname Path to destination WBMP file. - * @param int $dest_height Destination image height. - * @param int $dest_width Destination image width. - * @param int $threshold Threshold value, between 0 and 8 (inclusive). - * @throws ImageException - * - */ -function jpeg2wbmp(string $jpegname, string $wbmpname, int $dest_height, int $dest_width, int $threshold): void -{ - error_clear_last(); - $safeResult = \jpeg2wbmp($jpegname, $wbmpname, $dest_height, $dest_width, $threshold); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} - - -/** - * Converts a PNG file into a WBMP file. - * - * @param string $pngname Path to PNG file. - * @param string $wbmpname Path to destination WBMP file. - * @param int $dest_height Destination image height. - * @param int $dest_width Destination image width. - * @param int $threshold Threshold value, between 0 and 8 (inclusive). - * @throws ImageException - * - */ -function png2wbmp(string $pngname, string $wbmpname, int $dest_height, int $dest_width, int $threshold): void -{ - error_clear_last(); - $safeResult = \png2wbmp($pngname, $wbmpname, $dest_height, $dest_width, $threshold); - if ($safeResult === false) { - throw ImageException::createFromPhpError(); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/imap.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/imap.php deleted file mode 100644 index a654470d9..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/imap.php +++ /dev/null @@ -1,2289 +0,0 @@ - - * - * - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_add($ldap, string $dn, array $entry, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_add($ldap, $dn, $entry, $controls); - } else { - $safeResult = \ldap_add($ldap, $dn, $entry); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Binds to the LDAP directory with specified RDN and password. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string|null $dn - * @param string|null $password - * @throws LdapException - * - */ -function ldap_bind($ldap, ?string $dn = null, ?string $password = null): void -{ - error_clear_last(); - if ($password !== null) { - $safeResult = \ldap_bind($ldap, $dn, $password); - } elseif ($dn !== null) { - $safeResult = \ldap_bind($ldap, $dn); - } else { - $safeResult = \ldap_bind($ldap); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Retrieve the pagination information send by the server. - * - * @param resource $link An LDAP resource, returned by ldap_connect. - * @param resource $result - * @param string|null $cookie An opaque structure sent by the server. - * @param int|null $estimated The estimated number of entries to retrieve. - * @throws LdapException - * - */ -function ldap_control_paged_result_response($link, $result, ?string &$cookie = null, ?int &$estimated = null): void -{ - error_clear_last(); - $safeResult = \ldap_control_paged_result_response($link, $result, $cookie, $estimated); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Enable LDAP pagination by sending the pagination control (page size, cookie...). - * - * @param resource $link An LDAP resource, returned by ldap_connect. - * @param int $pagesize The number of entries by page. - * @param bool $iscritical Indicates whether the pagination is critical or not. - * If true and if the server doesn't support pagination, the search - * will return no result. - * @param string $cookie An opaque structure sent by the server - * (ldap_control_paged_result_response). - * @throws LdapException - * - */ -function ldap_control_paged_result($link, int $pagesize, bool $iscritical = false, string $cookie = ""): void -{ - error_clear_last(); - $safeResult = \ldap_control_paged_result($link, $pagesize, $iscritical, $cookie); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Returns the number of entries stored in the result of previous search - * operations. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @return int Returns number of entries in the result. - * @throws LdapException - * - */ -function ldap_count_entries($ldap, $result): int -{ - error_clear_last(); - $safeResult = \ldap_count_entries($ldap, $result); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Deletes a particular entry in LDAP directory. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_delete($ldap, string $dn, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_delete($ldap, $dn, $controls); - } else { - $safeResult = \ldap_delete($ldap, $dn); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Turns the specified dn, into a more user-friendly - * form, stripping off type names. - * - * @param string $dn The distinguished name of an LDAP entity. - * @return string Returns the user friendly name. - * @throws LdapException - * - */ -function ldap_dn2ufn(string $dn): string -{ - error_clear_last(); - $safeResult = \ldap_dn2ufn($dn); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Performs a PASSWD extended operation. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $user dn of the user to change the password of. - * @param string $old_password The old password of this user. May be ommited depending of server configuration. - * @param string $new_password The new password for this user. May be omitted or empty to have a generated password. - * @param array $controls If provided, a password policy request control is send with the request and this is - * filled with an array of LDAP Controls - * returned with the request. - * @return string|bool Returns the generated password if new_password is empty or omitted. - * Otherwise returns TRUE on success. - * @throws LdapException - * - */ -function ldap_exop_passwd($ldap, string $user = "", string $old_password = "", string $new_password = "", array &$controls = null) -{ - error_clear_last(); - $safeResult = \ldap_exop_passwd($ldap, $user, $old_password, $new_password, $controls); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Performs a WHOAMI extended operation and returns the data. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @return string|bool The data returned by the server. - * @throws LdapException - * - */ -function ldap_exop_whoami($ldap) -{ - error_clear_last(); - $safeResult = \ldap_exop_whoami($ldap); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Performs an extended operation on the specified ldap with - * request_oid the OID of the operation and - * request_data the data. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $request_oid The extended operation request OID. You may use one of LDAP_EXOP_START_TLS, LDAP_EXOP_MODIFY_PASSWD, LDAP_EXOP_REFRESH, LDAP_EXOP_WHO_AM_I, LDAP_EXOP_TURN, or a string with the OID of the operation you want to send. - * @param string $request_data The extended operation request data. May be NULL for some operations like LDAP_EXOP_WHO_AM_I, may also need to be BER encoded. - * @param array|null $controls Array of LDAP Controls to send with the request. - * @param string|null $response_data Will be filled with the extended operation response data if provided. - * If not provided you may use ldap_parse_exop on the result object - * later to get this data. - * @param string|null $response_oid Will be filled with the response OID if provided, usually equal to the request OID. - * @return resource|bool When used with response_data, returns TRUE on success. - * When used without response_data, returns a result identifier. - * @throws LdapException - * - */ -function ldap_exop($ldap, string $request_oid, string $request_data = null, ?array $controls = null, ?string &$response_data = null, ?string &$response_oid = null) -{ - error_clear_last(); - if ($response_oid !== null) { - $safeResult = \ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); - } elseif ($response_data !== null) { - $safeResult = \ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data); - } elseif ($controls !== null) { - $safeResult = \ldap_exop($ldap, $request_oid, $request_data, $controls); - } elseif ($request_data !== null) { - $safeResult = \ldap_exop($ldap, $request_oid, $request_data); - } else { - $safeResult = \ldap_exop($ldap, $request_oid); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Splits the DN returned by ldap_get_dn and breaks it - * up into its component parts. Each part is known as Relative Distinguished - * Name, or RDN. - * - * @param string $dn The distinguished name of an LDAP entity. - * @param int $with_attrib Used to request if the RDNs are returned with only values or their - * attributes as well. To get RDNs with the attributes (i.e. in - * attribute=value format) set with_attrib to 0 - * and to get only values set it to 1. - * @return array Returns an array of all DN components. - * The first element in the array has count key and - * represents the number of returned values, next elements are numerically - * indexed DN components. - * @throws LdapException - * - */ -function ldap_explode_dn(string $dn, int $with_attrib): array -{ - error_clear_last(); - $safeResult = \ldap_explode_dn($dn, $with_attrib); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Gets the first attribute in the given entry. Remaining attributes are - * retrieved by calling ldap_next_attribute successively. - * - * Similar to reading entries, attributes are also read one by one from a - * particular entry. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @return string Returns the first attribute in the entry on success and FALSE on - * error. - * @throws LdapException - * - */ -function ldap_first_attribute($ldap, $entry): string -{ - error_clear_last(); - $safeResult = \ldap_first_attribute($ldap, $entry); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Returns the entry identifier for first entry in the result. This entry - * identifier is then supplied to ldap_next_entry - * routine to get successive entries from the result. - * - * Entries in the LDAP result are read sequentially using the - * ldap_first_entry and - * ldap_next_entry functions. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @return resource Returns an LDAP\ResultEntry instance. - * @throws LdapException - * - */ -function ldap_first_entry($ldap, $result) -{ - error_clear_last(); - $safeResult = \ldap_first_entry($ldap, $result); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Frees up the memory allocated internally to store the result. All result - * memory will be automatically freed when the script terminates. - * - * Typically all the memory allocated for the LDAP result gets freed at the - * end of the script. In case the script is making successive searches which - * return large result sets, ldap_free_result could be - * called to keep the runtime memory usage by the script low. - * - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @throws LdapException - * - */ -function ldap_free_result($result): void -{ - error_clear_last(); - $safeResult = \ldap_free_result($result); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Reads attributes and values from an entry in the search result. - * - * Having located a specific entry in the directory, you can find out what - * information is held for that entry by using this call. You would use this - * call for an application which "browses" directory entries and/or where you - * do not know the structure of the directory entries. In many applications - * you will be searching for a specific attribute such as an email address or - * a surname, and won't care what other data is held. - * - * - * - * - * - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @return array Returns a complete entry information in a multi-dimensional array - * on success and FALSE on error. - * @throws LdapException - * - */ -function ldap_get_attributes($ldap, $entry): array -{ - error_clear_last(); - $safeResult = \ldap_get_attributes($ldap, $entry); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Finds out the DN of an entry in the result. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @return string Returns the DN of the result entry and FALSE on error. - * @throws LdapException - * - */ -function ldap_get_dn($ldap, $entry): string -{ - error_clear_last(); - $safeResult = \ldap_get_dn($ldap, $entry); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Reads multiple entries from the given result, and then reading the - * attributes and multiple values. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @return array Returns a complete result information in a multi-dimensional array on - * success. - * - * The structure of the array is as follows. - * The attribute index is converted to lowercase. (Attributes are - * case-insensitive for directory servers, but not when used as - * array indices.) - * - * - * - * - * - * @throws LdapException - * - */ -function ldap_get_entries($ldap, $result): array -{ - error_clear_last(); - $safeResult = \ldap_get_entries($ldap, $result); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Sets value to the value of the specified option. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param int $option The parameter option can be one of: - * - * - * - * - * Option - * Type - * since - * - * - * - * - * LDAP_OPT_DEREF - * int - * - * - * - * LDAP_OPT_SIZELIMIT - * int - * - * - * - * LDAP_OPT_TIMELIMIT - * int - * - * - * - * LDAP_OPT_NETWORK_TIMEOUT - * int - * - * - * - * LDAP_OPT_PROTOCOL_VERSION - * int - * - * - * - * LDAP_OPT_ERROR_NUMBER - * int - * - * - * - * LDAP_OPT_DIAGNOSTIC_MESSAGE - * string - * - * - * - * LDAP_OPT_REFERRALS - * int - * - * - * - * LDAP_OPT_RESTART - * int - * - * - * - * LDAP_OPT_HOST_NAME - * string - * - * - * - * LDAP_OPT_ERROR_STRING - * string - * - * - * - * LDAP_OPT_MATCHED_DN - * string - * - * - * - * LDAP_OPT_SERVER_CONTROLS - * array - * - * - * - * LDAP_OPT_CLIENT_CONTROLS - * array - * - * - * - * LDAP_OPT_X_KEEPALIVE_IDLE - * int - * 7.1 - * - * - * LDAP_OPT_X_KEEPALIVE_PROBES - * int - * 7.1 - * - * - * LDAP_OPT_X_KEEPALIVE_INTERVAL - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_CACERTDIR - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_CACERTFILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_CERTFILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_CIPHER_SUITE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_CRLCHECK - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_CRL_NONE - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_CRL_PEER - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_CRL_ALL - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_CRLFILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_DHFILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_KEYFILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_PACKAGE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_PROTOCOL_MIN - * int - * 7.1 - * - * - * LDAP_OPT_X_TLS_RANDOM_FILE - * string - * 7.1 - * - * - * LDAP_OPT_X_TLS_REQUIRE_CERT - * int - * - * - * - * - * - * @param mixed $value This will be set to the option value. - * @throws LdapException - * - */ -function ldap_get_option($ldap, int $option, &$value = null): void -{ - error_clear_last(); - $safeResult = \ldap_get_option($ldap, $option, $value); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Reads all the values of the attribute in the entry in the result. - * - * This function is used exactly like ldap_get_values - * except that it handles binary data and not string data. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @param string $attribute - * @return array Returns an array of values for the attribute on success and FALSE on - * error. Individual values are accessed by integer index in the array. The - * first index is 0. The number of values can be found by indexing "count" - * in the resultant array. - * @throws LdapException - * - */ -function ldap_get_values_len($ldap, $entry, string $attribute): array -{ - error_clear_last(); - $safeResult = \ldap_get_values_len($ldap, $entry, $attribute); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Reads all the values of the attribute in the entry in the result. - * - * This call needs a entry, - * so needs to be preceded by one of the ldap search calls and one - * of the calls to get an individual entry. - * - * You application will either be hard coded to look for certain - * attributes (such as "surname" or "mail") or you will have to use - * the ldap_get_attributes call to work out - * what attributes exist for a given entry. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @param string $attribute - * @return array Returns an array of values for the attribute on success and FALSE on - * error. The number of values can be found by indexing "count" in the - * resultant array. Individual values are accessed by integer index in the - * array. The first index is 0. - * - * LDAP allows more than one entry for an attribute, so it can, for example, - * store a number of email addresses for one person's directory entry all - * labeled with the attribute "mail" - * - * - * return_value["count"] = number of values for attribute - * return_value[0] = first value of attribute - * return_value[i] = ith value of attribute - * - * - * @throws LdapException - * - */ -function ldap_get_values($ldap, $entry, string $attribute): array -{ - error_clear_last(); - $safeResult = \ldap_get_values($ldap, $entry, $attribute); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Adds one or more attribute values to the specified dn. - * To add a whole new object see ldap_add function. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param array $entry An associative array listing the attirbute values to add. If an attribute was not existing yet it will be added. If an attribute is existing you can only add values to it if it supports multiple values. - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_mod_add($ldap, string $dn, array $entry, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_mod_add($ldap, $dn, $entry, $controls); - } else { - $safeResult = \ldap_mod_add($ldap, $dn, $entry); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Removes one or more attribute values from the specified dn. - * Object deletions are done by the - * ldap_delete function. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param array $entry - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_mod_del($ldap, string $dn, array $entry, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_mod_del($ldap, $dn, $entry, $controls); - } else { - $safeResult = \ldap_mod_del($ldap, $dn, $entry); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Replaces one or more attributes from the specified dn. - * It may also add or remove attributes. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param array $entry An associative array listing the attributes to replace. Sending an empty array as value will remove the attribute, while sending an attribute not existing yet on this entry will add it. - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_mod_replace($ldap, string $dn, array $entry, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_mod_replace($ldap, $dn, $entry, $controls); - } else { - $safeResult = \ldap_mod_replace($ldap, $dn, $entry); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Modifies an existing entry in the LDAP directory. Allows detailed - * specification of the modifications to perform. - * - * @param resource $ldap An LDAP resource, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param array $modifications_info An array that specifies the modifications to make. Each entry in this - * array is an associative array with two or three keys: - * attrib maps to the name of the attribute to modify, - * modtype maps to the type of modification to perform, - * and (depending on the type of modification) values - * maps to an array of attribute values relevant to the modification. - * - * Possible values for modtype include: - * - * - * LDAP_MODIFY_BATCH_ADD - * - * - * Each value specified through values is added (as - * an additional value) to the attribute named by - * attrib. - * - * - * - * - * LDAP_MODIFY_BATCH_REMOVE - * - * - * Each value specified through values is removed - * from the attribute named by attrib. Any value of - * the attribute not contained in the values array - * will remain untouched. - * - * - * - * - * LDAP_MODIFY_BATCH_REMOVE_ALL - * - * - * All values are removed from the attribute named by - * attrib. A values entry must - * not be provided. - * - * - * - * - * LDAP_MODIFY_BATCH_REPLACE - * - * - * All current values of the attribute named by - * attrib are replaced with the values specified - * through values. - * - * - * - * - * - * Each value specified through values is added (as - * an additional value) to the attribute named by - * attrib. - * - * Each value specified through values is removed - * from the attribute named by attrib. Any value of - * the attribute not contained in the values array - * will remain untouched. - * - * All values are removed from the attribute named by - * attrib. A values entry must - * not be provided. - * - * All current values of the attribute named by - * attrib are replaced with the values specified - * through values. - * - * Note that any value for attrib must be a string, any - * value for values must be an array of strings, and - * any value for modtype must be one of the - * LDAP_MODIFY_BATCH_* constants listed above. - * @param array $controls Each value specified through values is added (as - * an additional value) to the attribute named by - * attrib. - * @throws LdapException - * - */ -function ldap_modify_batch($ldap, string $dn, array $modifications_info, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_modify_batch($ldap, $dn, $modifications_info, $controls); - } else { - $safeResult = \ldap_modify_batch($ldap, $dn, $modifications_info); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Retrieves the attributes in an entry. The first call to - * ldap_next_attribute is made with the - * entry returned from - * ldap_first_attribute. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $entry An LDAP\ResultEntry instance. - * @return string Returns the next attribute in an entry on success and FALSE on - * error. - * @throws LdapException - * - */ -function ldap_next_attribute($ldap, $entry): string -{ - error_clear_last(); - $safeResult = \ldap_next_attribute($ldap, $entry); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Parse LDAP extended operation data from result object result - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @param string|null $response_data Will be filled by the response data. - * @param string|null $response_oid Will be filled by the response OID. - * @throws LdapException - * - */ -function ldap_parse_exop($ldap, $result, ?string &$response_data = null, ?string &$response_oid = null): void -{ - error_clear_last(); - $safeResult = \ldap_parse_exop($ldap, $result, $response_data, $response_oid); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Parses an LDAP search result. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param resource $result An LDAP\Result instance, returned by ldap_list or ldap_search. - * @param int|null $error_code A reference to a variable that will be set to the LDAP error code in - * the result, or 0 if no error occurred. - * @param string|null $matched_dn A reference to a variable that will be set to a matched DN if one was - * recognised within the request, otherwise it will be set to NULL. - * @param string|null $error_message A reference to a variable that will be set to the LDAP error message in - * the result, or an empty string if no error occurred. - * @param array|null $referrals A reference to a variable that will be set to an array set - * to all of the referral strings in the result, or an empty array if no - * referrals were returned. - * @param array|null $controls An array of LDAP Controls which have been sent with the response. - * @throws LdapException - * - */ -function ldap_parse_result($ldap, $result, ?int &$error_code, ?string &$matched_dn = null, ?string &$error_message = null, ?array &$referrals = null, ?array &$controls = null): void -{ - error_clear_last(); - $safeResult = \ldap_parse_result($ldap, $result, $error_code, $matched_dn, $error_message, $referrals, $controls); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * The entry specified by dn is renamed/moved. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @param string $dn The distinguished name of an LDAP entity. - * @param string $new_rdn The new RDN. - * @param string $new_parent The new parent/superior entry. - * @param bool $delete_old_rdn If TRUE the old RDN value(s) is removed, else the old RDN value(s) - * is retained as non-distinguished values of the entry. - * @param array $controls Array of LDAP Controls to send with the request. - * @throws LdapException - * - */ -function ldap_rename($ldap, string $dn, string $new_rdn, string $new_parent, bool $delete_old_rdn, array $controls = null): void -{ - error_clear_last(); - if ($controls !== null) { - $safeResult = \ldap_rename($ldap, $dn, $new_rdn, $new_parent, $delete_old_rdn, $controls); - } else { - $safeResult = \ldap_rename($ldap, $dn, $new_rdn, $new_parent, $delete_old_rdn); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * - * - * @param resource $ldap - * @param string $dn - * @param string $password - * @param string $mech - * @param string $realm - * @param string $authc_id - * @param string $authz_id - * @param string $props - * @throws LdapException - * - */ -function ldap_sasl_bind($ldap, string $dn = null, string $password = null, string $mech = null, string $realm = null, string $authc_id = null, string $authz_id = null, string $props = null): void -{ - error_clear_last(); - if ($props !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password, $mech, $realm, $authc_id, $authz_id, $props); - } elseif ($authz_id !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password, $mech, $realm, $authc_id, $authz_id); - } elseif ($authc_id !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password, $mech, $realm, $authc_id); - } elseif ($realm !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password, $mech, $realm); - } elseif ($mech !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password, $mech); - } elseif ($password !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn, $password); - } elseif ($dn !== null) { - $safeResult = \ldap_sasl_bind($ldap, $dn); - } else { - $safeResult = \ldap_sasl_bind($ldap); - } - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Sets the value of the specified option to be value. - * - * @param resource|null $ldap Either an LDAP\Connection instance, returned by - * ldap_connect, to set the option for that connection, - * or NULL to set the option globally. - * @param int $option The parameter option can be one of: - * - * - * - * - * Option - * Type - * Available since - * - * - * - * - * LDAP_OPT_DEREF - * int - * - * - * - * LDAP_OPT_SIZELIMIT - * int - * - * - * - * LDAP_OPT_TIMELIMIT - * int - * - * - * - * LDAP_OPT_NETWORK_TIMEOUT - * int - * - * - * - * LDAP_OPT_PROTOCOL_VERSION - * int - * - * - * - * LDAP_OPT_ERROR_NUMBER - * int - * - * - * - * LDAP_OPT_REFERRALS - * bool - * - * - * - * LDAP_OPT_RESTART - * bool - * - * - * - * LDAP_OPT_HOST_NAME - * string - * - * - * - * LDAP_OPT_ERROR_STRING - * string - * - * - * - * LDAP_OPT_DIAGNOSTIC_MESSAGE - * string - * - * - * - * LDAP_OPT_MATCHED_DN - * string - * - * - * - * LDAP_OPT_SERVER_CONTROLS - * array - * - * - * - * LDAP_OPT_CLIENT_CONTROLS - * array - * - * - * - * LDAP_OPT_X_KEEPALIVE_IDLE - * int - * PHP 7.1.0 - * - * - * LDAP_OPT_X_KEEPALIVE_PROBES - * int - * PHP 7.1.0 - * - * - * LDAP_OPT_X_KEEPALIVE_INTERVAL - * int - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CACERTDIR - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CACERTFILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CERTFILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CIPHER_SUITE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CRLCHECK - * int - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_CRLFILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_DHFILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_KEYFILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_PROTOCOL_MIN - * int - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_RANDOM_FILE - * string - * PHP 7.1.0 - * - * - * LDAP_OPT_X_TLS_REQUIRE_CERT - * int - * PHP 7.0.5 - * - * - * - * - * - * LDAP_OPT_SERVER_CONTROLS and - * LDAP_OPT_CLIENT_CONTROLS require a list of - * controls, this means that the value must be an array of controls. A - * control consists of an oid identifying the control, - * an optional value, and an optional flag for - * criticality. In PHP a control is given by an - * array containing an element with the key oid - * and string value, and two optional elements. The optional - * elements are key value with string value - * and key iscritical with boolean value. - * iscritical defaults to FALSE - * if not supplied. See draft-ietf-ldapext-ldap-c-api-xx.txt - * for details. See also the second example below. - * @param mixed $value The new value for the specified option. - * @throws LdapException - * - */ -function ldap_set_option($ldap, int $option, $value): void -{ - error_clear_last(); - $safeResult = \ldap_set_option($ldap, $option, $value); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} - - -/** - * Unbinds from the LDAP directory. - * - * @param resource $ldap An LDAP\Connection instance, returned by ldap_connect. - * @throws LdapException - * - */ -function ldap_unbind($ldap): void -{ - error_clear_last(); - $safeResult = \ldap_unbind($ldap); - if ($safeResult === false) { - throw LdapException::createFromPhpError(); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/libxml.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/libxml.php deleted file mode 100644 index 20d32408d..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/libxml.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * The above example will output: - * - * example: , this is a test - * example: , this is a test - * ]]> - * - * - * So, $out[0] contains array of strings that matched full pattern, - * and $out[1] contains array of strings enclosed by tags. - * - * - * - * - * If the pattern contains named subpatterns, $matches - * additionally contains entries for keys with the subpattern name. - * - * - * If the pattern contains duplicate named subpatterns, only the rightmost - * subpattern is stored in $matches[NAME]. - * - * - * - * ]]> - * - * The above example will output: - * - * - * [1] => bar - * ) - * ]]> - * - * - * - * - * - * - * PREG_SET_ORDER - * - * - * Orders results so that $matches[0] is an array of first set - * of matches, $matches[1] is an array of second set of matches, - * and so on. - * - * - * - * ]]> - * - * The above example will output: - * - * example: , example: - * this is a test, this is a test - * ]]> - * - * - * - * - * - * - * PREG_OFFSET_CAPTURE - * - * - * If this flag is passed, for every occurring match the appendant string - * offset (in bytes) will also be returned. Note that this changes the value of - * matches into an array of arrays where every element is an - * array consisting of the matched string at offset 0 - * and its string offset into subject at offset - * 1. - * - * - * - * ]]> - * - * The above example will output: - * - * Array - * ( - * [0] => Array - * ( - * [0] => foobarbaz - * [1] => 0 - * ) - * - * ) - * - * [1] => Array - * ( - * [0] => Array - * ( - * [0] => foo - * [1] => 0 - * ) - * - * ) - * - * [2] => Array - * ( - * [0] => Array - * ( - * [0] => bar - * [1] => 3 - * ) - * - * ) - * - * [3] => Array - * ( - * [0] => Array - * ( - * [0] => baz - * [1] => 6 - * ) - * - * ) - * - * ) - * ]]> - * - * - * - * - * - * - * PREG_UNMATCHED_AS_NULL - * - * - * If this flag is passed, unmatched subpatterns are reported as NULL; - * otherwise they are reported as an empty string. - * - * - * - * - * - * Orders results so that $matches[0] is an array of full - * pattern matches, $matches[1] is an array of strings matched by - * the first parenthesized subpattern, and so on. - * - * - * - * - * ]]> - * - * The above example will output: - * - * example: , this is a test - * example: , this is a test - * ]]> - * - * - * So, $out[0] contains array of strings that matched full pattern, - * and $out[1] contains array of strings enclosed by tags. - * - * - * - * The above example will output: - * - * So, $out[0] contains array of strings that matched full pattern, - * and $out[1] contains array of strings enclosed by tags. - * - * If the pattern contains named subpatterns, $matches - * additionally contains entries for keys with the subpattern name. - * - * If the pattern contains duplicate named subpatterns, only the rightmost - * subpattern is stored in $matches[NAME]. - * - * - * - * ]]> - * - * The above example will output: - * - * - * [1] => bar - * ) - * ]]> - * - * - * - * The above example will output: - * - * Orders results so that $matches[0] is an array of first set - * of matches, $matches[1] is an array of second set of matches, - * and so on. - * - * - * - * ]]> - * - * The above example will output: - * - * example: , example: - * this is a test, this is a test - * ]]> - * - * - * - * The above example will output: - * - * If this flag is passed, for every occurring match the appendant string - * offset (in bytes) will also be returned. Note that this changes the value of - * matches into an array of arrays where every element is an - * array consisting of the matched string at offset 0 - * and its string offset into subject at offset - * 1. - * - * - * - * ]]> - * - * The above example will output: - * - * Array - * ( - * [0] => Array - * ( - * [0] => foobarbaz - * [1] => 0 - * ) - * - * ) - * - * [1] => Array - * ( - * [0] => Array - * ( - * [0] => foo - * [1] => 0 - * ) - * - * ) - * - * [2] => Array - * ( - * [0] => Array - * ( - * [0] => bar - * [1] => 3 - * ) - * - * ) - * - * [3] => Array - * ( - * [0] => Array - * ( - * [0] => baz - * [1] => 6 - * ) - * - * ) - * - * ) - * ]]> - * - * - * - * The above example will output: - * - * If this flag is passed, unmatched subpatterns are reported as NULL; - * otherwise they are reported as an empty string. - * - * If no order flag is given, PREG_PATTERN_ORDER is - * assumed. - * @param int $offset Orders results so that $matches[0] is an array of full - * pattern matches, $matches[1] is an array of strings matched by - * the first parenthesized subpattern, and so on. - * - * - * - * - * ]]> - * - * The above example will output: - * - * example: , this is a test - * example: , this is a test - * ]]> - * - * - * So, $out[0] contains array of strings that matched full pattern, - * and $out[1] contains array of strings enclosed by tags. - * - * - * - * The above example will output: - * - * So, $out[0] contains array of strings that matched full pattern, - * and $out[1] contains array of strings enclosed by tags. - * - * If the pattern contains named subpatterns, $matches - * additionally contains entries for keys with the subpattern name. - * - * If the pattern contains duplicate named subpatterns, only the rightmost - * subpattern is stored in $matches[NAME]. - * - * - * - * ]]> - * - * The above example will output: - * - * - * [1] => bar - * ) - * ]]> - * - * - * - * The above example will output: - * @return int|null Returns the number of full pattern matches (which might be zero). - * @throws PcreException - * - */ -function preg_match_all(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): ?int -{ - error_clear_last(); - $safeResult = \preg_match_all($pattern, $subject, $matches, $flags, $offset); - if ($safeResult === false) { - throw PcreException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Searches subject for a match to the regular - * expression given in pattern. - * - * @param string $pattern The pattern to search for, as a string. - * @param string $subject The input string. - * @param string[]|null $matches If matches is provided, then it is filled with - * the results of search. $matches[0] will contain the - * text that matched the full pattern, $matches[1] - * will have the text that matched the first captured parenthesized - * subpattern, and so on. - * @param int $flags flags can be a combination of the following flags: - * - * - * PREG_OFFSET_CAPTURE - * - * - * If this flag is passed, for every occurring match the appendant string - * offset (in bytes) will also be returned. Note that this changes the value of - * matches into an array where every element is an - * array consisting of the matched string at offset 0 - * and its string offset into subject at offset - * 1. - * - * - * - * ]]> - * - * The above example will output: - * - * Array - * ( - * [0] => foobarbaz - * [1] => 0 - * ) - * - * [1] => Array - * ( - * [0] => foo - * [1] => 0 - * ) - * - * [2] => Array - * ( - * [0] => bar - * [1] => 3 - * ) - * - * [3] => Array - * ( - * [0] => baz - * [1] => 6 - * ) - * - * ) - * ]]> - * - * - * - * - * - * - * PREG_UNMATCHED_AS_NULL - * - * - * If this flag is passed, unmatched subpatterns are reported as NULL; - * otherwise they are reported as an empty string. - * - * - * - * ]]> - * - * The above example will output: - * - * - * string(2) "ac" - * [1]=> - * string(1) "a" - * [2]=> - * string(0) "" - * [3]=> - * string(1) "c" - * } - * array(4) { - * [0]=> - * string(2) "ac" - * [1]=> - * string(1) "a" - * [2]=> - * NULL - * [3]=> - * string(1) "c" - * } - * ]]> - * - * - * - * - * - * - * - * If this flag is passed, for every occurring match the appendant string - * offset (in bytes) will also be returned. Note that this changes the value of - * matches into an array where every element is an - * array consisting of the matched string at offset 0 - * and its string offset into subject at offset - * 1. - * - * - * - * ]]> - * - * The above example will output: - * - * Array - * ( - * [0] => foobarbaz - * [1] => 0 - * ) - * - * [1] => Array - * ( - * [0] => foo - * [1] => 0 - * ) - * - * [2] => Array - * ( - * [0] => bar - * [1] => 3 - * ) - * - * [3] => Array - * ( - * [0] => baz - * [1] => 6 - * ) - * - * ) - * ]]> - * - * - * - * The above example will output: - * - * If this flag is passed, unmatched subpatterns are reported as NULL; - * otherwise they are reported as an empty string. - * - * - * - * ]]> - * - * The above example will output: - * - * - * string(2) "ac" - * [1]=> - * string(1) "a" - * [2]=> - * string(0) "" - * [3]=> - * string(1) "c" - * } - * array(4) { - * [0]=> - * string(2) "ac" - * [1]=> - * string(1) "a" - * [2]=> - * NULL - * [3]=> - * string(1) "c" - * } - * ]]> - * - * - * - * The above example will output: - * @param int $offset If this flag is passed, for every occurring match the appendant string - * offset (in bytes) will also be returned. Note that this changes the value of - * matches into an array where every element is an - * array consisting of the matched string at offset 0 - * and its string offset into subject at offset - * 1. - * - * - * - * ]]> - * - * The above example will output: - * - * Array - * ( - * [0] => foobarbaz - * [1] => 0 - * ) - * - * [1] => Array - * ( - * [0] => foo - * [1] => 0 - * ) - * - * [2] => Array - * ( - * [0] => bar - * [1] => 3 - * ) - * - * [3] => Array - * ( - * [0] => baz - * [1] => 6 - * ) - * - * ) - * ]]> - * - * - * - * The above example will output: - * @return int preg_match returns 1 if the pattern - * matches given subject, 0 if it does not. - * @throws PcreException - * - */ -function preg_match(string $pattern, string $subject, ?iterable &$matches = null, int $flags = 0, int $offset = 0): int -{ - error_clear_last(); - $safeResult = \preg_match($pattern, $subject, $matches, $flags, $offset); - if ($safeResult === false) { - throw PcreException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * Split the given string by a regular expression. - * - * @param string $pattern The pattern to search for, as a string. - * @param string $subject The input string. - * @param int|null $limit If specified, then only substrings up to limit - * are returned with the rest of the string being placed in the last - * substring. A limit of -1 or 0 means "no limit". - * @param int $flags flags can be any combination of the following - * flags (combined with the | bitwise operator): - * - * - * PREG_SPLIT_NO_EMPTY - * - * - * If this flag is set, only non-empty pieces will be returned by - * preg_split. - * - * - * - * - * PREG_SPLIT_DELIM_CAPTURE - * - * - * If this flag is set, parenthesized expression in the delimiter pattern - * will be captured and returned as well. - * - * - * - * - * PREG_SPLIT_OFFSET_CAPTURE - * - * - * If this flag is set, for every occurring match the appendant string - * offset will also be returned. Note that this changes the return - * value in an array where every element is an array consisting of the - * matched string at offset 0 and its string offset - * into subject at offset 1. - * - * - * - * - * - * If this flag is set, for every occurring match the appendant string - * offset will also be returned. Note that this changes the return - * value in an array where every element is an array consisting of the - * matched string at offset 0 and its string offset - * into subject at offset 1. - * @return array Returns an array containing substrings of subject - * split along boundaries matched by pattern. - * @throws PcreException - * - */ -function preg_split(string $pattern, string $subject, ?int $limit = -1, int $flags = 0): array -{ - error_clear_last(); - $safeResult = \preg_split($pattern, $subject, $limit, $flags); - if ($safeResult === false) { - throw PcreException::createFromPhpError(); - } - return $safeResult; -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/pgsql.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/pgsql.php deleted file mode 100644 index 9968a5ae8..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/pgsql.php +++ /dev/null @@ -1,1360 +0,0 @@ - - * - * - * @param bool $use_include_path Setting use_include_path to TRUE will result - * in PHP trying to open the file along the standard include path as per - * the include_path directive. - * This is used for local files, not URLs. - * @return array Returns an array with all the parsed meta tags. - * - * The value of the name property becomes the key, the value of the content - * property becomes the value of the returned array, so you can easily use - * standard array functions to traverse it or access single values. - * Special characters in the value of the name property are substituted with - * '_', the rest is converted to lower case. If two meta tags have the same - * name, only the last one is returned. - * - * Returns FALSE on failure. - * @throws UrlException - * - */ -function get_meta_tags(string $filename, bool $use_include_path = false): array -{ - error_clear_last(); - $safeResult = \get_meta_tags($filename, $use_include_path); - if ($safeResult === false) { - throw UrlException::createFromPhpError(); - } - return $safeResult; -} - - -/** - * This function parses a URL and returns an associative array containing any - * of the various components of the URL that are present. - * The values of the array elements are not URL decoded. - * - * This function is not meant to validate - * the given URL, it only breaks it up into the parts listed below. Partial and invalid - * URLs are also accepted, parse_url tries its best to - * parse them correctly. - * - * @param string $url The URL to parse. - * @param int $component Specify one of PHP_URL_SCHEME, - * PHP_URL_HOST, PHP_URL_PORT, - * PHP_URL_USER, PHP_URL_PASS, - * PHP_URL_PATH, PHP_URL_QUERY - * or PHP_URL_FRAGMENT to retrieve just a specific - * URL component as a string (except when - * PHP_URL_PORT is given, in which case the return - * value will be an int). - * @return array|int|string|null On seriously malformed URLs, parse_url. - * - * If the component parameter is omitted, an - * associative array is returned. At least one element will be - * present within the array. Potential keys within this array are: - * - * - * - * scheme - e.g. http - * - * - * - * - * host - * - * - * - * - * port - * - * - * - * - * user - * - * - * - * - * pass - * - * - * - * - * path - * - * - * - * - * query - after the question mark ? - * - * - * - * - * fragment - after the hashmark # - * - * - * - * - * If the component parameter is specified, - * parse_url returns a string (or an - * int, in the case of PHP_URL_PORT) - * instead of an array. If the requested component doesn't exist - * within the given URL, NULL will be returned. - * As of PHP 8.0.0, parse_url distinguishes absent and empty - * queries and fragments: - * - * - * - * - * - * - * - * Previously all cases resulted in query and fragment being NULL. - * - * Note that control characters (cf. ctype_cntrl) in the - * components are replaced with underscores (_). - * @throws UrlException - * - */ -function parse_url(string $url, int $component = -1) -{ - error_clear_last(); - $safeResult = \parse_url($url, $component); - if ($safeResult === false) { - throw UrlException::createFromPhpError(); - } - return $safeResult; -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/var.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/var.php deleted file mode 100644 index 70f048df2..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/var.php +++ /dev/null @@ -1,60 +0,0 @@ - - * ]]> - * - * See section 4.7 of the XML 1.0 - * spec for the definition of notation declarations. - * - * @param resource $parser A reference to the XML parser to set up notation declaration handler function. - * @param callable $handler handler is a string containing the name of a - * function that must exist when xml_parse is called - * for parser. - * - * The function named by handler must accept - * five parameters: - * - * handler - * XMLParserparser - * stringnotation_name - * stringbase - * stringsystem_id - * stringpublic_id - * - * - * - * - * parser - * - * - * - * The first parameter, parser, is a - * reference to the XML parser calling the handler. - * - * - * - * - * notation_name - * - * - * This is the notation's name, as per - * the notation format described above. - * - * - * - * - * - * base - * - * - * - * This is the base for resolving the system identifier - * (system_id) of the notation declaration. - * Currently this parameter will always be set to an empty string. - * - * - * - * - * system_id - * - * - * System identifier of the external notation declaration. - * - * - * - * - * - * public_id - * - * - * - * Public identifier of the external notation declaration. - * - * - * - * - * - * If a handler function is set to an empty string, or FALSE, the handler - * in question is disabled. - * @throws XmlException - * - */ -function xml_set_notation_decl_handler($parser, callable $handler): void -{ - error_clear_last(); - $safeResult = \xml_set_notation_decl_handler($parser, $handler); - if ($safeResult === false) { - throw XmlException::createFromPhpError(); - } -} - - -/** - * This function allows to use parser inside - * object. All callback functions could be set with - * xml_set_element_handler etc and assumed to be - * methods of object. - * - * @param resource $parser A reference to the XML parser to use inside the object. - * @param object $object The object where to use the XML parser. - * @throws XmlException - * - */ -function xml_set_object($parser, object $object): void -{ - error_clear_last(); - $safeResult = \xml_set_object($parser, $object); - if ($safeResult === false) { - throw XmlException::createFromPhpError(); - } -} - - -/** - * Sets the processing instruction (PI) handler function for the XML parser - * parser. - * - * A processing instruction has the following format: - * - * <?target - * data?> - * - * - * You can put PHP code into such a tag, but be aware of one limitation: in - * an XML PI, the PI end tag (?>) can not be quoted, - * so this character sequence should not appear in the PHP code you embed - * with PIs in XML documents.If it does, the rest of the PHP code, as well - * as the "real" PI end tag, will be treated as character data. - * - * @param resource $parser A reference to the XML parser to set up processing instruction (PI) handler function. - * @param callable $handler handler is a string containing the name of a - * function that must exist when xml_parse is called - * for parser. - * - * The function named by handler must accept - * three parameters: - * - * handler - * XMLParserparser - * stringtarget - * stringdata - * - * - * - * parser - * - * - * The first parameter, parser, is a - * reference to the XML parser calling the handler. - * - * - * - * - * target - * - * - * The second parameter, target, contains the PI - * target. - * - * - * - * - * data - * - * - * The third parameter, data, contains the PI - * data. - * - * - * - * - * - * If a handler function is set to an empty string, or FALSE, the handler - * in question is disabled. - * @throws XmlException - * - */ -function xml_set_processing_instruction_handler($parser, callable $handler): void -{ - error_clear_last(); - $safeResult = \xml_set_processing_instruction_handler($parser, $handler); - if ($safeResult === false) { - throw XmlException::createFromPhpError(); - } -} - - -/** - * Set a handler to be called when a namespace is declared. Namespace - * declarations occur inside start tags. But the namespace declaration start - * handler is called before the start tag handler for each namespace declared - * in that start tag. - * - * @param resource $parser A reference to the XML parser. - * @param callable $handler handler is a string containing the name of a - * function that must exist when xml_parse is called - * for parser. - * - * The function named by handler must accept - * three parameters, and should return an integer value. If the - * value returned from the handler is FALSE (which it will be if no - * value is returned), the XML parser will stop parsing and - * xml_get_error_code will return - * XML_ERROR_EXTERNAL_ENTITY_HANDLING. - * - * handler - * XMLParserparser - * stringprefix - * stringuri - * - * - * - * parser - * - * - * The first parameter, parser, is a - * reference to the XML parser calling the handler. - * - * - * - * - * prefix - * - * - * The prefix is a string used to reference the namespace within an XML object. - * - * - * - * - * uri - * - * - * Uniform Resource Identifier (URI) of namespace. - * - * - * - * - * - * If a handler function is set to an empty string, or FALSE, the handler - * in question is disabled. - * @throws XmlException - * - */ -function xml_set_start_namespace_decl_handler($parser, callable $handler): void -{ - error_clear_last(); - $safeResult = \xml_set_start_namespace_decl_handler($parser, $handler); - if ($safeResult === false) { - throw XmlException::createFromPhpError(); - } -} - - -/** - * Sets the unparsed entity declaration handler function for the XML parser - * parser. - * - * The handler will be called if the XML parser - * encounters an external entity declaration with an NDATA declaration, like - * the following: - * - * name {publicId | systemId} - * NDATA notationName - * ]]> - * - * - * See section 4.2.2 of - * the XML 1.0 spec for the definition of notation declared - * external entities. - * - * @param resource $parser A reference to the XML parser to set up unparsed entity declaration handler function. - * @param callable $handler handler is a string containing the name of a - * function that must exist when xml_parse is called - * for parser. - * - * The function named by handler must accept six - * parameters: - * - * handler - * XMLParserparser - * stringentity_name - * stringbase - * stringsystem_id - * stringpublic_id - * stringnotation_name - * - * - * - * parser - * - * - * The first parameter, parser, is a - * reference to the XML parser calling the - * handler. - * - * - * - * - * entity_name - * - * - * The name of the entity that is about to be defined. - * - * - * - * - * base - * - * - * This is the base for resolving the system identifier - * (systemId) of the external entity.Currently - * this parameter will always be set to an empty string. - * - * - * - * - * system_id - * - * - * System identifier for the external entity. - * - * - * - * - * public_id - * - * - * Public identifier for the external entity. - * - * - * - * - * notation_name - * - * - * Name of the notation of this entity (see - * xml_set_notation_decl_handler). - * - * - * - * - * - * If a handler function is set to an empty string, or FALSE, the handler - * in question is disabled. - * @throws XmlException - * - */ -function xml_set_unparsed_entity_decl_handler($parser, callable $handler): void -{ - error_clear_last(); - $safeResult = \xml_set_unparsed_entity_decl_handler($parser, $handler); - if ($safeResult === false) { - throw XmlException::createFromPhpError(); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/xmlrpc.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/xmlrpc.php deleted file mode 100644 index 3a1f5362f..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/generated/xmlrpc.php +++ /dev/null @@ -1,22 +0,0 @@ -format('Y-m-d H:i:s.u'), $datetime->getTimezone()); - } - - /** - * @param string $format - * @param string $time - * @param DateTimeZone|null $timezone - * @throws DatetimeException - */ - public static function createFromFormat($format, $time, $timezone = null): self - { - $datetime = \DateTime::createFromFormat($format, $time, $timezone); - if ($datetime === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($datetime); - } - - /** - * @param DateTimeInterface $datetime2 The date to compare to. - * @param boolean $absolute [optional] Whether to return absolute difference. - * @return DateInterval The DateInterval object representing the difference between the two dates. - * @throws DatetimeException - */ - public function diff($datetime2, $absolute = false): DateInterval - { - /** @var \DateInterval|false $result */ - $result = parent::diff($datetime2, $absolute); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } - - /** - * @param string $modify A date/time string. Valid formats are explained in Date and Time Formats. - * @return DateTime Returns the DateTime object for method chaining. - * @throws DatetimeException - */ - public function modify($modify): self - { - /** @var DateTime|false $result */ - $result = parent::modify($modify); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } - - /** - * @param int $year - * @param int $month - * @param int $day - * @return DateTime - * @throws DatetimeException - */ - public function setDate($year, $month, $day): self - { - /** @var DateTime|false $result */ - $result = parent::setDate($year, $month, $day); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/DateTimeImmutable.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/DateTimeImmutable.php deleted file mode 100644 index 4926da0bd..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/DateTimeImmutable.php +++ /dev/null @@ -1,271 +0,0 @@ -innerDateTime = new parent($time, $timezone); - } - - //switch between regular datetime and safe version - public static function createFromRegular(\DateTimeImmutable $datetime): self - { - $safeDatetime = new self($datetime->format('Y-m-d H:i:s.u'), $datetime->getTimezone()); //we need to also update the wrapper to not break the operators '<' and '>' - $safeDatetime->innerDateTime = $datetime; //to make sure we don't lose information because of the format(). - return $safeDatetime; - } - - //usefull if you need to switch back to regular DateTimeImmutable (for example when using DatePeriod) - public function getInnerDateTime(): \DateTimeImmutable - { - return $this->innerDateTime; - } - - ///////////////////////////////////////////////////////////////////////////// - // overload functions with false errors - - /** - * @param string $format - * @param string $time - * @param \DateTimeZone|null $timezone - * @throws DatetimeException - */ - public static function createFromFormat($format, $time, $timezone = null): self - { - $datetime = \DateTimeImmutable::createFromFormat($format, $time, $timezone); - if ($datetime === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($datetime); - } - - /** - * @param string $format - * @return string - * @throws DatetimeException - */ - public function format($format): string - { - /** @var string|false $result */ - $result = $this->innerDateTime->format($format); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } - - /** - * @param \DateTimeInterface $datetime2 - * @param bool $absolute - * @return \DateInterval - * @throws DatetimeException - */ - public function diff($datetime2, $absolute = false): \DateInterval - { - /** @var \DateInterval|false $result */ - $result = $this->innerDateTime->diff($datetime2, $absolute); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } - - /** - * @param string $modify - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function modify($modify): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->modify($modify); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable - } - - /** - * @param int $year - * @param int $month - * @param int $day - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function setDate($year, $month, $day): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->setDate($year, $month, $day); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable - } - - /** - * @param int $year - * @param int $week - * @param int $day - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function setISODate($year, $week, $day = 1): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->setISODate($year, $week, $day); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable - } - - /** - * @param int $hour - * @param int $minute - * @param int $second - * @param int $microseconds - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function setTime($hour, $minute, $second = 0, $microseconds = 0): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->setTime($hour, $minute, $second, $microseconds); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); - } - - /** - * @param int $unixtimestamp - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function setTimestamp($unixtimestamp): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->setTimestamp($unixtimestamp); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); - } - - /** - * @param \DateTimeZone $timezone - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function setTimezone($timezone): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->setTimezone($timezone); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); - } - - /** - * @param \DateInterval $interval - * @return DateTimeImmutable - * @throws DatetimeException - */ - public function sub($interval): self - { - /** @var \DateTimeImmutable|false $result */ - $result = $this->innerDateTime->sub($interval); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return self::createFromRegular($result); - } - - /** - * @throws DatetimeException - */ - public function getOffset(): int - { - /** @var int|false $result */ - $result = $this->innerDateTime->getOffset(); - if ($result === false) { - throw DatetimeException::createFromPhpError(); - } - return $result; - } - - ////////////////////////////////////////////////////////////////////////////////////////// - //overload getters to use the inner datetime immutable instead of itself - - /** - * @param \DateInterval $interval - * @return DateTimeImmutable - */ - public function add($interval): self - { - return self::createFromRegular($this->innerDateTime->add($interval)); - } - - /** - * @param \DateTime $dateTime - * @return DateTimeImmutable - */ - #[\ReturnTypeWillChange] - public static function createFromMutable($dateTime): self - { - $date = \DateTimeImmutable::createFromMutable($dateTime); - - return self::createFromRegular($date); - } - - public static function createFromInterface(\DateTimeInterface $object): self - { - if ($object instanceof \DateTime) { - $object = self::createFromMutable($object); - } elseif ($object instanceof DateTimeImmutable) { - $object = $object->getInnerDateTime(); - } - return self::createFromRegular($object); - } - - /** - * @param mixed[] $array - * @return DateTimeImmutable - */ - public static function __set_state($array): self - { - return self::createFromRegular(parent::__set_state($array)); - } - - public function getTimezone(): \DateTimeZone - { - return $this->innerDateTime->getTimezone(); - } - - public function getTimestamp(): int - { - return $this->innerDateTime->getTimestamp(); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/CurlException.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/CurlException.php deleted file mode 100644 index 3401b57b8..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/CurlException.php +++ /dev/null @@ -1,15 +0,0 @@ - 'PREG_INTERNAL_ERROR: Internal error', - PREG_BACKTRACK_LIMIT_ERROR => 'PREG_BACKTRACK_LIMIT_ERROR: Backtrack limit reached', - PREG_RECURSION_LIMIT_ERROR => 'PREG_RECURSION_LIMIT_ERROR: Recursion limit reached', - PREG_BAD_UTF8_ERROR => 'PREG_BAD_UTF8_ERROR: Invalid UTF8 character', - PREG_BAD_UTF8_OFFSET_ERROR => 'PREG_BAD_UTF8_OFFSET_ERROR', - PREG_JIT_STACKLIMIT_ERROR => 'PREG_JIT_STACKLIMIT_ERROR', - ]; - $errMsg = $errorMap[preg_last_error()] ?? 'Unknown PCRE error: '.preg_last_error(); - return new self($errMsg, \preg_last_error()); - } -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php deleted file mode 100644 index fbea6ad25..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php +++ /dev/null @@ -1,9 +0,0 @@ - $depth User specified recursion depth. - * @param int $flags Bitmask of JSON decode options. - * - * @return mixed - * @throws JsonException if the JSON cannot be decoded. - * @link http://www.php.net/manual/en/function.json-decode.php - */ -function json_decode(string $json, bool $assoc = false, int $depth = 512, int $flags = 0): mixed -{ - $data = \json_decode($json, $assoc, $depth, $flags); - if (JSON_ERROR_NONE !== json_last_error()) { - throw JsonException::createFromPhpError(); - } - return $data; -} - - -/** - * Fetchs a stored variable from the cache. - * - * @param mixed $key The key used to store the value (with - * apc_store). If an array is passed then each - * element is fetched and returned. - * @return mixed The stored variable or array of variables on success; FALSE on failure - * @throws ApcException - * - */ -function apc_fetch($key) -{ - error_clear_last(); - $result = \apc_fetch($key, $success); - if ($success === false) { - throw ApcException::createFromPhpError(); - } - return $result; -} - -/** - * Fetchs an entry from the cache. - * - * @param string|string[] $key The key used to store the value (with - * apcu_store). If an array is passed then each - * element is fetched and returned. - * @return mixed The stored variable or array of variables on success - * @throws ApcuException - * - */ -function apcu_fetch($key) -{ - error_clear_last(); - $result = \apcu_fetch($key, $success); - if ($success === false) { - throw ApcuException::createFromPhpError(); - } - return $result; -} - -/** - * Searches subject for matches to - * pattern and replaces them with - * replacement. - * - * @param string[]|string $pattern The pattern to search for. It can be either a string or an array with - * strings. - * - * Several PCRE modifiers - * are also available. - * @param string[]|string $replacement The string or an array with strings to replace. If this parameter is a - * string and the pattern parameter is an array, - * all patterns will be replaced by that string. If both - * pattern and replacement - * parameters are arrays, each pattern will be - * replaced by the replacement counterpart. If - * there are fewer elements in the replacement - * array than in the pattern array, any extra - * patterns will be replaced by an empty string. - * - * replacement may contain references of the form - * \\n or - * $n, with the latter form - * being the preferred one. Every such reference will be replaced by the text - * captured by the n'th parenthesized pattern. - * n can be from 0 to 99, and - * \\0 or $0 refers to the text matched - * by the whole pattern. Opening parentheses are counted from left to right - * (starting from 1) to obtain the number of the capturing subpattern. - * To use backslash in replacement, it must be doubled - * ("\\\\" PHP string). - * - * When working with a replacement pattern where a backreference is - * immediately followed by another number (i.e.: placing a literal number - * immediately after a matched pattern), you cannot use the familiar - * \\1 notation for your backreference. - * \\11, for example, would confuse - * preg_replace since it does not know whether you - * want the \\1 backreference followed by a literal - * 1, or the \\11 backreference - * followed by nothing. In this case the solution is to use - * ${1}1. This creates an isolated - * $1 backreference, leaving the 1 - * as a literal. - * - * When using the deprecated e modifier, this function escapes - * some characters (namely ', ", - * \ and NULL) in the strings that replace the - * backreferences. This is done to ensure that no syntax errors arise - * from backreference usage with either single or double quotes (e.g. - * 'strlen(\'$1\')+strlen("$2")'). Make sure you are - * aware of PHP's string - * syntax to know exactly how the interpreted string will look. - * @param string|array|string[] $subject The string or an array with strings to search and replace. - * - * If subject is an array, then the search and - * replace is performed on every entry of subject, - * and the return value is an array as well. - * @param int $limit The maximum possible replacements for each pattern in each - * subject string. Defaults to - * -1 (no limit). - * @param int $count If specified, this variable will be filled with the number of - * replacements done. - * @return string|array|string[] preg_replace returns an array if the - * subject parameter is an array, or a string - * otherwise. - * - * If matches are found, the new subject will - * be returned, otherwise subject will be - * returned unchanged. - * - * @throws PcreException - * - */ -function preg_replace($pattern, $replacement, $subject, int $limit = -1, int &$count = null) -{ - error_clear_last(); - $result = \preg_replace($pattern, $replacement, $subject, $limit, $count); - if (preg_last_error() !== PREG_NO_ERROR || $result === null) { - throw PcreException::createFromPhpError(); - } - return $result; -} - -/** - * @param resource|null $dir_handle - * @return string|false - * @deprecated - * This function is only in safe because the php documentation is wrong - */ -function readdir($dir_handle = null) -{ - if ($dir_handle !== null) { - $result = \readdir($dir_handle); - } else { - $result = \readdir(); - } - return $result; -} - -/** - * Encrypts given data with given method and key, returns a raw - * or base64 encoded string - * - * @param string $data The plaintext message data to be encrypted. - * @param string $method The cipher method. For a list of available cipher methods, use openssl_get_cipher_methods. - * @param string $key The key. - * @param int $options options is a bitwise disjunction of the flags - * OPENSSL_RAW_DATA and - * OPENSSL_ZERO_PADDING. - * @param string $iv A non-NULL Initialization Vector. - * @param string $tag The authentication tag passed by reference when using AEAD cipher mode (GCM or CCM). - * @param string $aad Additional authentication data. - * @param int $tag_length The length of the authentication tag. Its value can be between 4 and 16 for GCM mode. - * @return string Returns the encrypted string. - * @throws OpensslException - * - */ -function openssl_encrypt(string $data, string $method, string $key, int $options = 0, string $iv = "", string &$tag = "", string $aad = "", int $tag_length = 16): string -{ - error_clear_last(); - // The $tag parameter is handled in a weird way by openssl_encrypt. It cannot be provided unless encoding is AEAD - if (func_num_args() <= 5) { - $result = \openssl_encrypt($data, $method, $key, $options, $iv); - } else { - $result = \openssl_encrypt($data, $method, $key, $options, $iv, $tag, $aad, $tag_length); - } - if ($result === false) { - throw OpensslException::createFromPhpError(); - } - return $result; -} - -/** - * The function socket_write writes to the - * socket from the given - * buffer. - * - * @param \Socket $socket - * @param string $buffer The buffer to be written. - * @param int $length The optional parameter length can specify an - * alternate length of bytes written to the socket. If this length is - * greater than the buffer length, it is silently truncated to the length - * of the buffer. - * @return int Returns the number of bytes successfully written to the socket. - * The error code can be retrieved with - * socket_last_error. This code may be passed to - * socket_strerror to get a textual explanation of the - * error. - * @throws SocketsException - * - */ -function socket_write(\Socket $socket, string $buffer, int $length = 0): int -{ - error_clear_last(); - $result = $length === 0 ? \socket_write($socket, $buffer) : \socket_write($socket, $buffer, $length); - if ($result === false) { - throw SocketsException::createFromPhpError(); - } - return $result; -} - -/** - * This function takes a node of a DOM - * document and makes it into a SimpleXML node. This new object can - * then be used as a native SimpleXML element. - * - * @param \DOMNode $node A DOM Element node - * @param string $class_name You may use this optional parameter so that - * simplexml_import_dom will return an object of - * the specified class. That class should extend the - * SimpleXMLElement class. - * @return \SimpleXMLElement Returns a SimpleXMLElement. - * @throws SimplexmlException - * - */ -function simplexml_import_dom(\DOMNode $node, string $class_name = \SimpleXMLElement::class): \SimpleXMLElement -{ - error_clear_last(); - $result = \simplexml_import_dom($node, $class_name); - if ($result === null) { - throw SimplexmlException::createFromPhpError(); - } - return $result; -} - -/** - * Convert the well-formed XML document in the given file to an object. - * - * @param string $filename Path to the XML file - * @param string $class_name You may use this optional parameter so that - * simplexml_load_file will return an object of - * the specified class. That class should extend the - * SimpleXMLElement class. - * @param int $options Since Libxml 2.6.0, you may also use the - * options parameter to specify additional Libxml parameters. - * @param string $namespace_or_prefix Namespace prefix or URI. - * @param bool $is_prefix TRUE if namespace_or_prefix is a prefix, FALSE if it's a URI; - * defaults to FALSE. - * @return \SimpleXMLElement Returns an object of class SimpleXMLElement with - * properties containing the data held within the XML document. - * @throws SimplexmlException - * - */ -function simplexml_load_file(string $filename, string $class_name = \SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false): \SimpleXMLElement -{ - error_clear_last(); - $result = \simplexml_load_file($filename, $class_name, $options, $namespace_or_prefix, $is_prefix); - if ($result === false) { - throw SimplexmlException::createFromPhpError(); - } - return $result; -} - - -/** - * Takes a well-formed XML string and returns it as an object. - * - * @param string $data A well-formed XML string - * @param string $class_name You may use this optional parameter so that - * simplexml_load_string will return an object of - * the specified class. That class should extend the - * SimpleXMLElement class. - * @param int $options Since Libxml 2.6.0, you may also use the - * options parameter to specify additional Libxml parameters. - * @param string $namespace_or_prefix Namespace prefix or URI. - * @param bool $is_prefix TRUE if namespace_or_prefix is a prefix, FALSE if it's a URI; - * defaults to FALSE. - * @return \SimpleXMLElement Returns an object of class SimpleXMLElement with - * properties containing the data held within the xml document. - * @throws SimplexmlException - * - */ -function simplexml_load_string(string $data, string $class_name = \SimpleXMLElement::class, int $options = 0, string $namespace_or_prefix = "", bool $is_prefix = false): \SimpleXMLElement -{ - error_clear_last(); - $result = \simplexml_load_string($data, $class_name, $options, $namespace_or_prefix, $is_prefix); - if ($result === false) { - throw SimplexmlException::createFromPhpError(); - } - return $result; -} - -/** - * Returns three samples representing the average system load - * (the number of processes in the system run queue) over the last 1, 5 and 15 - * minutes, respectively. Returns FALSE on failure. - * - * @return array Returns an array with three samples (last 1, 5 and 15 - * minutes). - * @throws MiscException - * - */ -function sys_getloadavg(): array -{ - error_clear_last(); - $result = \sys_getloadavg(); - if ($result === false) { - throw MiscException::createFromPhpError(); - } - return $result; -} - -/** - * Returns the process group identifier of the process - * process_id. - * - * @param int $process_id The process id. - * @return int Returns the identifier, as an int. - * @throws PosixException - * - */ -function posix_getpgid(int $process_id): int -{ - error_clear_last(); - $result = \posix_getpgid($process_id); - if ($result === false) { - throw PosixException::createFromPhpError(); - } - return $result; -} - - -/** - * fputcsv formats a line (passed as a - * fields array) as CSV and writes it (terminated by a - * newline) to the specified file stream. - * - * @param resource $stream The file pointer must be valid, and must point to - * a file successfully opened by fopen or - * fsockopen (and not yet closed by - * fclose). - * @phpstan-param (scalar|\Stringable|null)[] $fields - * @param array $fields An array of strings. - * @param string $separator The optional separator parameter sets the field - * delimiter (one single-byte character only). - * @param string $enclosure The optional enclosure parameter sets the field - * enclosure (one single-byte character only). - * @param string $escape The optional escape parameter sets the - * escape character (at most one single-byte character). - * An empty string ("") disables the proprietary escape mechanism. - * @param string $eol The optional eol parameter sets - * a custom End of Line sequence. - * @return int Returns the length of the written string. - * @throws FilesystemException - * - */ -function fputcsv($stream, array $fields, string $separator = ",", string $enclosure = "\"", string $escape = "\\", string $eol = "\n"): int -{ - error_clear_last(); - if (PHP_VERSION_ID >= 80100) { - /** @phpstan-ignore-next-line */ - $result = \fputcsv($stream, $fields, $separator, $enclosure, $escape, $eol); - } else { - $result = \fputcsv($stream, $fields, $separator, $enclosure, $escape); - } - - if ($result === false) { - throw FilesystemException::createFromPhpError(); - } - return $result; -} - -/** - * Similar to fgets except that - * fgetcsv parses the line it reads for fields in - * CSV format and returns an array containing the fields - * read. - * - * @param resource $stream A valid file pointer to a file successfully opened by - * fopen, popen, or - * fsockopen. - * @param int<0, max>|null $length Must be greater than the longest line (in characters) to be found in - * the CSV file (allowing for trailing line-end characters). Otherwise the - * line is split in chunks of length characters, - * unless the split would occur inside an enclosure. - * - * Omitting this parameter (or setting it to 0, - * or NULL in PHP 8.0.0 or later) the maximum line length is not limited, - * which is slightly slower. - * @param string $separator The optional separator parameter sets the field separator (one single-byte character only). - * @param string $enclosure The optional enclosure parameter sets the field enclosure character (one single-byte character only). - * @param string $escape The optional escape parameter sets the escape character (at most one single-byte character). - * An empty string ("") disables the proprietary escape mechanism. - * @return mixed[]|false Returns an indexed array containing the fields read on success or false when there is no more lines. - * @throws FilesystemException - * - */ -function fgetcsv($stream, int $length = null, string $separator = ",", string $enclosure = "\"", string $escape = "\\"): array|false -{ - error_clear_last(); - $safeResult = \fgetcsv($stream, $length, $separator, $enclosure, $escape); - if ($safeResult === false && \feof($stream) === false) { - throw FilesystemException::createFromPhpError(); - } - return $safeResult; -} diff --git a/lam/lib/3rdParty/composer/thecodingmachine/safe/rector-migrate.php b/lam/lib/3rdParty/composer/thecodingmachine/safe/rector-migrate.php deleted file mode 100644 index 8bd9d7bd8..000000000 --- a/lam/lib/3rdParty/composer/thecodingmachine/safe/rector-migrate.php +++ /dev/null @@ -1,1104 +0,0 @@ -ruleWithConfiguration( - RenameFunctionRector::class,[ 'apache_getenv' => 'Safe\apache_getenv', - 'apache_get_version' => 'Safe\apache_get_version', - 'apache_lookup_uri' => 'Safe\apache_lookup_uri', - 'apache_request_headers' => 'Safe\apache_request_headers', - 'apache_response_headers' => 'Safe\apache_response_headers', - 'apache_setenv' => 'Safe\apache_setenv', - 'apcu_cache_info' => 'Safe\apcu_cache_info', - 'apcu_cas' => 'Safe\apcu_cas', - 'apcu_dec' => 'Safe\apcu_dec', - 'apcu_fetch' => 'Safe\apcu_fetch', - 'apcu_inc' => 'Safe\apcu_inc', - 'apcu_sma_info' => 'Safe\apcu_sma_info', - 'apc_fetch' => 'Safe\apc_fetch', - 'array_walk_recursive' => 'Safe\array_walk_recursive', - 'assert_options' => 'Safe\assert_options', - 'base64_decode' => 'Safe\base64_decode', - 'bindtextdomain' => 'Safe\bindtextdomain', - 'bzclose' => 'Safe\bzclose', - 'bzflush' => 'Safe\bzflush', - 'bzread' => 'Safe\bzread', - 'bzwrite' => 'Safe\bzwrite', - 'chdir' => 'Safe\chdir', - 'chgrp' => 'Safe\chgrp', - 'chmod' => 'Safe\chmod', - 'chown' => 'Safe\chown', - 'chroot' => 'Safe\chroot', - 'class_alias' => 'Safe\class_alias', - 'class_implements' => 'Safe\class_implements', - 'class_parents' => 'Safe\class_parents', - 'class_uses' => 'Safe\class_uses', - 'cli_set_process_title' => 'Safe\cli_set_process_title', - 'closelog' => 'Safe\closelog', - 'com_create_guid' => 'Safe\com_create_guid', - 'com_event_sink' => 'Safe\com_event_sink', - 'com_load_typelib' => 'Safe\com_load_typelib', - 'com_print_typeinfo' => 'Safe\com_print_typeinfo', - 'convert_uudecode' => 'Safe\convert_uudecode', - 'copy' => 'Safe\copy', - 'create_function' => 'Safe\create_function', - 'cubrid_bind' => 'Safe\cubrid_bind', - 'cubrid_column_names' => 'Safe\cubrid_column_names', - 'cubrid_column_types' => 'Safe\cubrid_column_types', - 'cubrid_col_size' => 'Safe\cubrid_col_size', - 'cubrid_commit' => 'Safe\cubrid_commit', - 'cubrid_connect' => 'Safe\cubrid_connect', - 'cubrid_connect_with_url' => 'Safe\cubrid_connect_with_url', - 'cubrid_current_oid' => 'Safe\cubrid_current_oid', - 'cubrid_disconnect' => 'Safe\cubrid_disconnect', - 'cubrid_drop' => 'Safe\cubrid_drop', - 'cubrid_free_result' => 'Safe\cubrid_free_result', - 'cubrid_get_charset' => 'Safe\cubrid_get_charset', - 'cubrid_get_class_name' => 'Safe\cubrid_get_class_name', - 'cubrid_get_client_info' => 'Safe\cubrid_get_client_info', - 'cubrid_get_db_parameter' => 'Safe\cubrid_get_db_parameter', - 'cubrid_get_query_timeout' => 'Safe\cubrid_get_query_timeout', - 'cubrid_get_server_info' => 'Safe\cubrid_get_server_info', - 'cubrid_insert_id' => 'Safe\cubrid_insert_id', - 'cubrid_lob2_bind' => 'Safe\cubrid_lob2_bind', - 'cubrid_lob2_close' => 'Safe\cubrid_lob2_close', - 'cubrid_lob2_export' => 'Safe\cubrid_lob2_export', - 'cubrid_lob2_import' => 'Safe\cubrid_lob2_import', - 'cubrid_lob2_new' => 'Safe\cubrid_lob2_new', - 'cubrid_lob2_read' => 'Safe\cubrid_lob2_read', - 'cubrid_lob2_seek' => 'Safe\cubrid_lob2_seek', - 'cubrid_lob2_seek64' => 'Safe\cubrid_lob2_seek64', - 'cubrid_lob2_size' => 'Safe\cubrid_lob2_size', - 'cubrid_lob2_size64' => 'Safe\cubrid_lob2_size64', - 'cubrid_lob2_tell' => 'Safe\cubrid_lob2_tell', - 'cubrid_lob2_tell64' => 'Safe\cubrid_lob2_tell64', - 'cubrid_lob2_write' => 'Safe\cubrid_lob2_write', - 'cubrid_lob_close' => 'Safe\cubrid_lob_close', - 'cubrid_lob_export' => 'Safe\cubrid_lob_export', - 'cubrid_lob_get' => 'Safe\cubrid_lob_get', - 'cubrid_lob_send' => 'Safe\cubrid_lob_send', - 'cubrid_lob_size' => 'Safe\cubrid_lob_size', - 'cubrid_lock_read' => 'Safe\cubrid_lock_read', - 'cubrid_lock_write' => 'Safe\cubrid_lock_write', - 'cubrid_move_cursor' => 'Safe\cubrid_move_cursor', - 'cubrid_next_result' => 'Safe\cubrid_next_result', - 'cubrid_pconnect' => 'Safe\cubrid_pconnect', - 'cubrid_pconnect_with_url' => 'Safe\cubrid_pconnect_with_url', - 'cubrid_prepare' => 'Safe\cubrid_prepare', - 'cubrid_put' => 'Safe\cubrid_put', - 'cubrid_rollback' => 'Safe\cubrid_rollback', - 'cubrid_schema' => 'Safe\cubrid_schema', - 'cubrid_seq_drop' => 'Safe\cubrid_seq_drop', - 'cubrid_seq_insert' => 'Safe\cubrid_seq_insert', - 'cubrid_seq_put' => 'Safe\cubrid_seq_put', - 'cubrid_set_add' => 'Safe\cubrid_set_add', - 'cubrid_set_autocommit' => 'Safe\cubrid_set_autocommit', - 'cubrid_set_db_parameter' => 'Safe\cubrid_set_db_parameter', - 'cubrid_set_drop' => 'Safe\cubrid_set_drop', - 'cubrid_set_query_timeout' => 'Safe\cubrid_set_query_timeout', - 'curl_copy_handle' => 'Safe\curl_copy_handle', - 'curl_escape' => 'Safe\curl_escape', - 'curl_exec' => 'Safe\curl_exec', - 'curl_getinfo' => 'Safe\curl_getinfo', - 'curl_init' => 'Safe\curl_init', - 'curl_multi_info_read' => 'Safe\curl_multi_info_read', - 'curl_multi_init' => 'Safe\curl_multi_init', - 'curl_multi_setopt' => 'Safe\curl_multi_setopt', - 'curl_setopt' => 'Safe\curl_setopt', - 'curl_share_errno' => 'Safe\curl_share_errno', - 'curl_share_setopt' => 'Safe\curl_share_setopt', - 'curl_unescape' => 'Safe\curl_unescape', - 'curl_upkeep' => 'Safe\curl_upkeep', - 'date' => 'Safe\date', - 'date_parse' => 'Safe\date_parse', - 'date_parse_from_format' => 'Safe\date_parse_from_format', - 'date_sunrise' => 'Safe\date_sunrise', - 'date_sunset' => 'Safe\date_sunset', - 'date_sun_info' => 'Safe\date_sun_info', - 'db2_autocommit' => 'Safe\db2_autocommit', - 'db2_bind_param' => 'Safe\db2_bind_param', - 'db2_client_info' => 'Safe\db2_client_info', - 'db2_close' => 'Safe\db2_close', - 'db2_commit' => 'Safe\db2_commit', - 'db2_execute' => 'Safe\db2_execute', - 'db2_free_result' => 'Safe\db2_free_result', - 'db2_free_stmt' => 'Safe\db2_free_stmt', - 'db2_get_option' => 'Safe\db2_get_option', - 'db2_pclose' => 'Safe\db2_pclose', - 'db2_rollback' => 'Safe\db2_rollback', - 'db2_server_info' => 'Safe\db2_server_info', - 'db2_set_option' => 'Safe\db2_set_option', - 'define' => 'Safe\define', - 'deflate_add' => 'Safe\deflate_add', - 'deflate_init' => 'Safe\deflate_init', - 'disk_free_space' => 'Safe\disk_free_space', - 'disk_total_space' => 'Safe\disk_total_space', - 'dl' => 'Safe\dl', - 'dns_get_record' => 'Safe\dns_get_record', - 'eio_busy' => 'Safe\eio_busy', - 'eio_chmod' => 'Safe\eio_chmod', - 'eio_chown' => 'Safe\eio_chown', - 'eio_close' => 'Safe\eio_close', - 'eio_custom' => 'Safe\eio_custom', - 'eio_dup2' => 'Safe\eio_dup2', - 'eio_event_loop' => 'Safe\eio_event_loop', - 'eio_fallocate' => 'Safe\eio_fallocate', - 'eio_fchmod' => 'Safe\eio_fchmod', - 'eio_fchown' => 'Safe\eio_fchown', - 'eio_fdatasync' => 'Safe\eio_fdatasync', - 'eio_fstat' => 'Safe\eio_fstat', - 'eio_fstatvfs' => 'Safe\eio_fstatvfs', - 'eio_fsync' => 'Safe\eio_fsync', - 'eio_ftruncate' => 'Safe\eio_ftruncate', - 'eio_futime' => 'Safe\eio_futime', - 'eio_grp' => 'Safe\eio_grp', - 'eio_lstat' => 'Safe\eio_lstat', - 'eio_mkdir' => 'Safe\eio_mkdir', - 'eio_mknod' => 'Safe\eio_mknod', - 'eio_nop' => 'Safe\eio_nop', - 'eio_readahead' => 'Safe\eio_readahead', - 'eio_readdir' => 'Safe\eio_readdir', - 'eio_readlink' => 'Safe\eio_readlink', - 'eio_rename' => 'Safe\eio_rename', - 'eio_rmdir' => 'Safe\eio_rmdir', - 'eio_seek' => 'Safe\eio_seek', - 'eio_sendfile' => 'Safe\eio_sendfile', - 'eio_stat' => 'Safe\eio_stat', - 'eio_statvfs' => 'Safe\eio_statvfs', - 'eio_symlink' => 'Safe\eio_symlink', - 'eio_sync' => 'Safe\eio_sync', - 'eio_syncfs' => 'Safe\eio_syncfs', - 'eio_sync_file_range' => 'Safe\eio_sync_file_range', - 'eio_truncate' => 'Safe\eio_truncate', - 'eio_unlink' => 'Safe\eio_unlink', - 'eio_utime' => 'Safe\eio_utime', - 'eio_write' => 'Safe\eio_write', - 'error_log' => 'Safe\error_log', - 'exec' => 'Safe\exec', - 'fastcgi_finish_request' => 'Safe\fastcgi_finish_request', - 'fbird_blob_cancel' => 'Safe\fbird_blob_cancel', - 'fclose' => 'Safe\fclose', - 'fdatasync' => 'Safe\fdatasync', - 'fflush' => 'Safe\fflush', - 'fgetcsv' => 'Safe\fgetcsv', - 'file' => 'Safe\file', - 'fileatime' => 'Safe\fileatime', - 'filectime' => 'Safe\filectime', - 'fileinode' => 'Safe\fileinode', - 'filemtime' => 'Safe\filemtime', - 'fileowner' => 'Safe\fileowner', - 'fileperms' => 'Safe\fileperms', - 'filesize' => 'Safe\filesize', - 'file_get_contents' => 'Safe\file_get_contents', - 'file_put_contents' => 'Safe\file_put_contents', - 'filter_input_array' => 'Safe\filter_input_array', - 'filter_var_array' => 'Safe\filter_var_array', - 'finfo_close' => 'Safe\finfo_close', - 'finfo_open' => 'Safe\finfo_open', - 'flock' => 'Safe\flock', - 'fopen' => 'Safe\fopen', - 'fputcsv' => 'Safe\fputcsv', - 'fread' => 'Safe\fread', - 'fsockopen' => 'Safe\fsockopen', - 'fstat' => 'Safe\fstat', - 'fsync' => 'Safe\fsync', - 'ftp_alloc' => 'Safe\ftp_alloc', - 'ftp_append' => 'Safe\ftp_append', - 'ftp_cdup' => 'Safe\ftp_cdup', - 'ftp_chdir' => 'Safe\ftp_chdir', - 'ftp_chmod' => 'Safe\ftp_chmod', - 'ftp_close' => 'Safe\ftp_close', - 'ftp_connect' => 'Safe\ftp_connect', - 'ftp_delete' => 'Safe\ftp_delete', - 'ftp_fget' => 'Safe\ftp_fget', - 'ftp_fput' => 'Safe\ftp_fput', - 'ftp_get' => 'Safe\ftp_get', - 'ftp_login' => 'Safe\ftp_login', - 'ftp_mkdir' => 'Safe\ftp_mkdir', - 'ftp_mlsd' => 'Safe\ftp_mlsd', - 'ftp_nb_put' => 'Safe\ftp_nb_put', - 'ftp_nlist' => 'Safe\ftp_nlist', - 'ftp_pasv' => 'Safe\ftp_pasv', - 'ftp_put' => 'Safe\ftp_put', - 'ftp_pwd' => 'Safe\ftp_pwd', - 'ftp_raw' => 'Safe\ftp_raw', - 'ftp_rename' => 'Safe\ftp_rename', - 'ftp_rmdir' => 'Safe\ftp_rmdir', - 'ftp_site' => 'Safe\ftp_site', - 'ftp_ssl_connect' => 'Safe\ftp_ssl_connect', - 'ftp_systype' => 'Safe\ftp_systype', - 'ftruncate' => 'Safe\ftruncate', - 'fwrite' => 'Safe\fwrite', - 'getallheaders' => 'Safe\getallheaders', - 'getcwd' => 'Safe\getcwd', - 'gethostname' => 'Safe\gethostname', - 'getimagesize' => 'Safe\getimagesize', - 'getlastmod' => 'Safe\getlastmod', - 'getmygid' => 'Safe\getmygid', - 'getmyinode' => 'Safe\getmyinode', - 'getmypid' => 'Safe\getmypid', - 'getmyuid' => 'Safe\getmyuid', - 'getopt' => 'Safe\getopt', - 'getprotobyname' => 'Safe\getprotobyname', - 'getprotobynumber' => 'Safe\getprotobynumber', - 'getrusage' => 'Safe\getrusage', - 'getservbyport' => 'Safe\getservbyport', - 'get_headers' => 'Safe\get_headers', - 'get_include_path' => 'Safe\get_include_path', - 'get_meta_tags' => 'Safe\get_meta_tags', - 'glob' => 'Safe\glob', - 'gmmktime' => 'Safe\gmmktime', - 'gmp_random_seed' => 'Safe\gmp_random_seed', - 'gmstrftime' => 'Safe\gmstrftime', - 'gnupg_adddecryptkey' => 'Safe\gnupg_adddecryptkey', - 'gnupg_addencryptkey' => 'Safe\gnupg_addencryptkey', - 'gnupg_addsignkey' => 'Safe\gnupg_addsignkey', - 'gnupg_cleardecryptkeys' => 'Safe\gnupg_cleardecryptkeys', - 'gnupg_clearencryptkeys' => 'Safe\gnupg_clearencryptkeys', - 'gnupg_clearsignkeys' => 'Safe\gnupg_clearsignkeys', - 'gnupg_deletekey' => 'Safe\gnupg_deletekey', - 'gnupg_setarmor' => 'Safe\gnupg_setarmor', - 'gnupg_setsignmode' => 'Safe\gnupg_setsignmode', - 'gzclose' => 'Safe\gzclose', - 'gzcompress' => 'Safe\gzcompress', - 'gzdecode' => 'Safe\gzdecode', - 'gzdeflate' => 'Safe\gzdeflate', - 'gzencode' => 'Safe\gzencode', - 'gzfile' => 'Safe\gzfile', - 'gzgets' => 'Safe\gzgets', - 'gzgetss' => 'Safe\gzgetss', - 'gzinflate' => 'Safe\gzinflate', - 'gzopen' => 'Safe\gzopen', - 'gzpassthru' => 'Safe\gzpassthru', - 'gzread' => 'Safe\gzread', - 'gzrewind' => 'Safe\gzrewind', - 'gzuncompress' => 'Safe\gzuncompress', - 'gzwrite' => 'Safe\gzwrite', - 'hash_hkdf' => 'Safe\hash_hkdf', - 'hash_update_file' => 'Safe\hash_update_file', - 'header_register_callback' => 'Safe\header_register_callback', - 'hex2bin' => 'Safe\hex2bin', - 'highlight_file' => 'Safe\highlight_file', - 'highlight_string' => 'Safe\highlight_string', - 'hrtime' => 'Safe\hrtime', - 'ibase_add_user' => 'Safe\ibase_add_user', - 'ibase_backup' => 'Safe\ibase_backup', - 'ibase_blob_cancel' => 'Safe\ibase_blob_cancel', - 'ibase_blob_create' => 'Safe\ibase_blob_create', - 'ibase_blob_get' => 'Safe\ibase_blob_get', - 'ibase_close' => 'Safe\ibase_close', - 'ibase_commit' => 'Safe\ibase_commit', - 'ibase_commit_ret' => 'Safe\ibase_commit_ret', - 'ibase_connect' => 'Safe\ibase_connect', - 'ibase_delete_user' => 'Safe\ibase_delete_user', - 'ibase_drop_db' => 'Safe\ibase_drop_db', - 'ibase_free_event_handler' => 'Safe\ibase_free_event_handler', - 'ibase_free_query' => 'Safe\ibase_free_query', - 'ibase_free_result' => 'Safe\ibase_free_result', - 'ibase_maintain_db' => 'Safe\ibase_maintain_db', - 'ibase_modify_user' => 'Safe\ibase_modify_user', - 'ibase_name_result' => 'Safe\ibase_name_result', - 'ibase_pconnect' => 'Safe\ibase_pconnect', - 'ibase_restore' => 'Safe\ibase_restore', - 'ibase_rollback' => 'Safe\ibase_rollback', - 'ibase_rollback_ret' => 'Safe\ibase_rollback_ret', - 'ibase_service_attach' => 'Safe\ibase_service_attach', - 'ibase_service_detach' => 'Safe\ibase_service_detach', - 'iconv' => 'Safe\iconv', - 'iconv_get_encoding' => 'Safe\iconv_get_encoding', - 'iconv_set_encoding' => 'Safe\iconv_set_encoding', - 'idate' => 'Safe\idate', - 'image2wbmp' => 'Safe\image2wbmp', - 'imageaffine' => 'Safe\imageaffine', - 'imageaffinematrixconcat' => 'Safe\imageaffinematrixconcat', - 'imageaffinematrixget' => 'Safe\imageaffinematrixget', - 'imagealphablending' => 'Safe\imagealphablending', - 'imageantialias' => 'Safe\imageantialias', - 'imagearc' => 'Safe\imagearc', - 'imageavif' => 'Safe\imageavif', - 'imagebmp' => 'Safe\imagebmp', - 'imagechar' => 'Safe\imagechar', - 'imagecharup' => 'Safe\imagecharup', - 'imagecolorat' => 'Safe\imagecolorat', - 'imagecolordeallocate' => 'Safe\imagecolordeallocate', - 'imagecolormatch' => 'Safe\imagecolormatch', - 'imagecolorset' => 'Safe\imagecolorset', - 'imageconvolution' => 'Safe\imageconvolution', - 'imagecopy' => 'Safe\imagecopy', - 'imagecopymerge' => 'Safe\imagecopymerge', - 'imagecopymergegray' => 'Safe\imagecopymergegray', - 'imagecopyresampled' => 'Safe\imagecopyresampled', - 'imagecopyresized' => 'Safe\imagecopyresized', - 'imagecreate' => 'Safe\imagecreate', - 'imagecreatefromavif' => 'Safe\imagecreatefromavif', - 'imagecreatefrombmp' => 'Safe\imagecreatefrombmp', - 'imagecreatefromgd' => 'Safe\imagecreatefromgd', - 'imagecreatefromgd2' => 'Safe\imagecreatefromgd2', - 'imagecreatefromgd2part' => 'Safe\imagecreatefromgd2part', - 'imagecreatefromgif' => 'Safe\imagecreatefromgif', - 'imagecreatefromjpeg' => 'Safe\imagecreatefromjpeg', - 'imagecreatefrompng' => 'Safe\imagecreatefrompng', - 'imagecreatefromstring' => 'Safe\imagecreatefromstring', - 'imagecreatefromtga' => 'Safe\imagecreatefromtga', - 'imagecreatefromwbmp' => 'Safe\imagecreatefromwbmp', - 'imagecreatefromwebp' => 'Safe\imagecreatefromwebp', - 'imagecreatefromxbm' => 'Safe\imagecreatefromxbm', - 'imagecreatefromxpm' => 'Safe\imagecreatefromxpm', - 'imagecreatetruecolor' => 'Safe\imagecreatetruecolor', - 'imagecrop' => 'Safe\imagecrop', - 'imagecropauto' => 'Safe\imagecropauto', - 'imagedashedline' => 'Safe\imagedashedline', - 'imagedestroy' => 'Safe\imagedestroy', - 'imageellipse' => 'Safe\imageellipse', - 'imagefill' => 'Safe\imagefill', - 'imagefilledarc' => 'Safe\imagefilledarc', - 'imagefilledellipse' => 'Safe\imagefilledellipse', - 'imagefilledrectangle' => 'Safe\imagefilledrectangle', - 'imagefilltoborder' => 'Safe\imagefilltoborder', - 'imagefilter' => 'Safe\imagefilter', - 'imageflip' => 'Safe\imageflip', - 'imageftbbox' => 'Safe\imageftbbox', - 'imagefttext' => 'Safe\imagefttext', - 'imagegammacorrect' => 'Safe\imagegammacorrect', - 'imagegd' => 'Safe\imagegd', - 'imagegd2' => 'Safe\imagegd2', - 'imagegif' => 'Safe\imagegif', - 'imagegrabscreen' => 'Safe\imagegrabscreen', - 'imagegrabwindow' => 'Safe\imagegrabwindow', - 'imagejpeg' => 'Safe\imagejpeg', - 'imagelayereffect' => 'Safe\imagelayereffect', - 'imageline' => 'Safe\imageline', - 'imageloadfont' => 'Safe\imageloadfont', - 'imagepng' => 'Safe\imagepng', - 'imagerectangle' => 'Safe\imagerectangle', - 'imageresolution' => 'Safe\imageresolution', - 'imagerotate' => 'Safe\imagerotate', - 'imagesavealpha' => 'Safe\imagesavealpha', - 'imagescale' => 'Safe\imagescale', - 'imagesetbrush' => 'Safe\imagesetbrush', - 'imagesetclip' => 'Safe\imagesetclip', - 'imagesetinterpolation' => 'Safe\imagesetinterpolation', - 'imagesetpixel' => 'Safe\imagesetpixel', - 'imagesetstyle' => 'Safe\imagesetstyle', - 'imagesetthickness' => 'Safe\imagesetthickness', - 'imagesettile' => 'Safe\imagesettile', - 'imagestring' => 'Safe\imagestring', - 'imagestringup' => 'Safe\imagestringup', - 'imagesx' => 'Safe\imagesx', - 'imagesy' => 'Safe\imagesy', - 'imagetruecolortopalette' => 'Safe\imagetruecolortopalette', - 'imagettfbbox' => 'Safe\imagettfbbox', - 'imagettftext' => 'Safe\imagettftext', - 'imagewbmp' => 'Safe\imagewbmp', - 'imagewebp' => 'Safe\imagewebp', - 'imagexbm' => 'Safe\imagexbm', - 'image_type_to_extension' => 'Safe\image_type_to_extension', - 'imap_8bit' => 'Safe\imap_8bit', - 'imap_append' => 'Safe\imap_append', - 'imap_base64' => 'Safe\imap_base64', - 'imap_binary' => 'Safe\imap_binary', - 'imap_body' => 'Safe\imap_body', - 'imap_bodystruct' => 'Safe\imap_bodystruct', - 'imap_check' => 'Safe\imap_check', - 'imap_clearflag_full' => 'Safe\imap_clearflag_full', - 'imap_close' => 'Safe\imap_close', - 'imap_createmailbox' => 'Safe\imap_createmailbox', - 'imap_deletemailbox' => 'Safe\imap_deletemailbox', - 'imap_fetchbody' => 'Safe\imap_fetchbody', - 'imap_fetchheader' => 'Safe\imap_fetchheader', - 'imap_fetchmime' => 'Safe\imap_fetchmime', - 'imap_fetchstructure' => 'Safe\imap_fetchstructure', - 'imap_fetch_overview' => 'Safe\imap_fetch_overview', - 'imap_gc' => 'Safe\imap_gc', - 'imap_getacl' => 'Safe\imap_getacl', - 'imap_getmailboxes' => 'Safe\imap_getmailboxes', - 'imap_getsubscribed' => 'Safe\imap_getsubscribed', - 'imap_headerinfo' => 'Safe\imap_headerinfo', - 'imap_headers' => 'Safe\imap_headers', - 'imap_listscan' => 'Safe\imap_listscan', - 'imap_lsub' => 'Safe\imap_lsub', - 'imap_mail' => 'Safe\imap_mail', - 'imap_mailboxmsginfo' => 'Safe\imap_mailboxmsginfo', - 'imap_mail_compose' => 'Safe\imap_mail_compose', - 'imap_mail_copy' => 'Safe\imap_mail_copy', - 'imap_mail_move' => 'Safe\imap_mail_move', - 'imap_mime_header_decode' => 'Safe\imap_mime_header_decode', - 'imap_mutf7_to_utf8' => 'Safe\imap_mutf7_to_utf8', - 'imap_num_msg' => 'Safe\imap_num_msg', - 'imap_open' => 'Safe\imap_open', - 'imap_qprint' => 'Safe\imap_qprint', - 'imap_renamemailbox' => 'Safe\imap_renamemailbox', - 'imap_rfc822_write_address' => 'Safe\imap_rfc822_write_address', - 'imap_savebody' => 'Safe\imap_savebody', - 'imap_setacl' => 'Safe\imap_setacl', - 'imap_setflag_full' => 'Safe\imap_setflag_full', - 'imap_set_quota' => 'Safe\imap_set_quota', - 'imap_sort' => 'Safe\imap_sort', - 'imap_status' => 'Safe\imap_status', - 'imap_subscribe' => 'Safe\imap_subscribe', - 'imap_thread' => 'Safe\imap_thread', - 'imap_timeout' => 'Safe\imap_timeout', - 'imap_undelete' => 'Safe\imap_undelete', - 'imap_unsubscribe' => 'Safe\imap_unsubscribe', - 'imap_utf8_to_mutf7' => 'Safe\imap_utf8_to_mutf7', - 'inet_ntop' => 'Safe\inet_ntop', - 'inflate_add' => 'Safe\inflate_add', - 'inflate_get_read_len' => 'Safe\inflate_get_read_len', - 'inflate_get_status' => 'Safe\inflate_get_status', - 'inflate_init' => 'Safe\inflate_init', - 'ini_get' => 'Safe\ini_get', - 'ini_set' => 'Safe\ini_set', - 'inotify_init' => 'Safe\inotify_init', - 'inotify_rm_watch' => 'Safe\inotify_rm_watch', - 'iptcembed' => 'Safe\iptcembed', - 'iptcparse' => 'Safe\iptcparse', - 'jpeg2wbmp' => 'Safe\jpeg2wbmp', - 'json_decode' => 'Safe\json_decode', - 'json_encode' => 'Safe\json_encode', - 'lchgrp' => 'Safe\lchgrp', - 'lchown' => 'Safe\lchown', - 'ldap_8859_to_t61' => 'Safe\ldap_8859_to_t61', - 'ldap_add' => 'Safe\ldap_add', - 'ldap_bind' => 'Safe\ldap_bind', - 'ldap_control_paged_result' => 'Safe\ldap_control_paged_result', - 'ldap_control_paged_result_response' => 'Safe\ldap_control_paged_result_response', - 'ldap_count_entries' => 'Safe\ldap_count_entries', - 'ldap_delete' => 'Safe\ldap_delete', - 'ldap_dn2ufn' => 'Safe\ldap_dn2ufn', - 'ldap_exop' => 'Safe\ldap_exop', - 'ldap_exop_passwd' => 'Safe\ldap_exop_passwd', - 'ldap_exop_whoami' => 'Safe\ldap_exop_whoami', - 'ldap_explode_dn' => 'Safe\ldap_explode_dn', - 'ldap_first_attribute' => 'Safe\ldap_first_attribute', - 'ldap_first_entry' => 'Safe\ldap_first_entry', - 'ldap_free_result' => 'Safe\ldap_free_result', - 'ldap_get_attributes' => 'Safe\ldap_get_attributes', - 'ldap_get_dn' => 'Safe\ldap_get_dn', - 'ldap_get_entries' => 'Safe\ldap_get_entries', - 'ldap_get_option' => 'Safe\ldap_get_option', - 'ldap_get_values' => 'Safe\ldap_get_values', - 'ldap_get_values_len' => 'Safe\ldap_get_values_len', - 'ldap_modify_batch' => 'Safe\ldap_modify_batch', - 'ldap_mod_add' => 'Safe\ldap_mod_add', - 'ldap_mod_del' => 'Safe\ldap_mod_del', - 'ldap_mod_replace' => 'Safe\ldap_mod_replace', - 'ldap_next_attribute' => 'Safe\ldap_next_attribute', - 'ldap_parse_exop' => 'Safe\ldap_parse_exop', - 'ldap_parse_result' => 'Safe\ldap_parse_result', - 'ldap_rename' => 'Safe\ldap_rename', - 'ldap_sasl_bind' => 'Safe\ldap_sasl_bind', - 'ldap_set_option' => 'Safe\ldap_set_option', - 'ldap_unbind' => 'Safe\ldap_unbind', - 'libxml_get_last_error' => 'Safe\libxml_get_last_error', - 'libxml_set_external_entity_loader' => 'Safe\libxml_set_external_entity_loader', - 'link' => 'Safe\link', - 'long2ip' => 'Safe\long2ip', - 'lstat' => 'Safe\lstat', - 'lzf_compress' => 'Safe\lzf_compress', - 'lzf_decompress' => 'Safe\lzf_decompress', - 'mailparse_msg_extract_part_file' => 'Safe\mailparse_msg_extract_part_file', - 'mailparse_msg_free' => 'Safe\mailparse_msg_free', - 'mailparse_msg_parse' => 'Safe\mailparse_msg_parse', - 'mailparse_msg_parse_file' => 'Safe\mailparse_msg_parse_file', - 'mailparse_stream_encode' => 'Safe\mailparse_stream_encode', - 'mb_chr' => 'Safe\mb_chr', - 'mb_convert_encoding' => 'Safe\mb_convert_encoding', - 'mb_detect_order' => 'Safe\mb_detect_order', - 'mb_encoding_aliases' => 'Safe\mb_encoding_aliases', - 'mb_eregi_replace' => 'Safe\mb_eregi_replace', - 'mb_ereg_replace' => 'Safe\mb_ereg_replace', - 'mb_ereg_replace_callback' => 'Safe\mb_ereg_replace_callback', - 'mb_ereg_search_getregs' => 'Safe\mb_ereg_search_getregs', - 'mb_ereg_search_init' => 'Safe\mb_ereg_search_init', - 'mb_ereg_search_regs' => 'Safe\mb_ereg_search_regs', - 'mb_ereg_search_setpos' => 'Safe\mb_ereg_search_setpos', - 'mb_get_info' => 'Safe\mb_get_info', - 'mb_http_output' => 'Safe\mb_http_output', - 'mb_internal_encoding' => 'Safe\mb_internal_encoding', - 'mb_ord' => 'Safe\mb_ord', - 'mb_parse_str' => 'Safe\mb_parse_str', - 'mb_regex_encoding' => 'Safe\mb_regex_encoding', - 'mb_send_mail' => 'Safe\mb_send_mail', - 'mb_split' => 'Safe\mb_split', - 'md5_file' => 'Safe\md5_file', - 'mime_content_type' => 'Safe\mime_content_type', - 'mkdir' => 'Safe\mkdir', - 'msg_get_queue' => 'Safe\msg_get_queue', - 'msg_queue_exists' => 'Safe\msg_queue_exists', - 'msg_receive' => 'Safe\msg_receive', - 'msg_remove_queue' => 'Safe\msg_remove_queue', - 'msg_send' => 'Safe\msg_send', - 'msg_set_queue' => 'Safe\msg_set_queue', - 'msg_stat_queue' => 'Safe\msg_stat_queue', - 'mysql_close' => 'Safe\mysql_close', - 'mysql_connect' => 'Safe\mysql_connect', - 'mysql_create_db' => 'Safe\mysql_create_db', - 'mysql_data_seek' => 'Safe\mysql_data_seek', - 'mysql_db_name' => 'Safe\mysql_db_name', - 'mysql_db_query' => 'Safe\mysql_db_query', - 'mysql_drop_db' => 'Safe\mysql_drop_db', - 'mysql_fetch_lengths' => 'Safe\mysql_fetch_lengths', - 'mysql_field_flags' => 'Safe\mysql_field_flags', - 'mysql_field_len' => 'Safe\mysql_field_len', - 'mysql_field_name' => 'Safe\mysql_field_name', - 'mysql_field_seek' => 'Safe\mysql_field_seek', - 'mysql_free_result' => 'Safe\mysql_free_result', - 'mysql_get_host_info' => 'Safe\mysql_get_host_info', - 'mysql_get_proto_info' => 'Safe\mysql_get_proto_info', - 'mysql_get_server_info' => 'Safe\mysql_get_server_info', - 'mysql_info' => 'Safe\mysql_info', - 'mysql_list_dbs' => 'Safe\mysql_list_dbs', - 'mysql_list_fields' => 'Safe\mysql_list_fields', - 'mysql_list_processes' => 'Safe\mysql_list_processes', - 'mysql_list_tables' => 'Safe\mysql_list_tables', - 'mysql_num_fields' => 'Safe\mysql_num_fields', - 'mysql_num_rows' => 'Safe\mysql_num_rows', - 'mysql_query' => 'Safe\mysql_query', - 'mysql_real_escape_string' => 'Safe\mysql_real_escape_string', - 'mysql_result' => 'Safe\mysql_result', - 'mysql_select_db' => 'Safe\mysql_select_db', - 'mysql_set_charset' => 'Safe\mysql_set_charset', - 'mysql_tablename' => 'Safe\mysql_tablename', - 'mysql_thread_id' => 'Safe\mysql_thread_id', - 'mysql_unbuffered_query' => 'Safe\mysql_unbuffered_query', - 'net_get_interfaces' => 'Safe\net_get_interfaces', - 'ob_clean' => 'Safe\ob_clean', - 'ob_end_clean' => 'Safe\ob_end_clean', - 'ob_end_flush' => 'Safe\ob_end_flush', - 'ob_flush' => 'Safe\ob_flush', - 'ob_start' => 'Safe\ob_start', - 'oci_bind_array_by_name' => 'Safe\oci_bind_array_by_name', - 'oci_bind_by_name' => 'Safe\oci_bind_by_name', - 'oci_cancel' => 'Safe\oci_cancel', - 'oci_commit' => 'Safe\oci_commit', - 'oci_connect' => 'Safe\oci_connect', - 'oci_define_by_name' => 'Safe\oci_define_by_name', - 'oci_execute' => 'Safe\oci_execute', - 'oci_field_name' => 'Safe\oci_field_name', - 'oci_field_precision' => 'Safe\oci_field_precision', - 'oci_field_scale' => 'Safe\oci_field_scale', - 'oci_field_size' => 'Safe\oci_field_size', - 'oci_field_type' => 'Safe\oci_field_type', - 'oci_field_type_raw' => 'Safe\oci_field_type_raw', - 'oci_free_descriptor' => 'Safe\oci_free_descriptor', - 'oci_free_statement' => 'Safe\oci_free_statement', - 'oci_new_collection' => 'Safe\oci_new_collection', - 'oci_new_connect' => 'Safe\oci_new_connect', - 'oci_new_cursor' => 'Safe\oci_new_cursor', - 'oci_new_descriptor' => 'Safe\oci_new_descriptor', - 'oci_num_rows' => 'Safe\oci_num_rows', - 'oci_parse' => 'Safe\oci_parse', - 'oci_pconnect' => 'Safe\oci_pconnect', - 'oci_register_taf_callback' => 'Safe\oci_register_taf_callback', - 'oci_result' => 'Safe\oci_result', - 'oci_rollback' => 'Safe\oci_rollback', - 'oci_server_version' => 'Safe\oci_server_version', - 'oci_set_action' => 'Safe\oci_set_action', - 'oci_set_call_timeout' => 'Safe\oci_set_call_timeout', - 'oci_set_client_identifier' => 'Safe\oci_set_client_identifier', - 'oci_set_client_info' => 'Safe\oci_set_client_info', - 'oci_set_db_operation' => 'Safe\oci_set_db_operation', - 'oci_set_edition' => 'Safe\oci_set_edition', - 'oci_set_module_name' => 'Safe\oci_set_module_name', - 'oci_set_prefetch' => 'Safe\oci_set_prefetch', - 'oci_set_prefetch_lob' => 'Safe\oci_set_prefetch_lob', - 'oci_statement_type' => 'Safe\oci_statement_type', - 'oci_unregister_taf_callback' => 'Safe\oci_unregister_taf_callback', - 'odbc_autocommit' => 'Safe\odbc_autocommit', - 'odbc_binmode' => 'Safe\odbc_binmode', - 'odbc_columnprivileges' => 'Safe\odbc_columnprivileges', - 'odbc_columns' => 'Safe\odbc_columns', - 'odbc_commit' => 'Safe\odbc_commit', - 'odbc_connect' => 'Safe\odbc_connect', - 'odbc_cursor' => 'Safe\odbc_cursor', - 'odbc_data_source' => 'Safe\odbc_data_source', - 'odbc_exec' => 'Safe\odbc_exec', - 'odbc_execute' => 'Safe\odbc_execute', - 'odbc_fetch_into' => 'Safe\odbc_fetch_into', - 'odbc_field_len' => 'Safe\odbc_field_len', - 'odbc_field_name' => 'Safe\odbc_field_name', - 'odbc_field_num' => 'Safe\odbc_field_num', - 'odbc_field_scale' => 'Safe\odbc_field_scale', - 'odbc_field_type' => 'Safe\odbc_field_type', - 'odbc_foreignkeys' => 'Safe\odbc_foreignkeys', - 'odbc_gettypeinfo' => 'Safe\odbc_gettypeinfo', - 'odbc_longreadlen' => 'Safe\odbc_longreadlen', - 'odbc_pconnect' => 'Safe\odbc_pconnect', - 'odbc_prepare' => 'Safe\odbc_prepare', - 'odbc_primarykeys' => 'Safe\odbc_primarykeys', - 'odbc_procedurecolumns' => 'Safe\odbc_procedurecolumns', - 'odbc_procedures' => 'Safe\odbc_procedures', - 'odbc_result' => 'Safe\odbc_result', - 'odbc_result_all' => 'Safe\odbc_result_all', - 'odbc_rollback' => 'Safe\odbc_rollback', - 'odbc_setoption' => 'Safe\odbc_setoption', - 'odbc_specialcolumns' => 'Safe\odbc_specialcolumns', - 'odbc_statistics' => 'Safe\odbc_statistics', - 'odbc_tableprivileges' => 'Safe\odbc_tableprivileges', - 'odbc_tables' => 'Safe\odbc_tables', - 'opcache_compile_file' => 'Safe\opcache_compile_file', - 'opcache_get_status' => 'Safe\opcache_get_status', - 'opendir' => 'Safe\opendir', - 'openlog' => 'Safe\openlog', - 'openssl_cipher_iv_length' => 'Safe\openssl_cipher_iv_length', - 'openssl_cipher_key_length' => 'Safe\openssl_cipher_key_length', - 'openssl_cms_decrypt' => 'Safe\openssl_cms_decrypt', - 'openssl_cms_encrypt' => 'Safe\openssl_cms_encrypt', - 'openssl_cms_read' => 'Safe\openssl_cms_read', - 'openssl_cms_sign' => 'Safe\openssl_cms_sign', - 'openssl_cms_verify' => 'Safe\openssl_cms_verify', - 'openssl_csr_export' => 'Safe\openssl_csr_export', - 'openssl_csr_export_to_file' => 'Safe\openssl_csr_export_to_file', - 'openssl_csr_get_public_key' => 'Safe\openssl_csr_get_public_key', - 'openssl_csr_get_subject' => 'Safe\openssl_csr_get_subject', - 'openssl_csr_new' => 'Safe\openssl_csr_new', - 'openssl_csr_sign' => 'Safe\openssl_csr_sign', - 'openssl_decrypt' => 'Safe\openssl_decrypt', - 'openssl_dh_compute_key' => 'Safe\openssl_dh_compute_key', - 'openssl_digest' => 'Safe\openssl_digest', - 'openssl_encrypt' => 'Safe\openssl_encrypt', - 'openssl_get_curve_names' => 'Safe\openssl_get_curve_names', - 'openssl_open' => 'Safe\openssl_open', - 'openssl_pbkdf2' => 'Safe\openssl_pbkdf2', - 'openssl_pkcs7_decrypt' => 'Safe\openssl_pkcs7_decrypt', - 'openssl_pkcs7_encrypt' => 'Safe\openssl_pkcs7_encrypt', - 'openssl_pkcs7_read' => 'Safe\openssl_pkcs7_read', - 'openssl_pkcs7_sign' => 'Safe\openssl_pkcs7_sign', - 'openssl_pkcs12_export' => 'Safe\openssl_pkcs12_export', - 'openssl_pkcs12_export_to_file' => 'Safe\openssl_pkcs12_export_to_file', - 'openssl_pkcs12_read' => 'Safe\openssl_pkcs12_read', - 'openssl_pkey_derive' => 'Safe\openssl_pkey_derive', - 'openssl_pkey_export' => 'Safe\openssl_pkey_export', - 'openssl_pkey_export_to_file' => 'Safe\openssl_pkey_export_to_file', - 'openssl_pkey_get_details' => 'Safe\openssl_pkey_get_details', - 'openssl_pkey_get_private' => 'Safe\openssl_pkey_get_private', - 'openssl_pkey_get_public' => 'Safe\openssl_pkey_get_public', - 'openssl_pkey_new' => 'Safe\openssl_pkey_new', - 'openssl_private_decrypt' => 'Safe\openssl_private_decrypt', - 'openssl_private_encrypt' => 'Safe\openssl_private_encrypt', - 'openssl_public_decrypt' => 'Safe\openssl_public_decrypt', - 'openssl_public_encrypt' => 'Safe\openssl_public_encrypt', - 'openssl_seal' => 'Safe\openssl_seal', - 'openssl_sign' => 'Safe\openssl_sign', - 'openssl_spki_export' => 'Safe\openssl_spki_export', - 'openssl_spki_export_challenge' => 'Safe\openssl_spki_export_challenge', - 'openssl_spki_new' => 'Safe\openssl_spki_new', - 'openssl_spki_verify' => 'Safe\openssl_spki_verify', - 'openssl_verify' => 'Safe\openssl_verify', - 'openssl_x509_export' => 'Safe\openssl_x509_export', - 'openssl_x509_export_to_file' => 'Safe\openssl_x509_export_to_file', - 'openssl_x509_fingerprint' => 'Safe\openssl_x509_fingerprint', - 'openssl_x509_read' => 'Safe\openssl_x509_read', - 'output_add_rewrite_var' => 'Safe\output_add_rewrite_var', - 'output_reset_rewrite_vars' => 'Safe\output_reset_rewrite_vars', - 'pack' => 'Safe\pack', - 'parse_ini_file' => 'Safe\parse_ini_file', - 'parse_ini_string' => 'Safe\parse_ini_string', - 'parse_url' => 'Safe\parse_url', - 'passthru' => 'Safe\passthru', - 'pcntl_getpriority' => 'Safe\pcntl_getpriority', - 'pcntl_setpriority' => 'Safe\pcntl_setpriority', - 'pcntl_signal' => 'Safe\pcntl_signal', - 'pcntl_signal_dispatch' => 'Safe\pcntl_signal_dispatch', - 'pcntl_sigprocmask' => 'Safe\pcntl_sigprocmask', - 'pcntl_sigtimedwait' => 'Safe\pcntl_sigtimedwait', - 'pcntl_sigwaitinfo' => 'Safe\pcntl_sigwaitinfo', - 'pfsockopen' => 'Safe\pfsockopen', - 'pg_cancel_query' => 'Safe\pg_cancel_query', - 'pg_connect' => 'Safe\pg_connect', - 'pg_connection_reset' => 'Safe\pg_connection_reset', - 'pg_convert' => 'Safe\pg_convert', - 'pg_copy_from' => 'Safe\pg_copy_from', - 'pg_copy_to' => 'Safe\pg_copy_to', - 'pg_delete' => 'Safe\pg_delete', - 'pg_end_copy' => 'Safe\pg_end_copy', - 'pg_execute' => 'Safe\pg_execute', - 'pg_field_table' => 'Safe\pg_field_table', - 'pg_flush' => 'Safe\pg_flush', - 'pg_free_result' => 'Safe\pg_free_result', - 'pg_host' => 'Safe\pg_host', - 'pg_insert' => 'Safe\pg_insert', - 'pg_last_oid' => 'Safe\pg_last_oid', - 'pg_lo_close' => 'Safe\pg_lo_close', - 'pg_lo_export' => 'Safe\pg_lo_export', - 'pg_lo_import' => 'Safe\pg_lo_import', - 'pg_lo_open' => 'Safe\pg_lo_open', - 'pg_lo_read' => 'Safe\pg_lo_read', - 'pg_lo_seek' => 'Safe\pg_lo_seek', - 'pg_lo_truncate' => 'Safe\pg_lo_truncate', - 'pg_lo_unlink' => 'Safe\pg_lo_unlink', - 'pg_lo_write' => 'Safe\pg_lo_write', - 'pg_meta_data' => 'Safe\pg_meta_data', - 'pg_parameter_status' => 'Safe\pg_parameter_status', - 'pg_pconnect' => 'Safe\pg_pconnect', - 'pg_ping' => 'Safe\pg_ping', - 'pg_prepare' => 'Safe\pg_prepare', - 'pg_put_line' => 'Safe\pg_put_line', - 'pg_query' => 'Safe\pg_query', - 'pg_query_params' => 'Safe\pg_query_params', - 'pg_result_error_field' => 'Safe\pg_result_error_field', - 'pg_result_seek' => 'Safe\pg_result_seek', - 'pg_select' => 'Safe\pg_select', - 'pg_socket' => 'Safe\pg_socket', - 'pg_trace' => 'Safe\pg_trace', - 'pg_update' => 'Safe\pg_update', - 'phpcredits' => 'Safe\phpcredits', - 'phpinfo' => 'Safe\phpinfo', - 'php_sapi_name' => 'Safe\php_sapi_name', - 'png2wbmp' => 'Safe\png2wbmp', - 'posix_access' => 'Safe\posix_access', - 'posix_getgrgid' => 'Safe\posix_getgrgid', - 'posix_getgrnam' => 'Safe\posix_getgrnam', - 'posix_getgroups' => 'Safe\posix_getgroups', - 'posix_getlogin' => 'Safe\posix_getlogin', - 'posix_getpwuid' => 'Safe\posix_getpwuid', - 'posix_getrlimit' => 'Safe\posix_getrlimit', - 'posix_getsid' => 'Safe\posix_getsid', - 'posix_initgroups' => 'Safe\posix_initgroups', - 'posix_kill' => 'Safe\posix_kill', - 'posix_mkfifo' => 'Safe\posix_mkfifo', - 'posix_mknod' => 'Safe\posix_mknod', - 'posix_setegid' => 'Safe\posix_setegid', - 'posix_seteuid' => 'Safe\posix_seteuid', - 'posix_setgid' => 'Safe\posix_setgid', - 'posix_setpgid' => 'Safe\posix_setpgid', - 'posix_setrlimit' => 'Safe\posix_setrlimit', - 'posix_setuid' => 'Safe\posix_setuid', - 'posix_times' => 'Safe\posix_times', - 'posix_uname' => 'Safe\posix_uname', - 'preg_grep' => 'Safe\preg_grep', - 'preg_match' => 'Safe\preg_match', - 'preg_match_all' => 'Safe\preg_match_all', - 'preg_replace' => 'Safe\preg_replace', - 'preg_split' => 'Safe\preg_split', - 'proc_nice' => 'Safe\proc_nice', - 'pspell_add_to_personal' => 'Safe\pspell_add_to_personal', - 'pspell_add_to_session' => 'Safe\pspell_add_to_session', - 'pspell_clear_session' => 'Safe\pspell_clear_session', - 'pspell_config_create' => 'Safe\pspell_config_create', - 'pspell_config_data_dir' => 'Safe\pspell_config_data_dir', - 'pspell_config_dict_dir' => 'Safe\pspell_config_dict_dir', - 'pspell_config_ignore' => 'Safe\pspell_config_ignore', - 'pspell_config_mode' => 'Safe\pspell_config_mode', - 'pspell_config_personal' => 'Safe\pspell_config_personal', - 'pspell_config_repl' => 'Safe\pspell_config_repl', - 'pspell_config_runtogether' => 'Safe\pspell_config_runtogether', - 'pspell_config_save_repl' => 'Safe\pspell_config_save_repl', - 'pspell_new' => 'Safe\pspell_new', - 'pspell_new_config' => 'Safe\pspell_new_config', - 'pspell_new_personal' => 'Safe\pspell_new_personal', - 'pspell_save_wordlist' => 'Safe\pspell_save_wordlist', - 'pspell_store_replacement' => 'Safe\pspell_store_replacement', - 'ps_add_launchlink' => 'Safe\ps_add_launchlink', - 'ps_add_locallink' => 'Safe\ps_add_locallink', - 'ps_add_note' => 'Safe\ps_add_note', - 'ps_add_pdflink' => 'Safe\ps_add_pdflink', - 'ps_add_weblink' => 'Safe\ps_add_weblink', - 'ps_arc' => 'Safe\ps_arc', - 'ps_arcn' => 'Safe\ps_arcn', - 'ps_begin_page' => 'Safe\ps_begin_page', - 'ps_begin_pattern' => 'Safe\ps_begin_pattern', - 'ps_begin_template' => 'Safe\ps_begin_template', - 'ps_circle' => 'Safe\ps_circle', - 'ps_clip' => 'Safe\ps_clip', - 'ps_close' => 'Safe\ps_close', - 'ps_closepath' => 'Safe\ps_closepath', - 'ps_closepath_stroke' => 'Safe\ps_closepath_stroke', - 'ps_close_image' => 'Safe\ps_close_image', - 'ps_continue_text' => 'Safe\ps_continue_text', - 'ps_curveto' => 'Safe\ps_curveto', - 'ps_delete' => 'Safe\ps_delete', - 'ps_end_page' => 'Safe\ps_end_page', - 'ps_end_pattern' => 'Safe\ps_end_pattern', - 'ps_end_template' => 'Safe\ps_end_template', - 'ps_fill' => 'Safe\ps_fill', - 'ps_fill_stroke' => 'Safe\ps_fill_stroke', - 'ps_get_parameter' => 'Safe\ps_get_parameter', - 'ps_hyphenate' => 'Safe\ps_hyphenate', - 'ps_include_file' => 'Safe\ps_include_file', - 'ps_lineto' => 'Safe\ps_lineto', - 'ps_moveto' => 'Safe\ps_moveto', - 'ps_new' => 'Safe\ps_new', - 'ps_open_file' => 'Safe\ps_open_file', - 'ps_place_image' => 'Safe\ps_place_image', - 'ps_rect' => 'Safe\ps_rect', - 'ps_restore' => 'Safe\ps_restore', - 'ps_rotate' => 'Safe\ps_rotate', - 'ps_save' => 'Safe\ps_save', - 'ps_scale' => 'Safe\ps_scale', - 'ps_setcolor' => 'Safe\ps_setcolor', - 'ps_setdash' => 'Safe\ps_setdash', - 'ps_setflat' => 'Safe\ps_setflat', - 'ps_setfont' => 'Safe\ps_setfont', - 'ps_setgray' => 'Safe\ps_setgray', - 'ps_setlinecap' => 'Safe\ps_setlinecap', - 'ps_setlinejoin' => 'Safe\ps_setlinejoin', - 'ps_setlinewidth' => 'Safe\ps_setlinewidth', - 'ps_setmiterlimit' => 'Safe\ps_setmiterlimit', - 'ps_setoverprintmode' => 'Safe\ps_setoverprintmode', - 'ps_setpolydash' => 'Safe\ps_setpolydash', - 'ps_set_border_color' => 'Safe\ps_set_border_color', - 'ps_set_border_dash' => 'Safe\ps_set_border_dash', - 'ps_set_border_style' => 'Safe\ps_set_border_style', - 'ps_set_info' => 'Safe\ps_set_info', - 'ps_set_parameter' => 'Safe\ps_set_parameter', - 'ps_set_text_pos' => 'Safe\ps_set_text_pos', - 'ps_set_value' => 'Safe\ps_set_value', - 'ps_shading' => 'Safe\ps_shading', - 'ps_shading_pattern' => 'Safe\ps_shading_pattern', - 'ps_shfill' => 'Safe\ps_shfill', - 'ps_show' => 'Safe\ps_show', - 'ps_show2' => 'Safe\ps_show2', - 'ps_show_xy' => 'Safe\ps_show_xy', - 'ps_show_xy2' => 'Safe\ps_show_xy2', - 'ps_stroke' => 'Safe\ps_stroke', - 'ps_symbol' => 'Safe\ps_symbol', - 'ps_translate' => 'Safe\ps_translate', - 'putenv' => 'Safe\putenv', - 'readfile' => 'Safe\readfile', - 'readgzfile' => 'Safe\readgzfile', - 'readline_add_history' => 'Safe\readline_add_history', - 'readline_callback_handler_install' => 'Safe\readline_callback_handler_install', - 'readline_clear_history' => 'Safe\readline_clear_history', - 'readline_completion_function' => 'Safe\readline_completion_function', - 'readline_read_history' => 'Safe\readline_read_history', - 'readline_write_history' => 'Safe\readline_write_history', - 'readlink' => 'Safe\readlink', - 'realpath' => 'Safe\realpath', - 'register_tick_function' => 'Safe\register_tick_function', - 'rename' => 'Safe\rename', - 'rewind' => 'Safe\rewind', - 'rmdir' => 'Safe\rmdir', - 'rpmaddtag' => 'Safe\rpmaddtag', - 'rrd_create' => 'Safe\rrd_create', - 'rrd_first' => 'Safe\rrd_first', - 'rrd_graph' => 'Safe\rrd_graph', - 'rrd_info' => 'Safe\rrd_info', - 'rrd_lastupdate' => 'Safe\rrd_lastupdate', - 'rrd_restore' => 'Safe\rrd_restore', - 'rrd_tune' => 'Safe\rrd_tune', - 'rrd_update' => 'Safe\rrd_update', - 'rrd_xport' => 'Safe\rrd_xport', - 'sapi_windows_cp_conv' => 'Safe\sapi_windows_cp_conv', - 'sapi_windows_cp_set' => 'Safe\sapi_windows_cp_set', - 'sapi_windows_generate_ctrl_event' => 'Safe\sapi_windows_generate_ctrl_event', - 'sapi_windows_set_ctrl_handler' => 'Safe\sapi_windows_set_ctrl_handler', - 'sapi_windows_vt100_support' => 'Safe\sapi_windows_vt100_support', - 'scandir' => 'Safe\scandir', - 'sem_acquire' => 'Safe\sem_acquire', - 'sem_get' => 'Safe\sem_get', - 'sem_release' => 'Safe\sem_release', - 'sem_remove' => 'Safe\sem_remove', - 'session_abort' => 'Safe\session_abort', - 'session_create_id' => 'Safe\session_create_id', - 'session_decode' => 'Safe\session_decode', - 'session_destroy' => 'Safe\session_destroy', - 'session_encode' => 'Safe\session_encode', - 'session_id' => 'Safe\session_id', - 'session_module_name' => 'Safe\session_module_name', - 'session_name' => 'Safe\session_name', - 'session_regenerate_id' => 'Safe\session_regenerate_id', - 'session_reset' => 'Safe\session_reset', - 'session_save_path' => 'Safe\session_save_path', - 'session_unset' => 'Safe\session_unset', - 'session_write_close' => 'Safe\session_write_close', - 'settype' => 'Safe\settype', - 'set_include_path' => 'Safe\set_include_path', - 'set_time_limit' => 'Safe\set_time_limit', - 'sha1_file' => 'Safe\sha1_file', - 'shell_exec' => 'Safe\shell_exec', - 'shmop_delete' => 'Safe\shmop_delete', - 'shmop_read' => 'Safe\shmop_read', - 'shm_attach' => 'Safe\shm_attach', - 'shm_detach' => 'Safe\shm_detach', - 'shm_put_var' => 'Safe\shm_put_var', - 'shm_remove' => 'Safe\shm_remove', - 'shm_remove_var' => 'Safe\shm_remove_var', - 'shuffle' => 'Safe\shuffle', - 'simplexml_import_dom' => 'Safe\simplexml_import_dom', - 'simplexml_load_file' => 'Safe\simplexml_load_file', - 'simplexml_load_string' => 'Safe\simplexml_load_string', - 'socket_accept' => 'Safe\socket_accept', - 'socket_addrinfo_bind' => 'Safe\socket_addrinfo_bind', - 'socket_addrinfo_connect' => 'Safe\socket_addrinfo_connect', - 'socket_addrinfo_lookup' => 'Safe\socket_addrinfo_lookup', - 'socket_bind' => 'Safe\socket_bind', - 'socket_connect' => 'Safe\socket_connect', - 'socket_create' => 'Safe\socket_create', - 'socket_create_listen' => 'Safe\socket_create_listen', - 'socket_create_pair' => 'Safe\socket_create_pair', - 'socket_export_stream' => 'Safe\socket_export_stream', - 'socket_getpeername' => 'Safe\socket_getpeername', - 'socket_getsockname' => 'Safe\socket_getsockname', - 'socket_get_option' => 'Safe\socket_get_option', - 'socket_import_stream' => 'Safe\socket_import_stream', - 'socket_listen' => 'Safe\socket_listen', - 'socket_read' => 'Safe\socket_read', - 'socket_send' => 'Safe\socket_send', - 'socket_sendmsg' => 'Safe\socket_sendmsg', - 'socket_sendto' => 'Safe\socket_sendto', - 'socket_set_block' => 'Safe\socket_set_block', - 'socket_set_nonblock' => 'Safe\socket_set_nonblock', - 'socket_set_option' => 'Safe\socket_set_option', - 'socket_shutdown' => 'Safe\socket_shutdown', - 'socket_write' => 'Safe\socket_write', - 'socket_wsaprotocol_info_export' => 'Safe\socket_wsaprotocol_info_export', - 'socket_wsaprotocol_info_import' => 'Safe\socket_wsaprotocol_info_import', - 'socket_wsaprotocol_info_release' => 'Safe\socket_wsaprotocol_info_release', - 'sodium_crypto_aead_aes256gcm_decrypt' => 'Safe\sodium_crypto_aead_aes256gcm_decrypt', - 'sodium_crypto_aead_chacha20poly1305_decrypt' => 'Safe\sodium_crypto_aead_chacha20poly1305_decrypt', - 'sodium_crypto_aead_chacha20poly1305_encrypt' => 'Safe\sodium_crypto_aead_chacha20poly1305_encrypt', - 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => 'Safe\sodium_crypto_aead_chacha20poly1305_ietf_decrypt', - 'sodium_crypto_aead_chacha20poly1305_ietf_encrypt' => 'Safe\sodium_crypto_aead_chacha20poly1305_ietf_encrypt', - 'sodium_crypto_aead_xchacha20poly1305_ietf_decrypt' => 'Safe\sodium_crypto_aead_xchacha20poly1305_ietf_decrypt', - 'sodium_crypto_aead_xchacha20poly1305_ietf_encrypt' => 'Safe\sodium_crypto_aead_xchacha20poly1305_ietf_encrypt', - 'sodium_crypto_auth_verify' => 'Safe\sodium_crypto_auth_verify', - 'sodium_crypto_box_open' => 'Safe\sodium_crypto_box_open', - 'sodium_crypto_box_seal_open' => 'Safe\sodium_crypto_box_seal_open', - 'sodium_crypto_generichash_update' => 'Safe\sodium_crypto_generichash_update', - 'sodium_crypto_secretbox_open' => 'Safe\sodium_crypto_secretbox_open', - 'sodium_crypto_sign_open' => 'Safe\sodium_crypto_sign_open', - 'sodium_crypto_sign_verify_detached' => 'Safe\sodium_crypto_sign_verify_detached', - 'sodium_crypto_stream_xchacha20_xor_ic' => 'Safe\sodium_crypto_stream_xchacha20_xor_ic', - 'solr_get_version' => 'Safe\solr_get_version', - 'spl_autoload_register' => 'Safe\spl_autoload_register', - 'spl_autoload_unregister' => 'Safe\spl_autoload_unregister', - 'sqlsrv_begin_transaction' => 'Safe\sqlsrv_begin_transaction', - 'sqlsrv_cancel' => 'Safe\sqlsrv_cancel', - 'sqlsrv_client_info' => 'Safe\sqlsrv_client_info', - 'sqlsrv_close' => 'Safe\sqlsrv_close', - 'sqlsrv_commit' => 'Safe\sqlsrv_commit', - 'sqlsrv_configure' => 'Safe\sqlsrv_configure', - 'sqlsrv_execute' => 'Safe\sqlsrv_execute', - 'sqlsrv_free_stmt' => 'Safe\sqlsrv_free_stmt', - 'sqlsrv_get_field' => 'Safe\sqlsrv_get_field', - 'sqlsrv_next_result' => 'Safe\sqlsrv_next_result', - 'sqlsrv_num_fields' => 'Safe\sqlsrv_num_fields', - 'sqlsrv_num_rows' => 'Safe\sqlsrv_num_rows', - 'sqlsrv_prepare' => 'Safe\sqlsrv_prepare', - 'sqlsrv_query' => 'Safe\sqlsrv_query', - 'sqlsrv_rollback' => 'Safe\sqlsrv_rollback', - 'ssdeep_fuzzy_compare' => 'Safe\ssdeep_fuzzy_compare', - 'ssdeep_fuzzy_hash' => 'Safe\ssdeep_fuzzy_hash', - 'ssdeep_fuzzy_hash_filename' => 'Safe\ssdeep_fuzzy_hash_filename', - 'ssh2_auth_agent' => 'Safe\ssh2_auth_agent', - 'ssh2_auth_hostbased_file' => 'Safe\ssh2_auth_hostbased_file', - 'ssh2_auth_password' => 'Safe\ssh2_auth_password', - 'ssh2_auth_pubkey_file' => 'Safe\ssh2_auth_pubkey_file', - 'ssh2_connect' => 'Safe\ssh2_connect', - 'ssh2_disconnect' => 'Safe\ssh2_disconnect', - 'ssh2_exec' => 'Safe\ssh2_exec', - 'ssh2_forward_accept' => 'Safe\ssh2_forward_accept', - 'ssh2_forward_listen' => 'Safe\ssh2_forward_listen', - 'ssh2_publickey_add' => 'Safe\ssh2_publickey_add', - 'ssh2_publickey_init' => 'Safe\ssh2_publickey_init', - 'ssh2_publickey_remove' => 'Safe\ssh2_publickey_remove', - 'ssh2_scp_recv' => 'Safe\ssh2_scp_recv', - 'ssh2_scp_send' => 'Safe\ssh2_scp_send', - 'ssh2_send_eof' => 'Safe\ssh2_send_eof', - 'ssh2_sftp' => 'Safe\ssh2_sftp', - 'ssh2_sftp_chmod' => 'Safe\ssh2_sftp_chmod', - 'ssh2_sftp_mkdir' => 'Safe\ssh2_sftp_mkdir', - 'ssh2_sftp_rename' => 'Safe\ssh2_sftp_rename', - 'ssh2_sftp_rmdir' => 'Safe\ssh2_sftp_rmdir', - 'ssh2_sftp_symlink' => 'Safe\ssh2_sftp_symlink', - 'ssh2_sftp_unlink' => 'Safe\ssh2_sftp_unlink', - 'ssh2_shell' => 'Safe\ssh2_shell', - 'stream_context_set_params' => 'Safe\stream_context_set_params', - 'stream_copy_to_stream' => 'Safe\stream_copy_to_stream', - 'stream_filter_append' => 'Safe\stream_filter_append', - 'stream_filter_prepend' => 'Safe\stream_filter_prepend', - 'stream_filter_register' => 'Safe\stream_filter_register', - 'stream_filter_remove' => 'Safe\stream_filter_remove', - 'stream_get_contents' => 'Safe\stream_get_contents', - 'stream_get_line' => 'Safe\stream_get_line', - 'stream_isatty' => 'Safe\stream_isatty', - 'stream_resolve_include_path' => 'Safe\stream_resolve_include_path', - 'stream_set_blocking' => 'Safe\stream_set_blocking', - 'stream_set_timeout' => 'Safe\stream_set_timeout', - 'stream_socket_accept' => 'Safe\stream_socket_accept', - 'stream_socket_client' => 'Safe\stream_socket_client', - 'stream_socket_get_name' => 'Safe\stream_socket_get_name', - 'stream_socket_pair' => 'Safe\stream_socket_pair', - 'stream_socket_recvfrom' => 'Safe\stream_socket_recvfrom', - 'stream_socket_sendto' => 'Safe\stream_socket_sendto', - 'stream_socket_server' => 'Safe\stream_socket_server', - 'stream_socket_shutdown' => 'Safe\stream_socket_shutdown', - 'stream_supports_lock' => 'Safe\stream_supports_lock', - 'stream_wrapper_register' => 'Safe\stream_wrapper_register', - 'stream_wrapper_restore' => 'Safe\stream_wrapper_restore', - 'stream_wrapper_unregister' => 'Safe\stream_wrapper_unregister', - 'strftime' => 'Safe\strftime', - 'strptime' => 'Safe\strptime', - 'strtotime' => 'Safe\strtotime', - 'swoole_async_dns_lookup' => 'Safe\swoole_async_dns_lookup', - 'swoole_async_readfile' => 'Safe\swoole_async_readfile', - 'swoole_async_write' => 'Safe\swoole_async_write', - 'swoole_async_writefile' => 'Safe\swoole_async_writefile', - 'swoole_event_defer' => 'Safe\swoole_event_defer', - 'swoole_event_del' => 'Safe\swoole_event_del', - 'swoole_event_write' => 'Safe\swoole_event_write', - 'symlink' => 'Safe\symlink', - 'syslog' => 'Safe\syslog', - 'system' => 'Safe\system', - 'tempnam' => 'Safe\tempnam', - 'timezone_name_from_abbr' => 'Safe\timezone_name_from_abbr', - 'time_nanosleep' => 'Safe\time_nanosleep', - 'time_sleep_until' => 'Safe\time_sleep_until', - 'tmpfile' => 'Safe\tmpfile', - 'touch' => 'Safe\touch', - 'unixtojd' => 'Safe\unixtojd', - 'unlink' => 'Safe\unlink', - 'unpack' => 'Safe\unpack', - 'uopz_extend' => 'Safe\uopz_extend', - 'uopz_implement' => 'Safe\uopz_implement', - 'variant_date_to_timestamp' => 'Safe\variant_date_to_timestamp', - 'variant_round' => 'Safe\variant_round', - 'virtual' => 'Safe\virtual', - 'xdiff_file_bdiff' => 'Safe\xdiff_file_bdiff', - 'xdiff_file_bpatch' => 'Safe\xdiff_file_bpatch', - 'xdiff_file_diff' => 'Safe\xdiff_file_diff', - 'xdiff_file_diff_binary' => 'Safe\xdiff_file_diff_binary', - 'xdiff_file_patch_binary' => 'Safe\xdiff_file_patch_binary', - 'xdiff_file_rabdiff' => 'Safe\xdiff_file_rabdiff', - 'xdiff_string_bpatch' => 'Safe\xdiff_string_bpatch', - 'xdiff_string_patch' => 'Safe\xdiff_string_patch', - 'xdiff_string_patch_binary' => 'Safe\xdiff_string_patch_binary', - 'xmlrpc_set_type' => 'Safe\xmlrpc_set_type', - 'xml_parser_free' => 'Safe\xml_parser_free', - 'xml_set_character_data_handler' => 'Safe\xml_set_character_data_handler', - 'xml_set_default_handler' => 'Safe\xml_set_default_handler', - 'xml_set_element_handler' => 'Safe\xml_set_element_handler', - 'xml_set_end_namespace_decl_handler' => 'Safe\xml_set_end_namespace_decl_handler', - 'xml_set_external_entity_ref_handler' => 'Safe\xml_set_external_entity_ref_handler', - 'xml_set_notation_decl_handler' => 'Safe\xml_set_notation_decl_handler', - 'xml_set_object' => 'Safe\xml_set_object', - 'xml_set_processing_instruction_handler' => 'Safe\xml_set_processing_instruction_handler', - 'xml_set_start_namespace_decl_handler' => 'Safe\xml_set_start_namespace_decl_handler', - 'xml_set_unparsed_entity_decl_handler' => 'Safe\xml_set_unparsed_entity_decl_handler', - 'yaml_parse' => 'Safe\yaml_parse', - 'yaml_parse_file' => 'Safe\yaml_parse_file', - 'yaml_parse_url' => 'Safe\yaml_parse_url', - 'yaz_ccl_parse' => 'Safe\yaz_ccl_parse', - 'yaz_close' => 'Safe\yaz_close', - 'yaz_connect' => 'Safe\yaz_connect', - 'yaz_database' => 'Safe\yaz_database', - 'yaz_element' => 'Safe\yaz_element', - 'yaz_present' => 'Safe\yaz_present', - 'yaz_search' => 'Safe\yaz_search', - 'yaz_wait' => 'Safe\yaz_wait', - 'zip_entry_close' => 'Safe\zip_entry_close', - 'zip_entry_compressedsize' => 'Safe\zip_entry_compressedsize', - 'zip_entry_compressionmethod' => 'Safe\zip_entry_compressionmethod', - 'zip_entry_filesize' => 'Safe\zip_entry_filesize', - 'zip_entry_name' => 'Safe\zip_entry_name', - 'zip_entry_open' => 'Safe\zip_entry_open', - 'zip_entry_read' => 'Safe\zip_entry_read', - 'zlib_decode' => 'Safe\zlib_decode', - ]); -}; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/.deepsource.toml b/lam/lib/3rdParty/composer/voku/portable-ascii/.deepsource.toml deleted file mode 100644 index 3f8f43cef..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/.deepsource.toml +++ /dev/null @@ -1,4 +0,0 @@ -version = 1 - -[[analyzers]] -name = "php" \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/CHANGELOG.md b/lam/lib/3rdParty/composer/voku/portable-ascii/CHANGELOG.md deleted file mode 100644 index 52f4912e7..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/CHANGELOG.md +++ /dev/null @@ -1,210 +0,0 @@ -# Changelog - -### 2.0.3 (2024-11-21) - -- use modern phpdocs e.g. list or conditional-return annotations - -### 2.0.2 (2024-11-21) - -- small fix for PHP 8.4 (thanks to @gilbertoalbino) - -### 2.0.1 (2022-03-08) - -- "To people of Russia": There is a war in Ukraine right now. The forces of the Russian Federation are attacking civilians. -- optimize some phpdocs - -### 2.0.0 (2022-01-24) - -- prefer "Russian - Passport (2013), ICAO" instead of "Russian - GOST 7.79-2000(B)" -- fix "Ukrainian" char-mapping (thanks to @Andr1yk0) -- fix "Persian" char-mapping (thanks to @frost-cyber) - -### 1.6.1 (2022-01-24) - -- revert: prefer "Russian - Passport (2013), ICAO" instead of "Russian - GOST 7.79-2000(B)" -- revert: fix "Ukrainian" char-mapping (thanks to @Andr1yk0) -- revert: fix "Persian" char-mapping (thanks to @frost-cyber) - -### 1.6.0 (2022-01-24) - -- prefer "Russian - Passport (2013), ICAO" instead of "Russian - GOST 7.79-2000(B)" -- fix "Ukrainian" char-mapping (thanks to @Andr1yk0) -- fix "Persian" char-mapping (thanks to @frost-cyber) -- fix "ASCII::normalize_whitespace()" -> "CARRIAGE RETURN" is more like "
    " and no "\n" -- add "ASCII::to_ascii_remap()" -> this method will return broken characters and is only for special cases - -### 1.5.6 (2020-11-12) - -- "ASCII::normalize_whitespace()" -> can now also remove "control characters" if needed v2 - -### 1.5.5 (2020-11-12) - -- fix "Greeklish" char-mapping (thanks @sebdesign) -- "ASCII::normalize_whitespace()" -> can now also remove "control characters" if needed - -### 1.5.4 (2020-11-08) - -- add some missing replacements in U+23xx page (thanks @marcoffee) -- fix "Russian" char-mapping (thanks @ilyahoilik) -- running test with PHP 8.0 rc3 - -### 1.5.3 (2020-07-23) - -- fix "Georgian" char-mapping (thanks @waska14) - -### 1.5.2 (2020-06-16) - -- add "Bengali" (bn) language support (thanks @eliyas5044) -- fix "Portuguese" char-mapping -- reduce the file size (removed extra comments from "avian2/unidecode") - -### 1.5.1 (2020-05-26) - -- fix merge ASCII transliterations from "avian2/unidecode" (python) - -> https://github.com/avian2/unidecode/ - -### 1.5.0 (2020-05-24) - -- merge ASCII transliterations from "avian2/unidecode" (python) - -> https://github.com/avian2/unidecode/ - -### 1.4.11 (2020-05-23) - -- "composer.json" -> remove "autoload-dev" stuff from "autoload" -- "voku/php-readme-helper" -> auto-generate the API documentation in the README - -### 1.4.10 (2020-03-13) - -- ASCII::to_ascii() -> fix extra symbol handling in the regex -- ASCII::to_ascii() -> fix for languages with multi-length-special-char (e.g. Greek -> 'ει' => 'i') - -### 1.4.9 (2020-03-06) - -- ASCII::to_slugify() -> fix php warning from empty "separator" - -### 1.4.8 (2020-02-06) - -- small optimization for "ASCII::to_ascii()" performance - -### 1.4.7 (2020-01-27) - -- fix possible wrong type from "getDataIfExists()" -> e.g. a bug reported where "/data/" was modified -- inline variables -- do not use "=== true" for "bool"-types - -### 1.4.6 (2019-12-23) - -- optimize "ASCII::to_ascii()" performance -- add "armenian" chars -- add "ASCII:getAllLanguages()" - -### 1.4.5 (2019-12-19) - -- use "@psalm-pure" v2 - -### 1.4.4 (2019-12-19) - -- use "@psalm-pure" - -### 1.4.3 (2019-12-19) - -- use "@psalm-immutable" - -### 1.4.2 (2019-12-13) - -- optimize the performance v2 -- more fixes for non-ascii regex - -### 1.4.1 (2019-12-13) - -- fix regex for non-ascii - -### 1.4.0 (2019-12-13) - -- optimize the performance, via single char replacements - -### 1.3.6 (2019-12-13) - -- "ascii_extras" -> convert the static content into ascii - -> e.g.: instead of replacing "+" with "più" we use "piu" (Italian), because we want to use ascii anyway - -### 1.3.5 (2019-11-11) - -- fix "ASCII::remove_invisible_characters()" -> do not remove invisible encoded url strings by default - -### 1.3.4 (2019-10-14) - -- fix static cache for "ASCII::charsArrayWithOneLanguage" - -### 1.3.3 (2019-10-14) - -- fix "Turkish" mapping -> 'ä' -> 'a' - -### 1.3.2 (2019-10-14) - -- fix language parameter usage with e.g. "de_DE" -- re-add missing "extra"-mapping chars - -### 1.3.1 (2019-10-13) - -- fix "ASCII::to_slugify" -> remove unicode chars -- add more test for ascii chars in the mapping -- fix non ascii chars in the mapping - -### 1.3.0 (2019-10-12) - -- add transliteration "fr" (was supported before, but with chars from other languages) -- add transliteration "ru" - Passport (2013), ICAO -- add transliteration "ru" - GOST 7.79-2000(B) -- add transliteration "el" - greeklish -- add transliteration "zh" -- add transliteration "nl" -- add transliteration "it" -- add transliteration "mk" -- add transliteration "pt" -- add constants -> ASCII::*LANGUAGE_CODES -- add more special latin chars / (currency) symbols -- add simple tests for all supported languages -- optimize "Russian" to ASCII (via "translit.ru") -- optimize performance of string replacement -- optimize performance of array merging -- optimize phpdoc comments -- "ASCII::to_transliterate" -> use "transliterator_create" + static cache -- "ASCII::to_ascii" -> fix "remove unsupported chars" -- "ASCII::to_ascii" -> add some more special chars -- run/fix static analyse via "pslam" + "phpstan" -- auto fix code style via "php-cs-fixer" -- fix transliteration for "german" -- fix transliteration for "persian" (thanks @mardep) -- fix transliteration for "polish" (thanks @dariusz.drobisz) -- fix transliteration for "bulgarian" (thanks @mkosturkov) -- fix transliteration for "croatian" (thanks @ludifonovac) -- fix transliteration for "serbian" (thanks @ludifonovac) -- fix transliteration for "swedish" (thanks @nicholasruunu) -- fix transliteration for "france" (thanks @sharptsa) -- fix transliteration for "serbian" (thanks @nikolaposa) -- fix transliteration for "czech" (thanks @slepic) - -### 1.2.3 (2019-09-10) - -- fix language depending ASCII chars (the order matters) - -### 1.2.2 (2019-09-10) - -- fix bulgarian ASCII chars | thanks @bgphp - -### 1.2.1 (2019-09-07) - -- "charsArray()" -> add access to "ASCII::$ASCII_MAPS*"" - -### 1.2.0 (2019-09-07) - -- "to_slugify()" -> use the extra ascii array - -### 1.1.0 (2019-09-07) - -- add + split extra ascii replacements - -### 1.0.0 (2019-09-05) - -- initial commit \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/README.md b/lam/lib/3rdParty/composer/voku/portable-ascii/README.md deleted file mode 100644 index 3ce36d604..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/README.md +++ /dev/null @@ -1,451 +0,0 @@ -[//]: # (AUTO-GENERATED BY "PHP README Helper": base file -> docs/base.md) -[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) - -[![Build Status](https://github.com/voku/portable-ascii/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/voku/portable-ascii/actions) -[![Build status](https://ci.appveyor.com/api/projects/status/gnejjnk7qplr7f5t/branch/master?svg=true)](https://ci.appveyor.com/project/voku/portable-ascii/branch/master) -[![codecov.io](https://codecov.io/github/voku/portable-ascii/coverage.svg?branch=master)](https://codecov.io/github/voku/portable-ascii?branch=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/997c9bb10d1c4791967bdf2e42013e8e)](https://www.codacy.com/app/voku/portable-ascii) -[![Latest Stable Version](https://poser.pugx.org/voku/portable-ascii/v/stable)](https://packagist.org/packages/voku/portable-ascii) -[![Total Downloads](https://poser.pugx.org/voku/portable-ascii/downloads)](https://packagist.org/packages/voku/portable-ascii) -[![License](https://poser.pugx.org/voku/portable-ascii/license)](https://packagist.org/packages/voku/portable-ascii) -[![Donate to this project using Paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.me/moelleken) -[![Donate to this project using Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://www.patreon.com/voku) - -# 🔡 Portable ASCII - -## Description - -It is written in PHP (PHP 7+) and can work without "mbstring", "iconv" or any other extra encoding php-extension on your server. - -The benefit of Portable ASCII is that it is easy to use, easy to bundle. - -The project based on ... -+ Sean M. Burke's work (https://metacpan.org/pod/Text::Unidecode) -+ Tomaz Solc's work (https://pypi.org/project/Unidecode/) -+ Portable UTF-8 work (https://github.com/voku/portable-utf8) -+ Daniel St. Jules's work (https://github.com/danielstjules/Stringy) -+ Johnny Broadway's work (https://github.com/jbroadway/urlify) -+ and many cherry-picks from "github"-gists and "Stack Overflow"-snippets ... - -## Index - -* [Alternative](#alternative) -* [Install](#install-portable-ascii-via-composer-require) -* [Why Portable ASCII?](#why-portable-ascii) -* [Requirements and Recommendations](#requirements-and-recommendations) -* [Usage](#usage) -* [Class methods](#class-methods) -* [Unit Test](#unit-test) -* [License and Copyright](#license-and-copyright) - -## Alternative - -If you like a more Object Oriented Way to edit strings, then you can take a look at [voku/Stringy](https://github.com/voku/Stringy), it's a fork of "danielstjules/Stringy" but it used the "Portable ASCII"-Class and some extra methods. - -```php -// Portable ASCII -use voku\helper\ASCII; -ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii' - -// voku/Stringy -use Stringy\Stringy as S; -$stringy = S::create('déjà σσς iıii'); -$stringy->toTransliterate(); // 'deja sss iiii' -``` - -## Install "Portable ASCII" via "composer require" -```shell -composer require voku/portable-ascii -``` - -## Why Portable ASCII?[]() -I need ASCII char handling in different classes and before I added this functions into "Portable UTF-8", -but this repo is more modular and portable, because it has no dependencies. - -## Requirements and Recommendations - -* No extensions are required to run this library. Portable ASCII only needs PCRE library that is available by default since PHP 4.2.0 and cannot be disabled since PHP 5.3.0. "\u" modifier support in PCRE for ASCII handling is not a must. -* PHP 7.0 is the minimum requirement -* PHP 8.0 is also supported - -## Usage - -Example: ASCII::to_ascii() -```php - echo ASCII::to_ascii('�Düsseldorf�', 'de'); - - // will output - // Duesseldorf - - echo ASCII::to_ascii('�Düsseldorf�', 'en'); - - // will output - // Dusseldorf -``` - -# Portable ASCII | API - -The API from the "ASCII"-Class is written as small static methods. - - -## Class methods - -

    charsArray -charsArrayWithMultiLanguageValues -charsArrayWithOneLanguage -charsArrayWithSingleLanguageValues -
    clean -getAllLanguages -is_ascii -normalize_msword -
    normalize_whitespace -remove_invisible_characters -to_ascii -to_ascii_remap -
    to_filename -to_slugify -to_transliterate -
    - -#### charsArray(bool $replace_extra_symbols): array - -Returns an replacement array for ASCII methods. - -EXAMPLE: -$array = ASCII::charsArray(); -var_dump($array['ru']['б']); // 'b' - - -**Parameters:** -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    ` - -**Return:** -- `array` - --------- - -#### charsArrayWithMultiLanguageValues(bool $replace_extra_symbols): array - -Returns an replacement array for ASCII methods with a mix of multiple languages. - -EXAMPLE: -$array = ASCII::charsArrayWithMultiLanguageValues(); -var_dump($array['b']); // ['β', 'б', 'ဗ', 'ბ', 'ب'] - - -**Parameters:** -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    ` - -**Return:** -- `array

    An array of replacements.

    ` - --------- - -#### charsArrayWithOneLanguage(string $language, bool $replace_extra_symbols, bool $asOrigReplaceArray): array - -Returns an replacement array for ASCII methods with one language. - -For example, German will map 'ä' to 'ae', while other languages -will simply return e.g. 'a'. - -EXAMPLE: -$array = ASCII::charsArrayWithOneLanguage('ru'); -$tmpKey = \array_search('yo', $array['replace']); -echo $array['orig'][$tmpKey]; // 'ё' - - -**Parameters:** -- `ASCII::* $language [optional]

    Language of the source string e.g.: en, de_at, or de-ch. -(default is 'en') | ASCII::*_LANGUAGE_CODE

    ` -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    ` -- `bool $asOrigReplaceArray [optional]

    TRUE === return {orig: string[], replace: string[]} -array

    ` - -**Return:** -- `array

    An array of replacements.

    ` - --------- - -#### charsArrayWithSingleLanguageValues(bool $replace_extra_symbols, bool $asOrigReplaceArray): array - -Returns an replacement array for ASCII methods with multiple languages. - -EXAMPLE: -$array = ASCII::charsArrayWithSingleLanguageValues(); -$tmpKey = \array_search('hnaik', $array['replace']); -echo $array['orig'][$tmpKey]; // '၌' - - -**Parameters:** -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    ` -- `bool $asOrigReplaceArray [optional]

    TRUE === return {orig: string[], replace: string[]} -array

    ` - -**Return:** -- `array

    An array of replacements.

    ` - --------- - -#### clean(string $str, bool $normalize_whitespace, bool $keep_non_breaking_space, bool $normalize_msword, bool $remove_invisible_characters): string - -Accepts a string and removes all non-UTF-8 characters from it + extras if needed. - -**Parameters:** -- `string $str

    The string to be sanitized.

    ` -- `bool $normalize_whitespace [optional]

    Set to true, if you need to normalize the -whitespace.

    ` -- `bool $keep_non_breaking_space [optional]

    Set to true, to keep non-breaking-spaces, in -combination with -$normalize_whitespace

    ` -- `bool $normalize_msword [optional]

    Set to true, if you need to normalize MS Word chars -e.g.: "…" -=> "..."

    ` -- `bool $remove_invisible_characters [optional]

    Set to false, if you not want to remove invisible -characters e.g.: "\0"

    ` - -**Return:** -- `string

    A clean UTF-8 string.

    ` - --------- - -#### getAllLanguages(): string[] - -Get all languages from the constants "ASCII::.*LANGUAGE_CODE". - -**Parameters:** -__nothing__ - -**Return:** -- `string[]` - --------- - -#### is_ascii(string $str): bool - -Checks if a string is 7 bit ASCII. - -EXAMPLE: -ASCII::is_ascii('白'); // false - - -**Parameters:** -- `string $str

    The string to check.

    ` - -**Return:** -- `bool

    -true if it is ASCII
    -false otherwise -

    ` - --------- - -#### normalize_msword(string $str): string - -Returns a string with smart quotes, ellipsis characters, and dashes from -Windows-1252 (commonly used in Word documents) replaced by their ASCII -equivalents. - -EXAMPLE: -ASCII::normalize_msword('„Abcdef…”'); // '"Abcdef..."' - - -**Parameters:** -- `string $str

    The string to be normalized.

    ` - -**Return:** -- `string

    A string with normalized characters for commonly used chars in Word documents.

    ` - --------- - -#### normalize_whitespace(string $str, bool $keepNonBreakingSpace, bool $keepBidiUnicodeControls, bool $normalize_control_characters): string - -Normalize the whitespace. - -EXAMPLE: -ASCII::normalize_whitespace("abc-\xc2\xa0-öäü-\xe2\x80\xaf-\xE2\x80\xAC", true); // "abc-\xc2\xa0-öäü- -" - - -**Parameters:** -- `string $str

    The string to be normalized.

    ` -- `bool $keepNonBreakingSpace [optional]

    Set to true, to keep non-breaking-spaces.

    ` -- `bool $keepBidiUnicodeControls [optional]

    Set to true, to keep non-printable (for the web) -bidirectional text chars.

    ` -- `bool $normalize_control_characters [optional]

    Set to true, to convert e.g. LINE-, PARAGRAPH-SEPARATOR with "\n" and LINE TABULATION with "\t".

    ` - -**Return:** -- `string

    A string with normalized whitespace.

    ` - --------- - -#### remove_invisible_characters(string $str, bool $url_encoded, string $replacement, bool $keep_basic_control_characters): string - -Remove invisible characters from a string. - -e.g.: This prevents sandwiching null characters between ascii characters, like Java\0script. - -copy&past from https://github.com/bcit-ci/CodeIgniter/blob/develop/system/core/Common.php - -**Parameters:** -- `string $str` -- `bool $url_encoded` -- `string $replacement` -- `bool $keep_basic_control_characters` - -**Return:** -- `string` - --------- - -#### to_ascii(string $str, string $language, bool $remove_unsupported_chars, bool $replace_extra_symbols, bool $use_transliterate, bool|null $replace_single_chars_only): string - -Returns an ASCII version of the string. A set of non-ASCII characters are -replaced with their closest ASCII counterparts, and the rest are removed -by default. The language or locale of the source string can be supplied -for language-specific transliteration in any of the following formats: -en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping -to "aeoeue" rather than "aou" as in other languages. - -EXAMPLE: -ASCII::to_ascii('�Düsseldorf�', 'en'); // Dusseldorf - - -**Parameters:** -- `string $str

    The input string.

    ` -- `ASCII::* $language [optional]

    Language of the source string. -(default is 'en') | ASCII::*_LANGUAGE_CODE

    ` -- `bool $remove_unsupported_chars [optional]

    Whether or not to remove the -unsupported characters.

    ` -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound -".

    ` -- `bool $use_transliterate [optional]

    Use ASCII::to_transliterate() for unknown chars.

    ` -- `bool|null $replace_single_chars_only [optional]

    Single char replacement is better for the -performance, but some languages need to replace more then one char -at the same time. | NULL === auto-setting, depended on the -language

    ` - -**Return:** -- `string

    A string that contains only ASCII characters.

    ` - --------- - -#### to_ascii_remap(string $str1, string $str2): string[] - -WARNING: This method will return broken characters and is only for special cases. - -Convert two UTF-8 encoded string to a single-byte strings suitable for -functions that need the same string length after the conversion. - -The function simply uses (and updates) a tailored dynamic encoding -(in/out map parameter) where non-ascii characters are remapped to -the range [128-255] in order of appearance. - -**Parameters:** -- `string $str1` -- `string $str2` - -**Return:** -- `string[]` - --------- - -#### to_filename(string $str, bool $use_transliterate, string $fallback_char): string - -Convert given string to safe filename (and keep string case). - -EXAMPLE: -ASCII::to_filename('שדגשדג.png', true)); // 'shdgshdg.png' - - -**Parameters:** -- `string $str` -- `bool $use_transliterate

    ASCII::to_transliterate() is used by default - unsafe characters are -simply replaced with hyphen otherwise.

    ` -- `string $fallback_char` - -**Return:** -- `string

    A string that contains only safe characters for a filename.

    ` - --------- - -#### to_slugify(string $str, string $separator, string $language, string[] $replacements, bool $replace_extra_symbols, bool $use_str_to_lower, bool $use_transliterate): string - -Converts the string into an URL slug. This includes replacing non-ASCII -characters with their closest ASCII equivalents, removing remaining -non-ASCII and non-alphanumeric characters, and replacing whitespace with -$separator. The separator defaults to a single dash, and the string -is also converted to lowercase. The language of the source string can -also be supplied for language-specific transliteration. - -**Parameters:** -- `string $str` -- `string $separator [optional]

    The string used to replace whitespace.

    ` -- `ASCII::* $language [optional]

    Language of the source string. -(default is 'en') | ASCII::*_LANGUAGE_CODE

    ` -- `array $replacements [optional]

    A map of replaceable strings.

    ` -- `bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " -pound ".

    ` -- `bool $use_str_to_lower [optional]

    Use "string to lower" for the input.

    ` -- `bool $use_transliterate [optional]

    Use ASCII::to_transliterate() for unknown -chars.

    ` - -**Return:** -- `string

    A string that has been converted to an URL slug.

    ` - --------- - -#### to_transliterate(string $str, string|null $unknown, bool $strict): string - -Returns an ASCII version of the string. A set of non-ASCII characters are -replaced with their closest ASCII counterparts, and the rest are removed -unless instructed otherwise. - -EXAMPLE: -ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii' - - -**Parameters:** -- `string $str

    The input string.

    ` -- `string|null $unknown [optional]

    Character use if character unknown. (default is '?') -But you can also use NULL to keep the unknown chars.

    ` -- `bool $strict [optional]

    Use "transliterator_transliterate()" from PHP-Intl` - -**Return:** -- `string

    A String that contains only ASCII characters.

    ` - --------- - - - -## Unit Test - -1) [Composer](https://getcomposer.org) is a prerequisite for running the tests. - -``` -composer install -``` - -2) The tests can be executed by running this command from the root directory: - -```bash -./vendor/bin/phpunit -``` - -### Support - -For support and donations please visit [Github](https://github.com/voku/portable-ascii/) | [Issues](https://github.com/voku/portable-ascii/issues) | [PayPal](https://paypal.me/moelleken) | [Patreon](https://www.patreon.com/voku). - -For status updates and release announcements please visit [Releases](https://github.com/voku/portable-ascii/releases) | [Twitter](https://twitter.com/suckup_de) | [Patreon](https://www.patreon.com/voku/posts). - -For professional support please contact [me](https://about.me/voku). - -### Thanks - -- Thanks to [GitHub](https://github.com) (Microsoft) for hosting the code and a good infrastructure including Issues-Managment, etc. -- Thanks to [IntelliJ](https://www.jetbrains.com) as they make the best IDEs for PHP and they gave me an open source license for PhpStorm! -- Thanks to [Travis CI](https://travis-ci.com/) for being the most awesome, easiest continous integration tool out there! -- Thanks to [StyleCI](https://styleci.io/) for the simple but powerful code style check. -- Thanks to [PHPStan](https://github.com/phpstan/phpstan) && [Psalm](https://github.com/vimeo/psalm) for really great Static analysis tools and for discover bugs in the code! - -### License and Copyright - -Released under the MIT License - see `LICENSE.txt` for details. diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/composer.json b/lam/lib/3rdParty/composer/voku/portable-ascii/composer.json deleted file mode 100644 index b3a22fa8c..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/composer.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "voku/portable-ascii", - "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", - "type": "library", - "keywords": [ - "clean", - "php", - "ascii" - ], - "homepage": "https://github.com/voku/portable-ascii", - "license": "MIT", - "authors": [ - { - "name": "Lars Moelleken", - "homepage": "https://www.moelleken.org/" - } - ], - "require": { - "php": ">=7.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" - }, - "suggest": { - "ext-intl": "Use Intl for transliterator_transliterate() support" - }, - "autoload": { - "psr-4": { - "voku\\": "src/voku/" - } - }, - "autoload-dev": { - "psr-4": { - "voku\\tests\\": "tests/" - } - } -} diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/ASCII.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/ASCII.php deleted file mode 100644 index 406407e19..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/ASCII.php +++ /dev/null @@ -1,1424 +0,0 @@ ->|null - */ - private static $ASCII_MAPS; - - /** - * @var array>|null - */ - private static $ASCII_MAPS_AND_EXTRAS; - - /** - * @var array>|null - */ - private static $ASCII_EXTRAS; - - /** - * @var array|null - */ - private static $ORD; - - /** - * @var array|null - */ - private static $LANGUAGE_MAX_KEY; - - /** - * url: https://en.wikipedia.org/wiki/Wikipedia:ASCII#ASCII_printable_characters - * - * @var string - */ - private static $REGEX_ASCII = "[^\x09\x10\x13\x0A\x0D\x20-\x7E]"; - - /** - * bidirectional text chars - * - * url: https://www.w3.org/International/questions/qa-bidi-unicode-controls - * - * @var array - */ - private static $BIDI_UNI_CODE_CONTROLS_TABLE = [ - // LEFT-TO-RIGHT EMBEDDING (use -> dir = "ltr") - 8234 => "\xE2\x80\xAA", - // RIGHT-TO-LEFT EMBEDDING (use -> dir = "rtl") - 8235 => "\xE2\x80\xAB", - // POP DIRECTIONAL FORMATTING // (use -> ) - 8236 => "\xE2\x80\xAC", - // LEFT-TO-RIGHT OVERRIDE // (use -> ) - 8237 => "\xE2\x80\xAD", - // RIGHT-TO-LEFT OVERRIDE // (use -> ) - 8238 => "\xE2\x80\xAE", - // LEFT-TO-RIGHT ISOLATE // (use -> dir = "ltr") - 8294 => "\xE2\x81\xA6", - // RIGHT-TO-LEFT ISOLATE // (use -> dir = "rtl") - 8295 => "\xE2\x81\xA7", - // FIRST STRONG ISOLATE // (use -> dir = "auto") - 8296 => "\xE2\x81\xA8", - // POP DIRECTIONAL ISOLATE - 8297 => "\xE2\x81\xA9", - ]; - - /** - * Get all languages from the constants "ASCII::.*LANGUAGE_CODE". - * - * @return array - *

    An associative array where the key is the language code in lowercase - * and the value is the corresponding language string.

    - */ - public static function getAllLanguages(): array - { - // init - static $LANGUAGES = []; - - if ($LANGUAGES !== []) { - return $LANGUAGES; - } - - foreach ((new \ReflectionClass(__CLASS__))->getConstants() as $constant => $lang) { - if (\strpos($constant, 'EXTRA') !== false) { - $LANGUAGES[\strtolower($constant)] = $lang; - } else { - $LANGUAGES[\strtolower(\str_replace('_LANGUAGE_CODE', '', $constant))] = $lang; - } - } - - return $LANGUAGES; - } - - /** - * Returns an replacement array for ASCII methods. - * - * EXAMPLE: - * $array = ASCII::charsArray(); - * var_dump($array['ru']['б']); // 'b' - * - * - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    - * - * @psalm-pure - * - * @return array> - *

    An array where the key is the language code, and the value is - * an associative array mapping original characters to their replacements.

    - */ - public static function charsArray(bool $replace_extra_symbols = false): array - { - if ($replace_extra_symbols) { - self::prepareAsciiAndExtrasMaps(); - - return self::$ASCII_MAPS_AND_EXTRAS ?? []; - } - - self::prepareAsciiMaps(); - - return self::$ASCII_MAPS ?? []; - } - - /** - * Returns an replacement array for ASCII methods with a mix of multiple languages. - * - * EXAMPLE: - * $array = ASCII::charsArrayWithMultiLanguageValues(); - * var_dump($array['b']); // ['β', 'б', 'ဗ', 'ბ', 'ب'] - * - * - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    - * - * @psalm-pure - * - * @return array> - *

    An array of replacements.

    - */ - public static function charsArrayWithMultiLanguageValues(bool $replace_extra_symbols = false): array - { - static $CHARS_ARRAY = []; - $cacheKey = '' . $replace_extra_symbols; - - if (isset($CHARS_ARRAY[$cacheKey])) { - return $CHARS_ARRAY[$cacheKey]; - } - - // init - $return = []; - $language_all_chars = self::charsArrayWithSingleLanguageValues( - $replace_extra_symbols, - false - ); - - /* @noinspection AlterInForeachInspection | ok here */ - foreach ($language_all_chars as $key => &$value) { - $return[$value][] = $key; - } - - $CHARS_ARRAY[$cacheKey] = $return; - - return $return; - } - - /** - * Returns an replacement array for ASCII methods with one language. - * - * For example, German will map 'ä' to 'ae', while other languages - * will simply return e.g. 'a'. - * - * EXAMPLE: - * $array = ASCII::charsArrayWithOneLanguage('ru'); - * $tmpKey = \array_search('yo', $array['replace']); - * echo $array['orig'][$tmpKey]; // 'ё' - * - * - * @param string $language [optional]

    Language of the source string e.g.: en, de_at, or de-ch. - * (default is 'en') | ASCII::*_LANGUAGE_CODE

    - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    - * @param bool $asOrigReplaceArray [optional]

    TRUE === return {orig: list, replace: list} - * array

    - * - * @psalm-pure - * - * @return ($asOrigReplaceArray is true ? array{orig: list, replace: list} : array) - * - * @phpstan-param ASCII::*_LANGUAGE_CODE $language - */ - public static function charsArrayWithOneLanguage( - string $language = self::ENGLISH_LANGUAGE_CODE, - bool $replace_extra_symbols = false, - bool $asOrigReplaceArray = true - ): array { - $language = self::get_language($language); - - // init - static $CHARS_ARRAY = []; - $cacheKey = '' . $replace_extra_symbols . '-' . $asOrigReplaceArray; - - // check static cache - if (isset($CHARS_ARRAY[$cacheKey][$language])) { - return $CHARS_ARRAY[$cacheKey][$language]; - } - - if ($replace_extra_symbols) { - self::prepareAsciiAndExtrasMaps(); - - if (isset(self::$ASCII_MAPS_AND_EXTRAS[$language])) { - $tmpArray = self::$ASCII_MAPS_AND_EXTRAS[$language]; - - if ($asOrigReplaceArray) { - $CHARS_ARRAY[$cacheKey][$language] = [ - 'orig' => \array_keys($tmpArray), - 'replace' => \array_values($tmpArray), - ]; - } else { - $CHARS_ARRAY[$cacheKey][$language] = $tmpArray; - } - } else { - if ($asOrigReplaceArray) { - $CHARS_ARRAY[$cacheKey][$language] = [ - 'orig' => [], - 'replace' => [], - ]; - } else { - $CHARS_ARRAY[$cacheKey][$language] = []; - } - } - } else { - self::prepareAsciiMaps(); - - if (isset(self::$ASCII_MAPS[$language])) { - $tmpArray = self::$ASCII_MAPS[$language]; - - if ($asOrigReplaceArray) { - $CHARS_ARRAY[$cacheKey][$language] = [ - 'orig' => \array_keys($tmpArray), - 'replace' => \array_values($tmpArray), - ]; - } else { - $CHARS_ARRAY[$cacheKey][$language] = $tmpArray; - } - } else { - if ($asOrigReplaceArray) { - $CHARS_ARRAY[$cacheKey][$language] = [ - 'orig' => [], - 'replace' => [], - ]; - } else { - $CHARS_ARRAY[$cacheKey][$language] = []; - } - } - } - - return $CHARS_ARRAY[$cacheKey][$language] ?? ['orig' => [], 'replace' => []]; - } - - /** - * Returns an replacement array for ASCII methods with multiple languages. - * - * EXAMPLE: - * $array = ASCII::charsArrayWithSingleLanguageValues(); - * $tmpKey = \array_search('hnaik', $array['replace']); - * echo $array['orig'][$tmpKey]; // '၌' - * - * - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound ".

    - * @param bool $asOrigReplaceArray [optional]

    TRUE === return {orig: list, replace: list} - * array

    - * - * @psalm-pure - * - * @return ($asOrigReplaceArray is true ? array{orig: list, replace: list} : array) - */ - public static function charsArrayWithSingleLanguageValues( - bool $replace_extra_symbols = false, - bool $asOrigReplaceArray = true - ): array { - // init - static $CHARS_ARRAY = []; - $cacheKey = '' . $replace_extra_symbols . '-' . $asOrigReplaceArray; - - if (isset($CHARS_ARRAY[$cacheKey])) { - return $CHARS_ARRAY[$cacheKey]; - } - - if ($replace_extra_symbols) { - self::prepareAsciiAndExtrasMaps(); - - /* @noinspection AlterInForeachInspection | ok here */ - foreach (self::$ASCII_MAPS_AND_EXTRAS ?? [] as &$map) { - $CHARS_ARRAY[$cacheKey][] = $map; - } - } else { - self::prepareAsciiMaps(); - - /* @noinspection AlterInForeachInspection | ok here */ - foreach (self::$ASCII_MAPS ?? [] as &$map) { - $CHARS_ARRAY[$cacheKey][] = $map; - } - } - - $CHARS_ARRAY[$cacheKey] = \array_merge([], ...$CHARS_ARRAY[$cacheKey]); - - if ($asOrigReplaceArray) { - $CHARS_ARRAY[$cacheKey] = [ - 'orig' => \array_keys($CHARS_ARRAY[$cacheKey]), - 'replace' => \array_values($CHARS_ARRAY[$cacheKey]), - ]; - } - - return $CHARS_ARRAY[$cacheKey]; - } - - /** - * Accepts a string and removes all non-UTF-8 characters from it + extras if needed. - * - * @param string $str

    The string to be sanitized.

    - * @param bool $normalize_whitespace [optional]

    Set to true, if you need to normalize the - * whitespace.

    - * @param bool $normalize_msword [optional]

    Set to true, if you need to normalize MS Word chars - * e.g.: "…" - * => "..."

    - * @param bool $keep_non_breaking_space [optional]

    Set to true, to keep non-breaking-spaces, in - * combination with - * $normalize_whitespace

    - * @param bool $remove_invisible_characters [optional]

    Set to false, if you not want to remove invisible - * characters e.g.: "\0"

    - * - * @psalm-pure - * - * @return string - *

    A clean UTF-8 string.

    - */ - public static function clean( - string $str, - bool $normalize_whitespace = true, - bool $keep_non_breaking_space = false, - bool $normalize_msword = true, - bool $remove_invisible_characters = true - ): string { - // http://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string - // caused connection reset problem on larger strings - - $regex = '/ - ( - (?: [\x00-\x7F] # single-byte sequences 0xxxxxxx - | [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx - | [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2 - | [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3 - ){1,100} # ...one or more times - ) - | ( [\x80-\xBF] ) # invalid byte in range 10000000 - 10111111 - | ( [\xC0-\xFF] ) # invalid byte in range 11000000 - 11111111 - /x'; - $str = (string) \preg_replace($regex, '$1', $str); - - if ($normalize_whitespace) { - $str = self::normalize_whitespace($str, $keep_non_breaking_space); - } - - if ($normalize_msword) { - $str = self::normalize_msword($str); - } - - if ($remove_invisible_characters) { - $str = self::remove_invisible_characters($str); - } - - return $str; - } - - /** - * Checks if a string is 7 bit ASCII. - * - * EXAMPLE: - * ASCII::is_ascii('白'); // false - * - * - * @param string $str

    The string to check.

    - * - * @psalm-pure - * - * @return bool - *

    - * true if it is ASCII
    - * false otherwise - *

    - */ - public static function is_ascii(string $str): bool - { - if ($str === '') { - return true; - } - - return !\preg_match('/' . self::$REGEX_ASCII . '/', $str); - } - - /** - * Returns a string with smart quotes, ellipsis characters, and dashes from - * Windows-1252 (commonly used in Word documents) replaced by their ASCII - * equivalents. - * - * EXAMPLE: - * ASCII::normalize_msword('„Abcdef…”'); // '"Abcdef..."' - * - * - * @param string $str

    The string to be normalized.

    - * - * @psalm-pure - * - * @return string - *

    A string with normalized characters for commonly used chars in Word documents.

    - */ - public static function normalize_msword(string $str): string - { - if ($str === '') { - return ''; - } - - static $MSWORD_CACHE = ['orig' => [], 'replace' => []]; - - if (empty($MSWORD_CACHE['orig'])) { - self::prepareAsciiMaps(); - - $map = self::$ASCII_MAPS[self::EXTRA_MSWORD_CHARS_LANGUAGE_CODE] ?? []; - - $MSWORD_CACHE = [ - 'orig' => \array_keys($map), - 'replace' => \array_values($map), - ]; - } - - return \str_replace($MSWORD_CACHE['orig'], $MSWORD_CACHE['replace'], $str); - } - - /** - * Normalize the whitespace. - * - * EXAMPLE: - * ASCII::normalize_whitespace("abc-\xc2\xa0-öäü-\xe2\x80\xaf-\xE2\x80\xAC", true); // "abc-\xc2\xa0-öäü- -" - * - * - * @param string $str

    The string to be normalized.

    - * @param bool $keepNonBreakingSpace [optional]

    Set to true, to keep non-breaking-spaces.

    - * @param bool $keepBidiUnicodeControls [optional]

    Set to true, to keep non-printable (for the web) - * bidirectional text chars.

    - * @param bool $normalize_control_characters [optional]

    Set to true, to convert e.g. LINE-, PARAGRAPH-SEPARATOR with "\n" and LINE TABULATION with "\t".

    - * - * @psalm-pure - * - * @return string - *

    A string with normalized whitespace.

    - */ - public static function normalize_whitespace( - string $str, - bool $keepNonBreakingSpace = false, - bool $keepBidiUnicodeControls = false, - bool $normalize_control_characters = false - ): string { - if ($str === '') { - return ''; - } - - static $WHITESPACE_CACHE = []; - $cacheKey = (int) $keepNonBreakingSpace; - - if ($normalize_control_characters) { - $str = \str_replace( - [ - "\x0d\x0c", // 'END OF LINE' - "\xe2\x80\xa8", // 'LINE SEPARATOR' - "\xe2\x80\xa9", // 'PARAGRAPH SEPARATOR' - "\x0c", // 'FORM FEED' // "\f" - "\x0b", // 'VERTICAL TAB' // "\v" - ], - [ - "\n", - "\n", - "\n", - "\n", - "\t", - ], - $str - ); - } - - if (!isset($WHITESPACE_CACHE[$cacheKey])) { - self::prepareAsciiMaps(); - - $WHITESPACE_CACHE[$cacheKey] = self::$ASCII_MAPS[self::EXTRA_WHITESPACE_CHARS_LANGUAGE_CODE] ?? []; - - if ($keepNonBreakingSpace) { - unset($WHITESPACE_CACHE[$cacheKey]["\xc2\xa0"]); - } - - $WHITESPACE_CACHE[$cacheKey] = array_keys($WHITESPACE_CACHE[$cacheKey]); - } - - if (!$keepBidiUnicodeControls) { - static $BIDI_UNICODE_CONTROLS_CACHE = null; - - if ($BIDI_UNICODE_CONTROLS_CACHE === null) { - $BIDI_UNICODE_CONTROLS_CACHE = self::$BIDI_UNI_CODE_CONTROLS_TABLE; - } - - $str = \str_replace($BIDI_UNICODE_CONTROLS_CACHE, '', $str); - } - - return \str_replace($WHITESPACE_CACHE[$cacheKey], ' ', $str); - } - - /** - * Remove invisible characters from a string. - * - * This prevents malicious code injection through null bytes or other control characters. - * - * copy&past from https://github.com/bcit-ci/CodeIgniter/blob/develop/system/core/Common.php - * - * @param string $str - * @param bool $url_encoded - * @param string $replacement - * @param bool $keep_basic_control_characters - * - * @psalm-pure - * - * @return string - */ - public static function remove_invisible_characters( - string $str, - bool $url_encoded = false, - string $replacement = '', - bool $keep_basic_control_characters = true - ): string { - // init - $non_displayables = []; - - // every control character except: - // - newline (dec 10), - // - carriage return (dec 13), - // - horizontal tab (dec 09) - if ($url_encoded) { - $non_displayables[] = '/%0[0-8bcefBCEF]/'; // url encoded 00-08, 11, 12, 14, 15 - $non_displayables[] = '/%1[0-9a-fA-F]/'; // url encoded 16-31 - } - - if ($keep_basic_control_characters) { - $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 - } else { - $str = self::normalize_whitespace($str, false, false, true); - $non_displayables[] = '/[^\P{C}\s]/u'; - } - - do { - $str = (string) \preg_replace($non_displayables, $replacement, $str, -1, $count); - } while ($count !== 0); - - return $str; - } - - /** - * WARNING: This method will return broken characters and is only for special cases. - * - * Convert two UTF-8 encoded strings to a single-byte strings suitable for - * functions that need the same string length after the conversion. - * - * The function simply uses (and updates) a tailored dynamic encoding - * (in/out map parameter) where non-ascii characters are remapped to - * the range [128-255] in order of appearance. - * - * @return array{0: string, 1: string} - */ - public static function to_ascii_remap(string $str1, string $str2): array - { - $charMap = []; - $str1 = self::to_ascii_remap_intern($str1, $charMap); - $str2 = self::to_ascii_remap_intern($str2, $charMap); - - return [$str1, $str2]; - } - - /** - * Returns an ASCII version of the string. A set of non-ASCII characters are - * replaced with their closest ASCII counterparts, and the rest are removed - * by default. The language or locale of the source string can be supplied - * for language-specific transliteration in any of the following formats: - * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping - * to "aeoeue" rather than "aou" as in other languages. - * - * EXAMPLE: - * ASCII::to_ascii('�Düsseldorf�', 'en'); // Dusseldorf - * - * - * @param string $str

    The input string.

    - * @param string $language [optional]

    Language of the source string. - * (default is 'en') | ASCII::*_LANGUAGE_CODE

    - * @param bool $remove_unsupported_chars [optional]

    Whether to remove the - * unsupported characters.

    - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " pound - * ".

    - * @param bool $use_transliterate [optional]

    Use ASCII::to_transliterate() for unknown chars.

    - * @param bool $replace_single_chars_only [optional]

    Single char replacement is better for the - * performance, but some languages need to replace more than one char - * at the same time. If FALSE === auto-setting, depended on the - * language

    - * - * @psalm-pure - * - * @return string - *

    A string that contains only ASCII characters.

    - * - * @phpstan-param ASCII::*_LANGUAGE_CODE $language - */ - public static function to_ascii( - string $str, - string $language = self::ENGLISH_LANGUAGE_CODE, - bool $remove_unsupported_chars = true, - bool $replace_extra_symbols = false, - bool $use_transliterate = false, - bool $replace_single_chars_only = false - ): string { - if ($str === '') { - return ''; - } - - /** @phpstan-var ASCII::*_LANGUAGE_CODE $language - hack for phpstan */ - $language = self::get_language($language); - - static $EXTRA_SYMBOLS_CACHE = null; - - static $REPLACE_HELPER_CACHE = []; - $cacheKey = $language . '-' . $replace_extra_symbols; - - if (!isset($REPLACE_HELPER_CACHE[$cacheKey])) { - $langAll = self::charsArrayWithSingleLanguageValues($replace_extra_symbols, false); - - $langSpecific = self::charsArrayWithOneLanguage($language, $replace_extra_symbols, false); - - if ($langSpecific === []) { - $REPLACE_HELPER_CACHE[$cacheKey] = $langAll; - } else { - $REPLACE_HELPER_CACHE[$cacheKey] = \array_merge([], $langAll, $langSpecific); - } - } - - if ( - $replace_extra_symbols - && - $EXTRA_SYMBOLS_CACHE === null - ) { - $EXTRA_SYMBOLS_CACHE = []; - foreach (self::$ASCII_EXTRAS ?? [] as $extrasDataTmp) { - foreach ($extrasDataTmp as $extrasDataKeyTmp => $extrasDataValueTmp) { - $EXTRA_SYMBOLS_CACHE[$extrasDataKeyTmp] = $extrasDataKeyTmp; - } - } - $EXTRA_SYMBOLS_CACHE = \implode('', $EXTRA_SYMBOLS_CACHE); - } - - $charDone = []; - if (\preg_match_all('/' . self::$REGEX_ASCII . ($replace_extra_symbols ? '|[' . $EXTRA_SYMBOLS_CACHE . ']' : '') . '/u', $str, $matches)) { - if (!$replace_single_chars_only) { - if (self::$LANGUAGE_MAX_KEY === null) { - self::$LANGUAGE_MAX_KEY = self::getData('ascii_language_max_key'); - } - - $maxKeyLength = self::$LANGUAGE_MAX_KEY[$language] ?? 0; - - if ($maxKeyLength >= 5) { - foreach ($matches[0] as $keyTmp => $char) { - if (isset($matches[0][$keyTmp + 4])) { - $fiveChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2] . $matches[0][$keyTmp + 3] . $matches[0][$keyTmp + 4]; - } else { - $fiveChars = null; - } - if ( - $fiveChars - && - !isset($charDone[$fiveChars]) - && - isset($REPLACE_HELPER_CACHE[$cacheKey][$fiveChars]) - && - \strpos($str, $fiveChars) !== false - ) { - // DEBUG - //\var_dump($str, $fiveChars, $REPLACE_HELPER_CACHE[$cacheKey][$fiveChars]); - - $charDone[$fiveChars] = true; - $str = \str_replace($fiveChars, $REPLACE_HELPER_CACHE[$cacheKey][$fiveChars], $str); - - // DEBUG - //\var_dump($str, "\n"); - } - } - } - - if ($maxKeyLength >= 4) { - foreach ($matches[0] as $keyTmp => $char) { - if (isset($matches[0][$keyTmp + 3])) { - $fourChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2] . $matches[0][$keyTmp + 3]; - } else { - $fourChars = null; - } - if ( - $fourChars - && - !isset($charDone[$fourChars]) - && - isset($REPLACE_HELPER_CACHE[$cacheKey][$fourChars]) - && - \strpos($str, $fourChars) !== false - ) { - // DEBUG - //\var_dump($str, $fourChars, $REPLACE_HELPER_CACHE[$cacheKey][$fourChars]); - - $charDone[$fourChars] = true; - $str = \str_replace($fourChars, $REPLACE_HELPER_CACHE[$cacheKey][$fourChars], $str); - - // DEBUG - //\var_dump($str, "\n"); - } - } - } - - foreach ($matches[0] as $keyTmp => $char) { - if (isset($matches[0][$keyTmp + 2])) { - $threeChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1] . $matches[0][$keyTmp + 2]; - } else { - $threeChars = null; - } - if ( - $threeChars - && - !isset($charDone[$threeChars]) - && - isset($REPLACE_HELPER_CACHE[$cacheKey][$threeChars]) - && - \strpos($str, $threeChars) !== false - ) { - // DEBUG - //\var_dump($str, $threeChars, $REPLACE_HELPER_CACHE[$cacheKey][$threeChars]); - - $charDone[$threeChars] = true; - $str = \str_replace($threeChars, $REPLACE_HELPER_CACHE[$cacheKey][$threeChars], $str); - - // DEBUG - //\var_dump($str, "\n"); - } - } - - foreach ($matches[0] as $keyTmp => $char) { - if (isset($matches[0][$keyTmp + 1])) { - $twoChars = $matches[0][$keyTmp + 0] . $matches[0][$keyTmp + 1]; - } else { - $twoChars = null; - } - if ( - $twoChars - && - !isset($charDone[$twoChars]) - && - isset($REPLACE_HELPER_CACHE[$cacheKey][$twoChars]) - && - \strpos($str, $twoChars) !== false - ) { - // DEBUG - //\var_dump($str, $twoChars, $REPLACE_HELPER_CACHE[$cacheKey][$twoChars]); - - $charDone[$twoChars] = true; - $str = \str_replace($twoChars, $REPLACE_HELPER_CACHE[$cacheKey][$twoChars], $str); - - // DEBUG - //\var_dump($str, "\n"); - } - } - } - - foreach ($matches[0] as $char) { - if ( - !isset($charDone[$char]) - && - isset($REPLACE_HELPER_CACHE[$cacheKey][$char]) - && - \strpos($str, $char) !== false - ) { - // DEBUG - //\var_dump($str, $char, $REPLACE_HELPER_CACHE[$cacheKey][$char]); - - $charDone[$char] = true; - $str = \str_replace($char, $REPLACE_HELPER_CACHE[$cacheKey][$char], $str); - - // DEBUG - //\var_dump($str, "\n"); - } - } - } - - if (!isset(self::$ASCII_MAPS[$language])) { - $use_transliterate = true; - } - - if ($use_transliterate) { - $str = self::to_transliterate($str, null, false); - } - - if ($remove_unsupported_chars) { - $str = (string) \str_replace(["\n\r", "\n", "\r", "\t"], ' ', $str); - $str = (string) \preg_replace('/' . self::$REGEX_ASCII . '/', '', $str); - } - - return $str; - } - - /** - * Convert given string to safe filename (and keep string case). - * - * EXAMPLE: - * ASCII::to_filename('שדגשדג.png', true)); // 'shdgshdg.png' - * - * - * @param string $str

    The string input.

    - * @param bool $use_transliterate

    ASCII::to_transliterate() is used by default - unsafe characters are - * simply replaced with hyphen otherwise.

    - * @param string $fallback_char

    The fallback character. - "-" is the default

    - * - * @psalm-pure - * - * @return string - *

    A string that contains only safe characters for a filename.

    - */ - public static function to_filename( - string $str, - bool $use_transliterate = true, - string $fallback_char = '-' - ): string { - if ($use_transliterate) { - $str = self::to_transliterate($str, $fallback_char); - } - - $fallback_char_escaped = \preg_quote($fallback_char, '/'); - - $str = (string) \preg_replace( - [ - '/[^' . $fallback_char_escaped . '.\\-a-zA-Z\d\\s]/', // 1) remove un-needed chars - '/\s+/u', // 2) convert spaces to $fallback_char - '/[' . $fallback_char_escaped . ']+/u', // 3) remove double $fallback_char's - ], - [ - '', - $fallback_char, - $fallback_char, - ], - $str - ); - - return \trim($str, $fallback_char); - } - - /** - * Converts a string into a URL-friendly slug. - * - * - This includes replacing non-ASCII characters with their closest ASCII equivalents, removing remaining - * non-ASCII and non-alphanumeric characters, and replacing whitespace with $separator. - * - The separator defaults to a single dash, and the string is also converted to lowercase. - * - The language of the source string can also be supplied for language-specific transliteration. - * - * @param string $str

    The string input.

    - * @param string $separator [optional]

    The string used to replace whitespace.

    - * @param string $language [optional]

    Language of the source string. - * (default is 'en') | ASCII::*_LANGUAGE_CODE

    - * @param array $replacements [optional]

    A map of replaceable strings.

    - * @param bool $replace_extra_symbols [optional]

    Add some more replacements e.g. "£" with " - * pound ".

    - * @param bool $use_str_to_lower [optional]

    Use "string to lower" for the input.

    - * @param bool $use_transliterate [optional]

    Use ASCII::to_transliterate() for unknown - * chars.

    - * @psalm-pure - * - * @return string - *

    The URL-friendly slug.

    - * - * @phpstan-param ASCII::*_LANGUAGE_CODE $language - */ - public static function to_slugify( - string $str, - string $separator = '-', - string $language = self::ENGLISH_LANGUAGE_CODE, - array $replacements = [], - bool $replace_extra_symbols = false, - bool $use_str_to_lower = true, - bool $use_transliterate = false - ): string { - if ($str === '') { - return ''; - } - - foreach ($replacements as $from => $to) { - $str = \str_replace($from, $to, $str); - } - - $str = self::to_ascii( - $str, - $language, - false, - $replace_extra_symbols, - $use_transliterate - ); - - $str = \str_replace('@', $separator, $str); - - $str = (string) \preg_replace( - '/[^a-zA-Z\\d\\s\\-_' . \preg_quote($separator, '/') . ']/', - '', - $str - ); - - if ($use_str_to_lower) { - $str = \strtolower($str); - } - - $str = (string) \preg_replace('/^[\'\\s]+|[\'\\s]+$/', '', $str); - $str = (string) \preg_replace('/\\B([A-Z])/', '-\1', $str); - $str = (string) \preg_replace('/[\\-_\\s]+/', $separator, $str); - - $l = \strlen($separator); - if ($l && \strpos($str, $separator) === 0) { - $str = (string) \substr($str, $l); - } - - if (\substr($str, -$l) === $separator) { - $str = (string) \substr($str, 0, \strlen($str) - $l); - } - - return $str; - } - - /** - * Returns an ASCII version of the string. A set of non-ASCII characters are - * replaced with their closest ASCII counterparts, and the rest are removed - * unless instructed otherwise. - * - * EXAMPLE: - * ASCII::to_transliterate('déjà σσς iıii'); // 'deja sss iiii' - * - * - * @param string $str

    The input string.

    - * @param string|null $unknown [optional]

    Character use if character unknown. (default is '?') - * But you can also use NULL to keep the unknown chars.

    - * @param bool $strict [optional]

    Use "transliterator_transliterate()" from PHP-Intl - * - * @psalm-pure - * - * @return string - *

    A String that contains only ASCII characters.

    - */ - public static function to_transliterate( - string $str, - $unknown = '?', - bool $strict = false - ): string { - static $UTF8_TO_TRANSLIT = null; - - static $TRANSLITERATOR = null; - - static $SUPPORT_INTL = null; - - if ($str === '') { - return ''; - } - - if ($SUPPORT_INTL === null) { - $SUPPORT_INTL = \extension_loaded('intl'); - } - - // check if we only have ASCII, first (better performance) - $str_tmp = $str; - if (self::is_ascii($str)) { - return $str; - } - - $str = self::clean($str); - - // check again if we only have ASCII, now ... - if ( - $str_tmp !== $str - && - self::is_ascii($str) - ) { - return $str; - } - - if ( - $strict - && - $SUPPORT_INTL === true - ) { - if (!isset($TRANSLITERATOR)) { - // INFO: see "*-Latin" rules via "transliterator_list_ids()" - $TRANSLITERATOR = \transliterator_create('NFKC; [:Nonspacing Mark:] Remove; NFKC; Any-Latin; Latin-ASCII;'); - } - - // INFO: https://unicode.org/cldr/utility/character.jsp - $str_tmp = \transliterator_transliterate($TRANSLITERATOR, $str); - - if ($str_tmp !== false) { - // check again if we only have ASCII, now ... - if ( - $str_tmp !== $str - && - self::is_ascii($str_tmp) - ) { - return $str_tmp; - } - - $str = $str_tmp; - } - } - - if (self::$ORD === null) { - self::$ORD = self::getData('ascii_ord'); - } - - \preg_match_all('/.|[^\x00]$/us', $str, $array_tmp); - $chars = $array_tmp[0]; - $ord = null; - $str_tmp = ''; - foreach ($chars as &$c) { - $ordC0 = self::$ORD[$c[0]]; - - if ($ordC0 >= 0 && $ordC0 <= 127) { - $str_tmp .= $c; - - continue; - } - - $ordC1 = self::$ORD[$c[1]]; - - // ASCII - next please - if ($ordC0 >= 192 && $ordC0 <= 223) { - $ord = ($ordC0 - 192) * 64 + ($ordC1 - 128); - } - - if ($ordC0 >= 224) { - $ordC2 = self::$ORD[$c[2]]; - - if ($ordC0 <= 239) { - $ord = ($ordC0 - 224) * 4096 + ($ordC1 - 128) * 64 + ($ordC2 - 128); - } - - if ($ordC0 >= 240) { - $ordC3 = self::$ORD[$c[3]]; - - if ($ordC0 <= 247) { - $ord = ($ordC0 - 240) * 262144 + ($ordC1 - 128) * 4096 + ($ordC2 - 128) * 64 + ($ordC3 - 128); - } - - // We only process valid UTF-8 chars (<= 4 byte), so we don't need this code here ... - /* - if ($ordC0 >= 248) { - $ordC4 = self::$ORD[$c[4]]; - - if ($ordC0 <= 251) { - $ord = ($ordC0 - 248) * 16777216 + ($ordC1 - 128) * 262144 + ($ordC2 - 128) * 4096 + ($ordC3 - 128) * 64 + ($ordC4 - 128); - } - - if ($ordC0 >= 252) { - $ordC5 = self::$ORD[$c[5]]; - - if ($ordC0 <= 253) { - $ord = ($ordC0 - 252) * 1073741824 + ($ordC1 - 128) * 16777216 + ($ordC2 - 128) * 262144 + ($ordC3 - 128) * 4096 + ($ordC4 - 128) * 64 + ($ordC5 - 128); - } - } - } - */ - } - } - - if ( - $ordC0 === 254 - || - $ordC0 === 255 - || - $ord === null - ) { - $str_tmp .= $unknown ?? $c; - - continue; - } - - $bank = $ord >> 8; - if (!isset($UTF8_TO_TRANSLIT[$bank])) { - $UTF8_TO_TRANSLIT[$bank] = self::getDataIfExists(\sprintf('x%03x', $bank)); - } - - $new_char = $ord & 255; - - if (isset($UTF8_TO_TRANSLIT[$bank][$new_char])) { - // keep for debugging - /* - echo "file: " . sprintf('x%02x', $bank) . "\n"; - echo "char: " . $c . "\n"; - echo "ord: " . $ord . "\n"; - echo "new_char: " . $new_char . "\n"; - echo "new_char: " . mb_chr($new_char) . "\n"; - echo "ascii: " . $UTF8_TO_TRANSLIT[$bank][$new_char] . "\n"; - echo "bank:" . $bank . "\n\n"; - */ - - $new_char = $UTF8_TO_TRANSLIT[$bank][$new_char]; - - /* @noinspection PhpStatementHasEmptyBodyInspection */ - if ($unknown === null && $new_char === '') { - // nothing - } elseif ( - $new_char === '[?]' - || - $new_char === '[?] ' - ) { - $c = $unknown ?? $c; - } else { - $c = $new_char; - } - } else { - // keep for debugging missing chars - /* - echo "file: " . sprintf('x%02x', $bank) . "\n"; - echo "char: " . $c . "\n"; - echo "ord: " . $ord . "\n"; - echo "new_char: " . $new_char . "\n"; - echo "new_char: " . mb_chr($new_char) . "\n"; - echo "bank:" . $bank . "\n\n"; - */ - - $c = $unknown ?? $c; - } - - $str_tmp .= $c; - } - - return $str_tmp; - } - - /** - * WARNING: This method will return broken characters and is only for special cases. - * - * Convert a UTF-8 encoded string to a single-byte string suitable for - * functions that need the same string length after the conversion. - * - * The function simply uses (and updates) a tailored dynamic encoding - * (in/out map parameter) where non-ascii characters are remapped to - * the range [128-255] in order of appearance. - * - * Thus, it supports up to 128 different multibyte code points max over - * the whole set of strings sharing this encoding. - * - * Source: https://github.com/KEINOS/mb_levenshtein - * - * @param string $str

    UTF-8 string to be converted to extended ASCII.

    - * @param array $map

    Internal-Map of code points to ASCII characters.

    - * - * @return string - *

    Mapped broken string.

    - * - * @phpstan-param array $map - */ - private static function to_ascii_remap_intern(string $str, array &$map): string - { - // find all utf-8 characters - $matches = []; - if (!\preg_match_all('/[\xC0-\xF7][\x80-\xBF]+/', $str, $matches)) { - return $str; // plain ascii string - } - - // update the encoding map with the characters not already met - $mapCount = \count($map); - foreach ($matches[0] as $mbc) { - if (!isset($map[$mbc])) { - $map[$mbc] = \chr(128 + $mapCount); - ++$mapCount; - } - } - - // finally, remap non-ascii characters - return \strtr($str, $map); - } - - /** - * Get the language from a string. - * - * e.g.: de_at -> de_at - * de_DE -> de - * DE_DE -> de - * de-de -> de - * - * @return string - */ - private static function get_language(string $language) - { - if ($language === '') { - return ''; - } - - if ( - \strpos($language, '_') === false - && - \strpos($language, '-') === false - ) { - return \strtolower($language); - } - - $language = \str_replace('-', '_', \strtolower($language)); - - $regex = '/(?[a-z]+)_\g{first}/'; - - return (string) \preg_replace($regex, '$1', $language); - } - - /** - * Get data from "/data/*.php". - * - * @return array - */ - private static function getData(string $file) - { - return include __DIR__ . '/data/' . $file . '.php'; - } - - /** - * Get data from "/data/*.php". - * - * @return array - */ - private static function getDataIfExists(string $file): array - { - $file = __DIR__ . '/data/' . $file . '.php'; - if (\is_file($file)) { - return include $file; - } - - return []; - } - - /** - * @return void - */ - private static function prepareAsciiAndExtrasMaps() - { - if (self::$ASCII_MAPS_AND_EXTRAS === null) { - self::prepareAsciiMaps(); - self::prepareAsciiExtras(); - - self::$ASCII_MAPS_AND_EXTRAS = \array_merge_recursive( - self::$ASCII_MAPS ?? [], - self::$ASCII_EXTRAS ?? [] - ); - } - } - - /** - * @return void - */ - private static function prepareAsciiMaps() - { - if (self::$ASCII_MAPS === null) { - self::$ASCII_MAPS = self::getData('ascii_by_languages'); - } - } - - /** - * @return void - */ - private static function prepareAsciiExtras() - { - if (self::$ASCII_EXTRAS === null) { - self::$ASCII_EXTRAS = self::getData('ascii_extras_by_languages'); - } - } -} diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_by_languages.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_by_languages.php deleted file mode 100644 index 68c3f9d25..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_by_languages.php +++ /dev/null @@ -1,2950 +0,0 @@ - [ - 'Á' => 'A', - 'á' => 'a', - 'Ä' => 'A', - 'ä' => 'a', - 'À' => 'A', - 'à' => 'a', - 'Â' => 'A', - 'â' => 'a', - 'É' => 'E', - 'é' => 'e', - 'Ë' => 'E', - 'ë' => 'e', - 'È' => 'E', - 'è' => 'e', - 'Ê' => 'E', - 'ê' => 'e', - 'Í' => 'I', - 'í' => 'i', - 'Ï' => 'I', - 'ï' => 'i', - 'Ì' => 'I', - 'ì' => 'i', - 'Î' => 'I', - 'î' => 'i', - 'Ó' => 'O', - 'ó' => 'o', - 'Ö' => 'O', - 'ö' => 'o', - 'Ò' => 'O', - 'ò' => 'o', - 'Ô' => 'O', - 'ô' => 'o', - 'Ú' => 'U', - 'ú' => 'u', - 'Ü' => 'U', - 'ü' => 'u', - 'Ù' => 'U', - 'ù' => 'u', - 'Û' => 'U', - 'û' => 'u', - 'Ý' => 'Y', - 'ý' => 'y', - 'Ÿ' => 'Y', - ], - // Italian - 'it' => [ - 'à' => 'a', - 'À' => 'A', - 'é' => 'e', - 'É' => 'E', - 'è' => 'e', - 'È' => 'E', - 'ì' => 'i', - 'Ì' => 'I', - 'Ò' => 'O', - 'ò' => 'o', - 'ù' => 'u', - 'Ù' => 'U', - ], - // Macedonian - 'mk' => [ - 'А' => 'A', - 'Б' => 'B', - 'В' => 'V', - 'Г' => 'G', - 'Д' => 'D', - 'Ѓ' => 'Gj', - 'Е' => 'E', - 'Ж' => 'Zh', - 'З' => 'Z', - 'Ѕ' => 'Dz', - 'И' => 'I', - 'Ј' => 'J', - 'К' => 'K', - 'Л' => 'L', - 'Љ' => 'Lj', - 'М' => 'M', - 'Н' => 'N', - 'Њ' => 'Nj', - 'О' => 'O', - 'П' => 'P', - 'Р' => 'R', - 'С' => 'S', - 'Т' => 'T', - 'Ќ' => 'Kj', - 'У' => 'U', - 'Ф' => 'F', - 'Х' => 'H', - 'Ц' => 'C', - 'Ч' => 'Ch', - 'Џ' => 'Dj', - 'Ш' => 'Sh', - 'а' => 'a', - 'б' => 'b', - 'в' => 'v', - 'г' => 'g', - 'д' => 'd', - 'ѓ' => 'gj', - 'е' => 'e', - 'ж' => 'zh', - 'з' => 'z', - 'ѕ' => 'dz', - 'и' => 'i', - 'ј' => 'j', - 'к' => 'k', - 'л' => 'l', - 'љ' => 'lj', - 'м' => 'm', - 'н' => 'n', - 'њ' => 'nj', - 'о' => 'o', - 'п' => 'p', - 'р' => 'r', - 'с' => 's', - 'т' => 't', - 'ќ' => 'kj', - 'у' => 'u', - 'ф' => 'f', - 'х' => 'h', - 'ц' => 'c', - 'ч' => 'ch', - 'џ' => 'dj', - 'ш' => 'sh', - ], - // Portuguese (Brazil) - 'pt' => [ - 'æ' => 'ae', - 'ǽ' => 'ae', - 'À' => 'A', - 'Á' => 'A', - 'Â' => 'A', - 'Ã' => 'A', - 'Å' => 'AA', - 'Ǻ' => 'A', - 'Ă' => 'A', - 'Ǎ' => 'A', - 'Æ' => 'AE', - 'Ǽ' => 'AE', - 'à' => 'a', - 'á' => 'a', - 'â' => 'a', - 'ã' => 'a', - 'å' => 'aa', - 'ǻ' => 'a', - 'ă' => 'a', - 'ǎ' => 'a', - 'ª' => 'a', - 'Ĉ' => 'C', - 'Ċ' => 'C', - 'Ç' => 'C', - 'ç' => 'c', - 'ĉ' => 'c', - 'ċ' => 'c', - 'Ð' => 'Dj', - 'Đ' => 'D', - 'ð' => 'dj', - 'đ' => 'd', - 'È' => 'E', - 'É' => 'E', - 'Ê' => 'E', - 'Ë' => 'E', - 'Ĕ' => 'E', - 'Ė' => 'E', - 'è' => 'e', - 'é' => 'e', - 'ê' => 'e', - 'ë' => 'e', - 'ĕ' => 'e', - 'ė' => 'e', - 'ƒ' => 'f', - 'Ĝ' => 'G', - 'Ġ' => 'G', - 'ĝ' => 'g', - 'ġ' => 'g', - 'Ĥ' => 'H', - 'Ħ' => 'H', - 'ĥ' => 'h', - 'ħ' => 'h', - 'Ì' => 'I', - 'Í' => 'I', - 'Î' => 'I', - 'Ï' => 'I', - 'Ĩ' => 'I', - 'Ĭ' => 'I', - 'Ǐ' => 'I', - 'Į' => 'I', - 'IJ' => 'IJ', - 'ì' => 'i', - 'í' => 'i', - 'î' => 'i', - 'ï' => 'i', - 'ĩ' => 'i', - 'ĭ' => 'i', - 'ǐ' => 'i', - 'į' => 'i', - 'ij' => 'ij', - 'Ĵ' => 'J', - 'ĵ' => 'j', - 'Ĺ' => 'L', - 'Ľ' => 'L', - 'Ŀ' => 'L', - 'ĺ' => 'l', - 'ľ' => 'l', - 'ŀ' => 'l', - 'Ñ' => 'N', - 'ñ' => 'n', - 'ʼn' => 'n', - 'Ò' => 'O', - 'Ó' => 'O', - 'Ô' => 'O', - 'Õ' => 'O', - 'Ō' => 'O', - 'Ŏ' => 'O', - 'Ǒ' => 'O', - 'Ő' => 'O', - 'Ơ' => 'O', - 'Ø' => 'OE', - 'Ǿ' => 'O', - 'Œ' => 'OE', - 'ò' => 'o', - 'ó' => 'o', - 'ô' => 'o', - 'õ' => 'o', - 'ō' => 'o', - 'ŏ' => 'o', - 'ǒ' => 'o', - 'ő' => 'o', - 'ơ' => 'o', - 'ø' => 'oe', - 'ǿ' => 'o', - 'º' => 'o', - 'œ' => 'oe', - 'Ŕ' => 'R', - 'Ŗ' => 'R', - 'ŕ' => 'r', - 'ŗ' => 'r', - 'Ŝ' => 'S', - 'Ș' => 'S', - 'ŝ' => 's', - 'ș' => 's', - 'ſ' => 's', - 'Ţ' => 'T', - 'Ț' => 'T', - 'Ŧ' => 'T', - 'Þ' => 'TH', - 'ţ' => 't', - 'ț' => 't', - 'ŧ' => 't', - 'þ' => 'th', - 'Ù' => 'U', - 'Ú' => 'U', - 'Û' => 'U', - 'Ü' => 'U', - 'Ũ' => 'U', - 'Ŭ' => 'U', - 'Ű' => 'U', - 'Ų' => 'U', - 'Ư' => 'U', - 'Ǔ' => 'U', - 'Ǖ' => 'U', - 'Ǘ' => 'U', - 'Ǚ' => 'U', - 'Ǜ' => 'U', - 'ù' => 'u', - 'ú' => 'u', - 'û' => 'u', - 'ü' => 'u', - 'ũ' => 'u', - 'ŭ' => 'u', - 'ű' => 'u', - 'ų' => 'u', - 'ư' => 'u', - 'ǔ' => 'u', - 'ǖ' => 'u', - 'ǘ' => 'u', - 'ǚ' => 'u', - 'ǜ' => 'u', - 'Ŵ' => 'W', - 'ŵ' => 'w', - 'Ý' => 'Y', - 'Ÿ' => 'Y', - 'Ŷ' => 'Y', - 'ý' => 'y', - 'ÿ' => 'y', - 'ŷ' => 'y', - ], - // Greek(lish) (Elláda) - 'el__greeklish' => [ - 'ΑΥ' => 'AU', - 'ΑΎ' => 'AU', - 'Αυ' => 'Au', - 'Αύ' => 'Au', - 'ΕΊ' => 'EI', - 'ΕΙ' => 'EI', - 'Ει' => 'EI', - 'ΕΥ' => 'EU', - 'ΕΎ' => 'EU', - 'Εί' => 'Ei', - 'Ευ' => 'Eu', - 'Εύ' => 'Eu', - 'ΟΙ' => 'OI', - 'ΟΊ' => 'OI', - 'ΟΥ' => 'OU', - 'ΟΎ' => 'OU', - 'Οι' => 'Oi', - 'Οί' => 'Oi', - 'Ου' => 'Ou', - 'Ού' => 'Ou', - 'ΥΙ' => 'YI', - 'ΎΙ' => 'YI', - 'Υι' => 'Yi', - 'Ύι' => 'Yi', - 'ΥΊ' => 'Yi', - 'Υί' => 'Yi', - 'αυ' => 'au', - 'αύ' => 'au', - 'εί' => 'ei', - 'ει' => 'ei', - 'ευ' => 'eu', - 'εύ' => 'eu', - 'οι' => 'oi', - 'οί' => 'oi', - 'ου' => 'ou', - 'ού' => 'ou', - 'υι' => 'yi', - 'ύι' => 'yi', - 'υί' => 'yi', - 'Α' => 'A', - 'Ά' => 'A', - 'Β' => 'B', - 'Δ' => 'D', - 'Ε' => 'E', - 'Έ' => 'E', - 'Φ' => 'F', - 'Γ' => 'G', - 'Η' => 'H', - 'Ή' => 'H', - 'Ι' => 'I', - 'Ί' => 'I', - 'Ϊ' => 'I', - 'Κ' => 'K', - 'Ξ' => 'Ks', - 'Λ' => 'L', - 'Μ' => 'M', - 'Ν' => 'N', - 'Π' => 'N', - 'Ο' => 'O', - 'Ό' => 'O', - 'Ψ' => 'Ps', - 'Ρ' => 'R', - 'Σ' => 'S', - 'Τ' => 'T', - 'Θ' => 'Th', - 'Ω' => 'W', - 'Ώ' => 'W', - 'Χ' => 'X', - 'ϒ' => 'Y', - 'Υ' => 'Y', - 'Ύ' => 'Y', - 'Ϋ' => 'Y', - 'Ζ' => 'Z', - 'α' => 'a', - 'ά' => 'a', - 'β' => 'b', - 'δ' => 'd', - 'ε' => 'e', - 'έ' => 'e', - 'φ' => 'f', - 'γ' => 'g', - 'η' => 'h', - 'ή' => 'h', - 'ι' => 'i', - 'ί' => 'i', - 'ϊ' => 'i', - 'ΐ' => 'i', - 'κ' => 'k', - 'ξ' => 'ks', - 'λ' => 'l', - 'μ' => 'm', - 'ν' => 'n', - 'ο' => 'o', - 'ό' => 'o', - 'π' => 'p', - 'ψ' => 'ps', - 'ρ' => 'r', - 'σ' => 's', - 'ς' => 's', - 'τ' => 't', - 'ϑ' => 'th', - 'θ' => 'th', - 'ϐ' => 'v', - 'ω' => 'w', - 'ώ' => 'w', - 'χ' => 'x', - 'υ' => 'y', - 'ύ' => 'y', - 'ΰ' => 'y', - 'ϋ' => 'y', - 'ζ' => 'z', - ], - // Greek (Elláda) - 'el' => [ - 'ΑΥ' => 'AU', - 'Αυ' => 'Au', - 'ΟΥ' => 'U', - 'Ου' => 'u', - 'ΕΥ' => 'EF', - 'Ευ' => 'Ef', - 'ΕΙ' => 'I', - 'Ει' => 'I', - 'ΟΙ' => 'I', - 'Οι' => 'I', - 'ΥΙ' => 'I', - 'Υι' => 'I', - 'ΑΎ' => 'AU', - 'Αύ' => 'Au', - 'ΟΎ' => 'OU', - 'Ού' => 'Ou', - 'ΕΎ' => 'EU', - 'Εύ' => 'Eu', - 'ΕΊ' => 'I', - 'Εί' => 'I', - 'ΟΊ' => 'I', - 'Οί' => 'I', - 'ΎΙ' => 'I', - 'Ύι' => 'I', - 'ΥΊ' => 'I', - 'Υί' => 'I', - 'αυ' => 'au', - 'ου' => 'u', - 'ευ' => 'ef', - 'ει' => 'i', - 'οι' => 'i', - 'υι' => 'i', - 'αύ' => 'au', - 'ού' => 'ou', - 'εύ' => 'eu', - 'εί' => 'i', - 'οί' => 'i', - 'ύι' => 'i', - 'υί' => 'i', - 'α' => 'a', - 'β' => 'v', - 'γ' => 'gh', - 'δ' => 'd', - 'ε' => 'e', - 'ζ' => 'z', - 'η' => 'i', - 'θ' => 'th', - 'ι' => 'i', - 'κ' => 'k', - 'λ' => 'l', - 'μ' => 'm', - 'ν' => 'n', - 'ξ' => 'ks', - 'ο' => 'o', - 'π' => 'p', - 'ρ' => 'r', - 'σ' => 's', - 'τ' => 't', - 'υ' => 'i', - 'φ' => 'f', - 'χ' => 'kh', - 'ψ' => 'ps', - 'ω' => 'o', - 'ά' => 'a', - 'έ' => 'e', - 'ί' => 'i', - 'ό' => 'o', - 'ϒ' => 'Y', - 'ύ' => 'y', - 'ή' => 'i', - 'ώ' => 'w', - 'ς' => 's', - 'ϊ' => 'i', - 'ΰ' => 'y', - 'ϋ' => 'y', - 'ΐ' => 'i', - 'Α' => 'A', - 'Β' => 'B', - 'Γ' => 'G', - 'Δ' => 'D', - 'Ε' => 'E', - 'Ζ' => 'Z', - 'Η' => 'H', - 'Θ' => 'Th', - 'Ι' => 'I', - 'Κ' => 'K', - 'Λ' => 'L', - 'Μ' => 'M', - 'Ν' => 'N', - 'Ξ' => 'Ks', - 'Ο' => 'O', - 'Π' => 'P', - 'Ρ' => 'R', - 'Σ' => 'S', - 'Τ' => 'T', - 'Υ' => 'Y', - 'Φ' => 'F', - 'Χ' => 'X', - 'Ψ' => 'Ps', - 'Ω' => 'O', - 'Ά' => 'A', - 'Έ' => 'E', - 'Ί' => 'I', - 'Ό' => 'O', - 'Ύ' => 'Y', - 'Ή' => 'I', - 'Ώ' => 'W', - 'Ϊ' => 'I', - 'Ϋ' => 'Y', - 'ϐ' => 'v', - 'ϑ' => 'th', - ], - // Hindi - 'hi' => [ - 'अ' => 'a', - 'आ' => 'aa', - 'ए' => 'e', - 'ई' => 'ii', - 'ऍ' => 'ei', - 'ऎ' => 'ae', - 'ऐ' => 'ai', - 'इ' => 'i', - 'ओ' => 'o', - 'ऑ' => 'oi', - 'ऒ' => 'oii', - 'ऊ' => 'uu', - 'औ' => 'ou', - 'उ' => 'u', - 'ब' => 'B', - 'भ' => 'Bha', - 'च' => 'Ca', - 'छ' => 'Chha', - 'ड' => 'Da', - 'ढ' => 'Dha', - 'फ' => 'Fa', - 'फ़' => 'Fi', - 'ग' => 'Ga', - 'घ' => 'Gha', - 'ग़' => 'Ghi', - 'ह' => 'Ha', - 'ज' => 'Ja', - 'झ' => 'Jha', - 'क' => 'Ka', - 'ख' => 'Kha', - 'ख़' => 'Khi', - 'ल' => 'L', - 'ळ' => 'Li', - 'ऌ' => 'Li', - 'ऴ' => 'Lii', - 'ॡ' => 'Lii', - 'म' => 'Ma', - 'न' => 'Na', - 'ङ' => 'Na', - 'ञ' => 'Nia', - 'ण' => 'Nae', - 'ऩ' => 'Ni', - 'ॐ' => 'oms', - 'प' => 'Pa', - 'क़' => 'Qi', - 'र' => 'Ra', - 'ऋ' => 'Ri', - 'ॠ' => 'Ri', - 'ऱ' => 'Ri', - 'स' => 'Sa', - 'श' => 'Sha', - 'ष' => 'Shha', - 'ट' => 'Ta', - 'त' => 'Ta', - 'ठ' => 'Tha', - 'द' => 'Tha', - 'थ' => 'Tha', - 'ध' => 'Thha', - 'ड़' => 'ugDha', - 'ढ़' => 'ugDhha', - 'व' => 'Va', - 'य' => 'Ya', - 'य़' => 'Yi', - 'ज़' => 'Za', - ], - // Armenian - 'hy' => [ - 'Ա' => 'A', - 'Բ' => 'B', - 'Գ' => 'G', - 'Դ' => 'D', - 'Ե' => 'E', - 'Զ' => 'Z', - 'Է' => 'E', - 'Ը' => 'Y', - 'Թ' => 'Th', - 'Ժ' => 'Zh', - 'Ի' => 'I', - 'Լ' => 'L', - 'Խ' => 'Kh', - 'Ծ' => 'Ts', - 'Կ' => 'K', - 'Հ' => 'H', - 'Ձ' => 'Dz', - 'Ղ' => 'Gh', - 'Ճ' => 'Tch', - 'Մ' => 'M', - 'Յ' => 'Y', - 'Ն' => 'N', - 'Շ' => 'Sh', - 'Ո' => 'Vo', - 'Չ' => 'Ch', - 'Պ' => 'P', - 'Ջ' => 'J', - 'Ռ' => 'R', - 'Ս' => 'S', - 'Վ' => 'V', - 'Տ' => 'T', - 'Ր' => 'R', - 'Ց' => 'C', - 'Ւ' => 'u', - 'Փ' => 'Ph', - 'Ք' => 'Q', - 'և' => 'ev', - 'Օ' => 'O', - 'Ֆ' => 'F', - 'ա' => 'a', - 'բ' => 'b', - 'գ' => 'g', - 'դ' => 'd', - 'ե' => 'e', - 'զ' => 'z', - 'է' => 'e', - 'ը' => 'y', - 'թ' => 'th', - 'ժ' => 'zh', - 'ի' => 'i', - 'լ' => 'l', - 'խ' => 'kh', - 'ծ' => 'ts', - 'կ' => 'k', - 'հ' => 'h', - 'ձ' => 'dz', - 'ղ' => 'gh', - 'ճ' => 'tch', - 'մ' => 'm', - 'յ' => 'y', - 'ն' => 'n', - 'շ' => 'sh', - 'ո' => 'vo', - 'չ' => 'ch', - 'պ' => 'p', - 'ջ' => 'j', - 'ռ' => 'r', - 'ս' => 's', - 'վ' => 'v', - 'տ' => 't', - 'ր' => 'r', - 'ց' => 'c', - 'ւ' => 'u', - 'փ' => 'ph', - 'ք' => 'q', - 'օ' => 'o', - 'ֆ' => 'f', - ], - // Swedish - 'sv' => [ - 'Ä' => 'A', - 'ä' => 'a', - 'Å' => 'A', - 'å' => 'a', - 'Ö' => 'O', - 'ö' => 'o', - ], - // Turkmen - 'tk' => [ - 'Ç' => 'C', - 'Ä' => 'A', - 'Ž' => 'Z', - 'Ň' => 'N', - 'Ö' => 'O', - 'Ş' => 'S', - 'Ü' => 'U', - 'Ý' => 'Y', - 'ç' => 'c', - 'ä' => 'a', - 'ž' => 'z', - 'ň' => 'n', - 'ö' => 'o', - 'ş' => 's', - 'ü' => 'u', - 'ý' => 'y', - ], - // Turkish - 'tr' => [ - 'ň' => 'n', - 'Ň' => 'N', - 'ş' => 's', - 'Ş' => 'S', - 'ı' => 'i', - 'İ' => 'I', - 'ç' => 'c', - 'Ç' => 'C', - 'ä' => 'a', - 'Ä' => 'A', - 'ü' => 'u', - 'Ü' => 'U', - 'ö' => 'o', - 'Ö' => 'O', - 'ğ' => 'g', - 'Ğ' => 'G', - 'ý' => 'y', - 'Ý' => 'Y', - 'ž' => 'z', - 'Ž' => 'Z', - ], - // Bulgarian - 'bg' => [ - 'ьо' => 'yo', - 'А' => 'A', - 'Б' => 'B', - 'В' => 'V', - 'Г' => 'G', - 'Д' => 'D', - 'Е' => 'E', - 'Ж' => 'Zh', - 'З' => 'Z', - 'И' => 'I', - 'Й' => 'Y', - 'К' => 'K', - 'Л' => 'L', - 'М' => 'M', - 'Н' => 'N', - 'О' => 'O', - 'П' => 'P', - 'Р' => 'R', - 'С' => 'S', - 'Т' => 'T', - 'У' => 'U', - 'Ф' => 'F', - 'Х' => 'H', - 'Ц' => 'C', - 'Ч' => 'Ch', - 'Ш' => 'Sh', - 'Щ' => 'Sht', - 'Ъ' => 'A', - 'Ь' => '', - 'Ю' => 'Yu', - 'Я' => 'Ya', - 'а' => 'a', - 'б' => 'b', - 'в' => 'v', - 'г' => 'g', - 'д' => 'd', - 'е' => 'e', - 'ж' => 'zh', - 'з' => 'z', - 'и' => 'i', - 'й' => 'y', - 'к' => 'k', - 'л' => 'l', - 'м' => 'm', - 'н' => 'n', - 'о' => 'o', - 'п' => 'p', - 'р' => 'r', - 'с' => 's', - 'т' => 't', - 'у' => 'u', - 'ф' => 'f', - 'х' => 'h', - 'ц' => 'c', - 'ч' => 'ch', - 'ш' => 'sh', - 'щ' => 'sht', - 'ъ' => 'a', - 'ь' => '', - 'ю' => 'yu', - 'я' => 'ya', - ], - // Hungarian - 'hu' => [ - 'Á' => 'A', - 'Ē' => 'E', - 'É' => 'E', - 'Í' => 'I', - 'Ó' => 'O', - 'Ö' => 'O', - 'Ő' => 'O', - 'Ú' => 'U', - 'Ü' => 'U', - 'Ű' => 'U', - 'á' => 'a', - 'ē' => 'e', - 'é' => 'e', - 'í' => 'i', - 'ó' => 'o', - 'ö' => 'o', - 'ő' => 'o', - 'ú' => 'u', - 'ü' => 'u', - 'ű' => 'u', - ], - // Myanmar (Burmese) - 'my' => [ - 'န်ုပ်' => 'nub', - 'ောင်' => 'aung', - 'ိုက်' => 'aik', - 'ိုဒ်' => 'ok', - 'ိုင်' => 'aing', - 'ိုလ်' => 'ol', - 'ေါင်' => 'aung', - 'သြော' => 'aw', - 'ောက်' => 'auk', - 'ိတ်' => 'eik', - 'ုတ်' => 'ok', - 'ုန်' => 'on', - 'ေတ်' => 'it', - 'ုဒ်' => 'ait', - 'ာန်' => 'an', - 'ိန်' => 'ein', - 'ွတ်' => 'ut', - 'ေါ်' => 'aw', - 'ွန်' => 'un', - 'ိပ်' => 'eik', - 'ုပ်' => 'ok', - 'ွပ်' => 'ut', - 'ိမ်' => 'ein', - 'ုမ်' => 'on', - 'ော်' => 'aw', - 'ွမ်' => 'un', - 'က်' => 'et', - 'ေါ' => 'aw', - 'ော' => 'aw', - 'ျွ' => 'ywa', - 'ြွ' => 'yw', - 'ို' => 'o', - 'ုံ' => 'on', - 'တ်' => 'at', - 'င်' => 'in', - 'ည်' => 'i', - 'ဒ်' => 'd', - 'န်' => 'an', - 'ပ်' => 'at', - 'မ်' => 'an', - 'စျ' => 'za', - 'ယ်' => 'e', - 'ဉ်' => 'in', - 'စ်' => 'it', - 'ိံ' => 'ein', - 'ဲ' => 'e', - 'း' => '', - 'ာ' => 'a', - 'ါ' => 'a', - 'ေ' => 'e', - 'ံ' => 'an', - 'ိ' => 'i', - 'ီ' => 'i', - 'ု' => 'u', - 'ူ' => 'u', - '်' => 'at', - '္' => '', - '့' => '', - 'က' => 'k', - '၉' => '9', - 'တ' => 't', - 'ရ' => 'ya', - 'ယ' => 'y', - 'မ' => 'm', - 'ဘ' => 'ba', - 'ဗ' => 'b', - 'ဖ' => 'pa', - 'ပ' => 'p', - 'န' => 'n', - 'ဓ' => 'da', - 'ဒ' => 'd', - 'ထ' => 'ta', - 'ဏ' => 'na', - 'ဝ' => 'w', - 'ဎ' => 'da', - 'ဍ' => 'd', - 'ဌ' => 'ta', - 'ဋ' => 't', - 'ည' => 'ny', - 'ဇ' => 'z', - 'ဆ' => 'sa', - 'စ' => 's', - 'င' => 'ng', - 'ဃ' => 'ga', - 'ဂ' => 'g', - 'လ' => 'l', - 'သ' => 'th', - '၈' => '8', - 'ဩ' => 'aw', - 'ခ' => 'kh', - '၆' => '6', - '၅' => '5', - '၄' => '4', - '၃' => '3', - '၂' => '2', - '၁' => '1', - '၀' => '0', - '၌' => 'hnaik', - '၍' => 'ywae', - 'ဪ' => 'aw', - 'ဦ' => '-u', - 'ဟ' => 'h', - 'ဉ' => 'u', - 'ဤ' => '-i', - 'ဣ' => 'i', - '၏' => '-e', - 'ဧ' => 'e', - 'ှ' => 'h', - 'ွ' => 'w', - 'ျ' => 'ya', - 'ြ' => 'y', - 'အ' => 'a', - 'ဠ' => 'la', - '၇' => '7', - ], - // Croatian (Hrvatska) - 'hr' => [ - 'DŽ' => 'DZ', - 'Dž' => 'Dz', - 'dž' => 'dz', - 'DZ' => 'DZ', - 'Dz' => 'Dz', - 'dz' => 'dz', - 'IJ' => 'IJ', - 'ij' => 'ij', - 'LJ' => 'LJ', - 'Lj' => 'Lj', - 'lj' => 'lj', - 'NJ' => 'NJ', - 'Nj' => 'Nj', - 'nj' => 'nj', - 'ž' => 'z', - 'Ž' => 'Z', - 'đ' => 'dj', - 'Đ' => 'Dj', - 'č' => 'c', - 'Č' => 'C', - 'ć' => 'c', - 'Ć' => 'C', - 'š' => 's', - 'Š' => 'S', - ], - // Finnish - 'fi' => [ - 'Ä' => 'A', - 'Ö' => 'O', - 'ä' => 'a', - 'ö' => 'o', - ], - // Georgian (Kartvelian) - 'ka' => [ - 'ა' => 'a', - 'ბ' => 'b', - 'გ' => 'g', - 'დ' => 'd', - 'ე' => 'e', - 'ვ' => 'v', - 'ზ' => 'z', - 'თ' => 't', - 'ი' => 'i', - 'კ' => 'k', - 'ლ' => 'l', - 'მ' => 'm', - 'ნ' => 'n', - 'ო' => 'o', - 'პ' => 'p', - 'ჟ' => 'zh', - 'რ' => 'r', - 'ს' => 's', - 'ტ' => 't', - 'უ' => 'u', - 'ფ' => 'f', - 'ქ' => 'q', - 'ღ' => 'gh', - 'ყ' => 'y', - 'შ' => 'sh', - 'ჩ' => 'ch', - 'ც' => 'ts', - 'ძ' => 'dz', - 'წ' => 'ts', - 'ჭ' => 'ch', - 'ხ' => 'kh', - 'ჯ' => 'j', - 'ჰ' => 'h', - ], - // Russian - 'ru' => [ - 'А' => 'A', - 'а' => 'a', - 'Б' => 'B', - 'б' => 'b', - 'В' => 'V', - 'в' => 'v', - 'Г' => 'G', - 'г' => 'g', - 'Д' => 'D', - 'д' => 'd', - 'Е' => 'E', - 'е' => 'e', - 'Ё' => 'Yo', - 'ё' => 'yo', - 'Ж' => 'Zh', - 'ж' => 'zh', - 'З' => 'Z', - 'з' => 'z', - 'И' => 'I', - 'и' => 'i', - 'Й' => 'Y', - 'й' => 'y', - 'К' => 'K', - 'к' => 'k', - 'Л' => 'L', - 'л' => 'l', - 'М' => 'M', - 'м' => 'm', - 'Н' => 'N', - 'н' => 'n', - 'О' => 'O', - 'о' => 'o', - 'П' => 'P', - 'п' => 'p', - 'Р' => 'R', - 'р' => 'r', - 'С' => 'S', - 'с' => 's', - 'Т' => 'T', - 'т' => 't', - 'У' => 'U', - 'у' => 'u', - 'Ф' => 'F', - 'ф' => 'f', - 'Х' => 'H', - 'х' => 'h', - 'Ц' => 'Ts', - 'ц' => 'ts', - 'Ч' => 'Ch', - 'ч' => 'ch', - 'ш' => 'sh', - 'Ш' => 'Sh', - 'Щ' => 'Sch', - 'щ' => 'sch', - 'Ъ' => '', - 'ъ' => '', - 'Ы' => 'Y', - 'ы' => 'y', - 'Ь' => '', - 'ь' => '', - 'Э' => 'E', - 'э' => 'e', - 'Ю' => 'Yu', - 'ю' => 'yu', - 'Я' => 'Ya', - 'я' => 'ya', - ], - // Russian - GOST 7.79-2000(B) - // -> https://en.m.wikipedia.org/wiki/Romanization_of_Russian#content-collapsible-block-1 - 'ru__gost_2000_b' => [ - 'А' => 'A', - 'а' => 'a', - 'Б' => 'B', - 'б' => 'b', - 'В' => 'V', - 'в' => 'v', - 'Г' => 'G', - 'г' => 'g', - 'Д' => 'D', - 'д' => 'd', - 'Е' => 'E', - 'е' => 'e', - 'Ё' => 'Yo', - 'ё' => 'yo', - 'Ж' => 'Zh', - 'ж' => 'zh', - 'З' => 'Z', - 'з' => 'z', - 'И' => 'i', - 'и' => 'i', - 'Й' => 'i', - 'й' => 'i', - 'К' => 'K', - 'к' => 'k', - 'Л' => 'L', - 'л' => 'l', - 'М' => 'M', - 'м' => 'm', - 'Н' => 'N', - 'н' => 'n', - 'О' => 'O', - 'о' => 'o', - 'П' => 'P', - 'п' => 'p', - 'Р' => 'R', - 'р' => 'r', - 'С' => 'S', - 'с' => 's', - 'Т' => 'T', - 'т' => 't', - 'У' => 'U', - 'у' => 'u', - 'Ф' => 'F', - 'ф' => 'f', - 'Х' => 'X', - 'х' => 'x', - 'Ц' => 'Cz', - 'ц' => 'cz', - 'Ч' => 'Ch', - 'ч' => 'ch', - 'ш' => 'sh', - 'Ш' => 'Sh', - 'Щ' => 'Shh', - 'щ' => 'shh', - 'Ъ' => '', - 'ъ' => '', - 'Ы' => 'Y\'', - 'ы' => 'y\'', - 'Ь' => '', - 'ь' => '', - 'Э' => 'E\'', - 'э' => 'e\'', - 'Ю' => 'Yu', - 'ю' => 'yu', - 'Я' => 'Ya', - 'я' => 'ya', - 'І' => 'I', - 'і' => 'i', - 'Ѳ' => 'Fh', - 'ѳ' => 'fh', - 'Ѣ' => 'Ye', - 'ѣ' => 'ye', - 'Ѵ' => 'Yh', - 'ѵ' => 'yh', - 'Є' => '', - 'є' => '', - 'Ѥ' => '', - 'ѥ' => '', - 'Ѕ' => 'Js', - 'ѕ' => 'js', - 'Ꙋ' => '', - 'ꙋ' => '', - 'Ѡ' => '', - 'ѡ' => '', - 'Ѿ' => '', - 'ѿ' => '', - 'Ѫ' => '', - 'ѫ' => '', - 'Ѧ' => '', - 'ѧ' => '', - 'Ѭ' => '', - 'ѭ' => '', - 'Ѩ' => '', - 'ѩ' => '', - 'Ѯ' => '', - 'ѯ' => '', - 'Ѱ' => '', - 'ѱ' => '', - ], - // Russian - Passport (2013), ICAO - // -> https://en.m.wikipedia.org/wiki/Romanization_of_Russian#content-collapsible-block-1 - 'ru__passport_2013' => [ - 'А' => 'A', - 'а' => 'a', - 'Б' => 'B', - 'б' => 'b', - 'В' => 'V', - 'в' => 'v', - 'Г' => 'G', - 'г' => 'g', - 'Д' => 'D', - 'д' => 'd', - 'Е' => 'E', - 'е' => 'e', - 'Ё' => 'E', - 'ё' => 'e', - 'Ж' => 'Zh', - 'ж' => 'zh', - 'З' => 'Z', - 'з' => 'z', - 'И' => 'i', - 'и' => 'i', - 'Й' => 'i', - 'й' => 'i', - 'К' => 'K', - 'к' => 'k', - 'Л' => 'L', - 'л' => 'l', - 'М' => 'M', - 'м' => 'm', - 'Н' => 'N', - 'н' => 'n', - 'О' => 'O', - 'о' => 'o', - 'П' => 'P', - 'п' => 'p', - 'Р' => 'R', - 'р' => 'r', - 'С' => 'S', - 'с' => 's', - 'Т' => 'T', - 'т' => 't', - 'У' => 'U', - 'у' => 'u', - 'Ф' => 'F', - 'ф' => 'f', - 'Х' => 'Kh', - 'х' => 'kh', - 'Ц' => 'Ts', - 'ц' => 'ts', - 'Ч' => 'Ch', - 'ч' => 'ch', - 'ш' => 'sh', - 'Ш' => 'Sh', - 'Щ' => 'Shch', - 'щ' => 'shch', - 'Ъ' => 'Ie', - 'ъ' => 'ie', - 'Ы' => 'Y', - 'ы' => 'y', - 'Ь' => '', - 'ь' => '', - 'Э' => 'E', - 'э' => 'e', - 'Ю' => 'Iu', - 'ю' => 'iu', - 'Я' => 'Ia', - 'я' => 'ia', - 'І' => '', - 'і' => '', - 'Ѳ' => '', - 'ѳ' => '', - 'Ѣ' => '', - 'ѣ' => '', - 'Ѵ' => '', - 'ѵ' => '', - 'Є' => '', - 'є' => '', - 'Ѥ' => '', - 'ѥ' => '', - 'Ѕ' => '', - 'ѕ' => '', - 'Ꙋ' => '', - 'ꙋ' => '', - 'Ѡ' => '', - 'ѡ' => '', - 'Ѿ' => '', - 'ѿ' => '', - 'Ѫ' => '', - 'ѫ' => '', - 'Ѧ' => '', - 'ѧ' => '', - 'Ѭ' => '', - 'ѭ' => '', - 'Ѩ' => '', - 'ѩ' => '', - 'Ѯ' => '', - 'ѯ' => '', - 'Ѱ' => '', - 'ѱ' => '', - ], - // Ukrainian - // -> https://zakon.rada.gov.ua/laws/show/55-2010-%D0%BF?lang=en - 'uk' => [ - 'Г' => 'H', - 'г' => 'h', - 'Ґ' => 'G', - 'ґ' => 'g', - 'Є' => 'Ye', - 'є' => 'ye', - 'И' => 'Y', - 'и' => 'y', - 'І' => 'I', - 'і' => 'i', - 'Ї' => 'Yi', - 'ї' => 'yi', - 'Й' => 'Y', - 'й' => 'y', - 'Х' => 'Kh', - 'х' => 'kh', - 'Ц' => 'Ts', - 'ц' => 'ts', - 'Ч' => 'Ch', - 'ч' => 'ch', - 'Ш' => 'Sh', - 'ш' => 'sh', - 'Щ' => 'Shch', - 'щ' => 'shch', - ], - // Kazakh - 'kk' => [ - 'Ә' => 'A', - 'Ғ' => 'G', - 'Қ' => 'Q', - 'Ң' => 'N', - 'Ө' => 'O', - 'Ұ' => 'U', - 'Ү' => 'U', - 'Һ' => 'H', - 'ә' => 'a', - 'ғ' => 'g', - 'қ' => 'q', - 'ң' => 'n', - 'ө' => 'o', - 'ұ' => 'u', - 'ү' => 'u', - 'һ' => 'h', - ], - // Czech - 'cs' => [ - 'á' => 'a', - 'Á' => 'A', - 'č' => 'c', - 'Č' => 'C', - 'ď' => 'd', - 'Ď' => 'D', - 'é' => 'e', - 'É' => 'E', - 'ě' => 'e', - 'Ě' => 'E', - 'í' => 'i', - 'Í' => 'I', - 'ň' => 'n', - 'Ň' => 'N', - 'ó' => 'o', - 'Ó' => 'O', - 'ř' => 'r', - 'Ř' => 'R', - 'š' => 's', - 'Š' => 'S', - 'ť' => 't', - 'Ť' => 'T', - 'ú' => 'u', - 'Ú' => 'U', - 'ů' => 'u', - 'Ů' => 'U', - 'ý' => 'y', - 'Ý' => 'Y', - 'ž' => 'z', - 'Ž' => 'Z', - ], - // Danish - 'da' => [ - 'Æ' => 'Ae', - 'æ' => 'ae', - 'Ø' => 'Oe', - 'ø' => 'oe', - 'Å' => 'Aa', - 'å' => 'aa', - 'É' => 'E', - 'é' => 'e', - ], - // Polish - 'pl' => [ - 'ą' => 'a', - 'ć' => 'c', - 'ę' => 'e', - 'ł' => 'l', - 'ń' => 'n', - 'ó' => 'o', - 'ś' => 's', - 'ź' => 'z', - 'ż' => 'z', - 'Ą' => 'A', - 'Ć' => 'C', - 'Ę' => 'E', - 'Ł' => 'L', - 'Ń' => 'N', - 'Ó' => 'O', - 'Ś' => 'S', - 'Ź' => 'Z', - 'Ż' => 'Z', - ], - // Romanian - 'ro' => [ - 'ă' => 'a', - 'â' => 'a', - 'Ă' => 'A', - 'Â' => 'A', - 'î' => 'i', - 'Î' => 'I', - 'ș' => 's', - 'ş' => 's', - 'Ş' => 'S', - 'Ș' => 'S', - 'ț' => 't', - 'ţ' => 't', - 'Ţ' => 'T', - 'Ț' => 'T', - ], - // Esperanto - 'eo' => [ - 'ĉ' => 'cx', - 'ĝ' => 'gx', - 'ĥ' => 'hx', - 'ĵ' => 'jx', - 'ŝ' => 'sx', - 'ŭ' => 'ux', - 'Ĉ' => 'CX', - 'Ĝ' => 'GX', - 'Ĥ' => 'HX', - 'Ĵ' => 'JX', - 'Ŝ' => 'SX', - 'Ŭ' => 'UX', - ], - // Estonian - 'et' => [ - 'Š' => 'S', - 'Ž' => 'Z', - 'Õ' => 'O', - 'Ä' => 'A', - 'Ö' => 'O', - 'Ü' => 'U', - 'š' => 's', - 'ž' => 'z', - 'õ' => 'o', - 'ä' => 'a', - 'ö' => 'o', - 'ü' => 'u', - ], - // Latvian - 'lv' => [ - 'ā' => 'a', - 'č' => 'c', - 'ē' => 'e', - 'ģ' => 'g', - 'ī' => 'i', - 'ķ' => 'k', - 'ļ' => 'l', - 'ņ' => 'n', - 'š' => 's', - 'ū' => 'u', - 'ž' => 'z', - 'Ā' => 'A', - 'Č' => 'C', - 'Ē' => 'E', - 'Ģ' => 'G', - 'Ī' => 'i', - 'Ķ' => 'k', - 'Ļ' => 'L', - 'Ņ' => 'N', - 'Š' => 'S', - 'Ū' => 'u', - 'Ž' => 'Z', - ], - // Lithuanian - 'lt' => [ - 'ą' => 'a', - 'č' => 'c', - 'ę' => 'e', - 'ė' => 'e', - 'į' => 'i', - 'š' => 's', - 'ų' => 'u', - 'ū' => 'u', - 'ž' => 'z', - 'Ą' => 'A', - 'Č' => 'C', - 'Ę' => 'E', - 'Ė' => 'E', - 'Į' => 'I', - 'Š' => 'S', - 'Ų' => 'U', - 'Ū' => 'U', - 'Ž' => 'Z', - ], - // Norwegian - 'no' => [ - 'Æ' => 'AE', - 'æ' => 'ae', - 'Ø' => 'OE', - 'ø' => 'oe', - 'Å' => 'AA', - 'å' => 'aa', - ], - // Vietnamese - 'vi' => [ - 'Á' => 'A', - 'À' => 'A', - 'Ả' => 'A', - 'Ã' => 'A', - 'Ạ' => 'A', - 'Ă' => 'A', - 'Ắ' => 'A', - 'Ằ' => 'A', - 'Ẳ' => 'A', - 'Ẵ' => 'A', - 'Ặ' => 'A', - 'Â' => 'A', - 'Ấ' => 'A', - 'Ầ' => 'A', - 'Ẩ' => 'A', - 'Ẫ' => 'A', - 'Ậ' => 'A', - 'á' => 'a', - 'à' => 'a', - 'ả' => 'a', - 'ã' => 'a', - 'ạ' => 'a', - 'ă' => 'a', - 'ắ' => 'a', - 'ằ' => 'a', - 'ẳ' => 'a', - 'ẵ' => 'a', - 'ặ' => 'a', - 'â' => 'a', - 'ấ' => 'a', - 'ầ' => 'a', - 'ẩ' => 'a', - 'ẫ' => 'a', - 'ậ' => 'a', - 'É' => 'E', - 'È' => 'E', - 'Ẻ' => 'E', - 'Ẽ' => 'E', - 'Ẹ' => 'E', - 'Ê' => 'E', - 'Ế' => 'E', - 'Ề' => 'E', - 'Ể' => 'E', - 'Ễ' => 'E', - 'Ệ' => 'E', - 'é' => 'e', - 'è' => 'e', - 'ẻ' => 'e', - 'ẽ' => 'e', - 'ẹ' => 'e', - 'ê' => 'e', - 'ế' => 'e', - 'ề' => 'e', - 'ể' => 'e', - 'ễ' => 'e', - 'ệ' => 'e', - 'Í' => 'I', - 'Ì' => 'I', - 'Ỉ' => 'I', - 'Ĩ' => 'I', - 'Ị' => 'I', - 'í' => 'i', - 'ì' => 'i', - 'ỉ' => 'i', - 'ĩ' => 'i', - 'ị' => 'i', - 'Ó' => 'O', - 'Ò' => 'O', - 'Ỏ' => 'O', - 'Õ' => 'O', - 'Ọ' => 'O', - 'Ô' => 'O', - 'Ố' => 'O', - 'Ồ' => 'O', - 'Ổ' => 'O', - 'Ỗ' => 'O', - 'Ộ' => 'O', - 'Ơ' => 'O', - 'Ớ' => 'O', - 'Ờ' => 'O', - 'Ở' => 'O', - 'Ỡ' => 'O', - 'Ợ' => 'O', - 'ó' => 'o', - 'ò' => 'o', - 'ỏ' => 'o', - 'õ' => 'o', - 'ọ' => 'o', - 'ô' => 'o', - 'ố' => 'o', - 'ồ' => 'o', - 'ổ' => 'o', - 'ỗ' => 'o', - 'ộ' => 'o', - 'ơ' => 'o', - 'ớ' => 'o', - 'ờ' => 'o', - 'ở' => 'o', - 'ỡ' => 'o', - 'ợ' => 'o', - 'Ú' => 'U', - 'Ù' => 'U', - 'Ủ' => 'U', - 'Ũ' => 'U', - 'Ụ' => 'U', - 'Ư' => 'U', - 'Ứ' => 'U', - 'Ừ' => 'U', - 'Ử' => 'U', - 'Ữ' => 'U', - 'Ự' => 'U', - 'ú' => 'u', - 'ù' => 'u', - 'ủ' => 'u', - 'ũ' => 'u', - 'ụ' => 'u', - 'ư' => 'u', - 'ứ' => 'u', - 'ừ' => 'u', - 'ử' => 'u', - 'ữ' => 'u', - 'ự' => 'u', - 'Ý' => 'Y', - 'Ỳ' => 'Y', - 'Ỷ' => 'Y', - 'Ỹ' => 'Y', - 'Ỵ' => 'Y', - 'ý' => 'y', - 'ỳ' => 'y', - 'ỷ' => 'y', - 'ỹ' => 'y', - 'ỵ' => 'y', - 'Đ' => 'D', - 'đ' => 'd', - ], - // Persian (Farsi) - 'fa' => [ - 'ا' => 'a', - 'ب' => 'b', - 'پ' => 'p', - 'ت' => 't', - 'ث' => 's', - 'ج' => 'j', - 'چ' => 'ch', - 'ح' => 'h', - 'خ' => 'kh', - 'د' => 'd', - 'ذ' => 'z', - 'ر' => 'r', - 'ز' => 'z', - 'س' => 's', - 'ش' => 'sh', - 'ص' => 's', - 'ض' => 'z', - 'ط' => 't', - 'ظ' => 'z', - 'ع' => 'a', - 'غ' => 'gh', - 'ف' => 'f', - 'ق' => 'gh', - 'ک' => 'k', - 'گ' => 'g', - 'ل' => 'l', - 'ژ' => 'zh', - 'ك' => 'k', - 'م' => 'm', - 'ن' => 'n', - 'ه' => 'h', - 'و' => 'o', - 'ی' => 'y', - 'آ' => 'a', - '٠' => '0', - '١' => '1', - '٢' => '2', - '٣' => '3', - '٤' => '4', - '٥' => '5', - '٦' => '6', - '٧' => '7', - '٨' => '8', - '٩' => '9', - ], - // Arabic - 'ar' => [ - 'أ' => 'a', - 'ب' => 'b', - 'ت' => 't', - 'ث' => 'th', - 'ج' => 'g', - 'ح' => 'h', - 'خ' => 'kh', - 'د' => 'd', - 'ذ' => 'th', - 'ر' => 'r', - 'ز' => 'z', - 'س' => 's', - 'ش' => 'sh', - 'ص' => 's', - 'ض' => 'd', - 'ط' => 't', - 'ظ' => 'th', - 'ع' => 'aa', - 'غ' => 'gh', - 'ف' => 'f', - 'ق' => 'k', - 'ك' => 'k', - 'ل' => 'l', - 'م' => 'm', - 'ن' => 'n', - 'ه' => 'h', - 'و' => 'o', - 'ي' => 'y', - 'ا' => 'a', - 'إ' => 'a', - 'آ' => 'a', - 'ؤ' => 'o', - 'ئ' => 'y', - 'ء' => 'aa', - '٠' => '0', - '١' => '1', - '٢' => '2', - '٣' => '3', - '٤' => '4', - '٥' => '5', - '٦' => '6', - '٧' => '7', - '٨' => '8', - '٩' => '9', - ], - // Serbian - 'sr' => [ - 'đ' => 'dj', - 'ž' => 'z', - 'ć' => 'c', - 'č' => 'c', - 'š' => 's', - 'Đ' => 'Dj', - 'Ž' => 'Z', - 'Ć' => 'C', - 'Č' => 'C', - 'Š' => 'S', - 'а' => 'a', - 'б' => 'b', - 'в' => 'v', - 'г' => 'g', - 'д' => 'd', - 'ђ' => 'dj', - 'е' => 'e', - 'ж' => 'z', - 'з' => 'z', - 'и' => 'i', - 'ј' => 'j', - 'к' => 'k', - 'л' => 'l', - 'љ' => 'lj', - 'м' => 'm', - 'н' => 'n', - 'њ' => 'nj', - 'о' => 'o', - 'п' => 'p', - 'р' => 'r', - 'с' => 's', - 'т' => 't', - 'ћ' => 'c', - 'у' => 'u', - 'ф' => 'f', - 'х' => 'h', - 'ц' => 'c', - 'ч' => 'c', - 'џ' => 'dz', - 'ш' => 's', - 'А' => 'A', - 'Б' => 'B', - 'В' => 'V', - 'Г' => 'G', - 'Д' => 'D', - 'Ђ' => 'Dj', - 'Е' => 'E', - 'Ж' => 'Z', - 'З' => 'Z', - 'И' => 'I', - 'Ј' => 'j', - 'К' => 'K', - 'Л' => 'L', - 'Љ' => 'Lj', - 'М' => 'M', - 'Н' => 'N', - 'Њ' => 'Nj', - 'О' => 'O', - 'П' => 'P', - 'Р' => 'R', - 'С' => 'S', - 'Т' => 'T', - 'Ћ' => 'C', - 'У' => 'U', - 'Ф' => 'F', - 'Х' => 'H', - 'Ц' => 'C', - 'Ч' => 'C', - 'Џ' => 'Dz', - 'Ш' => 'S', - ], - // Serbian - Cyrillic - 'sr__cyr' => [ - 'а' => 'a', - 'б' => 'b', - 'в' => 'v', - 'г' => 'g', - 'д' => 'd', - 'ђ' => 'dj', - 'е' => 'e', - 'ж' => 'z', - 'з' => 'z', - 'и' => 'i', - 'ј' => 'j', - 'к' => 'k', - 'л' => 'l', - 'љ' => 'lj', - 'м' => 'm', - 'н' => 'n', - 'њ' => 'nj', - 'о' => 'o', - 'п' => 'p', - 'р' => 'r', - 'с' => 's', - 'т' => 't', - 'ћ' => 'c', - 'у' => 'u', - 'ф' => 'f', - 'х' => 'h', - 'ц' => 'c', - 'ч' => 'c', - 'џ' => 'dz', - 'ш' => 's', - 'А' => 'A', - 'Б' => 'B', - 'В' => 'V', - 'Г' => 'G', - 'Д' => 'D', - 'Ђ' => 'Dj', - 'Е' => 'E', - 'Ж' => 'Z', - 'З' => 'Z', - 'И' => 'I', - 'Ј' => 'j', - 'К' => 'K', - 'Л' => 'L', - 'Љ' => 'Lj', - 'М' => 'M', - 'Н' => 'N', - 'Њ' => 'Nj', - 'О' => 'O', - 'П' => 'P', - 'Р' => 'R', - 'С' => 'S', - 'Т' => 'T', - 'Ћ' => 'C', - 'У' => 'U', - 'Ф' => 'F', - 'Х' => 'H', - 'Ц' => 'C', - 'Ч' => 'C', - 'Џ' => 'Dz', - 'Ш' => 'S', - ], - // Serbian - Latin - 'sr__lat' => [ - 'đ' => 'dj', - 'ž' => 'z', - 'ć' => 'c', - 'č' => 'c', - 'š' => 's', - 'Đ' => 'Dj', - 'Ž' => 'Z', - 'Ć' => 'C', - 'Č' => 'C', - 'Š' => 'S', - ], - // Azerbaijani - 'az' => [ - 'ç' => 'c', - 'ə' => 'e', - 'ğ' => 'g', - 'ı' => 'i', - 'ö' => 'o', - 'ş' => 's', - 'ü' => 'u', - 'Ç' => 'C', - 'Ə' => 'E', - 'Ğ' => 'G', - 'İ' => 'I', - 'Ö' => 'O', - 'Ş' => 'S', - 'Ü' => 'U', - ], - // Slovak - 'sk' => [ - 'á' => 'a', - 'ä' => 'a', - 'č' => 'c', - 'ď' => 'd', - 'é' => 'e', - 'í' => 'i', - 'ľ' => 'l', - 'ĺ' => 'l', - 'ň' => 'n', - 'ó' => 'o', - 'ô' => 'o', - 'ŕ' => 'r', - 'š' => 's', - 'ť' => 't', - 'ú' => 'u', - 'ý' => 'y', - 'ž' => 'z', - 'Á' => 'A', - 'Ä' => 'A', - 'Č' => 'C', - 'Ď' => 'D', - 'É' => 'E', - 'Í' => 'I', - 'Ľ' => 'L', - 'Ĺ' => 'L', - 'Ň' => 'N', - 'Ó' => 'O', - 'Ô' => 'O', - 'Ŕ' => 'R', - 'Š' => 'S', - 'Ť' => 'T', - 'Ú' => 'U', - 'Ý' => 'Y', - 'Ž' => 'Z', - ], - // French - 'fr' => [ - 'Æ' => 'AE', - 'æ' => 'ae', - 'Œ' => 'OE', - 'œ' => 'oe', - 'â' => 'a', - 'Â' => 'A', - 'à' => 'a', - 'À' => 'A', - 'ä' => 'a', - 'Ä' => 'A', - 'ç' => 'c', - 'Ç' => 'C', - 'é' => 'e', - 'É' => 'E', - 'ê' => 'e', - 'Ê' => 'E', - 'ë' => 'e', - 'Ë' => 'E', - 'è' => 'e', - 'È' => 'E', - 'ï' => 'i', - 'î' => 'i', - 'Ï' => 'I', - 'Î' => 'I', - 'ÿ' => 'y', - 'Ÿ' => 'Y', - 'ô' => 'o', - 'Ô' => 'O', - 'ö' => 'o', - 'Ö' => 'O', - 'û' => 'u', - 'Û' => 'U', - 'ù' => 'u', - 'Ù' => 'U', - 'ü' => 'u', - 'Ü' => 'U', - ], - // Austrian (French) - 'fr_at' => [ - 'ß' => 'sz', - 'ẞ' => 'SZ', - 'Æ' => 'AE', - 'æ' => 'ae', - 'Œ' => 'OE', - 'œ' => 'oe', - 'â' => 'a', - 'Â' => 'A', - 'à' => 'a', - 'À' => 'A', - 'ä' => 'a', - 'Ä' => 'A', - 'ç' => 'c', - 'Ç' => 'C', - 'é' => 'e', - 'É' => 'E', - 'ê' => 'e', - 'Ê' => 'E', - 'ë' => 'e', - 'Ë' => 'E', - 'è' => 'e', - 'È' => 'E', - 'ï' => 'i', - 'î' => 'i', - 'Ï' => 'I', - 'Î' => 'I', - 'ÿ' => 'y', - 'Ÿ' => 'Y', - 'ô' => 'o', - 'Ô' => 'O', - 'ö' => 'o', - 'Ö' => 'O', - 'û' => 'u', - 'Û' => 'U', - 'ù' => 'u', - 'Ù' => 'U', - 'ü' => 'u', - 'Ü' => 'U', - ], - // Switzerland (French) - 'fr_ch' => [ - 'ß' => 'ss', - 'ẞ' => 'SS', - 'Æ' => 'AE', - 'æ' => 'ae', - 'Œ' => 'OE', - 'œ' => 'oe', - 'â' => 'a', - 'Â' => 'A', - 'à' => 'a', - 'À' => 'A', - 'ä' => 'a', - 'Ä' => 'A', - 'ç' => 'c', - 'Ç' => 'C', - 'é' => 'e', - 'É' => 'E', - 'ê' => 'e', - 'Ê' => 'E', - 'ë' => 'e', - 'Ë' => 'E', - 'è' => 'e', - 'È' => 'E', - 'ï' => 'i', - 'î' => 'i', - 'Ï' => 'I', - 'Î' => 'I', - 'ÿ' => 'y', - 'Ÿ' => 'Y', - 'ô' => 'o', - 'Ô' => 'O', - 'ö' => 'o', - 'Ö' => 'O', - 'û' => 'u', - 'Û' => 'U', - 'ù' => 'u', - 'Ù' => 'U', - 'ü' => 'u', - 'Ü' => 'U', - ], - // German - 'de' => [ - 'Ä' => 'Ae', - 'Ö' => 'Oe', - 'Ü' => 'Ue', - 'ä' => 'ae', - 'ö' => 'oe', - 'ü' => 'ue', - 'ß' => 'ss', - 'ẞ' => 'SS', - ], - // Austrian (German) - 'de_at' => [ - 'Ä' => 'Ae', - 'Ö' => 'Oe', - 'Ü' => 'Ue', - 'ä' => 'ae', - 'ö' => 'oe', - 'ü' => 'ue', - 'ß' => 'sz', - 'ẞ' => 'SZ', - ], - // Switzerland (German) - 'de_ch' => [ - 'Ä' => 'Ae', - 'Ö' => 'Oe', - 'Ü' => 'Ue', - 'ä' => 'ae', - 'ö' => 'oe', - 'ü' => 'ue', - 'ß' => 'ss', - 'ẞ' => 'SS', - ], - // Bengali (Bangla) - 'bn' => [ - 'ভ্ল' => 'vl', - 'পশ' => 'psh', - 'ব্ধ' => 'bdh', - 'ব্জ' => 'bj', - 'ব্দ' => 'bd', - 'ব্ব' => 'bb', - 'ব্ল' => 'bl', - 'ভ' => 'v', - 'ব' => 'b', - 'চ্ঞ' => 'cNG', - 'চ্ছ' => 'cch', - 'চ্চ' => 'cc', - 'ছ' => 'ch', - 'চ' => 'c', - 'ধ্ন' => 'dhn', - 'ধ্ম' => 'dhm', - 'দ্ঘ' => 'dgh', - 'দ্ধ' => 'ddh', - 'দ্ভ' => 'dv', - 'দ্ম' => 'dm', - 'ড্ড' => 'DD', - 'ঢ' => 'Dh', - 'ধ' => 'dh', - 'দ্গ' => 'dg', - 'দ্দ' => 'dd', - 'ড' => 'D', - 'দ' => 'd', - '।' => '.', - 'ঘ্ন' => 'Ghn', - 'গ্ধ' => 'Gdh', - 'গ্ণ' => 'GN', - 'গ্ন' => 'Gn', - 'গ্ম' => 'Gm', - 'গ্ল' => 'Gl', - 'জ্ঞ' => 'jNG', - 'ঘ' => 'Gh', - 'গ' => 'g', - 'হ্ণ' => 'hN', - 'হ্ন' => 'hn', - 'হ্ম' => 'hm', - 'হ্ল' => 'hl', - 'হ' => 'h', - 'জ্ঝ' => 'jjh', - 'ঝ' => 'jh', - 'জ্জ' => 'jj', - 'জ' => 'j', - 'ক্ষ্ণ' => 'kxN', - 'ক্ষ্ম' => 'kxm', - 'ক্ষ' => 'ksh', - 'কশ' => 'ksh', - 'ক্ক' => 'kk', - 'ক্ট' => 'kT', - 'ক্ত' => 'kt', - 'ক্ল' => 'kl', - 'ক্স' => 'ks', - 'খ' => 'kh', - 'ক' => 'k', - 'ল্ভ' => 'lv', - 'ল্ধ' => 'ldh', - 'লখ' => 'lkh', - 'লঘ' => 'lgh', - 'লফ' => 'lph', - 'ল্ক' => 'lk', - 'ল্গ' => 'lg', - 'ল্ট' => 'lT', - 'ল্ড' => 'lD', - 'ল্প' => 'lp', - 'ল্ম' => 'lm', - 'ল্ল' => 'll', - 'ল্ব' => 'lb', - 'ল' => 'l', - 'ম্থ' => 'mth', - 'ম্ফ' => 'mf', - 'ম্ভ' => 'mv', - 'মপ্ল' => 'mpl', - 'ম্ন' => 'mn', - 'ম্প' => 'mp', - 'ম্ম' => 'mm', - 'ম্ল' => 'ml', - 'ম্ব' => 'mb', - 'ম' => 'm', - '০' => '0', - '১' => '1', - '২' => '2', - '৩' => '3', - '৪' => '4', - '৫' => '5', - '৬' => '6', - '৭' => '7', - '৮' => '8', - '৯' => '9', - 'ঙ্ক্ষ' => 'Ngkx', - 'ঞ্ছ' => 'nch', - 'ঙ্ঘ' => 'ngh', - 'ঙ্খ' => 'nkh', - 'ঞ্ঝ' => 'njh', - 'ঙ্গৌ' => 'ngOU', - 'ঙ্গৈ' => 'ngOI', - 'ঞ্চ' => 'nc', - 'ঙ্ক' => 'nk', - 'ঙ্ষ' => 'Ngx', - 'ঙ্গ' => 'ngo', - 'ঙ্ম' => 'Ngm', - 'ঞ্জ' => 'nj', - 'ন্ধ' => 'ndh', - 'ন্ঠ' => 'nTh', - 'ণ্ঠ' => 'NTh', - 'ন্থ' => 'nth', - 'ঙ্গা' => 'nga', - 'ঙ্গি' => 'ngi', - 'ঙ্গী' => 'ngI', - 'ঙ্গু' => 'ngu', - 'ঙ্গূ' => 'ngU', - 'ঙ্গে' => 'nge', - 'ঙ্গো' => 'ngO', - 'ণ্ঢ' => 'NDh', - 'নশ' => 'nsh', - 'ঙর' => 'Ngr', - 'ঞর' => 'NGr', - 'ংর' => 'ngr', - 'ঙ' => 'Ng', - 'ঞ' => 'NG', - 'ং' => 'ng', - 'ন্ন' => 'nn', - 'ণ্ণ' => 'NN', - 'ণ্ন' => 'Nn', - 'ন্ম' => 'nm', - 'ণ্ম' => 'Nm', - 'ন্দ' => 'nd', - 'ন্ট' => 'nT', - 'ণ্ট' => 'NT', - 'ন্ড' => 'nD', - 'ণ্ড' => 'ND', - 'ন্ত' => 'nt', - 'ন্স' => 'ns', - 'ন' => 'n', - 'ণ' => 'N', - 'ৈ' => 'OI', - 'ৌ' => 'OU', - 'ো' => 'O', - 'ঐ' => 'OI', - 'ঔ' => 'OU', - 'অ' => 'o', - 'ও' => 'oo', - 'ফ্ল' => 'fl', - 'প্ট' => 'pT', - 'প্ত' => 'pt', - 'প্ন' => 'pn', - 'প্প' => 'pp', - 'প্ল' => 'pl', - 'প্স' => 'ps', - 'ফ' => 'f', - 'প' => 'p', - 'ৃ' => 'rri', - 'ঋ' => 'rri', - 'রর‍্য' => 'rry', - '্র্য' => 'ry', - '্রর' => 'rr', - 'ড়্গ' => 'Rg', - 'ঢ়' => 'Rh', - 'ড়' => 'R', - 'র' => 'r', - '্র' => 'r', - 'শ্ছ' => 'Sch', - 'ষ্ঠ' => 'ShTh', - 'ষ্ফ' => 'Shf', - 'স্ক্ল' => 'skl', - 'স্খ' => 'skh', - 'স্থ' => 'sth', - 'স্ফ' => 'sf', - 'শ্চ' => 'Sc', - 'শ্ত' => 'St', - 'শ্ন' => 'Sn', - 'শ্ম' => 'Sm', - 'শ্ল' => 'Sl', - 'ষ্ক' => 'Shk', - 'ষ্ট' => 'ShT', - 'ষ্ণ' => 'ShN', - 'ষ্প' => 'Shp', - 'ষ্ম' => 'Shm', - 'স্প্ল' => 'spl', - 'স্ক' => 'sk', - 'স্ট' => 'sT', - 'স্ত' => 'st', - 'স্ন' => 'sn', - 'স্প' => 'sp', - 'স্ম' => 'sm', - 'স্ল' => 'sl', - 'শ' => 'S', - 'ষ' => 'Sh', - 'স' => 's', - 'ু' => 'u', - 'উ' => 'u', - 'অ্য' => 'oZ', - 'ত্থ' => 'tth', - 'ৎ' => 'tt', - 'ট্ট' => 'TT', - 'ট্ম' => 'Tm', - 'ঠ' => 'Th', - 'ত্ন' => 'tn', - 'ত্ম' => 'tm', - 'থ' => 'th', - 'ত্ত' => 'tt', - 'ট' => 'T', - 'ত' => 't', - 'অ্যা' => 'AZ', - 'া' => 'a', - 'আ' => 'a', - 'য়া' => 'ya', - 'য়' => 'y', - 'ি' => 'i', - 'ই' => 'i', - 'ী' => 'ee', - 'ঈ' => 'ee', - 'ূ' => 'uu', - 'ঊ' => 'uu', - 'ে' => 'e', - 'এ' => 'e', - 'য' => 'z', - '্য' => 'Z', - 'ইয়' => 'y', - 'ওয়' => 'w', - '্ব' => 'w', - 'এক্স' => 'x', - 'ঃ' => ':', - 'ঁ' => 'nn', - '্‌' => '', - ], - // English - 'en' => [ - ], - // Latin (+ Cyrillic ?) chars - // - // -> Mix of languages, but we need to keep this here, so that different languages can handle there own behavior. - 'latin' => [ - '˚' => '0', - '¹' => '1', - '²' => '2', - '³' => '3', - '⁴' => '4', - '⁵' => '5', - '⁶' => '6', - '⁷' => '7', - '⁸' => '8', - '⁹' => '9', - '₀' => '0', - '₁' => '1', - '₂' => '2', - '₃' => '3', - '₄' => '4', - '₅' => '5', - '₆' => '6', - '₇' => '7', - '₈' => '8', - '₉' => '9', - '௦' => '0', - '௧' => '1', - '௨' => '2', - '௩' => '3', - '௪' => '4', - '௫' => '5', - '௬' => '6', - '௭' => '7', - '௮' => '8', - '௯' => '9', - '௰' => '10', - '௱' => '100', - '௲' => '1000', - 'Ꜳ' => 'AA', - 'ꜳ' => 'aa', - 'Æ' => 'AE', - 'æ' => 'ae', - 'Ǽ' => 'AE', - 'ǽ' => 'ae', - 'Ꜵ' => 'AO', - 'ꜵ' => 'ao', - 'Ꜷ' => 'AU', - 'ꜷ' => 'au', - 'Ꜹ' => 'AV', - 'ꜹ' => 'av', - 'Ꜻ' => 'av', - 'ꜻ' => 'av', - 'Ꜽ' => 'AY', - 'ꜽ' => 'ay', - 'ȸ' => 'db', - 'ʣ' => 'dz', - 'ʥ' => 'dz', - 'ʤ' => 'dezh', - '🙰' => 'et', - 'ff' => 'ff', - 'ffi' => 'ffi', - 'ffl' => 'ffl', - 'fi' => 'fi', - 'fl' => 'fl', - 'ʩ' => 'feng', - 'IJ' => 'IJ', - 'ij' => 'ij', - 'ʪ' => 'ls', - 'ʫ' => 'lz', - 'ɮ' => 'lezh', - 'ȹ' => 'qp', - 'ʨ' => 'tc', - 'ʦ' => 'ts', - 'ʧ' => 'tesh', - 'Œ' => 'OE', - 'œ' => 'oe', - 'Ꝏ' => 'OO', - 'ꝏ' => 'oo', - 'ẞ' => 'SS', - 'ß' => 'ss', - 'st' => 'st', - 'ſt' => 'st', - 'Ꜩ' => 'TZ', - 'ꜩ' => 'tz', - 'ᵫ' => 'ue', - 'Aι' => 'Ai', - 'αι' => 'ai', - 'Ει' => 'Ei', - 'ει' => 'ei', - 'Οι' => 'Oi', - 'οι' => 'oi', - 'Ου' => 'Oy', - 'ου' => 'oy', - 'Υι' => 'Yi', - 'υι' => 'yi', - 'ἀ' => 'a', - 'ἁ' => 'a', - 'ἂ' => 'a', - 'ἃ' => 'a', - 'ἄ' => 'a', - 'ἅ' => 'a', - 'ἆ' => 'a', - 'ἇ' => 'a', - 'Ἀ' => 'A', - 'Ἁ' => 'A', - 'Ἂ' => 'A', - 'Ἃ' => 'A', - 'Ἄ' => 'A', - 'Ἅ' => 'A', - 'Ἆ' => 'A', - 'Ἇ' => 'A', - 'ᾰ' => 'a', - 'ᾱ' => 'a', - 'ᾲ' => 'a', - 'ᾳ' => 'a', - 'ᾴ' => 'a', - 'ᾶ' => 'a', - 'ᾷ' => 'a', - 'Ᾰ' => 'A', - 'Ᾱ' => 'A', - 'Ὰ' => 'A', - 'Ά' => 'A', - 'ᾼ' => 'A', - 'Ä' => 'A', - 'ä' => 'a', - 'À' => 'A', - 'à' => 'a', - 'Á' => 'A', - 'á' => 'a', - 'Â' => 'A', - 'â' => 'a', - 'Ã' => 'A', - 'ã' => 'a', - 'A̧' => 'A', - 'a̧' => 'a', - 'Ą' => 'A', - 'ą' => 'a', - 'Ⱥ' => 'A', - 'ⱥ' => 'a', - 'Å' => 'A', - 'å' => 'a', - 'Ǻ' => 'A', - 'ǻ' => 'a', - 'Ă' => 'A', - 'ă' => 'a', - 'Ǎ' => 'A', - 'ǎ' => 'a', - 'Ȧ' => 'A', - 'ȧ' => 'a', - 'Ạ' => 'A', - 'ạ' => 'a', - 'Ā' => 'A', - 'ā' => 'a', - 'ª' => 'a', - 'Ɓ' => 'B', - 'Ѣ' => 'E', - 'ѣ' => 'e', - 'Ç' => 'C', - 'ç' => 'c', - 'Ĉ' => 'C', - 'ĉ' => 'c', - 'C̈' => 'C', - 'c̈' => 'c', - 'C̨' => 'C', - 'c̨' => 'c', - 'Ȼ' => 'C', - 'ȼ' => 'c', - 'Č' => 'C', - 'č' => 'c', - 'Ć' => 'C', - 'ć' => 'c', - 'C̀' => 'C', - 'c̀' => 'c', - 'Ċ' => 'C', - 'ċ' => 'c', - 'C̣' => 'C', - 'c̣' => 'c', - 'C̄' => 'C', - 'c̄' => 'c', - 'C̃' => 'C', - 'c̃' => 'c', - 'Ð' => 'D', - 'Đ' => 'D', - 'ð' => 'd', - 'đ' => 'd', - 'È' => 'E', - 'É' => 'E', - 'Ê' => 'E', - 'Ë' => 'E', - 'Ĕ' => 'E', - 'Ė' => 'E', - 'Ȩ' => 'E', - 'ȩ' => 'e', - 'Ę' => 'E', - 'ę' => 'e', - 'Ɇ' => 'E', - 'ɇ' => 'e', - 'Ě' => 'E', - 'ě' => 'e', - 'Ẹ' => 'E', - 'ẹ' => 'e', - 'Ē' => 'E', - 'ē' => 'e', - 'Ẽ' => 'E', - 'ẽ' => 'e', - 'è' => 'e', - 'é' => 'e', - 'ê' => 'e', - 'ë' => 'e', - 'ĕ' => 'e', - 'ė' => 'e', - 'ƒ' => 'f', - 'Ѳ' => 'F', - 'ѳ' => 'f', - 'Ĝ' => 'G', - 'Ġ' => 'G', - 'ĝ' => 'g', - 'ġ' => 'g', - 'Ĥ' => 'H', - 'Ħ' => 'H', - 'ĥ' => 'h', - 'ħ' => 'h', - 'Ì' => 'I', - 'Í' => 'I', - 'Î' => 'I', - 'Ï' => 'I', - 'Ĩ' => 'I', - 'Ĭ' => 'I', - 'Ǐ' => 'I', - 'Į' => 'I', - 'ì' => 'i', - 'í' => 'i', - 'î' => 'i', - 'ï' => 'i', - 'ĩ' => 'i', - 'ĭ' => 'i', - 'ǐ' => 'i', - 'į' => 'i', - 'І' => 'I', - 'і' => 'i', - 'I̧' => 'I', - 'i̧' => 'i', - 'Ɨ' => 'I', - 'ɨ' => 'i', - 'İ' => 'I', - 'i' => 'i', - 'Ị' => 'I', - 'ị' => 'i', - 'Ī' => 'I', - 'ī' => 'i', - 'Ĵ' => 'J', - 'ĵ' => 'j', - 'J́́' => 'J', - 'j́' => 'j', - 'J̀̀' => 'J', - 'j̀' => 'j', - 'J̈' => 'J', - 'j̈' => 'j', - 'J̧' => 'J', - 'j̧' => 'j', - 'J̨' => 'J', - 'j̨' => 'j', - 'Ɉ' => 'J', - 'ɉ' => 'j', - 'J̌' => 'J', - 'ǰ' => 'j', - 'J̇' => 'J', - 'j' => 'j', - 'J̣' => 'J', - 'j̣' => 'j', - 'J̄' => 'J', - 'j̄' => 'j', - 'J̃' => 'J', - 'j̃' => 'j', - 'Й' => 'i', - 'й' => 'i', - 'ĸ' => 'k', - 'Ĺ' => 'L', - 'Ľ' => 'L', - 'Ŀ' => 'L', - 'ĺ' => 'l', - 'ľ' => 'l', - 'ŀ' => 'l', - 'L̀' => 'L', - 'l̀' => 'l', - 'L̂' => 'L', - 'l̂' => 'l', - 'L̈' => 'L', - 'l̈' => 'l', - 'Ļ' => 'L', - 'ļ' => 'l', - 'L̨' => 'L', - 'l̨' => 'l', - 'Ł' => 'L', - 'ł' => 'l', - 'Ƚ' => 'L', - 'ƚ' => 'l', - 'L̇' => 'L', - 'l̇' => 'l', - 'Ḷ' => 'L', - 'ḷ' => 'l', - 'L̄' => 'L', - 'l̄' => 'l', - 'L̃' => 'L', - 'l̃' => 'l', - 'Ñ' => 'N', - 'ñ' => 'n', - 'Ŋ' => 'N', - 'ŋ' => 'n', - 'ʼn' => 'n', - 'Ń' => 'N', - 'ń' => 'n', - 'Ǹ' => 'N', - 'ǹ' => 'n', - 'N̂' => 'N', - 'n̂' => 'n', - 'N̈' => 'N', - 'n̈' => 'n', - 'Ņ' => 'N', - 'ņ' => 'n', - 'N̨' => 'N', - 'n̨' => 'n', - 'Ꞥ' => 'N', - 'ꞥ' => 'n', - 'Ň' => 'N', - 'ň' => 'n', - 'Ṅ' => 'N', - 'ṅ' => 'n', - 'Ṇ' => 'N', - 'ṇ' => 'n', - 'N̄' => 'N', - 'n̄' => 'n', - 'Ö' => 'O', - 'Ò' => 'O', - 'Ó' => 'O', - 'Ô' => 'O', - 'Õ' => 'O', - 'Ō' => 'O', - 'Ŏ' => 'O', - 'Ǒ' => 'O', - 'Ő' => 'O', - 'Ơ' => 'O', - 'Ø' => 'O', - 'Ǿ' => 'O', - 'ö' => 'o', - 'ò' => 'o', - 'ó' => 'o', - 'ô' => 'o', - 'õ' => 'o', - 'ō' => 'o', - 'ŏ' => 'o', - 'ǒ' => 'o', - 'ő' => 'o', - 'ơ' => 'o', - 'ø' => 'o', - 'ǿ' => 'o', - 'º' => 'o', - 'O̧' => 'O', - 'o̧' => 'o', - 'Ǫ' => 'O', - 'ǫ' => 'o', - 'Ɵ' => 'O', - 'ɵ' => 'o', - 'Ȯ' => 'O', - 'ȯ' => 'o', - 'Ọ' => 'O', - 'ọ' => 'o', - 'Ŕ' => 'R', - 'Ŗ' => 'R', - 'ŕ' => 'r', - 'ŗ' => 'r', - 'Ŝ' => 'S', - 'Ș' => 'S', - 'ș' => 's', - 'Ś' => 'S', - 'ś' => 's', - 'S̀' => 'S', - 's̀' => 's', - 'Ŝ̀' => 'S', - 'ŝ' => 's', - 'S̈' => 'S', - 's̈' => 's', - 'Ş' => 'S', - 'ş' => 's', - 'S̨' => 'S', - 's̨' => 's', - 'Ꞩ' => 'S', - 'ꞩ' => 's', - 'Š' => 'S', - 'š' => 's', - 'Ṡ' => 'S', - 'ṡ' => 's', - 'Ṣ' => 'S', - 'ṣ' => 's', - 'S̄' => 'S', - 's̄' => 's', - 'S̃' => 'S', - 's̃' => 's', - 'ſ' => 's', - 'Ţ' => 'T', - 'Ț' => 'T', - 'Ŧ' => 'T', - 'Þ' => 'TH', - 'ţ' => 't', - 'ț' => 't', - 'ŧ' => 't', - 'þ' => 'th', - 'T́' => 'T', - 't́' => 't', - 'T̀' => 'T', - 't̀' => 't', - 'T̂' => 'T', - 't̂' => 't', - 'T̈' => 'T', - 'ẗ' => 't', - 'T̨' => 'T', - 't̨' => 't', - 'Ⱦ' => 'T', - 'ⱦ' => 't', - 'Ť' => 'T', - 'ť' => 't', - 'Ṫ' => 'T', - 'ṫ' => 't', - 'Ṭ' => 'T', - 'ṭ' => 't', - 'T̄' => 'T', - 't̄' => 't', - 'T̃' => 'T', - 't̃' => 't', - 'Ü' => 'U', - 'Ù' => 'U', - 'Ú' => 'U', - 'Û' => 'U', - 'Ũ' => 'U', - 'Ŭ' => 'U', - 'Ű' => 'U', - 'Ų' => 'U', - 'Ư' => 'U', - 'Ǔ' => 'U', - 'Ǖ' => 'U', - 'Ǘ' => 'U', - 'Ǚ' => 'U', - 'Ǜ' => 'U', - 'ü' => 'u', - 'ù' => 'u', - 'ú' => 'u', - 'û' => 'u', - 'ũ' => 'u', - 'ŭ' => 'u', - 'ű' => 'u', - 'ų' => 'u', - 'ư' => 'u', - 'ǔ' => 'u', - 'ǖ' => 'u', - 'ǘ' => 'u', - 'ǚ' => 'u', - 'ǜ' => 'u', - 'U̧' => 'U', - 'u̧' => 'u', - 'Ʉ' => 'U', - 'ʉ' => 'u', - 'U̇' => 'U', - 'u̇' => 'u', - 'Ụ' => 'U', - 'ụ' => 'u', - 'Ū' => 'U', - 'ū' => 'u', - 'Ʊ' => 'U', - 'ʊ' => 'u', - 'Ŵ' => 'W', - 'ŵ' => 'w', - 'Ẁ' => 'W', - 'ẁ' => 'w', - 'Ẃ' => 'W', - 'ẃ' => 'w', - 'Ẅ' => 'W', - 'ẅ' => 'w', - 'Ѵ' => 'I', - 'ѵ' => 'i', - 'Ꙗ' => 'Ja', - 'ꙗ' => 'ja', - 'Є' => 'Je', - 'є' => 'je', - 'Ѥ' => 'Je', - 'ѥ' => 'je', - 'Ѕ' => 'Dz', - 'ѕ' => 'dz', - 'Ꙋ' => 'U', - 'ꙋ' => 'u', - 'Ѡ' => 'O', - 'ѡ' => 'o', - 'Ѿ' => 'Ot', - 'ѿ' => 'ot', - 'Ѫ' => 'U', - 'ѫ' => 'u', - 'Ѧ' => 'Ja', - 'ѧ' => 'ja', - 'Ѭ' => 'Ju', - 'ѭ' => 'ju', - 'Ѩ' => 'Ja', - 'ѩ' => 'Ja', - 'Ѯ' => 'Ks', - 'ѯ' => 'ks', - 'Ѱ' => 'Ps', - 'ѱ' => 'ps', - 'Х' => 'X', - 'х' => 'x', - 'Ý' => 'Y', - 'Ÿ' => 'Y', - 'Ŷ' => 'Y', - 'ý' => 'y', - 'ÿ' => 'y', - 'ŷ' => 'y', - 'Ỳ' => 'Y', - 'ỳ' => 'y', - 'Y̧' => 'Y', - 'y̧' => 'y', - 'Y̨' => 'Y', - 'y̨' => 'y', - 'Ɏ' => 'Y', - 'ɏ' => 'y', - 'Y̌' => 'Y', - 'y̌' => 'y', - 'Ẏ' => 'Y', - 'ẏ' => 'y', - 'Ỵ' => 'Y', - 'ỵ' => 'y', - 'Ȳ' => 'Y', - 'ȳ' => 'y', - 'Ỹ' => 'Y', - 'ỹ' => 'y', - 'Щ' => 'Shh', - 'щ' => 'shh', - 'Ź' => 'Z', - 'ź' => 'z', - 'Z̀' => 'Z', - 'z̀' => 'z', - 'Ẑ' => 'Z', - 'ẑ' => 'z', - 'Z̈' => 'Z', - 'z̈' => 'z', - 'Z̧' => 'Z', - 'z̧' => 'z', - 'Z̨' => 'Z', - 'z̨' => 'z', - 'Ƶ' => 'Z', - 'ƶ' => 'z', - 'Ž' => 'Z', - 'ž' => 'z', - 'Ż' => 'Z', - 'ż' => 'z', - 'Ẓ' => 'Z', - 'ẓ' => 'z', - 'Z̄' => 'Z', - 'z̄' => 'z', - 'Z̃' => 'Z', - 'z̃' => 'z', - ], - // whitespace chars - ' ' => [ - "\xc2\xa0" => ' ', // 'NO-BREAK SPACE' - "\xe1\x9a\x80" => ' ', // 'OGHAM SPACE MARK' - "\xe2\x80\x80" => ' ', // 'EN QUAD' - "\xe2\x80\x81" => ' ', // 'EM QUAD' - "\xe2\x80\x82" => ' ', // 'EN SPACE' - "\xe2\x80\x83" => ' ', // 'EM SPACE' - "\xe2\x80\x84" => ' ', // 'THREE-PER-EM SPACE' - "\xe2\x80\x85" => ' ', // 'FOUR-PER-EM SPACE' - "\xe2\x80\x86" => ' ', // 'SIX-PER-EM SPACE' - "\xe2\x80\x87" => ' ', // 'FIGURE SPACE' - "\xe2\x80\x88" => ' ', // 'PUNCTUATION SPACE' - "\xe2\x80\x89" => ' ', // 'THIN SPACE' - "\xe2\x80\x8a" => ' ', // 'HAIR SPACE' - "\xe2\x80\xa8" => ' ', // 'LINE SEPARATOR' - "\xe2\x80\xa9" => ' ', // 'PARAGRAPH SEPARATOR' - "\xe2\x80\x8b" => ' ', // 'ZERO WIDTH SPACE' - "\xe2\x80\xaf" => ' ', // 'NARROW NO-BREAK SPACE' - "\xe2\x81\x9f" => ' ', // 'MEDIUM MATHEMATICAL SPACE' - "\xe3\x80\x80" => ' ', // 'IDEOGRAPHIC SPACE' - "\xef\xbe\xa0" => ' ', // 'HALFWIDTH HANGUL FILLER' - ], - // commonly used in Word documents - 'msword' => [ - "\xc2\xab" => '<<', // « (U+00AB) in UTF-8 - "\xc2\xbb" => '>>', // » (U+00BB) in UTF-8 - "\xe2\x80\x98" => "'", // ‘ (U+2018) in UTF-8 - "\xe2\x80\x99" => "'", // ’ (U+2019) in UTF-8 - "\xe2\x80\x9a" => "'", // ‚ (U+201A) in UTF-8 - "\xe2\x80\x9b" => "'", // ‛ (U+201B) in UTF-8 - "\xe2\x80\x9c" => '"', // “ (U+201C) in UTF-8 - "\xe2\x80\x9d" => '"', // ” (U+201D) in UTF-8 - "\xe2\x80\x9e" => '"', // „ (U+201E) in UTF-8 - "\xe2\x80\x9f" => '"', // ‟ (U+201F) in UTF-8 - "\xe2\x80\xb9" => "'", // ‹ (U+2039) in UTF-8 - "\xe2\x80\xba" => "'", // › (U+203A) in UTF-8 - "\xe2\x80\x93" => '-', // – (U+2013) in UTF-8 - "\xe2\x80\x94" => '-', // — (U+2014) in UTF-8 - "\xe2\x80\xa6" => '...', // … (U+2026) in UTF-8 - ], - // Currency - // - // url => https://en.wikipedia.org/wiki/Currency_symbol - 'currency_short' => [ - '€' => 'EUR', - '$' => '$', - '₢' => 'Cr', - '₣' => 'Fr.', - '£' => 'PS', - '₤' => 'L.', - 'ℳ' => 'M', - '₥' => 'mil', - '₦' => 'N', - '₧' => 'Pts', - '₨' => 'Rs', - 'රු' => 'LKR', - 'ரூ' => 'LKR', - '௹' => 'Rs', - 'रू' => 'NPR', - '₹' => 'Rs', - '૱' => 'Rs', - '₩' => 'W', - '₪' => 'NS', - '₸' => 'KZT', - '₫' => 'D', - '֏' => 'AMD', - '₭' => 'K', - '₺' => 'TL', - '₼' => 'AZN', - '₮' => 'T', - '₯' => 'Dr', - '₲' => 'PYG', - '₾' => 'GEL', - '₳' => 'ARA', - '₴' => 'UAH', - '₽' => 'RUB', - '₵' => 'GHS', - '₡' => 'CL', - '¢' => 'c', - '¥' => 'YEN', - '円' => 'JPY', - '৳' => 'BDT', - '元' => 'CNY', - '﷼' => 'SAR', - '៛' => 'KR', - '₠' => 'ECU', - '¤' => '$?', - '฿' => 'THB', - '؋' => 'AFN', - ], -]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_extras_by_languages.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_extras_by_languages.php deleted file mode 100644 index afe31ae2c..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_extras_by_languages.php +++ /dev/null @@ -1,759 +0,0 @@ - [ - '=' => ' gelijk ', - '%' => ' procent ', - '∑' => ' som ', - '∆' => ' delta ', - '∞' => ' oneindig ', - '♥' => ' love ', - '&' => ' en ', - '+' => ' plus ', - ], - // Italian - 'it' => [ - '=' => ' uguale ', - '%' => ' percent ', - '∑' => ' somma ', - '∆' => ' delta ', - '∞' => ' infinito ', - '♥' => ' amore ', - '&' => ' e ', - '+' => ' piu ', - ], - // Macedonian - 'mk' => [ - '=' => ' ednakva ', - '%' => ' procenti ', - '∑' => ' zbir ', - '∆' => ' delta ', - '∞' => ' beskonecnost ', - '♥' => ' loveubov ', - '&' => ' i ', - '+' => ' plus ', - ], - // Portuguese (Brazil) - 'pt' => [ - '=' => ' igual ', - '%' => ' por cento ', - '∑' => ' soma ', - '∆' => ' delta ', - '∞' => ' infinito ', - '♥' => ' amor ', - '&' => ' e ', - '+' => ' mais ', - ], - // Greek(lish) (Elláda) - 'el__greeklish' => [ - '=' => ' isos ', - '%' => ' tois ekato ', - '∑' => ' athroisma ', - '∆' => ' delta ', - '∞' => ' apeiro ', - '♥' => ' agape ', - '&' => ' kai ', - '+' => ' syn ', - ], - // Greek (Elláda) - 'el' => [ - '=' => ' isos ', - '%' => ' tois ekato ', - '∑' => ' athroisma ', - '∆' => ' delta ', - '∞' => ' apeiro ', - '♥' => ' agape ', - '&' => ' kai ', - '+' => ' syn ', - ], - // Hindi - 'hi' => [ - '=' => ' samana ', - '%' => ' paratisata ', - '∑' => ' yoga ', - '∆' => ' dalata ', - '∞' => ' anata ', - '♥' => ' payara ', - '&' => ' aura ', - '+' => ' palasa ', - ], - // Armenian - 'hy' => [ - '=' => ' havasar ', - '%' => ' tvokvos ', - '∑' => ' gvoumar ', - '∆' => ' delta ', - '∞' => ' ansahmanvouthyvoun ', - '♥' => ' ser ', - '&' => ' ev ', - '+' => ' gvoumarats ', - ], - // Swedish - 'sv' => [ - '=' => ' lika ', - '%' => ' procent ', - '∑' => ' summa ', - '∆' => ' delta ', - '∞' => ' oandlighet ', - '♥' => ' alskar ', - '&' => ' och ', - '+' => ' plus ', - ], - // Turkmen - 'tk' => [ - '=' => ' den ', - '%' => ' yuzde ', - '∑' => ' jem ', - '∆' => ' delta ', - '∞' => ' mudimilik ', - '♥' => ' soygi ', - '&' => ' we ', - '+' => ' yzy ', - ], - // Turkish - 'tr' => [ - '=' => ' esit ', - '%' => ' yuzde ', - '∑' => ' Toplam ', - '∆' => ' delta ', - '∞' => ' sonsuzluk ', - '♥' => ' ask ', - '&' => ' ve ', - '+' => ' arti ', - ], - // Bulgarian - 'bg' => [ - '=' => ' raven ', - '%' => ' na sto ', - '∑' => ' suma ', - '∆' => ' delta ', - '∞' => ' bezkrajnost ', - '♥' => ' obicam ', - '&' => ' i ', - '+' => ' plus ', - ], - // Hungarian - 'hu' => [ - '=' => ' Egyenlo ', - '%' => ' Szazalek ', - '∑' => ' osszeg ', - '∆' => ' delta ', - '∞' => ' vegtelenitett ', - '♥' => ' love ', - '&' => ' Es ', - '+' => ' Plusz ', - ], - // Myanmar (Burmese) - 'my' => [ - '=' => ' ttn:ttnnym? ', - '%' => ' raakhngnn:k ', - '∑' => ' ld ', - '∆' => ' m?cwk?n:pe? ', - '∞' => ' ach:m ', - '♥' => ' mettttaa ', - '&' => ' n ', - '+' => ' ape?ng: ', - ], - // Croatian (Hrvatska) - 'hr' => [ - '=' => ' Jednaki ', - '%' => ' Posto ', - '∑' => ' zbroj ', - '∆' => ' Delta ', - '∞' => ' beskonacno ', - '♥' => ' ljubav ', - '&' => ' I ', - '+' => ' Plus ', - ], - // Finnish - 'fi' => [ - '=' => ' Sama ', - '%' => ' Prosenttia ', - '∑' => ' sum ', - '∆' => ' delta ', - '∞' => ' aareton ', - '♥' => ' rakkautta ', - '&' => ' Ja ', - '+' => ' Plus ', - ], - // Georgian (Kartvelian) - 'ka' => [ - '=' => ' tanasts\'ori ', - '%' => ' p\'rotsent\'i ', - '∑' => ' tankha ', - '∆' => ' delt\'a ', - '∞' => ' usasrulo ', - '♥' => ' siq\'varuli ', - '&' => ' da ', - '+' => ' p\'lus ', - ], - // Russian - 'ru' => [ - '=' => ' ravnyj ', - '%' => ' procent ', - '∑' => ' summa ', - '∆' => ' del\'ta ', - '∞' => ' beskonecnost\' ', - '♥' => ' lublu ', - '&' => ' i ', - '+' => ' plus ', - ], - // Russian - GOST 7.79-2000(B) - 'ru__gost_2000_b' => [ - '=' => ' ravnyj ', - '%' => ' procent ', - '∑' => ' summa ', - '∆' => ' del\'ta ', - '∞' => ' beskonecnost\' ', - '♥' => ' lublu ', - '&' => ' i ', - '+' => ' plus ', - ], - // Russian - Passport (2013), ICAO - 'ru__passport_2013' => [ - '=' => ' ravnyj ', - '%' => ' procent ', - '∑' => ' summa ', - '∆' => ' del\'ta ', - '∞' => ' beskonecnost\' ', - '♥' => ' lublu ', - '&' => ' i ', - '+' => ' plus ', - ], - // Ukrainian - 'uk' => [ - '=' => ' rivnij ', - '%' => ' vidsotkiv ', - '∑' => ' suma ', - '∆' => ' del\'ta ', - '∞' => ' neskincennist\' ', - '♥' => ' lubov ', - '&' => ' i ', - '+' => ' plus ', - ], - // Kazakh - 'kk' => [ - '=' => ' ten\' ', - '%' => ' Pajyzdar ', - '∑' => ' zalpy ', - '∆' => ' ajyrmasylyk, ', - '∞' => ' seksiz ', - '♥' => ' mahabbat ', - '&' => ' z@ne ', - '+' => ' plus ', - ], - // Czech - 'cs' => [ - '=' => ' rovnat se ', - '%' => ' procento ', - '∑' => ' soucet ', - '∆' => ' delta ', - '∞' => ' nekonecno ', - '♥' => ' laska ', - '&' => ' a ', - '+' => ' plus ', - ], - // Danish - 'da' => [ - '=' => ' Lige ', - '%' => ' Prozent ', - '∑' => ' sum ', - '∆' => ' delta ', - '∞' => ' uendelig ', - '♥' => ' kaerlighed ', - '&' => ' Og ', - '+' => ' Plus ', - ], - // Polish - 'pl' => [ - '=' => ' rowny ', - '%' => ' procent ', - '∑' => ' suma ', - '∆' => ' delta ', - '∞' => ' nieskonczonosc ', - '♥' => ' milosc ', - '&' => ' i ', - '+' => ' plus ', - ], - // Romanian - 'ro' => [ - '=' => ' egal ', - '%' => ' la suta ', - '∑' => ' suma ', - '∆' => ' delta ', - '∞' => ' infinit ', - '♥' => ' dragoste ', - '&' => ' si ', - '+' => ' la care se adauga ', - ], - // Esperanto - 'eo' => [ - '=' => ' Egalaj ', - '%' => ' Procento ', - '∑' => ' sumo ', - '∆' => ' delto ', - '∞' => ' senfina ', - '♥' => ' amo ', - '&' => ' Kaj ', - '+' => ' Pli ', - ], - // Estonian - 'et' => [ - '=' => ' Vordsed ', - '%' => ' Protsenti ', - '∑' => ' summa ', - '∆' => ' o ', - '∞' => ' loputut ', - '♥' => ' armastus ', - '&' => ' Ja ', - '+' => ' Pluss ', - ], - // Latvian - 'lv' => [ - '=' => ' vienads ', - '%' => ' procents ', - '∑' => ' summa ', - '∆' => ' delta ', - '∞' => ' bezgaliba ', - '♥' => ' milestiba ', - '&' => ' un ', - '+' => ' pluss ', - ], - // Lithuanian - 'lt' => [ - '=' => ' lygus ', - '%' => ' procentu ', - '∑' => ' suma ', - '∆' => ' delta ', - '∞' => ' begalybe ', - '♥' => ' meile ', - '&' => ' ir ', - '+' => ' plius ', - ], - // Norwegian - 'no' => [ - '=' => ' Lik ', - '%' => ' Prosent ', - '∑' => ' sum ', - '∆' => ' delta ', - '∞' => ' uendelig ', - '♥' => ' kjaerlighet ', - '&' => ' Og ', - '+' => ' Pluss ', - ], - // Vietnamese - 'vi' => [ - '=' => ' cong bang ', - '%' => ' phan tram ', - '∑' => ' tong so ', - '∆' => ' dong bang ', - '∞' => ' vo cuc ', - '♥' => ' Yeu ', - '&' => ' va ', - '+' => ' them ', - ], - // Arabic - 'ar' => [ - '=' => ' mtsawy ', - '%' => ' nsbh mywyh ', - '∑' => ' mjmw\' ', - '∆' => ' dlta ', - '∞' => ' ma la nhayt ', - '♥' => ' hb ', - '&' => ' w ', - '+' => ' zayd ', - ], - // Persian (Farsi) - 'fa' => [ - '=' => ' brabr ', - '%' => ' dr sd ', - '∑' => ' mjmw\' ', - '∆' => ' dlta ', - '∞' => ' by nhayt ', - '♥' => ' \'shq ', - '&' => ' w ', - '+' => ' bh \'lawh ', - ], - // Serbian - 'sr' => [ - '=' => ' jednak ', - '%' => ' procenat ', - '∑' => ' zbir ', - '∆' => ' delta ', - '∞' => ' beskraj ', - '♥' => ' lubav ', - '&' => ' i ', - '+' => ' vise ', - ], - // Serbian - Cyrillic - 'sr__cyr' => [ - '=' => ' jednak ', - '%' => ' procenat ', - '∑' => ' zbir ', - '∆' => ' delta ', - '∞' => ' beskraj ', - '♥' => ' lubav ', - '&' => ' i ', - '+' => ' vise ', - ], - // Serbian - Latin - 'sr__lat' => [ - '=' => ' jednak ', - '%' => ' procenat ', - '∑' => ' zbir ', - '∆' => ' delta ', - '∞' => ' beskraj ', - '♥' => ' lubav ', - '&' => ' i ', - '+' => ' vise ', - ], - // Azerbaijani - 'az' => [ - '=' => ' b@rab@r ', - '%' => ' faiz ', - '∑' => ' m@bl@g ', - '∆' => ' delta ', - '∞' => ' sonsuzluq ', - '♥' => ' sevgi ', - '&' => ' v@ ', - '+' => ' plus ', - ], - // Slovak - 'sk' => [ - '=' => ' rovny ', - '%' => ' percento ', - '∑' => ' sucet ', - '∆' => ' delta ', - '∞' => ' infinity ', - '♥' => ' milovat ', - '&' => ' a ', - '+' => ' viac ', - ], - // French - 'fr' => [ - '=' => ' Egal ', - '%' => ' Pourcentage ', - '∑' => ' somme ', - '∆' => ' delta ', - '∞' => ' infini ', - '♥' => ' amour ', - '&' => ' Et ', - '+' => ' Plus ', - ], - // Austrian (French) - 'fr_at' => [ - '=' => ' Egal ', - '%' => ' Pourcentage ', - '∑' => ' somme ', - '∆' => ' delta ', - '∞' => ' infini ', - '♥' => ' amour ', - '&' => ' Et ', - '+' => ' Plus ', - ], - // Switzerland (French) - 'fr_ch' => [ - '=' => ' Egal ', - '%' => ' Pourcentage ', - '∑' => ' somme ', - '∆' => ' delta ', - '∞' => ' infini ', - '♥' => ' amour ', - '&' => ' Et ', - '+' => ' Plus ', - ], - // German - 'de' => [ - '=' => ' gleich ', - '%' => ' Prozent ', - '∑' => ' gesamt ', - '∆' => ' Unterschied ', - '∞' => ' undendlich ', - '♥' => ' liebe ', - '&' => ' und ', - '+' => ' plus ', - ], - // Austrian (German) - 'de_at' => [ - '=' => ' gleich ', - '%' => ' Prozent ', - '∑' => ' gesamt ', - '∆' => ' Unterschied ', - '∞' => ' undendlich ', - '♥' => ' liebe ', - '&' => ' und ', - '+' => ' plus ', - ], - // Switzerland (German) - 'de_ch' => [ - '=' => ' gleich ', - '%' => ' Prozent ', - '∑' => ' gesamt ', - '∆' => ' Unterschied ', - '∞' => ' undendlich ', - '♥' => ' liebe ', - '&' => ' und ', - '+' => ' plus ', - ], - // Bengali (Bangla) - 'bn' => [ - '=' => ' Saman ', - '%' => ' Satakora ', - '∑' => ' Samasti ', - '∆' => ' Badhip ', - '∞' => ' Ananta ', - '♥' => ' Valobasa ', - '&' => ' Abong ', - '+' => ' Songzojon ', - ], - // English - 'en' => [ - '=' => ' equal ', - '%' => ' percent ', - '∑' => ' sum ', - '∆' => ' delta ', - '∞' => ' infinity ', - '♥' => ' love ', - '&' => ' and ', - '+' => ' plus ', - ], - // Currency - // - // url: https://en.wikipedia.org/wiki/Currency_symbol - 'currency' => [ - '€' => ' Euro ', - '$' => ' Dollar ', - '₢' => ' cruzeiro ', - '₣' => ' French franc ', - '£' => ' pound ', - '₤' => ' lira ', // Italian - '₶' => ' livre tournois ', - 'ℳ' => ' mark ', - '₥' => ' mill ', - '₦' => ' naira ', - '₧' => ' peseta ', - '₨' => ' rupee ', - 'රු' => ' rupee ', // Sri Lankan - 'ரூ' => ' rupee ', // Sri Lankan - '௹' => ' rupee ', // Tamil - 'रू' => ' rupee ', // Nepalese - '₹' => ' rupee ', // Indian - '૱' => ' rupee ', // Gujarat - '₩' => ' won ', - '₪' => ' new shequel ', - '₸' => ' tenge ', - '₫' => ' dong ', - '֏' => ' dram ', - '₭' => ' kip ', - '₺' => ' lira ', // Turkish - '₼' => ' manat ', - '₮' => ' tugrik ', - '₯' => ' drachma ', - '₰' => ' pfennig ', - '₷' => ' spesmilo ', - '₱' => ' peso ', // Philippine - '﷼‎' => ' riyal ', - '₲' => ' guarani ', - '₾' => ' lari ', - '₳' => ' austral ', - '₴' => ' hryvnia ', - '₽' => ' ruble ', - '₵' => ' cedi ', - '₡' => ' colon ', - '¢' => ' cent ', - '¥' => ' yen ', - '円' => ' yen ', - '৳' => ' taka ', - '元' => ' yuan ', - '﷼' => ' riyal ', - '៛' => ' riel ', - '₠' => ' European Currency ', - '¤' => ' currency ', - '฿' => ' baht ', - '؋' => ' afghani ', - ], - // Temperature - // - // url: https://en.wikipedia.org/wiki/Conversion_of_units_of_temperature - 'temperature' => [ - '°De' => ' Delisle ', - '°Re' => ' Reaumur ', // Réaumur - '°Ro' => ' Romer ', // Rømer - '°R' => ' Rankine ', - '°C' => ' Celsius ', - '°F' => ' Fahrenheit ', - '°N' => ' Newton ', - ], - 'latin_symbols' => [ - '=' => '=', - '%' => '%', - '∑' => '∑', - '∆' => '∆', - '∞' => '∞', - '♥' => '♥', - '&' => '&', - '+' => '+', - // --- - '©' => ' (c) ', - '®' => ' (r) ', - '@' => ' (at) ', - '№' => ' No. ', - '℞' => ' Rx ', - '[' => '[', - '\' => '\\', - ']' => ']', - '^' => '^', - '_' => '_', - '`' => '`', - '‐' => '-', - '‑' => '-', - '‒' => '-', - '–' => '-', - '−' => '-', - '—' => '-', - '―' => '-', - '﹘' => '-', - '│' => '|', - '∖' => '\\', - '∕' => '/', - '⁄' => '/', - '←' => '<-', - '→' => '->', - '↑' => '|', - '↓' => '|', - '⁅' => '[', - '⁆' => ']', - '⁎' => '*', - '、' => ',', - '。' => '.', - '〈' => '<', - '〉' => '>', - '《' => '<<', - '》' => '>>', - '〔' => '[', - '〕' => ']', - '〘' => '[', - '〙' => ']', - '〚' => '[', - '〛' => ']', - '﹝' => '[', - '﹞' => ']', - '︹' => '[', - '︺' => ']', - '﹇' => '[', - '﹈' => ']', - '︐' => ',', - '︑' => ',', - '︒' => '.', - '︓' => ':', - '︔' => ';', - '︕' => '!', - '︖' => '?', - '︙' => '...', - '︰' => '..', - '︵' => '(', - '︶' => ')', - '﹙' => '(', - '﹚' => ')', - '︷' => '{', - '︸' => '}', - '﹛' => '{', - '﹜' => '}', - '︽' => '<<', - '︾' => '>>', - '︿' => '<', - '﹀' => '>', - '×' => '*', - '÷' => '/', - '≪' => '<<', - '≫' => '>>', - '⦅' => '((', - '⦆' => '))', - '〇' => '0', - '′' => '\'', - '〝' => '"', - '〞' => '"', - '«' => '<<', - '»' => '>>', - '‘' => "'", - '’' => "'", - '‚' => ',', - '‛' => "'", - '“' => '"', - '”' => '"', - '„' => '"', - '‟' => '"', - '‹' => '<', - '›' => '>', - '․' => '.', - '‥' => '..', - '…' => '...', - '″' => '"', - '‴' => '\'\'\'', - '‶' => '``', - '‷' => '```', - '‼' => '!!', - '⁇' => '??', - '⁈' => '?!', - '⁉' => '!?', - '⁗' => '````', - '⩴' => '::=', - '⩵' => '==', - '⩶' => '===', - '﹔' => ';', - '﹕' => ':', - '﹖' => '?', - '﹗' => '!', - '﹍' => '_', - '﹎' => '_', - '﹏' => '_', - '﹐' => ',', - '﹑' => ',', - '﹒' => '.', - '﹟' => '#', - '﹠' => '&', - '﹡' => '*', - '﹢' => '+', - '﹣' => '-', - '﹤' => '<', - '﹥' => '>', - '﹦' => '=', - '﹨' => '\\', - '﹩' => '$', - '﹪' => '%', - '﹫' => '@', - '!' => '!', - '"' => '"', - '#' => '#', - '$' => '$', - '%' => '%', - '&' => '&', - ''' => '\'', - '(' => '(', - ')' => ')', - '*' => '*', - '+' => '+', - ',' => ',', - '-' => '-', - '.' => '.', - '/' => '/', - ':' => ':', - ';' => ';', - '<' => '<', - '=' => '=', - '>' => '>', - '?' => '?', - '@' => '@', - '{' => '{', - '|' => '|', - '}' => '}', - '~' => '~', - '⦅' => '((', - '⦆' => '))', - '¬' => '!', - ' ̄' => '-', - '¦' => '|', - '■' => '#', - ], -]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_language_max_key.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_language_max_key.php deleted file mode 100644 index da81ae236..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_language_max_key.php +++ /dev/null @@ -1,65 +0,0 @@ - 0, - 'tk' => 1, - 'th' => 0, - 'ps' => 0, - 'or' => 0, - 'mn' => 0, - 'ko' => 0, - 'ky' => 0, - 'hy' => 1, - 'bn' => 5, - 'be' => 0, - 'am' => 0, - 'ja' => 0, - 'zh' => 0, - 'nl' => 1, - 'it' => 1, - 'mk' => 1, - 'pt' => 1, - 'el__greeklish' => 2, - 'el' => 2, - 'hi' => 2, - 'sv' => 1, - 'tr' => 1, - 'bg' => 2, - 'hu' => 1, - 'my' => 5, - 'hr' => 2, - 'fi' => 1, - 'ka' => 1, - 'ru' => 1, - 'ru__gost_2000_b' => 1, - 'ru__passport_2013' => 1, - 'uk' => 1, - 'kk' => 1, - 'cs' => 1, - 'da' => 1, - 'pl' => 1, - 'ro' => 1, - 'eo' => 1, - 'et' => 1, - 'lv' => 1, - 'lt' => 1, - 'no' => 1, - 'vi' => 1, - 'ar' => 1, - 'fa' => 1, - 'sr' => 1, - 'sr__cyr' => 1, - 'sr__lat' => 1, - 'az' => 1, - 'sk' => 1, - 'fr' => 1, - 'fr_at' => 1, - 'fr_ch' => 1, - 'de' => 1, - 'de_at' => 1, - 'de_ch' => 1, - 'en' => 0, - 'latin' => 3, - ' ' => 1, - 'msword' => 1, -]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_ord.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_ord.php deleted file mode 100644 index 142318c33..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/ascii_ord.php +++ /dev/null @@ -1 +0,0 @@ - 0, "\x00" => 0, "\x01" => 1, "\x02" => 2, "\x03" => 3, "\x04" => 4, "\x05" => 5, "\x06" => 6, "\x07" => 7, "\x08" => 8, "\x09" => 9, "\x0A" => 10, "\x0B" => 11, "\x0C" => 12, "\x0D" => 13, "\x0E" => 14, "\x0F" => 15, "\x10" => 16, "\x11" => 17, "\x12" => 18, "\x13" => 19, "\x14" => 20, "\x15" => 21, "\x16" => 22, "\x17" => 23, "\x18" => 24, "\x19" => 25, "\x1A" => 26, "\x1B" => 27, "\x1C" => 28, "\x1D" => 29, "\x1E" => 30, "\x1F" => 31, "\x20" => 32, "\x21" => 33, "\x22" => 34, "\x23" => 35, "\x24" => 36, "\x25" => 37, "\x26" => 38, "\x27" => 39, "\x28" => 40, "\x29" => 41, "\x2A" => 42, "\x2B" => 43, "\x2C" => 44, "\x2D" => 45, "\x2E" => 46, "\x2F" => 47, "\x30" => 48, "\x31" => 49, "\x32" => 50, "\x33" => 51, "\x34" => 52, "\x35" => 53, "\x36" => 54, "\x37" => 55, "\x38" => 56, "\x39" => 57, "\x3A" => 58, "\x3B" => 59, "\x3C" => 60, "\x3D" => 61, "\x3E" => 62, "\x3F" => 63, "\x40" => 64, "\x41" => 65, "\x42" => 66, "\x43" => 67, "\x44" => 68, "\x45" => 69, "\x46" => 70, "\x47" => 71, "\x48" => 72, "\x49" => 73, "\x4A" => 74, "\x4B" => 75, "\x4C" => 76, "\x4D" => 77, "\x4E" => 78, "\x4F" => 79, "\x50" => 80, "\x51" => 81, "\x52" => 82, "\x53" => 83, "\x54" => 84, "\x55" => 85, "\x56" => 86, "\x57" => 87, "\x58" => 88, "\x59" => 89, "\x5A" => 90, "\x5B" => 91, "\x5C" => 92, "\x5D" => 93, "\x5E" => 94, "\x5F" => 95, "\x60" => 96, "\x61" => 97, "\x62" => 98, "\x63" => 99, "\x64" => 100, "\x65" => 101, "\x66" => 102, "\x67" => 103, "\x68" => 104, "\x69" => 105, "\x6A" => 106, "\x6B" => 107, "\x6C" => 108, "\x6D" => 109, "\x6E" => 110, "\x6F" => 111, "\x70" => 112, "\x71" => 113, "\x72" => 114, "\x73" => 115, "\x74" => 116, "\x75" => 117, "\x76" => 118, "\x77" => 119, "\x78" => 120, "\x79" => 121, "\x7A" => 122, "\x7B" => 123, "\x7C" => 124, "\x7D" => 125, "\x7E" => 126, "\x7F" => 127, "\x80" => 128, "\x81" => 129, "\x82" => 130, "\x83" => 131, "\x84" => 132, "\x85" => 133, "\x86" => 134, "\x87" => 135, "\x88" => 136, "\x89" => 137, "\x8A" => 138, "\x8B" => 139, "\x8C" => 140, "\x8D" => 141, "\x8E" => 142, "\x8F" => 143, "\x90" => 144, "\x91" => 145, "\x92" => 146, "\x93" => 147, "\x94" => 148, "\x95" => 149, "\x96" => 150, "\x97" => 151, "\x98" => 152, "\x99" => 153, "\x9A" => 154, "\x9B" => 155, "\x9C" => 156, "\x9D" => 157, "\x9E" => 158, "\x9F" => 159, "\xA0" => 160, "\xA1" => 161, "\xA2" => 162, "\xA3" => 163, "\xA4" => 164, "\xA5" => 165, "\xA6" => 166, "\xA7" => 167, "\xA8" => 168, "\xA9" => 169, "\xAA" => 170, "\xAB" => 171, "\xAC" => 172, "\xAD" => 173, "\xAE" => 174, "\xAF" => 175, "\xB0" => 176, "\xB1" => 177, "\xB2" => 178, "\xB3" => 179, "\xB4" => 180, "\xB5" => 181, "\xB6" => 182, "\xB7" => 183, "\xB8" => 184, "\xB9" => 185, "\xBA" => 186, "\xBB" => 187, "\xBC" => 188, "\xBD" => 189, "\xBE" => 190, "\xBF" => 191, "\xC0" => 192, "\xC1" => 193, "\xC2" => 194, "\xC3" => 195, "\xC4" => 196, "\xC5" => 197, "\xC6" => 198, "\xC7" => 199, "\xC8" => 200, "\xC9" => 201, "\xCA" => 202, "\xCB" => 203, "\xCC" => 204, "\xCD" => 205, "\xCE" => 206, "\xCF" => 207, "\xD0" => 208, "\xD1" => 209, "\xD2" => 210, "\xD3" => 211, "\xD4" => 212, "\xD5" => 213, "\xD6" => 214, "\xD7" => 215, "\xD8" => 216, "\xD9" => 217, "\xDA" => 218, "\xDB" => 219, "\xDC" => 220, "\xDD" => 221, "\xDE" => 222, "\xDF" => 223, "\xE0" => 224, "\xE1" => 225, "\xE2" => 226, "\xE3" => 227, "\xE4" => 228, "\xE5" => 229, "\xE6" => 230, "\xE7" => 231, "\xE8" => 232, "\xE9" => 233, "\xEA" => 234, "\xEB" => 235, "\xEC" => 236, "\xED" => 237, "\xEE" => 238, "\xEF" => 239, "\xF0" => 240, "\xF1" => 241, "\xF2" => 242, "\xF3" => 243, "\xF4" => 244, "\xF5" => 245, "\xF6" => 246, "\xF7" => 247, "\xF8" => 248, "\xF9" => 249, "\xFA" => 250, "\xFB" => 251, "\xFC" => 252, "\xFD" => 253, "\xFE" => 254, "\xFF" => 255]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x000.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x000.php deleted file mode 100644 index 6c9d81f9d..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x000.php +++ /dev/null @@ -1,16 +0,0 @@ -', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '', 'EUR', // "\xc2\x80" => "\xe2\x82\xac" => EURO SIGN - '', ',', 'f', ',,', // "\xc2\x84" => "\xe2\x80\x9e" => DOUBLE LOW-9 QUOTATION MARK - '...', // "\xc2\x85" => "\xe2\x80\xa6" => HORIZONTAL ELLIPSIS - '+', '++', // "\xc2\x87" => "\xe2\x80\xa1" => DOUBLE DAGGER - '^', '%0', // "\xc2\x89" => "\xe2\x80\xb0" => PER MILLE SIGN - 'S', '<', 'OE', // "\xc2\x8c" => "\xc5\x92" => LATIN CAPITAL LIGATURE OE - '', 'Z', '', '', '\'', // "\xc2\x91" => "\xe2\x80\x98" => LEFT SINGLE QUOTATION MARK - '\'', // "\xc2\x92" => "\xe2\x80\x99" => RIGHT SINGLE QUOTATION MARK - '"', '"', '*', '-', '--', // "\xc2\x97" => "\xe2\x80\x94" => EM DASH - '~', 'tm', 's', '>', 'oe', '', 'z', 'Y', ' ', '!', 'C/', 'PS', '$?', 'Y=', '|', 'SS', '"', '(c)', 'a', '<<', '!', '', '(r)', '-', 'deg', '+-', '2', '3', '\'', 'u', 'P', '*', ',', '1', 'o', '>>', '1/4', '1/2', '3/4', '?', 'A', 'A', 'A', 'A', // Not "AE" - used in languages other than German - 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', // Not "OE" - used in languages other than German - 'O', 'x', 'O', 'U', 'U', 'U', // Not "UE" - used in languages other than German - 'U', 'Y', 'Th', 'ss', 'a', 'a', 'a', 'a', // Not "ae" - used in languages other than German - 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'd', 'n', 'o', 'o', 'o', 'o', // Not "oe" - used in languages other than German - 'o', '/', 'o', 'u', 'u', 'u', // Not "ue" - used in languages other than German - 'u', 'y', 'th', 'y', ]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x001.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x001.php deleted file mode 100644 index 87fb12fb9..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x001.php +++ /dev/null @@ -1 +0,0 @@ -', '^', 'V', '^', 'V', '\'', '-', '/', '\\', ',', '_', '\\', '/', ':', '.', '`', '\'', '^', 'V', '+', '-', 'V', '.', '@', ',', '~', '"', 'R', 'X', 'G', 'l', 's', 'x', '?', '', '', '', '', '', '', '', 'V', '=', '"', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x003.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x003.php deleted file mode 100644 index 3d02b86e2..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x003.php +++ /dev/null @@ -1 +0,0 @@ -', '[?]', '[?]', '[?]', 'f', 'v', 'u', 'yr', 'y', 'w', 'th', 'th', 'a', 'o', 'ac', 'ae', 'o', 'o', 'o', 'oe', 'on', 'r', 'k', 'c', 'k', 'g', 'ng', 'g', 'g', 'w', 'h', 'h', 'h', 'h', 'n', 'n', 'n', 'i', 'e', 'j', 'g', 'ae', 'a', 'eo', 'p', 'z', 's', 's', 's', 'c', 'z', 't', 't', 'd', 'b', 'b', 'p', 'p', 'e', 'm', 'm', 'm', 'l', 'l', 'ng', 'ng', 'd', 'o', 'ear', 'ior', 'qu', 'qu', 'qu', 's', 'yr', 'yr', 'yr', 'q', 'x', '.', ':', '+', '17', '18', '19', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x017.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x017.php deleted file mode 100644 index 8f2a7cac1..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x017.php +++ /dev/null @@ -1 +0,0 @@ -', '.', '..', '...', '.', "\n", - "\n\n", - '', '', '', '', '', ' ', '%0', '%00', '\'', '\'\'', '\'\'\'', '`', '``', '```', '^', '<', '>', '*', '!!', '!?', '-', '_', '-', '^', '***', '--', '/', '-[', ']-', '??', '?!', '!?', '7', 'PP', '(]', '[)', '*', '[?]', '[?]', '[?]', '%', '~', '[?]', '[?]', '[?]', "''''", // 0x57 - '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ' ', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '0', 'i', '', '', '4', '5', '6', '7', '8', '9', '+', '-', '=', '(', ')', 'n', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '=', '(', ')', '[?]', 'a', 'e', 'o', 'x', '[?]', 'h', 'k', 'l', 'm', 'n', 'p', 's', 't', '[?]', '[?]', '[?]', 'ECU', 'CL', 'Cr', 'Fr.', 'L.', 'mil', 'N', 'Pts', 'Rs', 'W', 'NS', 'D', 'EUR', 'K', 'T', 'Dr', 'Pf', 'P', 'G', 'A', 'UAH', 'C|', 'L', 'Sm', 'T', 'Rs', 'L', 'M', 'm', 'R', 'l', 'BTC', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', ]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x021.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x021.php deleted file mode 100644 index 1643d67dc..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x021.php +++ /dev/null @@ -1 +0,0 @@ -=', '<=', '>=', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x023.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x023.php deleted file mode 100644 index b8f4ca0d2..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x023.php +++ /dev/null @@ -1 +0,0 @@ - ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x024.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x024.php deleted file mode 100644 index 26abcc69a..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x024.php +++ /dev/null @@ -1 +0,0 @@ -', '>', '>', '>', '>', '>', 'V', 'V', 'V', 'V', '<', '<', '<', '<', '<', '<', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '#', '#', '#', '#', '#', '^', '^', '^', 'O', '#', '#', '#', '#', 'O', 'O', 'O', 'O', '/', '\\\\', '\\\\', '#', '#', '#', '#', '/']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x026.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x026.php deleted file mode 100644 index 0c97de3f8..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x026.php +++ /dev/null @@ -1 +0,0 @@ - ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x028.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x028.php deleted file mode 100644 index 9585d9149..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x028.php +++ /dev/null @@ -1 +0,0 @@ -', 'n', 't', 'q', ',', '*', '5', '<', '-', 'u', '8', 'v', '.', '%', '[', '$', '+', 'x', '!', '&', ';', ':', '4', '\\', '0', 'z', '7', '(', '_', '?', 'w', ']', '#', 'y', ')', '=', '[d7]', '[d17]', '[d27]', '[d127]', '[d37]', '[d137]', '[d237]', '[d1237]', '[d47]', '[d147]', '[d247]', '[d1247]', '[d347]', '[d1347]', '[d2347]', '[d12347]', '[d57]', '[d157]', '[d257]', '[d1257]', '[d357]', '[d1357]', '[d2357]', '[d12357]', '[d457]', '[d1457]', '[d2457]', '[d12457]', '[d3457]', '[d13457]', '[d23457]', '[d123457]', '[d67]', '[d167]', '[d267]', '[d1267]', '[d367]', '[d1367]', '[d2367]', '[d12367]', '[d467]', '[d1467]', '[d2467]', '[d12467]', '[d3467]', '[d13467]', '[d23467]', '[d123467]', '[d567]', '[d1567]', '[d2567]', '[d12567]', '[d3567]', '[d13567]', '[d23567]', '[d123567]', '[d4567]', '[d14567]', '[d24567]', '[d124567]', '[d34567]', '[d134567]', '[d234567]', '[d1234567]', '[d8]', '[d18]', '[d28]', '[d128]', '[d38]', '[d138]', '[d238]', '[d1238]', '[d48]', '[d148]', '[d248]', '[d1248]', '[d348]', '[d1348]', '[d2348]', '[d12348]', '[d58]', '[d158]', '[d258]', '[d1258]', '[d358]', '[d1358]', '[d2358]', '[d12358]', '[d458]', '[d1458]', '[d2458]', '[d12458]', '[d3458]', '[d13458]', '[d23458]', '[d123458]', '[d68]', '[d168]', '[d268]', '[d1268]', '[d368]', '[d1368]', '[d2368]', '[d12368]', '[d468]', '[d1468]', '[d2468]', '[d12468]', '[d3468]', '[d13468]', '[d23468]', '[d123468]', '[d568]', '[d1568]', '[d2568]', '[d12568]', '[d3568]', '[d13568]', '[d23568]', '[d123568]', '[d4568]', '[d14568]', '[d24568]', '[d124568]', '[d34568]', '[d134568]', '[d234568]', '[d1234568]', '[d78]', '[d178]', '[d278]', '[d1278]', '[d378]', '[d1378]', '[d2378]', '[d12378]', '[d478]', '[d1478]', '[d2478]', '[d12478]', '[d3478]', '[d13478]', '[d23478]', '[d123478]', '[d578]', '[d1578]', '[d2578]', '[d12578]', '[d3578]', '[d13578]', '[d23578]', '[d123578]', '[d4578]', '[d14578]', '[d24578]', '[d124578]', '[d34578]', '[d134578]', '[d234578]', '[d1234578]', '[d678]', '[d1678]', '[d2678]', '[d12678]', '[d3678]', '[d13678]', '[d23678]', '[d123678]', '[d4678]', '[d14678]', '[d24678]', '[d124678]', '[d34678]', '[d134678]', '[d234678]', '[d1234678]', '[d5678]', '[d15678]', '[d25678]', '[d125678]', '[d35678]', '[d135678]', '[d235678]', '[d1235678]', '[d45678]', '[d145678]', '[d245678]', '[d1245678]', '[d345678]', '[d1345678]', '[d2345678]', '[d12345678]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x029.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x029.php deleted file mode 100644 index 5162de386..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x029.php +++ /dev/null @@ -1 +0,0 @@ -', '%', '[?]', '[?]', '>', '=', '[?]', '/', '-', '~', '\\', '/', '~', '~', '|-', '-|', '[?]', '[?]', '[?]', '[?]', '<=', '=>', '((', '))', '[?]', '[?]', '::', '[?]', '?', '\'', 'o', '.', ',', '.', ',', ';', '[?]', '[?]', '[?]', '[?]', '----', '------', 'x', '|', '[?]', '[?]', '=', ',', '"', '`--', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?] ', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x02f.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x02f.php deleted file mode 100644 index 5147b5740..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x02f.php +++ /dev/null @@ -1 +0,0 @@ - ', '<<', '>> ', '[', '] ', '{', '} ', '[(', ')] ', '@', 'X ', '[', '] ', '[[', ']] ', '((', ')) ', '[[', ']] ', '~ ', '``', '\'\'', ',,', '@', '1', '2', '3', '4', '5', '6', '7', '8', '9', '', '', '', '', '', '', '~', '+', '+', '+', '+', '', '@', ' // ', '+10+', '+20+', '+30+', '[?]', '[?]', '[?]', '', '', '[?]', 'a', 'a', 'i', 'i', 'u', 'u', 'e', 'e', 'o', 'o', 'ka', 'ga', 'ki', 'gi', 'ku', 'gu', 'ke', 'ge', 'ko', 'go', 'sa', 'za', 'shi', // 0x57 - 'zi', 'su', 'zu', 'se', 'ze', 'so', 'zo', 'ta', 'da', 'chi', // 0x61 - 'di', 'tsu', // 0x63 - 'tsu', // 0x64 - 'du', 'te', 'de', 'to', 'do', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'ba', 'pa', 'hi', 'bi', 'pi', 'hu', 'bu', 'pu', 'he', 'be', 'pe', 'ho', 'bo', 'po', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'ya', 'yu', 'yu', 'yo', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wa', 'wi', 'we', 'wo', 'n', 'vu', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '"', '"', '[?]', '[?]', 'a', 'a', 'i', 'i', 'u', 'u', 'e', 'e', 'o', 'o', 'ka', 'ga', 'ki', 'gi', 'ku', 'gu', 'ke', 'ge', 'ko', 'go', 'sa', 'za', 'shi', // 0xb7 - 'zi', 'su', 'zu', 'se', 'ze', 'so', 'zo', 'ta', 'da', 'chi', // 0xc1 - 'di', 'tsu', // 0xc3 - 'tsu', // 0xc4 - 'du', 'te', 'de', 'to', 'do', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'ba', 'pa', 'hi', 'bi', 'pi', 'hu', 'bu', 'pu', 'he', 'be', 'pe', 'ho', 'bo', 'po', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'ya', 'yu', 'yu', 'yo', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wa', 'wi', 'we', 'wo', 'n', 'vu', 'ka', 'ke', 'va', 'vi', 've', 'vo', '', '', '"', '"', ]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x031.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x031.php deleted file mode 100644 index 72c0260cf..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x031.php +++ /dev/null @@ -1 +0,0 @@ ->', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '(g)', '(n)', '(d)', '(r)', '(m)', '(b)', '(s)', '()', '(j)', '(c)', '(k)', '(t)', '(p)', '(h)', '(ga)', '(na)', '(da)', '(ra)', '(ma)', '(ba)', '(sa)', '(a)', '(ja)', '(ca)', '(ka)', '(ta)', '(pa)', '(ha)', '[?]', '[?]', '[?]', 'KIS ', '(1) ', '(2) ', '(3) ', '(4) ', '(5) ', '(6) ', '(7) ', '(8) ', '(9) ', '(10) ', '(Yue) ', '(Huo) ', '(Shui) ', '(Mu) ', '(Jin) ', '(Tu) ', '(Ri) ', '(Zhu) ', '(You) ', '(She) ', '(Ming) ', '(Te) ', '(Cai) ', '(Zhu) ', '(Lao) ', '(Mi) ', '(Nan) ', '(Nu) ', '(Shi) ', '(You) ', '(Yin) ', '(Zhu) ', '(Xiang) ', '(Xiu) ', '(Xie) ', '(Zheng) ', '(Shang) ', '(Zhong) ', '(Xia) ', '(Zuo) ', '(You) ', '(Yi) ', '(Zong) ', '(Xue) ', '(Jian) ', '(Qi) ', '(Zi) ', '(Xie) ', '(Ye) ', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '1M', '2M', '3M', '4M', '5M', '6M', '7M', '8M', '9M', '10M', '11M', '12M', 'Hg', 'erg', 'eV', 'LTD', 'a', 'i', 'u', 'u', 'o', 'ka', 'ki', 'ku', 'ke', 'ko', 'sa', 'si', 'su', 'se', 'so', 'ta', 'ti', 'tu', 'te', 'to', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'hi', 'hu', 'he', 'ho', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'yu', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'wi', 'we', 'wo']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x033.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x033.php deleted file mode 100644 index 8505337e3..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x033.php +++ /dev/null @@ -1 +0,0 @@ -> ', '<', '> ', '[', '] ', '{', '}', '[?]', '[?]', '[?]', '[?]', '', '', '', '', '', '', '', ',', ',', '.', '', ';', ':', '?', '!', '-', '(', ')', '{', '}', '{', '}', '#', '&', '*', '+', '-', '<', '>', '=', '', '\\', '$', '%', '@', '[?]', '[?]', '[?]', '[?]', '', '', '', '[?]', '', '[?]', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '[?]', '[?]', '']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x0ff.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x0ff.php deleted file mode 100644 index b3a15398c..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x0ff.php +++ /dev/null @@ -1 +0,0 @@ -', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '[?]', '[?]', '.', '[', ']', ',', '*', 'wo', 'a', 'i', 'u', 'e', 'o', 'ya', 'yu', 'yo', 'tu', '+', 'a', 'i', 'u', 'e', 'o', 'ka', 'ki', 'ku', 'ke', 'ko', 'sa', 'si', 'su', 'se', 'so', 'ta', 'ti', 'tu', 'te', 'to', 'na', 'ni', 'nu', 'ne', 'no', 'ha', 'hi', 'hu', 'he', 'ho', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'yu', 'yo', 'ra', 'ri', 'ru', 're', 'ro', 'wa', 'n', ':', ';', '', 'g', 'gg', 'gs', 'n', 'nj', 'nh', 'd', 'dd', 'r', 'lg', 'lm', 'lb', 'ls', 'lt', 'lp', 'rh', 'm', 'b', 'bb', 'bs', 's', 'ss', '', 'j', 'jj', 'c', 'k', 't', 'p', 'h', '[?]', '[?]', '[?]', 'a', 'ae', 'ya', 'yae', 'eo', 'e', '[?]', '[?]', 'yeo', 'ye', 'o', 'wa', 'wae', 'oe', '[?]', '[?]', 'yo', 'u', 'weo', 'we', 'wi', 'yu', '[?]', '[?]', 'eu', 'yi', 'i', '[?]', '[?]', '[?]', '/C', 'PS', '!', '-', '|', 'Y=', 'W=', '[?]', '|', '-', '|', '-', '|', '#', 'O', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '[?]', '{', '|', '}', '', '', '', '']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d4.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d4.php deleted file mode 100644 index ad8d3b257..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d4.php +++ /dev/null @@ -1 +0,0 @@ - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 52 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 78 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 104 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 130 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 156 => 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 181 => 'Z', 182 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 208 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 234 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d5.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d5.php deleted file mode 100644 index a2a9b908d..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d5.php +++ /dev/null @@ -1,4 +0,0 @@ - 'w', 'x', 'y', 'z', 4 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 30 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 56 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 82 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 108 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 134 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 160 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 186 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 212 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 238 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ]; diff --git a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d6.php b/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d6.php deleted file mode 100644 index 315ef5e40..000000000 --- a/lam/lib/3rdParty/composer/voku/portable-ascii/src/voku/helper/data/x1d6.php +++ /dev/null @@ -1 +0,0 @@ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 80 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 112 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 230 => 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ]; diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md b/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md index f3ee0777b..b8cc112b8 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md @@ -3,6 +3,16 @@ COSE Support for PHP **CBOR Object Signing and Encryption (COSE) Support for PHP** is a **PHP library** that will help you to perform cypher operations using Cose Keys. + +![Build Status](https://github.com/web-auth/cose-lib/workflows/Integrate/badge.svg) + +[![Latest Stable Version](https://poser.pugx.org/web-auth/cose-lib/v/stable.png)](https://packagist.org/packages/web-auth/cose-lib) +[![Total Downloads](https://poser.pugx.org/web-auth/cose-lib/downloads.png)](https://packagist.org/packages/web-auth/cose-lib) +[![Latest Unstable Version](https://poser.pugx.org/web-auth/cose-lib/v/unstable.png)](https://packagist.org/packages/web-auth/cose-lib) +[![License](https://poser.pugx.org/web-auth/cose-lib/license.png)](https://packagist.org/packages/web-auth/cose-lib) + +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/web-auth/cose-lib/badge)](https://api.securityscorecards.dev/projects/github.com/web-auth/cose-lib) + # Installation Install the library with Composer: `composer require web-auth/cose-lib`. diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json b/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json index 130ca4e37..acef13265 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json @@ -19,9 +19,8 @@ "php": ">=8.1", "ext-json": "*", "ext-openssl": "*", - "ext-mbstring": "*", - "brick/math": "^0.9|^0.10", - "fgrosse/phpasn1": "^2.1" + "brick/math": "^0.9|^0.10|^0.11|^0.12|^0.13", + "spomky-labs/pki-framework": "^1.0" }, "autoload": { "psr-4": { @@ -29,18 +28,19 @@ } }, "require-dev": { - "infection/infection": "^0.26.12", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.14", - "symplify/easy-coding-standard": "^11.0", - "symfony/phpunit-bridge": "^6.1", - "ekino/phpstan-banned-code": "^1.0", + "infection/infection": "^0.29", + "phpstan/phpstan": "^1.7|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.0|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^2.0", + "symplify/easy-coding-standard": "^12.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", "php-parallel-lint/php-parallel-lint": "^1.3", - "qossmic/deptrac-shim": "^0.24.0" + "deptrac/deptrac": "^3.0", + "phpstan/extension-installer": "^1.3" }, "autoload-dev": { "psr-4": { @@ -49,7 +49,8 @@ }, "config": { "allow-plugins": { - "infection/extension-installer": false + "infection/extension-installer": true, + "phpstan/extension-installer": true } }, "suggest": { diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Hmac.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Hmac.php index 593e4896c..54ef46076 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Hmac.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Hmac.php @@ -5,16 +5,20 @@ declare(strict_types=1); namespace Cose\Algorithm\Mac; use Cose\Key\Key; +use Cose\Key\SymmetricKey; use InvalidArgumentException; +/** + * @see \Cose\Tests\Algorithm\Mac\HmacTest + */ abstract class Hmac implements Mac { public function hash(string $data, Key $key): string { $this->checKey($key); - $signature = hash_hmac($this->getHashAlgorithm(), $data, (string) $key->get(-1), true); + $signature = hash_hmac($this->getHashAlgorithm(), $data, (string) $key->get(SymmetricKey::DATA_K), true); - return mb_substr($signature, 0, intdiv($this->getSignatureLength(), 8), '8bit'); + return substr($signature, 0, intdiv($this->getSignatureLength(), 8)); } public function verify(string $data, Key $key, string $signature): bool @@ -28,11 +32,11 @@ abstract class Hmac implements Mac private function checKey(Key $key): void { - if ($key->type() !== 4) { + if ($key->type() !== Key::TYPE_OCT && $key->type() !== Key::TYPE_NAME_OCT) { throw new InvalidArgumentException('Invalid key. Must be of type symmetric'); } - if (! $key->has(-1)) { + if (! $key->has(SymmetricKey::DATA_K)) { throw new InvalidArgumentException('Invalid key. The value of the key is missing'); } } diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Manager.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Manager.php index c3df4478a..0a80340e8 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Manager.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Manager.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace Cose\Algorithm; -use function array_key_exists; use InvalidArgumentException; +use function array_key_exists; final class Manager { diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php index 908403d38..380d1e0c7 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace Cose\Algorithm; -use function array_key_exists; use InvalidArgumentException; +use function array_key_exists; +use function sprintf; final class ManagerFactory { diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php index 82e47739a..dc78ac76b 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php @@ -11,6 +11,9 @@ use InvalidArgumentException; use function openssl_sign; use function openssl_verify; +/** + * @see \Cose\Tests\Algorithm\Signature\ECDSA\ECDSATest + */ abstract class ECDSA implements Signature { public function sign(string $data, Key $key): string @@ -26,7 +29,6 @@ abstract class ECDSA implements Signature $key = $this->handleKey($key); $publicKey = $key->toPublic(); $signature = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); - return openssl_verify($data, $signature, $publicKey->asPEM(), $this->getHashAlgorithm()) === 1; } diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php index 204c6c64c..5995131a1 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php @@ -4,14 +4,14 @@ declare(strict_types=1); namespace Cose\Algorithm\Signature\ECDSA; +use InvalidArgumentException; use function bin2hex; use function dechex; use function hex2bin; use function hexdec; -use InvalidArgumentException; -use function mb_strlen; -use function mb_substr; use function str_pad; +use function strlen; +use function substr; use const STR_PAD_LEFT; /** @@ -41,8 +41,8 @@ final class ECSignature throw new InvalidArgumentException('Invalid signature length.'); } - $pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit')); - $pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit')); + $pointR = self::preparePositiveInteger(substr($signature, 0, $length)); + $pointS = self::preparePositiveInteger(substr($signature, $length, null)); $lengthR = self::octetLength($pointR); $lengthS = self::octetLength($pointS); @@ -80,20 +80,20 @@ final class ECSignature private static function octetLength(string $data): int { - return intdiv(mb_strlen($data, '8bit'), self::BYTE_SIZE); + return intdiv(strlen($data), self::BYTE_SIZE); } private static function preparePositiveInteger(string $data): string { - if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) { + if (substr($data, 0, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT) { return self::ASN1_NEGATIVE_INTEGER . $data; } while ( - mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0 - && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT + str_starts_with($data, self::ASN1_NEGATIVE_INTEGER) + && substr($data, 2, self::BYTE_SIZE) <= self::ASN1_BIG_INTEGER_LIMIT ) { - $data = mb_substr($data, 2, null, '8bit'); + $data = substr($data, 2, null); } return $data; @@ -101,7 +101,7 @@ final class ECSignature private static function readAsn1Content(string $message, int &$position, int $length): string { - $content = mb_substr($message, $position, $length, '8bit'); + $content = substr($message, $position, $length); $position += $length; return $content; @@ -121,10 +121,10 @@ final class ECSignature private static function retrievePositiveInteger(string $data): string { while ( - mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0 - && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT + str_starts_with($data, self::ASN1_NEGATIVE_INTEGER) + && substr($data, 2, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT ) { - $data = mb_substr($data, 2, null, '8bit'); + $data = substr($data, 2, null); } return $data; diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/EdDSA.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/EdDSA.php index 21a2eed0c..37426e9fd 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/EdDSA.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/EdDSA.php @@ -9,10 +9,13 @@ use Cose\Algorithms; use Cose\Key\Key; use Cose\Key\OkpKey; use InvalidArgumentException; +use Throwable; use function sodium_crypto_sign_detached; use function sodium_crypto_sign_verify_detached; -use Throwable; +/** + * @see \Cose\Tests\Algorithm\Signature\EdDSA\EdDSATest + */ class EdDSA implements Signature { public function sign(string $data, Key $key): string @@ -28,6 +31,7 @@ class EdDSA implements Signature return match ($key->curve()) { OkpKey::CURVE_ED25519 => sodium_crypto_sign_detached($data, $secret), + OkpKey::CURVE_NAME_ED25519 => sodium_crypto_sign_detached($data, $secret), default => throw new InvalidArgumentException('Unsupported curve'), }; } @@ -35,16 +39,14 @@ class EdDSA implements Signature public function verify(string $data, Key $key, string $signature): bool { $key = $this->handleKey($key); - if ($key->curve() !== OkpKey::CURVE_ED25519) { + if ($key->curve() !== OkpKey::CURVE_ED25519 && $key->curve() !== OkpKey::CURVE_NAME_ED25519) { throw new InvalidArgumentException('Unsupported curve'); } try { - sodium_crypto_sign_verify_detached($signature, $data, $key->x()); + return sodium_crypto_sign_verify_detached($signature, $data, $key->x()); } catch (Throwable) { return false; } - - return true; } public static function identifier(): int diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PSSRSA.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PSSRSA.php index 2d3a28c6e..d383dce62 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PSSRSA.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PSSRSA.php @@ -4,24 +4,23 @@ declare(strict_types=1); namespace Cose\Algorithm\Signature\RSA; -use function ceil; -use function chr; use Cose\Algorithm\Signature\Signature; use Cose\BigInteger; use Cose\Hash; use Cose\Key\Key; use Cose\Key\RsaKey; -use function hash_equals; use InvalidArgumentException; -use function mb_strlen; -use function mb_substr; +use RuntimeException; +use function ceil; +use function chr; +use function hash_equals; use function ord; use function pack; use function random_bytes; -use RuntimeException; use function str_pad; -use const STR_PAD_LEFT; use function str_repeat; +use function strlen; +use const STR_PAD_LEFT; /** * @internal @@ -31,7 +30,7 @@ abstract class PSSRSA implements Signature public function sign(string $data, Key $key): string { $key = $this->handleKey($key); - $modulusLength = mb_strlen($key->n(), '8bit'); + $modulusLength = strlen($key->n()); $em = $this->encodeEMSAPSS($data, 8 * $modulusLength - 1, $this->getHashAlgorithm()); $message = BigInteger::createFromBinaryString($em); @@ -43,9 +42,8 @@ abstract class PSSRSA implements Signature public function verify(string $data, Key $key, string $signature): bool { $key = $this->handleKey($key); - $modulusLength = mb_strlen($key->n(), '8bit'); - - if (mb_strlen($signature, '8bit') !== $modulusLength) { + $modulusLength = strlen($key->n()); + if (strlen($signature) !== $modulusLength) { throw new InvalidArgumentException('Invalid modulus length'); } $s2 = BigInteger::createFromBinaryString($signature); @@ -100,7 +98,7 @@ abstract class PSSRSA implements Signature private function convertIntegerToOctetString(BigInteger $x, int $xLen): string { $xB = $x->toBytes(); - if (mb_strlen($xB, '8bit') > $xLen) { + if (strlen($xB) > $xLen) { throw new RuntimeException('Unable to convert the integer'); } @@ -119,7 +117,7 @@ abstract class PSSRSA implements Signature $t .= $mgfHash->hash($mgfSeed . $c); } - return mb_substr($t, 0, $maskLen, '8bit'); + return substr($t, 0, $maskLen); } /** @@ -156,11 +154,11 @@ abstract class PSSRSA implements Signature if ($emLen < $hash->getLength() + $sLen + 2) { throw new InvalidArgumentException(); } - if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) { + if ($em[strlen($em) - 1] !== chr(0xBC)) { throw new InvalidArgumentException(); } - $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit'); - $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit'); + $maskedDB = substr($em, 0, -$hash->getLength() - 1); + $h = substr($em, -$hash->getLength() - 1, $hash->getLength()); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) !== $temp) { throw new InvalidArgumentException(); @@ -169,13 +167,13 @@ abstract class PSSRSA implements Signature $db = $maskedDB ^ $dbMask; $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; $temp = $emLen - $hash->getLength() - $sLen - 2; - if (mb_strpos($db, str_repeat(chr(0), $temp), 0, '8bit') !== 0) { + if (! str_starts_with($db, str_repeat(chr(0), $temp))) { throw new InvalidArgumentException(); } if (ord($db[$temp]) !== 1) { throw new InvalidArgumentException(); } - $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long + $salt = substr($db, $temp + 1, null); // should be $sLen long $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $hash->hash($m2); diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RSA.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RSA.php index d50a33437..32e573396 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RSA.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RSA.php @@ -8,10 +8,13 @@ use Cose\Algorithm\Signature\Signature; use Cose\Key\Key; use Cose\Key\RsaKey; use InvalidArgumentException; +use Throwable; use function openssl_sign; use function openssl_verify; -use Throwable; +/** + * @see \Cose\Tests\Algorithm\Signature\RSA\RSATest + */ abstract class RSA implements Signature { public function sign(string $data, Key $key): string @@ -34,7 +37,7 @@ abstract class RSA implements Signature { $key = $this->handleKey($key); - return openssl_verify($data, $signature, $key->asPem(), $this->getHashAlgorithm()) === 1; + return openssl_verify($data, $signature, $key->toPublic()->asPem(), $this->getHashAlgorithm()) === 1; } abstract protected function getHashAlgorithm(): int; diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithms.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithms.php index 43e32b470..a0324b985 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithms.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithms.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace Cose; -use function array_key_exists; use InvalidArgumentException; +use function array_key_exists; use const OPENSSL_ALGO_SHA1; use const OPENSSL_ALGO_SHA256; use const OPENSSL_ALGO_SHA384; diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/BigInteger.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/BigInteger.php index e0ef082fa..d45fd39b6 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/BigInteger.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/BigInteger.php @@ -7,6 +7,7 @@ namespace Cose; use Brick\Math\BigInteger as BrickBigInteger; use function chr; use function hex2bin; +use function strlen; use function unpack; /** @@ -42,7 +43,7 @@ final class BigInteger } $temp = $this->value->toBase(16); - $temp = 0 !== (mb_strlen($temp, '8bit') & 1) ? '0' . $temp : $temp; + $temp = 0 !== (strlen($temp) & 1) ? '0' . $temp : $temp; $temp = hex2bin($temp); return ltrim($temp, chr(0)); diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php index faeaa32c4..38b916d29 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php @@ -4,18 +4,22 @@ declare(strict_types=1); namespace Cose\Key; -use function array_key_exists; -use FG\ASN1\ExplicitlyTaggedObject; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\Integer; -use FG\ASN1\Universal\ObjectIdentifier; -use FG\ASN1\Universal\OctetString; -use FG\ASN1\Universal\Sequence; -use function in_array; use InvalidArgumentException; +use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence; +use SpomkyLabs\Pki\ASN1\Type\Primitive\BitString; +use SpomkyLabs\Pki\ASN1\Type\Primitive\Integer; +use SpomkyLabs\Pki\ASN1\Type\Primitive\ObjectIdentifier; +use SpomkyLabs\Pki\ASN1\Type\Primitive\OctetString; +use SpomkyLabs\Pki\ASN1\Type\Tagged\ExplicitlyTaggedType; +use function array_key_exists; +use function in_array; +use function is_int; +use function sprintf; +use function strlen; /** * @final + * @see \Cose\Tests\Key\Ec2KeyTest */ class Ec2Key extends Key { @@ -27,6 +31,14 @@ class Ec2Key extends Key final public const CURVE_P521 = 3; + final public const CURVE_NAME_P256 = 'P-256'; + + final public const CURVE_NAME_P256K = 'P-256K'; + + final public const CURVE_NAME_P384 = 'P-384'; + + final public const CURVE_NAME_P521 = 'P-521'; + final public const DATA_CURVE = -1; final public const DATA_X = -2; @@ -35,7 +47,14 @@ class Ec2Key extends Key final public const DATA_D = -4; - private const SUPPORTED_CURVES = [self::CURVE_P256, self::CURVE_P256K, self::CURVE_P384, self::CURVE_P521]; + private const SUPPORTED_CURVES_INT = [self::CURVE_P256, self::CURVE_P256K, self::CURVE_P384, self::CURVE_P521]; + + private const SUPPORTED_CURVES_NAMES = [ + self::CURVE_NAME_P256, + self::CURVE_NAME_P256K, + self::CURVE_NAME_P384, + self::CURVE_NAME_P521, + ]; private const NAMED_CURVE_OID = [ self::CURVE_P256 => '1.2.840.10045.3.1.7', @@ -53,6 +72,10 @@ class Ec2Key extends Key self::CURVE_P256K => 32, self::CURVE_P384 => 48, self::CURVE_P521 => 66, + self::CURVE_NAME_P256 => 32, + self::CURVE_NAME_P256K => 32, + self::CURVE_NAME_P384 => 48, + self::CURVE_NAME_P521 => 66, ]; /** @@ -60,20 +83,29 @@ class Ec2Key extends Key */ public function __construct(array $data) { + foreach ([self::DATA_CURVE, self::TYPE] as $key) { + if (is_numeric($data[$key])) { + $data[$key] = (int) $data[$key]; + } + } parent::__construct($data); - if (! isset($data[self::TYPE]) || (int) $data[self::TYPE] !== self::TYPE_EC2) { + if ($data[self::TYPE] !== self::TYPE_EC2 && $data[self::TYPE] !== self::TYPE_NAME_EC2) { throw new InvalidArgumentException('Invalid EC2 key. The key type does not correspond to an EC2 key'); } if (! isset($data[self::DATA_CURVE], $data[self::DATA_X], $data[self::DATA_Y])) { throw new InvalidArgumentException('Invalid EC2 key. The curve or the "x/y" coordinates are missing'); } - if (mb_strlen((string) $data[self::DATA_X], '8bit') !== self::CURVE_KEY_LENGTH[(int) $data[self::DATA_CURVE]]) { + if (strlen((string) $data[self::DATA_X]) !== self::CURVE_KEY_LENGTH[$data[self::DATA_CURVE]]) { throw new InvalidArgumentException('Invalid length for x coordinate'); } - if (mb_strlen((string) $data[self::DATA_Y], '8bit') !== self::CURVE_KEY_LENGTH[(int) $data[self::DATA_CURVE]]) { + if (strlen((string) $data[self::DATA_Y]) !== self::CURVE_KEY_LENGTH[$data[self::DATA_CURVE]]) { throw new InvalidArgumentException('Invalid length for y coordinate'); } - if (! in_array((int) $data[self::DATA_CURVE], self::SUPPORTED_CURVES, true)) { + if (is_int($data[self::DATA_CURVE])) { + if (! in_array($data[self::DATA_CURVE], self::SUPPORTED_CURVES_INT, true)) { + throw new InvalidArgumentException('The curve is not supported'); + } + } elseif (! in_array($data[self::DATA_CURVE], self::SUPPORTED_CURVES_NAMES, true)) { throw new InvalidArgumentException('The curve is not supported'); } } @@ -117,30 +149,33 @@ class Ec2Key extends Key return $this->get(self::DATA_D); } - public function curve(): int + public function curve(): int|string { - return (int) $this->get(self::DATA_CURVE); + return $this->get(self::DATA_CURVE); } public function asPEM(): string { if ($this->isPrivate()) { - $der = new Sequence( - new Integer(1), - new OctetString(bin2hex($this->d())), - new ExplicitlyTaggedObject(0, new ObjectIdentifier($this->getCurveOid())), - new ExplicitlyTaggedObject(1, new BitString(bin2hex($this->getUncompressedCoordinates()))) + $der = Sequence::create( + Integer::create(1), + OctetString::create($this->d()), + ExplicitlyTaggedType::create(0, ObjectIdentifier::create($this->getCurveOid())), + ExplicitlyTaggedType::create(1, BitString::create($this->getUncompressedCoordinates())), ); - return $this->pem('EC PRIVATE KEY', $der->getBinary()); + return $this->pem('EC PRIVATE KEY', $der->toDER()); } - $der = new Sequence( - new Sequence(new ObjectIdentifier('1.2.840.10045.2.1'), new ObjectIdentifier($this->getCurveOid())), - new BitString(bin2hex($this->getUncompressedCoordinates())) + $der = Sequence::create( + Sequence::create( + ObjectIdentifier::create('1.2.840.10045.2.1'), + ObjectIdentifier::create($this->getCurveOid()) + ), + BitString::create($this->getUncompressedCoordinates()) ); - return $this->pem('PUBLIC KEY', $der->getBinary()); + return $this->pem('PUBLIC KEY', $der->toDER()); } public function getUncompressedCoordinates(): string @@ -155,8 +190,8 @@ class Ec2Key extends Key private function pem(string $type, string $der): string { - return sprintf("-----BEGIN %s-----\n", mb_strtoupper($type)) . + return sprintf("-----BEGIN %s-----\n", strtoupper($type)) . chunk_split(base64_encode($der), 64, "\n") . - sprintf("-----END %s-----\n", mb_strtoupper($type)); + sprintf("-----END %s-----\n", strtoupper($type)); } } diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php index 0d304e13c..b35010ceb 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php @@ -4,8 +4,9 @@ declare(strict_types=1); namespace Cose\Key; -use function array_key_exists; use InvalidArgumentException; +use function array_key_exists; +use function sprintf; class Key { @@ -19,6 +20,14 @@ class Key public const TYPE_OCT = 4; + public const TYPE_NAME_OKP = 'OKP'; + + public const TYPE_NAME_EC2 = 'EC'; + + public const TYPE_NAME_RSA = 'RSA'; + + public const TYPE_NAME_OCT = 'oct'; + public const KID = 2; public const ALG = 3; diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php index f156a639f..ad2b80069 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php @@ -4,12 +4,13 @@ declare(strict_types=1); namespace Cose\Key; +use InvalidArgumentException; use function array_key_exists; use function in_array; -use InvalidArgumentException; /** * @final + * @see \Cose\Tests\Key\OkpKeyTest */ class OkpKey extends Key { @@ -21,32 +22,56 @@ class OkpKey extends Key final public const CURVE_ED448 = 7; + final public const CURVE_NAME_X25519 = 'X25519'; + + final public const CURVE_NAME_X448 = 'X448'; + + final public const CURVE_NAME_ED25519 = 'Ed25519'; + + final public const CURVE_NAME_ED448 = 'Ed448'; + final public const DATA_CURVE = -1; final public const DATA_X = -2; final public const DATA_D = -4; - private const SUPPORTED_CURVES = [ + private const SUPPORTED_CURVES_INT = [ self::CURVE_X25519, self::CURVE_X448, self::CURVE_ED25519, self::CURVE_ED448, ]; + private const SUPPORTED_CURVES_NAME = [ + self::CURVE_NAME_X25519, + self::CURVE_NAME_X448, + self::CURVE_NAME_ED25519, + self::CURVE_NAME_ED448, + ]; + /** * @param array $data */ public function __construct(array $data) { + foreach ([self::DATA_CURVE, self::TYPE] as $key) { + if (is_numeric($data[$key])) { + $data[$key] = (int) $data[$key]; + } + } parent::__construct($data); - if (! isset($data[self::TYPE]) || (int) $data[self::TYPE] !== self::TYPE_OKP) { + if ($data[self::TYPE] !== self::TYPE_OKP && $data[self::TYPE] !== self::TYPE_NAME_OKP) { throw new InvalidArgumentException('Invalid OKP key. The key type does not correspond to an OKP key'); } if (! isset($data[self::DATA_CURVE], $data[self::DATA_X])) { throw new InvalidArgumentException('Invalid EC2 key. The curve or the "x" coordinate is missing'); } - if (! in_array((int) $data[self::DATA_CURVE], self::SUPPORTED_CURVES, true)) { + if (is_numeric($data[self::DATA_CURVE])) { + if (! in_array((int) $data[self::DATA_CURVE], self::SUPPORTED_CURVES_INT, true)) { + throw new InvalidArgumentException('The curve is not supported'); + } + } elseif (! in_array($data[self::DATA_CURVE], self::SUPPORTED_CURVES_NAME, true)) { throw new InvalidArgumentException('The curve is not supported'); } } @@ -78,8 +103,8 @@ class OkpKey extends Key return $this->get(self::DATA_D); } - public function curve(): int + public function curve(): int|string { - return (int) $this->get(self::DATA_CURVE); + return $this->get(self::DATA_CURVE); } } diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php index f49b7d985..77e2af503 100644 --- a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php @@ -4,19 +4,17 @@ declare(strict_types=1); namespace Cose\Key; -use function array_key_exists; use Brick\Math\BigInteger; -use FG\ASN1\Universal\BitString; -use FG\ASN1\Universal\Integer; -use FG\ASN1\Universal\NullObject; -use FG\ASN1\Universal\ObjectIdentifier; -use FG\ASN1\Universal\Sequence; use InvalidArgumentException; -use LogicException; -use function unpack; +use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PublicKeyInfo; +use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSAPrivateKey; +use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSAPublicKey; +use function array_key_exists; +use function in_array; /** * @final + * @see \Cose\Tests\Key\RsaKeyTest */ class RsaKey extends Key { @@ -49,8 +47,13 @@ class RsaKey extends Key */ public function __construct(array $data) { + foreach ([self::TYPE] as $key) { + if (is_numeric($data[$key])) { + $data[$key] = (int) $data[$key]; + } + } parent::__construct($data); - if (! isset($data[self::TYPE]) || (int) $data[self::TYPE] !== self::TYPE_RSA) { + if ($data[self::TYPE] !== self::TYPE_RSA && $data[self::TYPE] !== self::TYPE_NAME_RSA) { throw new InvalidArgumentException('Invalid RSA key. The key type does not correspond to a RSA key'); } if (! isset($data[self::DATA_N], $data[self::DATA_E])) { @@ -193,34 +196,53 @@ class RsaKey extends Key public function asPem(): string { if ($this->isPrivate()) { - throw new LogicException('Unsupported for private keys.'); + $privateKey = RSAPrivateKey::create( + $this->binaryToBigInteger($this->n()), + $this->binaryToBigInteger($this->e()), + $this->binaryToBigInteger($this->d()), + $this->binaryToBigInteger($this->p()), + $this->binaryToBigInteger($this->q()), + $this->binaryToBigInteger($this->dP()), + $this->binaryToBigInteger($this->dQ()), + $this->binaryToBigInteger($this->QInv()) + ); + + return $privateKey->toPEM() + ->string(); } - $bitSring = new Sequence( - new Integer($this->fromBase64ToInteger($this->n())), - new Integer($this->fromBase64ToInteger($this->e())) - ); - $der = new Sequence( - new Sequence(new ObjectIdentifier('1.2.840.113549.1.1.1'), new NullObject()), - new BitString(bin2hex($bitSring->getBinary())) + $publicKey = RSAPublicKey::create( + $this->binaryToBigInteger($this->n()), + $this->binaryToBigInteger($this->e()) ); + $rsaKey = PublicKeyInfo::fromPublicKey($publicKey); - return $this->pem('PUBLIC KEY', $der->getBinary()); + return $rsaKey->toPEM() + ->string(); } - private function fromBase64ToInteger(string $value): string + public function toPublic(): static { - $data = unpack('H*', $value); - $hex = current($data); + $toBeRemoved = [ + self::DATA_D, + self::DATA_P, + self::DATA_Q, + self::DATA_DP, + self::DATA_DQ, + self::DATA_QI, + self::DATA_OTHER, + self::DATA_RI, + self::DATA_DI, + self::DATA_TI, + ]; + $data = $this->getData(); + foreach ($data as $k => $v) { + if (in_array($k, $toBeRemoved, true)) { + unset($data[$k]); + } + } - return BigInteger::fromBase($hex, 16)->toBase(10); - } - - private function pem(string $type, string $der): string - { - return sprintf("-----BEGIN %s-----\n", mb_strtoupper($type)) . - chunk_split(base64_encode($der), 64, "\n") . - sprintf("-----END %s-----\n", mb_strtoupper($type)); + return new static($data); } private function checkKeyIsPrivate(): void @@ -229,4 +251,12 @@ class RsaKey extends Key throw new InvalidArgumentException('The key is not private.'); } } + + private function binaryToBigInteger(string $data): string + { + $res = unpack('H*', $data); + $res = current($res); + + return BigInteger::fromBase($res, 16)->toBase(10); + } } diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/LICENSE b/lam/lib/3rdParty/composer/web-auth/metadata-service/LICENSE deleted file mode 100644 index 8cb7b7487..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018-2022 Spomky-Labs - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/composer.json b/lam/lib/3rdParty/composer/web-auth/metadata-service/composer.json deleted file mode 100644 index 7e35f61e7..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/composer.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "web-auth/metadata-service", - "type": "library", - "license": "MIT", - "description": "Metadata Service for FIDO2/Webauthn", - "keywords": [ - "FIDO", - "FIDO2", - "webauthn" - ], - "homepage": "https://github.com/web-auth", - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-auth/metadata-service/contributors" - } - ], - "require": { - "php": ">=8.1", - "ext-json": "*", - "beberlei/assert": "^3.2", - "paragonie/constant_time_encoding": "^2.4", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/log": "^2.0|^3.0" - }, - "autoload": { - "psr-4": { - "Webauthn\\MetadataService\\": "src/" - } - }, - "suggest": { - "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for fetching Metadata Statement from distant sources", - "web-token/jwt-signature-algorithm-ecdsa": "Mandatory for fetching Metadata Statement from distant sources" - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/DistantResourceMetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/DistantResourceMetadataService.php deleted file mode 100644 index d12b5e446..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/DistantResourceMetadataService.php +++ /dev/null @@ -1,109 +0,0 @@ - $additionalHeaderParameters - */ - public function __construct( - private readonly RequestFactoryInterface $requestFactory, - private readonly ClientInterface $httpClient, - private readonly string $uri, - private readonly bool $isBase64Encoded = false, - private readonly array $additionalHeaderParameters = [], - ) { - } - - /** - * @param array $additionalHeaderParameters - */ - public static function create( - RequestFactoryInterface $requestFactory, - ClientInterface $httpClient, - string $uri, - bool $isBase64Encoded = false, - array $additionalHeaderParameters = [] - ): self { - return new self($requestFactory, $httpClient, $uri, $isBase64Encoded, $additionalHeaderParameters); - } - - public function list(): iterable - { - $this->loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - $aaguid = $this->statement->getAaguid(); - Assertion::notNull($aaguid, 'Unable to load the metadata statement'); - - yield from [$aaguid]; - } - - public function has(string $aaguid): bool - { - $this->loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - - return $aaguid === $this->statement->getAaguid(); - } - - public function get(string $aaguid): MetadataStatement - { - $this->loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - - if ($aaguid === $this->statement->getAaguid()) { - return $this->statement; - } - - throw new InvalidArgumentException(sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid)); - } - - private function loadData(): void - { - if ($this->statement !== null) { - return; - } - - $content = $this->fetch(); - if ($this->isBase64Encoded) { - $content = Base64::decode($content, true); - } - $this->statement = MetadataStatement::createFromString($content); - } - - private function fetch(): string - { - $request = $this->requestFactory->createRequest('GET', $this->uri); - foreach ($this->additionalHeaderParameters as $k => $v) { - $request = $request->withHeader($k, $v); - } - $response = $this->httpClient->sendRequest($request); - Assertion::eq( - 200, - $response->getStatusCode(), - sprintf('Unable to contact the server. Response code is %d', $response->getStatusCode()) - ); - $response->getBody() - ->rewind() - ; - $content = $response->getBody() - ->getContents() - ; - Assertion::notEmpty($content, 'Unable to contact the server. The response has no content'); - - return $content; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/FidoAllianceCompliantMetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/FidoAllianceCompliantMetadataService.php deleted file mode 100644 index be787fbed..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/FidoAllianceCompliantMetadataService.php +++ /dev/null @@ -1,181 +0,0 @@ -> - */ - private array $statusReports = []; - - /** - * @param array $additionalHeaderParameters - */ - public function __construct( - private readonly RequestFactoryInterface $requestFactory, - private readonly ClientInterface $httpClient, - private readonly string $uri, - private readonly array $additionalHeaderParameters = [], - ) { - } - - /** - * @param array $additionalHeaderParameters - */ - public static function create( - RequestFactoryInterface $requestFactory, - ClientInterface $httpClient, - string $uri, - array $additionalHeaderParameters = [] - ): self { - return new self($requestFactory, $httpClient, $uri, $additionalHeaderParameters); - } - - /** - * @return string[] - */ - public function list(): iterable - { - $this->loadData(); - - yield from array_keys($this->statements); - } - - public function has(string $aaguid): bool - { - $this->loadData(); - - return array_key_exists($aaguid, $this->statements); - } - - public function get(string $aaguid): MetadataStatement - { - $this->loadData(); - - Assertion::keyExists( - $this->statements, - $aaguid, - sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid) - ); - - return $this->statements[$aaguid]; - } - - /** - * @return StatusReport[] - */ - public function getStatusReports(string $aaguid): iterable - { - $this->loadData(); - - return $this->statusReports[$aaguid] ?? []; - } - - private function loadData(): void - { - if ($this->loaded) { - return; - } - - $content = $this->fetch(); - $rootCertificates = []; - try { - $payload = $this->getJwsPayload($content, $rootCertificates); - $data = json_decode($payload, true, 512, JSON_THROW_ON_ERROR); - - foreach ($data['entries'] as $datum) { - $entry = MetadataBLOBPayloadEntry::createFromArray($datum); - - $mds = $entry->getMetadataStatement(); - if ($mds !== null && $entry->getAaguid() !== null) { - $mds->setRootCertificates($rootCertificates); - $this->statements[$entry->getAaguid()] = $mds; - $this->statusReports[$entry->getAaguid()] = $entry->getStatusReports(); - } - } - } catch (Throwable) { - } - - $this->loaded = true; - } - - private function fetch(): string - { - $request = $this->requestFactory->createRequest('GET', $this->uri); - foreach ($this->additionalHeaderParameters as $k => $v) { - $request = $request->withHeader($k, $v); - } - $response = $this->httpClient->sendRequest($request); - Assertion::eq( - 200, - $response->getStatusCode(), - sprintf('Unable to contact the server. Response code is %d', $response->getStatusCode()) - ); - $response->getBody() - ->rewind() - ; - $content = $response->getBody() - ->getContents() - ; - Assertion::notEmpty($content, 'Unable to contact the server. The response has no content'); - - return $content; - } - - /** - * @param string[] $rootCertificates - */ - private function getJwsPayload(string $token, array &$rootCertificates): string - { - $jws = (new CompactSerializer())->unserialize($token); - Assertion::eq( - 1, - $jws->countSignatures(), - 'Invalid response from the metadata service. Only one signature shall be present.' - ); - $signature = $jws->getSignature(0); - $payload = $jws->getPayload(); - Assertion::notEmpty($payload, 'Invalid response from the metadata service. The token payload is empty.'); - $header = $signature->getProtectedHeader(); - Assertion::keyExists($header, 'alg', 'The "alg" parameter is missing.'); - //Assertion::eq($header['alg'], 'ES256', 'The expected "alg" parameter value should be "ES256".'); - Assertion::keyExists($header, 'x5c', 'The "x5c" parameter is missing.'); - Assertion::isArray($header['x5c'], 'The "x5c" parameter should be an array.'); - $key = JWKFactory::createFromX5C($header['x5c']); - $rootCertificates = $header['x5c']; - - $verifier = new JWSVerifier(new AlgorithmManager([new ES256(), new RS256()])); - $isValid = $verifier->verifyWithKey($jws, $key, 0); - Assertion::true($isValid, 'Invalid response from the metadata service. The token signature is invalid.'); - $payload = $jws->getPayload(); - Assertion::notNull($payload, 'Invalid response from the metadata service. The payload is missing.'); - - return $payload; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/InMemoryMetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/InMemoryMetadataService.php deleted file mode 100644 index 79337d33c..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/InMemoryMetadataService.php +++ /dev/null @@ -1,64 +0,0 @@ -addStatements($statement); - } - } - - public static function create(MetadataStatement ...$statements): self - { - return new self(...$statements); - } - - public function addStatements(MetadataStatement ...$statements): self - { - foreach ($statements as $statement) { - $aaguid = $statement->getAaguid(); - if ($aaguid === null) { - continue; - } - $this->statements[$aaguid] = $statement; - } - - return $this; - } - - public function list(): iterable - { - yield from array_keys($this->statements); - } - - public function has(string $aaguid): bool - { - return array_key_exists($aaguid, $this->statements); - } - - public function get(string $aaguid): MetadataStatement - { - Assertion::keyExists( - $this->statements, - $aaguid, - sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid) - ); - - return $this->statements[$aaguid]; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/LocalResourceMetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/LocalResourceMetadataService.php deleted file mode 100644 index 3fa9a6ec6..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/LocalResourceMetadataService.php +++ /dev/null @@ -1,71 +0,0 @@ -loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - $aaguid = $this->statement->getAaguid(); - Assertion::notNull($aaguid, 'Unable to load the metadata statement'); - - yield from [$aaguid]; - } - - public function has(string $aaguid): bool - { - $this->loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - - return $aaguid === $this->statement->getAaguid(); - } - - public function get(string $aaguid): MetadataStatement - { - $this->loadData(); - Assertion::notNull($this->statement, 'Unable to load the metadata statement'); - - if ($aaguid === $this->statement->getAaguid()) { - return $this->statement; - } - - throw new InvalidArgumentException(sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid)); - } - - private function loadData(): void - { - if ($this->statement !== null) { - return; - } - - $content = file_get_contents($this->filename); - if ($this->isBase64Encoded) { - $content = Base64::decode($content, true); - } - $this->statement = MetadataStatement::createFromString($content); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayload.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayload.php deleted file mode 100644 index 6171e125f..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayload.php +++ /dev/null @@ -1,119 +0,0 @@ -entries[] = $entry; - - return $this; - } - - public function getLegalHeader(): ?string - { - return $this->legalHeader; - } - - public function getNo(): int - { - return $this->no; - } - - public function getNextUpdate(): string - { - return $this->nextUpdate; - } - - /** - * @return MetadataBLOBPayloadEntry[] - */ - public function getEntries(): array - { - return $this->entries; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - foreach (['no', 'nextUpdate', 'entries'] as $key) { - Assertion::keyExists($data, $key, sprintf('Invalid data. The parameter "%s" is missing', $key)); - } - Assertion::integer($data['no'], 'Invalid data. The parameter "no" shall be an integer'); - Assertion::string($data['nextUpdate'], 'Invalid data. The parameter "nextUpdate" shall be a string'); - Assertion::isArray($data['entries'], 'Invalid data. The parameter "entries" shall be a n array of entries'); - if (array_key_exists('legalHeader', $data)) { - Assertion::string($data['legalHeader'], 'Invalid data. The parameter "legalHeader" shall be a string'); - } - $object = new self($data['no'], $data['nextUpdate'], $data['legalHeader'] ?? null); - foreach ($data['entries'] as $entry) { - $object->addEntry(MetadataBLOBPayloadEntry::createFromArray($entry)); - } - - return $object; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'legalHeader' => $this->legalHeader, - 'nextUpdate' => $this->nextUpdate, - 'no' => $this->no, - 'entries' => array_map( - static fn (MetadataBLOBPayloadEntry $object): array => $object->jsonSerialize(), - $this->entries - ), - ]; - - return Utils::filterNullValues($data); - } - - /** - * @return string[] - */ - public function getRootCertificates(): array - { - return $this->rootCertificates; - } - - /** - * @param string[] $rootCertificates - */ - public function setRootCertificates(array $rootCertificates): self - { - $this->rootCertificates = $rootCertificates; - - return $this; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayloadEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayloadEntry.php deleted file mode 100644 index f6412ee2e..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataBLOBPayloadEntry.php +++ /dev/null @@ -1,205 +0,0 @@ -attestationCertificateKeyIdentifiers = $attestationCertificateKeyIdentifiers; - } - - public function getAaid(): ?string - { - return $this->aaid; - } - - public function getAaguid(): ?string - { - return $this->aaguid; - } - - /** - * @return string[] - */ - public function getAttestationCertificateKeyIdentifiers(): array - { - return $this->attestationCertificateKeyIdentifiers; - } - - public function getMetadataStatement(): ?MetadataStatement - { - return $this->metadataStatement; - } - - public function addBiometricStatusReports(BiometricStatusReport ...$biometricStatusReports): self - { - foreach ($biometricStatusReports as $biometricStatusReport) { - $this->biometricStatusReports[] = $biometricStatusReport; - } - - return $this; - } - - /** - * @return BiometricStatusReport[] - */ - public function getBiometricStatusReports(): array - { - return $this->biometricStatusReports; - } - - public function addStatusReports(StatusReport ...$statusReports): self - { - foreach ($statusReports as $statusReport) { - $this->statusReports[] = $statusReport; - } - - return $this; - } - - /** - * @return StatusReport[] - */ - public function getStatusReports(): array - { - return $this->statusReports; - } - - public function getTimeOfLastStatusChange(): string - { - return $this->timeOfLastStatusChange; - } - - public function getRogueListURL(): string|null - { - return $this->rogueListURL; - } - - public function getRogueListHash(): string|null - { - return $this->rogueListHash; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - Assertion::keyExists( - $data, - 'timeOfLastStatusChange', - 'Invalid data. The parameter "timeOfLastStatusChange" is missing' - ); - Assertion::keyExists($data, 'statusReports', 'Invalid data. The parameter "statusReports" is missing'); - Assertion::isArray( - $data['statusReports'], - 'Invalid data. The parameter "statusReports" shall be an array of StatusReport objects' - ); - $object = new self( - $data['aaid'] ?? null, - $data['aaguid'] ?? null, - $data['attestationCertificateKeyIdentifiers'] ?? [], - isset($data['metadataStatement']) ? MetadataStatement::createFromArray($data['metadataStatement']) : null, - $data['timeOfLastStatusChange'], - $data['rogueListURL'] ?? null, - $data['rogueListHash'] ?? null - ); - foreach ($data['statusReports'] as $statusReport) { - $object->addStatusReports(StatusReport::createFromArray($statusReport)); - } - if (array_key_exists('biometricStatusReport', $data)) { - Assertion::isArray( - $data['biometricStatusReport'], - 'Invalid data. The parameter "biometricStatusReport" shall be an array of BiometricStatusReport objects' - ); - foreach ($data['biometricStatusReport'] as $biometricStatusReport) { - $object->addBiometricStatusReports(BiometricStatusReport::createFromArray($biometricStatusReport)); - } - } - - return $object; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'aaid' => $this->aaid, - 'aaguid' => $this->aaguid, - 'attestationCertificateKeyIdentifiers' => $this->attestationCertificateKeyIdentifiers, - 'statusReports' => array_map( - static fn (StatusReport $object): array => $object->jsonSerialize(), - $this->statusReports - ), - 'timeOfLastStatusChange' => $this->timeOfLastStatusChange, - 'rogueListURL' => $this->rogueListURL, - 'rogueListHash' => $this->rogueListHash, - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/StringMetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/StringMetadataService.php deleted file mode 100644 index f199e342f..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/StringMetadataService.php +++ /dev/null @@ -1,64 +0,0 @@ -addStatements(MetadataStatement::createFromString($statement)); - } - } - - public static function create(string ...$statements): self - { - return new self(...$statements); - } - - public function addStatements(MetadataStatement ...$statements): self - { - foreach ($statements as $statement) { - $aaguid = $statement->getAaguid(); - if ($aaguid === null) { - continue; - } - $this->statements[$aaguid] = $statement; - } - - return $this; - } - - public function list(): iterable - { - yield from array_keys($this->statements); - } - - public function has(string $aaguid): bool - { - return array_key_exists($aaguid, $this->statements); - } - - public function get(string $aaguid): MetadataStatement - { - Assertion::keyExists( - $this->statements, - $aaguid, - sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid) - ); - - return $this->statements[$aaguid]; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AbstractDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AbstractDescriptor.php deleted file mode 100644 index 944481669..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AbstractDescriptor.php +++ /dev/null @@ -1,42 +0,0 @@ -maxRetries = $maxRetries; - $this->blockSlowdown = $blockSlowdown; - } - - public function getMaxRetries(): ?int - { - return $this->maxRetries; - } - - public function getBlockSlowdown(): ?int - { - return $this->blockSlowdown; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AlternativeDescriptions.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AlternativeDescriptions.php deleted file mode 100644 index 9ddce560b..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AlternativeDescriptions.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ - private array $descriptions = []; - - /** - * @param array $descriptions - */ - public static function create(array $descriptions = []): self - { - $object = new self(); - foreach ($descriptions as $k => $v) { - $object->add($k, $v); - } - - return $object; - } - - /** - * @return array - */ - public function all(): array - { - return $this->descriptions; - } - - public function add(string $locale, string $description): self - { - $this->descriptions[$locale] = $description; - - return $this; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return $this->descriptions; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorGetInfo.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorGetInfo.php deleted file mode 100644 index 9553366ef..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorGetInfo.php +++ /dev/null @@ -1,46 +0,0 @@ - $data - */ - public static function create(array $data = []): self - { - $object = new self(); - foreach ($data as $k => $v) { - if (is_string($k)) { - $object->add($k, $v); - } - } - - return $object; - } - - public function add(string $key, mixed $value): self - { - $this->info[$key] = $value; - - return $this; - } - - /** - * @return string[] - */ - public function jsonSerialize(): array - { - return $this->info; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorStatus.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorStatus.php deleted file mode 100644 index 66b87190e..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/AuthenticatorStatus.php +++ /dev/null @@ -1,68 +0,0 @@ -selfAttestedFRR; - } - - public function getSelfAttestedFAR(): ?float - { - return $this->selfAttestedFAR; - } - - public function getMaxTemplates(): ?float - { - return $this->maxTemplates; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - return new self( - $data['selfAttestedFRR'] ?? null, - $data['selfAttestedFAR'] ?? null, - $data['maxTemplates'] ?? null, - $data['maxRetries'] ?? null, - $data['blockSlowdown'] ?? null - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'selfAttestedFRR' => $this->selfAttestedFRR, - 'selfAttestedFAR' => $this->selfAttestedFAR, - 'maxTemplates' => $this->maxTemplates, - 'maxRetries' => $this->getMaxRetries(), - 'blockSlowdown' => $this->getBlockSlowdown(), - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/BiometricStatusReport.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/BiometricStatusReport.php deleted file mode 100644 index 0be44555d..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/BiometricStatusReport.php +++ /dev/null @@ -1,94 +0,0 @@ -certLevel; - } - - public function getModality(): int|null - { - return $this->modality; - } - - public function getEffectiveDate(): ?string - { - return $this->effectiveDate; - } - - public function getCertificationDescriptor(): ?string - { - return $this->certificationDescriptor; - } - - public function getCertificateNumber(): ?string - { - return $this->certificateNumber; - } - - public function getCertificationPolicyVersion(): ?string - { - return $this->certificationPolicyVersion; - } - - public function getCertificationRequirementsVersion(): ?string - { - return $this->certificationRequirementsVersion; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $object = new self(); - $object->certLevel = $data['certLevel'] ?? null; - $object->modality = $data['modality'] ?? null; - $object->effectiveDate = $data['effectiveDate'] ?? null; - $object->certificationDescriptor = $data['certificationDescriptor'] ?? null; - $object->certificateNumber = $data['certificateNumber'] ?? null; - $object->certificationPolicyVersion = $data['certificationPolicyVersion'] ?? null; - $object->certificationRequirementsVersion = $data['certificationRequirementsVersion'] ?? null; - - return $object; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'certLevel' => $this->certLevel, - 'modality' => $this->modality, - 'effectiveDate' => $this->effectiveDate, - 'certificationDescriptor' => $this->certificationDescriptor, - 'certificateNumber' => $this->certificateNumber, - 'certificationPolicyVersion' => $this->certificationPolicyVersion, - 'certificationRequirementsVersion' => $this->certificationRequirementsVersion, - ]; - - return array_filter($data, static fn ($var): bool => $var !== null); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/CodeAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/CodeAccuracyDescriptor.php deleted file mode 100644 index aa266de73..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/CodeAccuracyDescriptor.php +++ /dev/null @@ -1,69 +0,0 @@ -base = $base; - $this->minLength = $minLength; - parent::__construct($maxRetries, $blockSlowdown); - } - - public function getBase(): int - { - return $this->base; - } - - public function getMinLength(): int - { - return $this->minLength; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - Assertion::keyExists($data, 'base', 'The parameter "base" is missing'); - Assertion::keyExists($data, 'minLength', 'The parameter "minLength" is missing'); - - return new self( - $data['base'], - $data['minLength'], - $data['maxRetries'] ?? null, - $data['blockSlowdown'] ?? null - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'base' => $this->base, - 'minLength' => $this->minLength, - 'maxRetries' => $this->getMaxRetries(), - 'blockSlowdown' => $this->getBlockSlowdown(), - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/DisplayPNGCharacteristicsDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/DisplayPNGCharacteristicsDescriptor.php deleted file mode 100644 index 5a7721ff2..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/DisplayPNGCharacteristicsDescriptor.php +++ /dev/null @@ -1,166 +0,0 @@ -width = $width; - $this->height = $height; - $this->bitDepth = $bitDepth; - $this->colorType = $colorType; - $this->compression = $compression; - $this->filter = $filter; - $this->interlace = $interlace; - } - - public function addPalettes(RgbPaletteEntry ...$rgbPaletteEntries): self - { - foreach ($rgbPaletteEntries as $rgbPaletteEntry) { - $this->plte[] = $rgbPaletteEntry; - } - - return $this; - } - - public function getWidth(): int - { - return $this->width; - } - - public function getHeight(): int - { - return $this->height; - } - - public function getBitDepth(): int - { - return $this->bitDepth; - } - - public function getColorType(): int - { - return $this->colorType; - } - - public function getCompression(): int - { - return $this->compression; - } - - public function getFilter(): int - { - return $this->filter; - } - - public function getInterlace(): int - { - return $this->interlace; - } - - /** - * @return RgbPaletteEntry[] - */ - public function getPaletteEntries(): array - { - return $this->plte; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - foreach ([ - 'width', - 'compression', - 'height', - 'bitDepth', - 'colorType', - 'compression', - 'filter', - 'interlace', - ] as $key) { - Assertion::keyExists($data, $key, sprintf('Invalid data. The key "%s" is missing', $key)); - } - $object = new self( - $data['width'], - $data['height'], - $data['bitDepth'], - $data['colorType'], - $data['compression'], - $data['filter'], - $data['interlace'] - ); - if (isset($data['plte'])) { - $plte = $data['plte']; - Assertion::isArray($plte, 'Invalid "plte" parameter'); - foreach ($plte as $item) { - $object->addPalettes(RgbPaletteEntry::createFromArray($item)); - } - } - - return $object; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'width' => $this->width, - 'height' => $this->height, - 'bitDepth' => $this->bitDepth, - 'colorType' => $this->colorType, - 'compression' => $this->compression, - 'filter' => $this->filter, - 'interlace' => $this->interlace, - 'plte' => $this->plte, - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/EcdaaTrustAnchor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/EcdaaTrustAnchor.php deleted file mode 100644 index 6e4e4e9a6..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/EcdaaTrustAnchor.php +++ /dev/null @@ -1,90 +0,0 @@ -X; - } - - public function getY(): string - { - return $this->Y; - } - - public function getC(): string - { - return $this->c; - } - - public function getSx(): string - { - return $this->sx; - } - - public function getSy(): string - { - return $this->sy; - } - - public function getG1Curve(): string - { - return $this->G1Curve; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - foreach (['X', 'Y', 'c', 'sx', 'sy', 'G1Curve'] as $key) { - Assertion::keyExists($data, $key, sprintf('Invalid data. The key "%s" is missing', $key)); - } - - return new self( - Base64UrlSafe::decode($data['X']), - Base64UrlSafe::decode($data['Y']), - Base64UrlSafe::decode($data['c']), - Base64UrlSafe::decode($data['sx']), - Base64UrlSafe::decode($data['sy']), - $data['G1Curve'] - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'X' => Base64UrlSafe::encodeUnpadded($this->X), - 'Y' => Base64UrlSafe::encodeUnpadded($this->Y), - 'c' => Base64UrlSafe::encodeUnpadded($this->c), - 'sx' => Base64UrlSafe::encodeUnpadded($this->sx), - 'sy' => Base64UrlSafe::encodeUnpadded($this->sy), - 'G1Curve' => $this->G1Curve, - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/ExtensionDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/ExtensionDescriptor.php deleted file mode 100644 index dd8a30d1a..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/ExtensionDescriptor.php +++ /dev/null @@ -1,85 +0,0 @@ -tag = $tag; - } - - public function getId(): string - { - return $this->id; - } - - public function getTag(): ?int - { - return $this->tag; - } - - public function getData(): ?string - { - return $this->data; - } - - public function isFailIfUnknown(): bool - { - return $this->failIfUnknown; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - Assertion::keyExists($data, 'id', 'Invalid data. The parameter "id" is missing'); - Assertion::string($data['id'], 'Invalid data. The parameter "id" shall be a string'); - Assertion::keyExists($data, 'fail_if_unknown', 'Invalid data. The parameter "fail_if_unknown" is missing'); - Assertion::boolean( - $data['fail_if_unknown'], - 'Invalid data. The parameter "fail_if_unknown" shall be a boolean' - ); - if (array_key_exists('tag', $data)) { - Assertion::integer($data['tag'], 'Invalid data. The parameter "tag" shall be a positive integer'); - } - if (array_key_exists('data', $data)) { - Assertion::string($data['data'], 'Invalid data. The parameter "data" shall be a string'); - } - - return new self($data['id'], $data['tag'] ?? null, $data['data'] ?? null, $data['fail_if_unknown']); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $result = [ - 'id' => $this->id, - 'tag' => $this->tag, - 'data' => $this->data, - 'fail_if_unknown' => $this->failIfUnknown, - ]; - - return Utils::filterNullValues($result); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/MetadataStatement.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/MetadataStatement.php deleted file mode 100644 index 41e28a673..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/MetadataStatement.php +++ /dev/null @@ -1,549 +0,0 @@ -alternativeDescriptions = new AlternativeDescriptions(); - $this->authenticatorGetInfo = new AuthenticatorGetInfo(); - } - - public static function createFromString(string $statement): self - { - $data = json_decode($statement, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid Metadata Statement'); - - return self::createFromArray($data); - } - - public function getLegalHeader(): ?string - { - return $this->legalHeader; - } - - public function getAaid(): ?string - { - return $this->aaid; - } - - public function getAaguid(): ?string - { - return $this->aaguid; - } - - public function isKeyRestricted(): ?bool - { - return $this->isKeyRestricted; - } - - public function isFreshUserVerificationRequired(): ?bool - { - return $this->isFreshUserVerificationRequired; - } - - public function getAuthenticatorGetInfo(): AuthenticatorGetInfo|null - { - return $this->authenticatorGetInfo; - } - - /** - * @return string[] - */ - public function getAttestationCertificateKeyIdentifiers(): array - { - return $this->attestationCertificateKeyIdentifiers; - } - - public function getDescription(): string - { - return $this->description; - } - - public function getAlternativeDescriptions(): AlternativeDescriptions - { - return $this->alternativeDescriptions; - } - - public function getAuthenticatorVersion(): int - { - return $this->authenticatorVersion; - } - - public function getProtocolFamily(): string - { - return $this->protocolFamily; - } - - /** - * @return Version[] - */ - public function getUpv(): array - { - return $this->upv; - } - - public function getSchema(): ?int - { - return $this->schema; - } - - /** - * @return string[] - */ - public function getAuthenticationAlgorithms(): array - { - return $this->authenticationAlgorithms; - } - - /** - * @return string[] - */ - public function getPublicKeyAlgAndEncodings(): array - { - return $this->publicKeyAlgAndEncodings; - } - - /** - * @return string[] - */ - public function getAttestationTypes(): array - { - return $this->attestationTypes; - } - - /** - * @return VerificationMethodANDCombinations[] - */ - public function getUserVerificationDetails(): array - { - return $this->userVerificationDetails; - } - - /** - * @return string[] - */ - public function getKeyProtection(): array - { - return $this->keyProtection; - } - - /** - * @return string[] - */ - public function getMatcherProtection(): array - { - return $this->matcherProtection; - } - - public function getCryptoStrength(): ?int - { - return $this->cryptoStrength; - } - - /** - * @return string[] - */ - public function getAttachmentHint(): array - { - return $this->attachmentHint; - } - - /** - * @return string[] - */ - public function getTcDisplay(): array - { - return $this->tcDisplay; - } - - public function getTcDisplayContentType(): ?string - { - return $this->tcDisplayContentType; - } - - /** - * @return DisplayPNGCharacteristicsDescriptor[] - */ - public function getTcDisplayPNGCharacteristics(): array - { - return $this->tcDisplayPNGCharacteristics; - } - - /** - * @return string[] - */ - public function getAttestationRootCertificates(): array - { - return $this->attestationRootCertificates; - } - - /** - * @return EcdaaTrustAnchor[] - */ - public function getEcdaaTrustAnchors(): array - { - return $this->ecdaaTrustAnchors; - } - - public function getIcon(): ?string - { - return $this->icon; - } - - /** - * @return ExtensionDescriptor[] - */ - public function getSupportedExtensions(): array - { - return $this->supportedExtensions; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $requiredKeys = [ - 'description', - 'authenticatorVersion', - 'protocolFamily', - 'schema', - 'upv', - 'authenticationAlgorithms', - 'publicKeyAlgAndEncodings', - 'attestationTypes', - 'userVerificationDetails', - 'matcherProtection', - 'tcDisplay', - 'attestationRootCertificates', - ]; - foreach ($requiredKeys as $key) { - Assertion::keyExists($data, $key, sprintf('The parameter "%s" is missing', $key)); - } - $subObjects = [ - 'authenticationAlgorithms', - 'publicKeyAlgAndEncodings', - 'attestationTypes', - 'matcherProtection', - 'tcDisplay', - 'attestationRootCertificates', - ]; - foreach ($subObjects as $subObject) { - Assertion::isArray( - $data[$subObject], - sprintf('Invalid Metadata Statement. The parameter "%s" shall be a list of strings.', $subObject) - ); - Assertion::allString( - $data[$subObject], - sprintf('Invalid Metadata Statement. The parameter "%s" shall be a list of strings.', $subObject) - ); - } - - $object = new self( - $data['description'], - $data['authenticatorVersion'], - $data['protocolFamily'], - $data['schema'], - array_map(static function ($upv): Version { - Assertion::isArray($upv, 'Invalid Metadata Statement'); - - return Version::createFromArray($upv); - }, $data['upv']), - $data['authenticationAlgorithms'], - $data['publicKeyAlgAndEncodings'], - $data['attestationTypes'], - array_map(static function ($userVerificationDetails): VerificationMethodANDCombinations { - Assertion::isArray($userVerificationDetails, 'Invalid Metadata Statement'); - - return VerificationMethodANDCombinations::createFromArray($userVerificationDetails); - }, $data['userVerificationDetails']), - $data['matcherProtection'], - $data['tcDisplay'], - $data['attestationRootCertificates'] - ); - - $object->legalHeader = $data['legalHeader'] ?? null; - $object->aaid = $data['aaid'] ?? null; - $object->aaguid = $data['aaguid'] ?? null; - $object->attestationCertificateKeyIdentifiers = $data['attestationCertificateKeyIdentifiers'] ?? []; - $object->alternativeDescriptions = AlternativeDescriptions::create($data['alternativeDescriptions'] ?? []); - $object->authenticatorGetInfo = isset($data['attestationTypes']) ? AuthenticatorGetInfo::create( - $data['attestationTypes'] - ) : null; - $object->keyProtection = $data['keyProtection'] ?? []; - $object->isKeyRestricted = $data['isKeyRestricted'] ?? null; - $object->isFreshUserVerificationRequired = $data['isFreshUserVerificationRequired'] ?? null; - $object->cryptoStrength = $data['cryptoStrength'] ?? null; - $object->attachmentHint = $data['attachmentHint'] ?? []; - $object->tcDisplayContentType = $data['tcDisplayContentType'] ?? null; - if (isset($data['tcDisplayPNGCharacteristics'])) { - $tcDisplayPNGCharacteristics = $data['tcDisplayPNGCharacteristics']; - Assertion::isArray($tcDisplayPNGCharacteristics, 'Invalid Metadata Statement'); - foreach ($tcDisplayPNGCharacteristics as $tcDisplayPNGCharacteristic) { - Assertion::isArray($tcDisplayPNGCharacteristic, 'Invalid Metadata Statement'); - $object->tcDisplayPNGCharacteristics[] = DisplayPNGCharacteristicsDescriptor::createFromArray( - $tcDisplayPNGCharacteristic - ); - } - } - $object->ecdaaTrustAnchors = $data['ecdaaTrustAnchors'] ?? []; - $object->icon = $data['icon'] ?? null; - if (isset($data['supportedExtensions'])) { - $supportedExtensions = $data['supportedExtensions']; - Assertion::isArray($supportedExtensions, 'Invalid Metadata Statement'); - foreach ($supportedExtensions as $supportedExtension) { - Assertion::isArray($supportedExtension, 'Invalid Metadata Statement'); - $object->supportedExtensions[] = ExtensionDescriptor::createFromArray($supportedExtension); - } - } - - return $object; - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'legalHeader' => $this->legalHeader, - 'aaid' => $this->aaid, - 'aaguid' => $this->aaguid, - 'attestationCertificateKeyIdentifiers' => $this->attestationCertificateKeyIdentifiers, - 'description' => $this->description, - 'alternativeDescriptions' => $this->alternativeDescriptions, - 'authenticatorVersion' => $this->authenticatorVersion, - 'protocolFamily' => $this->protocolFamily, - 'upv' => $this->upv, - 'authenticationAlgorithms' => $this->authenticationAlgorithms, - 'publicKeyAlgAndEncodings' => $this->publicKeyAlgAndEncodings, - 'attestationTypes' => $this->attestationTypes, - 'userVerificationDetails' => $this->userVerificationDetails, - 'keyProtection' => $this->keyProtection, - 'isKeyRestricted' => $this->isKeyRestricted, - 'isFreshUserVerificationRequired' => $this->isFreshUserVerificationRequired, - 'matcherProtection' => $this->matcherProtection, - 'cryptoStrength' => $this->cryptoStrength, - 'attachmentHint' => $this->attachmentHint, - 'tcDisplay' => $this->tcDisplay, - 'tcDisplayContentType' => $this->tcDisplayContentType, - 'tcDisplayPNGCharacteristics' => array_map( - static fn (DisplayPNGCharacteristicsDescriptor $object): array => $object->jsonSerialize(), - $this->tcDisplayPNGCharacteristics - ), - 'attestationRootCertificates' => $this->attestationRootCertificates, - 'ecdaaTrustAnchors' => array_map( - static fn (EcdaaTrustAnchor $object): array => $object->jsonSerialize(), - $this->ecdaaTrustAnchors - ), - 'icon' => $this->icon, - 'authenticatorGetInfo' => $this->authenticatorGetInfo, - 'supportedExtensions' => array_map( - static fn (ExtensionDescriptor $object): array => $object->jsonSerialize(), - $this->supportedExtensions - ), - ]; - - return Utils::filterNullValues($data); - } - - /** - * @param string[] $rootCertificates - */ - public function setRootCertificates(array $rootCertificates): void - { - $this->rootCertificates = $rootCertificates; - } - - /** - * @return string[] - */ - public function getRootCertificates(): array - { - return $this->rootCertificates; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/PatternAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/PatternAccuracyDescriptor.php deleted file mode 100644 index 4699904a9..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/PatternAccuracyDescriptor.php +++ /dev/null @@ -1,63 +0,0 @@ -minComplexity = $minComplexity; - parent::__construct($maxRetries, $blockSlowdown); - } - - public function getMinComplexity(): int - { - return $this->minComplexity; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - Assertion::keyExists($data, 'minComplexity', 'The key "minComplexity" is missing'); - foreach (['minComplexity', 'maxRetries', 'blockSlowdown'] as $key) { - if (array_key_exists($key, $data)) { - Assertion::integer( - $data[$key], - sprintf('Invalid data. The value of "%s" must be a positive integer', $key) - ); - } - } - - return new self($data['minComplexity'], $data['maxRetries'] ?? null, $data['blockSlowdown'] ?? null); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'minComplexity' => $this->minComplexity, - 'maxRetries' => $this->getMaxRetries(), - 'blockSlowdown' => $this->getBlockSlowdown(), - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RgbPaletteEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RgbPaletteEntry.php deleted file mode 100644 index fc3be78aa..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RgbPaletteEntry.php +++ /dev/null @@ -1,67 +0,0 @@ -r = $r; - $this->g = $g; - $this->b = $b; - } - - public function getR(): int - { - return $this->r; - } - - public function getG(): int - { - return $this->g; - } - - public function getB(): int - { - return $this->b; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - foreach (['r', 'g', 'b'] as $key) { - Assertion::keyExists($data, $key, sprintf('The key "%s" is missing', $key)); - Assertion::integer($data[$key], sprintf('The key "%s" is invalid', $key)); - } - - return new self($data['r'], $data['g'], $data['b']); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'r' => $this->r, - 'g' => $this->g, - 'b' => $this->b, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RogueListEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RogueListEntry.php deleted file mode 100644 index 7f35824df..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/RogueListEntry.php +++ /dev/null @@ -1,51 +0,0 @@ -sk; - } - - public function getDate(): ?string - { - return $this->date; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - Assertion::keyExists($data, 'sk', 'The key "sk" is missing'); - Assertion::string($data['sk'], 'The key "sk" is invalid'); - Assertion::keyExists($data, 'date', 'The key "date" is missing'); - Assertion::string($data['date'], 'The key "date" is invalid'); - - return new self($data['sk'], $data['date']); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'sk' => $this->sk, - 'date' => $this->date, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/StatusReport.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/StatusReport.php deleted file mode 100644 index 22706bcce..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/StatusReport.php +++ /dev/null @@ -1,135 +0,0 @@ -status = $status; - } - - public function isCompromised(): bool - { - return in_array($this->status, [ - AuthenticatorStatus::ATTESTATION_KEY_COMPROMISE, - AuthenticatorStatus::USER_KEY_PHYSICAL_COMPROMISE, - AuthenticatorStatus::USER_KEY_REMOTE_COMPROMISE, - AuthenticatorStatus::USER_VERIFICATION_BYPASS, - ], true); - } - - public function getStatus(): string - { - return $this->status; - } - - public function getEffectiveDate(): ?string - { - return $this->effectiveDate; - } - - public function getCertificate(): ?string - { - return $this->certificate; - } - - public function getUrl(): ?string - { - return $this->url; - } - - public function getCertificationDescriptor(): ?string - { - return $this->certificationDescriptor; - } - - public function getCertificateNumber(): ?string - { - return $this->certificateNumber; - } - - public function getCertificationPolicyVersion(): ?string - { - return $this->certificationPolicyVersion; - } - - public function getCertificationRequirementsVersion(): ?string - { - return $this->certificationRequirementsVersion; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - Assertion::keyExists($data, 'status', 'The key "status" is missing'); - foreach ([ - 'effectiveDate', - 'certificate', - 'url', - 'certificationDescriptor', - 'certificateNumber', - 'certificationPolicyVersion', - 'certificationRequirementsVersion', - ] as $key) { - if (isset($data[$key])) { - Assertion::nullOrString($data[$key], sprintf('The value of the key "%s" is invalid', $key)); - } - } - - return new self( - $data['status'], - $data['effectiveDate'] ?? null, - $data['certificate'] ?? null, - $data['url'] ?? null, - $data['certificationDescriptor'] ?? null, - $data['certificateNumber'] ?? null, - $data['certificationPolicyVersion'] ?? null, - $data['certificationRequirementsVersion'] ?? null - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'status' => $this->status, - 'effectiveDate' => $this->effectiveDate, - 'certificate' => $this->certificate, - 'url' => $this->url, - 'certificationDescriptor' => $this->certificationDescriptor, - 'certificateNumber' => $this->certificateNumber, - 'certificationPolicyVersion' => $this->certificationPolicyVersion, - 'certificationRequirementsVersion' => $this->certificationRequirementsVersion, - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodANDCombinations.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodANDCombinations.php deleted file mode 100644 index e44ca248c..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodANDCombinations.php +++ /dev/null @@ -1,57 +0,0 @@ -verificationMethods[] = $verificationMethodDescriptor; - - return $this; - } - - /** - * @return VerificationMethodDescriptor[] - */ - public function getVerificationMethods(): array - { - return $this->verificationMethods; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $object = new self(); - - foreach ($data as $datum) { - Assertion::isArray($datum, 'Invalid data'); - $object->addVerificationMethodDescriptor(VerificationMethodDescriptor::createFromArray($datum)); - } - - return $object; - } - - /** - * @return array> - */ - public function jsonSerialize(): array - { - return array_map( - static fn (VerificationMethodDescriptor $object): array => $object->jsonSerialize(), - $this->verificationMethods - ); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodDescriptor.php deleted file mode 100644 index 136e43482..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/VerificationMethodDescriptor.php +++ /dev/null @@ -1,179 +0,0 @@ -userVerificationMethod = $userVerificationMethod; - } - - public function getUserVerificationMethod(): string - { - return $this->userVerificationMethod; - } - - public function userPresence(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_PRESENCE_INTERNAL; - } - - public function fingerprint(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_FINGERPRINT_INTERNAL; - } - - public function passcodeInternal(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_PASSCODE_INTERNAL; - } - - public function voicePrint(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_VOICEPRINT_INTERNAL; - } - - public function facePrint(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_FACEPRINT_INTERNAL; - } - - public function location(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_LOCATION_INTERNAL; - } - - public function eyePrint(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_EYEPRINT_INTERNAL; - } - - public function patternInternal(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_PATTERN_INTERNAL; - } - - public function handprint(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_HANDPRINT_INTERNAL; - } - - public function passcodeExternal(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_PASSCODE_EXTERNAL; - } - - public function patternExternal(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_PATTERN_EXTERNAL; - } - - public function none(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_NONE; - } - - public function all(): bool - { - return $this->userVerificationMethod === self::USER_VERIFY_ALL; - } - - public function getCaDesc(): ?CodeAccuracyDescriptor - { - return $this->caDesc; - } - - public function getBaDesc(): ?BiometricAccuracyDescriptor - { - return $this->baDesc; - } - - public function getPaDesc(): ?PatternAccuracyDescriptor - { - return $this->paDesc; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - if (isset($data['userVerification']) && ! isset($data['userVerificationMethod'])) { - $data['userVerificationMethod'] = $data['userVerification']; - unset($data['userVerification']); - } - Assertion::keyExists($data, 'userVerificationMethod', 'The parameters "userVerificationMethod" is missing'); - - foreach (['caDesc', 'baDesc', 'paDesc'] as $key) { - if (isset($data[$key])) { - Assertion::isArray($data[$key], sprintf('Invalid parameter "%s"', $key)); - } - } - - $caDesc = isset($data['caDesc']) ? CodeAccuracyDescriptor::createFromArray($data['caDesc']) : null; - $baDesc = isset($data['baDesc']) ? BiometricAccuracyDescriptor::createFromArray($data['baDesc']) : null; - $paDesc = isset($data['paDesc']) ? PatternAccuracyDescriptor::createFromArray($data['paDesc']) : null; - - return new self($data['userVerificationMethod'], $caDesc, $baDesc, $paDesc); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'userVerificationMethod' => $this->userVerificationMethod, - 'caDesc' => $this->caDesc?->jsonSerialize(), - 'baDesc' => $this->baDesc?->jsonSerialize(), - 'paDesc' => $this->paDesc?->jsonSerialize(), - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/Version.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/Version.php deleted file mode 100644 index 4a6b3d170..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Statement/Version.php +++ /dev/null @@ -1,68 +0,0 @@ -major = $major; - $this->minor = $minor; - } - - public function getMajor(): ?int - { - return $this->major; - } - - public function getMinor(): ?int - { - return $this->minor; - } - - /** - * @param array $data - */ - public static function createFromArray(array $data): self - { - $data = Utils::filterNullValues($data); - foreach (['major', 'minor'] as $key) { - if (array_key_exists($key, $data)) { - Assertion::integer($data[$key], sprintf('Invalid value for key "%s"', $key)); - } - } - - return new self($data['major'] ?? null, $data['minor'] ?? null); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - $data = [ - 'major' => $this->major, - 'minor' => $this->minor, - ]; - - return Utils::filterNullValues($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Utils.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Utils.php deleted file mode 100644 index abc332bfb..000000000 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Utils.php +++ /dev/null @@ -1,21 +0,0 @@ - $data - * - * @return array - */ - public static function filterNullValues(array $data): array - { - return array_filter($data, static fn ($var): bool => $var !== null); - } -} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json index 3ed91f8d4..3e2bf7bea 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json @@ -24,29 +24,38 @@ "ext-json": "*", "ext-openssl": "*", "ext-mbstring": "*", - "beberlei/assert": "^3.2", - "fgrosse/phpasn1": "^2.1", - "paragonie/constant_time_encoding": "^2.4", + "lcobucci/clock": "^2.2|^3.0", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "psr/clock": "^1.0", + "psr/event-dispatcher": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", - "psr/log": "^2.0|^3.0", + "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", - "symfony/uid": "^6.0", - "thecodingmachine/safe": "^2.0", - "web-auth/cose-lib": "^4.0", - "web-auth/metadata-service": "self.version" + "spomky-labs/pki-framework": "^1.0", + "symfony/uid": "^6.1|^7.0", + "symfony/deprecation-contracts": "^3.2", + "web-auth/cose-lib": "^4.2.3" }, "autoload": { "psr-4": { "Webauthn\\": "src/" } }, + "extra": { + "thanks": { + "name": "web-auth/webauthn-framework", + "url": "https://github.com/web-auth/webauthn-framework" + } + }, "suggest": { + "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-rsa": "Mandatory for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-ecdsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-eddsa": "Recommended for the AndroidSafetyNet Attestation Statement support" + "symfony/event-dispatcher": "Recommended to use dispatched events", + "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", + "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php index 49faa3484..002423545 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php @@ -4,33 +4,48 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; use CBOR\Decoder; use CBOR\Normalizable; use Cose\Algorithms; use Cose\Key\Ec2Key; use Cose\Key\Key; use Cose\Key\RsaKey; -use function count; -use FG\ASN1\ASNObject; -use FG\ASN1\ExplicitlyTaggedObject; -use FG\ASN1\Universal\OctetString; -use FG\ASN1\Universal\Sequence; -use function Safe\hex2bin; -use function Safe\openssl_pkey_get_public; -use function Safe\openssl_verify; +use Psr\EventDispatcher\EventDispatcherInterface; +use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence; +use SpomkyLabs\Pki\ASN1\Type\Primitive\OctetString; +use SpomkyLabs\Pki\ASN1\Type\Tagged\ExplicitTagging; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\StringStream; use Webauthn\TrustPath\CertificateTrustPath; +use function array_key_exists; +use function count; +use function is_array; +use function openssl_pkey_get_public; +use function openssl_verify; +use function sprintf; -final class AndroidKeyAttestationStatementSupport implements AttestationStatementSupport +final class AndroidKeyAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { private readonly Decoder $decoder; + private EventDispatcherInterface $dispatcher; + public function __construct() { $this->decoder = Decoder::create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; } public static function create(): self @@ -48,31 +63,30 @@ final class AndroidKeyAttestationStatementSupport implements AttestationStatemen */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + array_key_exists('attStmt', $attestation) || throw AttestationStatementLoadingException::create($attestation); foreach (['sig', 'x5c', 'alg'] as $key) { - Assertion::keyExists( - $attestation['attStmt'], - $key, + array_key_exists($key, $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, sprintf('The attestation statement value "%s" is missing.', $key) ); } $certificates = $attestation['attStmt']['x5c']; - Assertion::greaterThan( - is_countable($certificates) ? count($certificates) : 0, - 0, - 'The attestation statement value "x5c" must be a list with at least one certificate.' - ); - Assertion::allString( - $certificates, + (is_countable($certificates) ? count( + $certificates + ) : 0) > 0 || throw AttestationStatementLoadingException::create( + $attestation, 'The attestation statement value "x5c" must be a list with at least one certificate.' ); $certificates = CertificateToolbox::convertAllDERToPEM($certificates); - return AttestationStatement::createBasic( + $attestationStatement = AttestationStatement::createBasic( $attestation['fmt'], $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -80,16 +94,19 @@ final class AndroidKeyAttestationStatementSupport implements AttestationStatemen AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $trustPath = $attestationStatement->getTrustPath(); - Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + $trustPath = $attestationStatement->trustPath; + $trustPath instanceof CertificateTrustPath || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid trust path. Shall contain certificates.' + ); - $certificates = $trustPath->getCertificates(); + $certificates = $trustPath->certificates; //Decode leaf attestation certificate $leaf = $certificates[0]; - $this->checkCertificateAndGetPublicKey($leaf, $clientDataJSONHash, $authenticatorData); + $this->checkCertificate($leaf, $clientDataJSONHash, $authenticatorData); - $signedData = $authenticatorData->getAuthData() . $clientDataJSONHash; + $signedData = $authenticatorData->authData . $clientDataJSONHash; $alg = $attestationStatement->get('alg'); return openssl_verify( @@ -100,76 +117,99 @@ final class AndroidKeyAttestationStatementSupport implements AttestationStatemen ) === 1; } - private function checkCertificateAndGetPublicKey( + private function checkCertificate( string $certificate, string $clientDataHash, AuthenticatorData $authenticatorData ): void { $resource = openssl_pkey_get_public($certificate); $details = openssl_pkey_get_details($resource); - Assertion::isArray($details, 'Unable to read the certificate'); + is_array($details) || throw AttestationStatementVerificationException::create( + 'Unable to read the certificate' + ); //Check that authData publicKey matches the public key in the attestation certificate - $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); - Assertion::notNull($attestedCredentialData, 'No attested credential data found'); - $publicKeyData = $attestedCredentialData->getCredentialPublicKey(); - Assertion::notNull($publicKeyData, 'No attested public key found'); + $attestedCredentialData = $authenticatorData->attestedCredentialData; + $attestedCredentialData !== null || throw AttestationStatementVerificationException::create( + 'No attested credential data found' + ); + $publicKeyData = $attestedCredentialData->credentialPublicKey; + $publicKeyData !== null || throw AttestationStatementVerificationException::create( + 'No attested public key found' + ); $publicDataStream = new StringStream($publicKeyData); $coseKey = $this->decoder->decode($publicDataStream); - Assertion::isInstanceOf($coseKey, Normalizable::class, 'Invalid attested public key found'); + $coseKey instanceof Normalizable || throw AttestationStatementVerificationException::create( + 'Invalid attested public key found' + ); - Assertion::true($publicDataStream->isEOF(), 'Invalid public key data. Presence of extra bytes.'); + $publicDataStream->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid public key data. Presence of extra bytes.' + ); $publicDataStream->close(); $publicKey = Key::createFromData($coseKey->normalize()); - Assertion::true(($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey), 'Unsupported key type'); - Assertion::eq($publicKey->asPEM(), $details['key'], 'Invalid key'); + ($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey) || throw AttestationStatementVerificationException::create( + 'Unsupported key type' + ); + $publicKey->asPEM() === $details['key'] || throw AttestationStatementVerificationException::create( + 'Invalid key' + ); /*---------------------------*/ $certDetails = openssl_x509_parse($certificate); - //Find Android KeyStore Extension with OID “1.3.6.1.4.1.11129.2.1.17” in certificate extensions - Assertion::isArray($certDetails, 'The certificate is not valid'); - Assertion::keyExists($certDetails, 'extensions', 'The certificate has no extension'); - Assertion::isArray($certDetails['extensions'], 'The certificate has no extension'); - Assertion::keyExists( - $certDetails['extensions'], + //Find Android KeyStore Extension with OID "1.3.6.1.4.1.11129.2.1.17" in certificate extensions + is_array( + $certDetails + ) || throw AttestationStatementVerificationException::create('The certificate is not valid'); + array_key_exists('extensions', $certDetails) || throw AttestationStatementVerificationException::create( + 'The certificate has no extension' + ); + is_array($certDetails['extensions']) || throw AttestationStatementVerificationException::create( + 'The certificate has no extension' + ); + array_key_exists( '1.3.6.1.4.1.11129.2.1.17', + $certDetails['extensions'] + ) || throw AttestationStatementVerificationException::create( 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is missing' ); $extension = $certDetails['extensions']['1.3.6.1.4.1.11129.2.1.17']; - $extensionAsAsn1 = ASNObject::fromBinary($extension); - Assertion::isInstanceOf( - $extensionAsAsn1, - Sequence::class, - 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' - ); - $objects = $extensionAsAsn1->getChildren(); + $extensionAsAsn1 = Sequence::fromDER($extension); + $extensionAsAsn1->has(4); //Check that attestationChallenge is set to the clientDataHash. - Assertion::keyExists($objects, 4, 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid'); - Assertion::isInstanceOf( - $objects[4], - OctetString::class, + $extensionAsAsn1->has(4) || throw AttestationStatementVerificationException::create( 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' ); - Assertion::eq($clientDataHash, hex2bin(($objects[4])->getContent()), 'The client data hash is not valid'); + $ext = $extensionAsAsn1->at(4) + ->asElement(); + $ext instanceof OctetString || throw AttestationStatementVerificationException::create( + 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' + ); + $clientDataHash === $ext->string() || throw AttestationStatementVerificationException::create( + 'The client data hash is not valid' + ); - //Check that both teeEnforced and softwareEnforced structures don’t contain allApplications(600) tag. - Assertion::keyExists($objects, 6, 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid'); - $softwareEnforcedFlags = $objects[6]; - Assertion::isInstanceOf( - $softwareEnforcedFlags, - Sequence::class, + //Check that both teeEnforced and softwareEnforced structures don't contain allApplications(600) tag. + $extensionAsAsn1->has(6) || throw AttestationStatementVerificationException::create( + 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' + ); + + $softwareEnforcedFlags = $extensionAsAsn1->at(6) + ->asElement(); + $softwareEnforcedFlags instanceof Sequence || throw AttestationStatementVerificationException::create( 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' ); $this->checkAbsenceOfAllApplicationsTag($softwareEnforcedFlags); - Assertion::keyExists($objects, 7, 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid'); - $teeEnforcedFlags = $objects[6]; - Assertion::isInstanceOf( - $teeEnforcedFlags, - Sequence::class, + $extensionAsAsn1->has(7) || throw AttestationStatementVerificationException::create( + 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' + ); + $teeEnforcedFlags = $extensionAsAsn1->at(7) + ->asElement(); + $teeEnforcedFlags instanceof Sequence || throw AttestationStatementVerificationException::create( 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid' ); $this->checkAbsenceOfAllApplicationsTag($teeEnforcedFlags); @@ -177,10 +217,12 @@ final class AndroidKeyAttestationStatementSupport implements AttestationStatemen private function checkAbsenceOfAllApplicationsTag(Sequence $sequence): void { - foreach ($sequence->getChildren() as $tag) { - Assertion::isInstanceOf($tag, ExplicitlyTaggedObject::class, 'Invalid tag'); - /** @var ExplicitlyTaggedObject $tag */ - Assertion::notEq(600, (int) $tag->getTag(), 'Forbidden tag 600 found'); + foreach ($sequence->elements() as $tag) { + $tag->asElement() instanceof ExplicitTagging || throw AttestationStatementVerificationException::create( + 'Invalid tag' + ); + $tag->asElement() + ->tag() !== 600 || throw AttestationStatementVerificationException::create('Forbidden tag 600 found'); } } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php index e8b7541ea..d852ce517 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php @@ -4,11 +4,8 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; -use InvalidArgumentException; use Jose\Component\Core\Algorithm as AlgorithmInterface; use Jose\Component\Core\AlgorithmManager; -use Jose\Component\Core\Util\JsonConverter; use Jose\Component\KeyManagement\JWKFactory; use Jose\Component\Signature\Algorithm\EdDSA; use Jose\Component\Signature\Algorithm\ES256; @@ -23,20 +20,38 @@ use Jose\Component\Signature\Algorithm\RS512; use Jose\Component\Signature\JWS; use Jose\Component\Signature\JWSVerifier; use Jose\Component\Signature\Serializer\CompactSerializer; -use const JSON_THROW_ON_ERROR; +use Psr\Clock\ClockInterface; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\ResponseInterface; -use RuntimeException; +use Symfony\Contracts\HttpClient\HttpClientInterface; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\Exception\UnsupportedFeatureException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\TrustPath\CertificateTrustPath; +use function array_key_exists; +use function count; +use function is_array; +use function is_int; +use function is_string; +use function sprintf; +use const JSON_THROW_ON_ERROR; -final class AndroidSafetyNetAttestationStatementSupport implements AttestationStatementSupport +/** + * @deprecated since 4.9.0 and will be removed in 5.0.0. Android SafetyNet is now deprecated. + */ +final class AndroidSafetyNetAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { private ?string $apiKey = null; - private ?ClientInterface $client = null; + private null|ClientInterface|HttpClientInterface $client = null; private readonly CompactSerializer $jwsSerializer; @@ -48,35 +63,53 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt private int $maxAge = 60000; - public function __construct() - { - if (! class_exists(RS256::class)) { - throw new RuntimeException( - 'The algorithm RS256 is missing. Did you forget to install the package web-token/jwt-signature-algorithm-rsa?' + private EventDispatcherInterface $dispatcher; + + public function __construct( + private readonly null|ClockInterface $clock = null + ) { + if ($this->clock === null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$clock" will be required in 5.0.0. Please set a clock instance.' ); } - if (! class_exists(JWKFactory::class)) { - throw new RuntimeException( - 'The class Jose\Component\KeyManagement\JWKFactory is missing. Did you forget to install the package web-token/jwt-key-mgmt?' + if (! class_exists(RS256::class) || ! class_exists(JWKFactory::class)) { + throw UnsupportedFeatureException::create( + 'The algorithm RS256 is missing. Did you forget to install the package web-token/jwt-library?' ); } $this->jwsSerializer = new CompactSerializer(); $this->initJwsVerifier(); + $this->dispatcher = new NullEventDispatcher(); } - public static function create(): self + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void { - return new self(); + $this->dispatcher = $eventDispatcher; + } + + public static function create(null|ClockInterface $clock = null): self + { + return new self($clock); } public function enableApiVerification( - ClientInterface $client, + ClientInterface|HttpClientInterface $client, string $apiKey, - RequestFactoryInterface $requestFactory + ?RequestFactoryInterface $requestFactory = null ): self { $this->apiKey = $apiKey; $this->client = $client; $this->requestFactory = $requestFactory; + if ($requestFactory !== null && ! $client instanceof HttpClientInterface) { + trigger_deprecation( + 'web-auth/metadata-service', + '4.7.0', + 'The parameter "$requestFactory" will be removed in 5.0.0. Please set it to null and set an Symfony\Contracts\HttpClient\HttpClientInterface as "$client" argument.' + ); + } return $this; } @@ -105,39 +138,43 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + array_key_exists('attStmt', $attestation) || throw AttestationStatementLoadingException::create( + $attestation + ); foreach (['ver', 'response'] as $key) { - Assertion::keyExists( - $attestation['attStmt'], - $key, + array_key_exists($key, $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, sprintf('The attestation statement value "%s" is missing.', $key) ); - Assertion::notEmpty( - $attestation['attStmt'][$key], + $attestation['attStmt'][$key] !== '' || throw AttestationStatementLoadingException::create( + $attestation, sprintf('The attestation statement value "%s" is empty.', $key) ); } $jws = $this->jwsSerializer->unserialize($attestation['attStmt']['response']); $jwsHeader = $jws->getSignature(0) - ->getProtectedHeader() - ; - Assertion::keyExists( - $jwsHeader, - 'x5c', + ->getProtectedHeader(); + array_key_exists('x5c', $jwsHeader) || throw AttestationStatementLoadingException::create( + $attestation, 'The response in the attestation statement must contain a "x5c" header.' ); - Assertion::notEmpty( - $jwsHeader['x5c'], + (is_countable($jwsHeader['x5c']) ? count( + $jwsHeader['x5c'] + ) : 0) > 0 || throw AttestationStatementLoadingException::create( + $attestation, 'The "x5c" parameter in the attestation statement response must contain at least one certificate.' ); $certificates = $this->convertCertificatesToPem($jwsHeader['x5c']); $attestation['attStmt']['jws'] = $jws; - return AttestationStatement::createBasic( + $attestationStatement = AttestationStatement::createBasic( $this->name(), $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -145,17 +182,35 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $trustPath = $attestationStatement->getTrustPath(); - Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); - $certificates = $trustPath->getCertificates(); + $trustPath = $attestationStatement->trustPath; + $trustPath instanceof CertificateTrustPath || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid trust path' + ); + $certificates = $trustPath->certificates; $firstCertificate = current($certificates); - Assertion::string($firstCertificate, 'No certificate'); + is_string($firstCertificate) || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'No certificate' + ); $parsedCertificate = openssl_x509_parse($firstCertificate); - Assertion::isArray($parsedCertificate, 'Invalid attestation object'); - Assertion::keyExists($parsedCertificate, 'subject', 'Invalid attestation object'); - Assertion::keyExists($parsedCertificate['subject'], 'CN', 'Invalid attestation object'); - Assertion::eq($parsedCertificate['subject']['CN'], 'attest.android.com', 'Invalid attestation object'); + is_array($parsedCertificate) || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid attestation object' + ); + array_key_exists('subject', $parsedCertificate) || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid attestation object' + ); + array_key_exists('CN', $parsedCertificate['subject']) || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid attestation object' + ); + $parsedCertificate['subject']['CN'] === 'attest.android.com' || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid attestation object' + ); /** @var JWS $jws */ $jws = $attestationStatement->get('jws'); @@ -176,32 +231,36 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt string $clientDataJSONHash, AuthenticatorData $authenticatorData ): void { - Assertion::notNull($payload, 'Invalid attestation object'); - $payload = JsonConverter::decode($payload); - Assertion::isArray($payload, 'Invalid attestation object'); - Assertion::keyExists($payload, 'nonce', 'Invalid attestation object. "nonce" is missing.'); - Assertion::eq( - $payload['nonce'], - base64_encode(hash('sha256', $authenticatorData->getAuthData() . $clientDataJSONHash, true)), - 'Invalid attestation object. Invalid nonce' + $payload !== null || throw AttestationStatementVerificationException::create('Invalid attestation object'); + $payload = json_decode($payload, true, flags: JSON_THROW_ON_ERROR); + array_key_exists('nonce', $payload) || throw AttestationStatementVerificationException::create( + 'Invalid attestation object. "nonce" is missing.' ); - Assertion::keyExists($payload, 'ctsProfileMatch', 'Invalid attestation object. "ctsProfileMatch" is missing.'); - Assertion::true($payload['ctsProfileMatch'], 'Invalid attestation object. "ctsProfileMatch" value is false.'); - Assertion::keyExists($payload, 'timestampMs', 'Invalid attestation object. Timestamp is missing.'); - Assertion::integer($payload['timestampMs'], 'Invalid attestation object. Timestamp shall be an integer.'); - $currentTime = time() * 1000; - Assertion::lessOrEqualThan( - $payload['timestampMs'], - $currentTime + $this->leeway, + $payload['nonce'] === base64_encode( + hash('sha256', $authenticatorData->authData . $clientDataJSONHash, true) + ) || throw AttestationStatementVerificationException::create('Invalid attestation object. Invalid nonce'); + array_key_exists('ctsProfileMatch', $payload) || throw AttestationStatementVerificationException::create( + 'Invalid attestation object. "ctsProfileMatch" is missing.' + ); + $payload['ctsProfileMatch'] || throw AttestationStatementVerificationException::create( + 'Invalid attestation object. "ctsProfileMatch" value is false.' + ); + array_key_exists('timestampMs', $payload) || throw AttestationStatementVerificationException::create( + 'Invalid attestation object. Timestamp is missing.' + ); + is_int($payload['timestampMs']) || throw AttestationStatementVerificationException::create( + 'Invalid attestation object. Timestamp shall be an integer.' + ); + + $currentTime = ($this->clock?->now()->getTimestamp() ?? time()) * 1000; + $payload['timestampMs'] <= $currentTime + $this->leeway || throw AttestationStatementVerificationException::create( sprintf( 'Invalid attestation object. Issued in the future. Current time: %d. Response time: %d', $currentTime, $payload['timestampMs'] ) ); - Assertion::lessOrEqualThan( - $currentTime - $payload['timestampMs'], - $this->maxAge, + $currentTime - $payload['timestampMs'] <= $this->maxAge || throw AttestationStatementVerificationException::create( sprintf( 'Invalid attestation object. Too old. Current time: %d. Response time: %d', $currentTime, @@ -212,14 +271,14 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt private function validateSignature(JWS $jws, CertificateTrustPath $trustPath): void { - $jwk = JWKFactory::createFromCertificate($trustPath->getCertificates()[0]); + $jwk = JWKFactory::createFromCertificate($trustPath->certificates[0]); $isValid = $this->jwsVerifier?->verifyWithKey($jws, $jwk, 0); - Assertion::true($isValid, 'Invalid response signature'); + $isValid === true || throw AttestationStatementVerificationException::create('Invalid response signature'); } private function validateUsingGoogleApi(AttestationStatement $attestationStatement): void { - if ($this->client === null || $this->apiKey === null || $this->requestFactory === null) { + if ($this->client === null || $this->apiKey === null) { return; } $uri = sprintf( @@ -227,31 +286,29 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt urlencode($this->apiKey) ); $requestBody = sprintf('{"signedAttestation":"%s"}', $attestationStatement->get('response')); - $request = $this->requestFactory->createRequest('POST', $uri); - $request = $request->withHeader('content-type', 'application/json'); - $request->getBody() - ->write($requestBody) - ; - - $response = $this->client->sendRequest($request); - $this->checkGoogleApiResponse($response); - $responseBody = $this->getResponseBody($response); - $responseBodyJson = json_decode($responseBody, true, 512, JSON_THROW_ON_ERROR); - Assertion::keyExists($responseBodyJson, 'isValidSignature', 'Invalid response.'); - Assertion::boolean($responseBodyJson['isValidSignature'], 'Invalid response.'); - Assertion::true($responseBodyJson['isValidSignature'], 'Invalid response.'); + if ($this->client instanceof HttpClientInterface) { + $responseBody = $this->validateUsingGoogleApiWithSymfonyClient($requestBody, $uri); + } else { + $responseBody = $this->validateUsingGoogleApiWithPsrClient($requestBody, $uri); + } + $responseBodyJson = json_decode($responseBody, true, flags: JSON_THROW_ON_ERROR); + array_key_exists( + 'isValidSignature', + $responseBodyJson + ) || throw AttestationStatementVerificationException::create('Invalid response.'); + $responseBodyJson['isValidSignature'] === true || throw AttestationStatementVerificationException::create( + 'Invalid response.' + ); } private function getResponseBody(ResponseInterface $response): string { $responseBody = ''; $response->getBody() - ->rewind() - ; + ->rewind(); do { $tmp = $response->getBody() - ->read(1024) - ; + ->read(1024); if ($tmp === '') { break; } @@ -261,20 +318,6 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt return $responseBody; } - private function checkGoogleApiResponse(ResponseInterface $response): void - { - Assertion::eq(200, $response->getStatusCode(), 'Request did not succeeded'); - Assertion::true($response->hasHeader('content-type'), 'Unrecognized response'); - - foreach ($response->getHeader('content-type') as $header) { - if (mb_strpos($header, 'application/json') === 0) { - return; - } - } - - throw new InvalidArgumentException('Unrecognized response'); - } - /** * @param string[] $certificates * @@ -301,11 +344,40 @@ final class AndroidSafetyNetAttestationStatementSupport implements AttestationSt $algorithms = []; foreach ($algorithmClasses as $algorithm) { if (class_exists($algorithm)) { - /** @var AlgorithmInterface $algorithm */ $algorithms[] = new $algorithm(); } } $algorithmManager = new AlgorithmManager($algorithms); $this->jwsVerifier = new JWSVerifier($algorithmManager); } + + private function validateUsingGoogleApiWithSymfonyClient(string $requestBody, string $uri): string + { + $response = $this->client->request('POST', $uri, [ + 'headers' => [ + 'content-type' => 'application/json', + ], + 'body' => $requestBody, + ]); + $response->getStatusCode() === 200 || throw AttestationStatementVerificationException::create( + 'Request did not succeeded' + ); + + return $response->getContent(); + } + + private function validateUsingGoogleApiWithPsrClient(string $requestBody, string $uri): string + { + $request = $this->requestFactory->createRequest('POST', $uri); + $request = $request->withHeader('content-type', 'application/json'); + $request->getBody() + ->write($requestBody); + + $response = $this->client->sendRequest($request); + $response->getStatusCode() === 200 || throw AttestationStatementVerificationException::create( + 'Request did not succeeded' + ); + + return $this->getResponseBody($response); + } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php index fcb6376c2..e57c33830 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php @@ -4,26 +4,42 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; use CBOR\Decoder; use CBOR\Normalizable; use Cose\Key\Ec2Key; use Cose\Key\Key; use Cose\Key\RsaKey; -use function count; -use function Safe\openssl_pkey_get_public; +use Psr\EventDispatcher\EventDispatcherInterface; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\StringStream; use Webauthn\TrustPath\CertificateTrustPath; +use function array_key_exists; +use function count; +use function is_array; +use function openssl_pkey_get_public; -final class AppleAttestationStatementSupport implements AttestationStatementSupport +final class AppleAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { private readonly Decoder $decoder; + private EventDispatcherInterface $dispatcher; + public function __construct() { $this->decoder = Decoder::create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; } public static function create(): self @@ -41,31 +57,31 @@ final class AppleAttestationStatementSupport implements AttestationStatementSupp */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); - foreach (['x5c'] as $key) { - Assertion::keyExists( - $attestation['attStmt'], - $key, - sprintf('The attestation statement value "%s" is missing.', $key) - ); - } - $certificates = $attestation['attStmt']['x5c']; - Assertion::greaterThan( - is_countable($certificates) ? count($certificates) : 0, - 0, - 'The attestation statement value "x5c" must be a list with at least one certificate.' + array_key_exists('attStmt', $attestation) || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' ); - Assertion::allString( - $certificates, + array_key_exists('x5c', $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, + 'The attestation statement value "x5c" is missing.' + ); + $certificates = $attestation['attStmt']['x5c']; + (is_countable($certificates) ? count( + $certificates + ) : 0) > 0 || throw AttestationStatementLoadingException::create( + $attestation, 'The attestation statement value "x5c" must be a list with at least one certificate.' ); $certificates = CertificateToolbox::convertAllDERToPEM($certificates); - return AttestationStatement::createAnonymizationCA( + $attestationStatement = AttestationStatement::createAnonymizationCA( $attestation['fmt'], $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -73,10 +89,13 @@ final class AppleAttestationStatementSupport implements AttestationStatementSupp AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $trustPath = $attestationStatement->getTrustPath(); - Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + $trustPath = $attestationStatement->trustPath; + $trustPath instanceof CertificateTrustPath || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid trust path' + ); - $certificates = $trustPath->getCertificates(); + $certificates = $trustPath->certificates; //Decode leaf attestation certificate $leaf = $certificates[0]; @@ -93,43 +112,66 @@ final class AppleAttestationStatementSupport implements AttestationStatementSupp ): void { $resource = openssl_pkey_get_public($certificate); $details = openssl_pkey_get_details($resource); - Assertion::isArray($details, 'Unable to read the certificate'); + is_array($details) || throw AttestationStatementVerificationException::create( + 'Unable to read the certificate' + ); //Check that authData publicKey matches the public key in the attestation certificate - $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); - Assertion::notNull($attestedCredentialData, 'No attested credential data found'); - $publicKeyData = $attestedCredentialData->getCredentialPublicKey(); - Assertion::notNull($publicKeyData, 'No attested public key found'); + $attestedCredentialData = $authenticatorData->attestedCredentialData; + $attestedCredentialData !== null || throw AttestationStatementVerificationException::create( + 'No attested credential data found' + ); + $publicKeyData = $attestedCredentialData->credentialPublicKey; + $publicKeyData !== null || throw AttestationStatementVerificationException::create( + 'No attested public key found' + ); $publicDataStream = new StringStream($publicKeyData); $coseKey = $this->decoder->decode($publicDataStream); - Assertion::isInstanceOf($coseKey, Normalizable::class, 'Invalid attested public key found'); - Assertion::true($publicDataStream->isEOF(), 'Invalid public key data. Presence of extra bytes.'); + $coseKey instanceof Normalizable || throw AttestationStatementVerificationException::create( + 'Invalid attested public key found' + ); + $publicDataStream->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid public key data. Presence of extra bytes.' + ); $publicDataStream->close(); $publicKey = Key::createFromData($coseKey->normalize()); - Assertion::true(($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey), 'Unsupported key type'); + ($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey) || throw AttestationStatementVerificationException::create( + 'Unsupported key type' + ); //We check the attested key corresponds to the key in the certificate - Assertion::eq($publicKey->asPEM(), $details['key'], 'Invalid key'); + $publicKey->asPEM() === $details['key'] || throw AttestationStatementVerificationException::create( + 'Invalid key' + ); /*---------------------------*/ $certDetails = openssl_x509_parse($certificate); - //Find Apple Extension with OID “1.2.840.113635.100.8.2” in certificate extensions - Assertion::isArray($certDetails, 'The certificate is not valid'); - Assertion::keyExists($certDetails, 'extensions', 'The certificate has no extension'); - Assertion::isArray($certDetails['extensions'], 'The certificate has no extension'); - Assertion::keyExists( - $certDetails['extensions'], + //Find Apple Extension with OID "1.2.840.113635.100.8.2" in certificate extensions + is_array( + $certDetails + ) || throw AttestationStatementVerificationException::create('The certificate is not valid'); + array_key_exists('extensions', $certDetails) || throw AttestationStatementVerificationException::create( + 'The certificate has no extension' + ); + is_array($certDetails['extensions']) || throw AttestationStatementVerificationException::create( + 'The certificate has no extension' + ); + array_key_exists( '1.2.840.113635.100.8.2', + $certDetails['extensions'] + ) || throw AttestationStatementVerificationException::create( 'The certificate extension "1.2.840.113635.100.8.2" is missing' ); $extension = $certDetails['extensions']['1.2.840.113635.100.8.2']; - $nonceToHash = $authenticatorData->getAuthData() . $clientDataHash; + $nonceToHash = $authenticatorData->authData . $clientDataHash; $nonce = hash('sha256', $nonceToHash); //'3024a1220420' corresponds to the Sequence+Explicitly Tagged Object + Octet Object - Assertion::eq('3024a1220420' . $nonce, bin2hex((string) $extension), 'The client data hash is not valid'); + '3024a1220420' . $nonce === bin2hex( + (string) $extension + ) || throw AttestationStatementVerificationException::create('The client data hash is not valid'); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php index c3884d9c1..a89cccac6 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php @@ -9,40 +9,72 @@ use Webauthn\MetadataService\Statement\MetadataStatement; class AttestationObject { - private ?MetadataStatement $metadataStatement = null; + public ?MetadataStatement $metadataStatement = null; public function __construct( - private readonly string $rawAttestationObject, - private AttestationStatement $attStmt, - private readonly AuthenticatorData $authData + public readonly string $rawAttestationObject, + public AttestationStatement $attStmt, + public readonly AuthenticatorData $authData ) { } + public static function create( + string $rawAttestationObject, + AttestationStatement $attStmt, + AuthenticatorData $authData + ): self { + return new self($rawAttestationObject, $attStmt, $authData); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRawAttestationObject(): string { return $this->rawAttestationObject; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAttStmt(): AttestationStatement { return $this->attStmt; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function setAttStmt(AttestationStatement $attStmt): void { $this->attStmt = $attStmt; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAuthData(): AuthenticatorData { return $this->authData; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getMetadataStatement(): ?MetadataStatement { return $this->metadataStatement; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function setMetadataStatement(MetadataStatement $metadataStatement): self { $this->metadataStatement = $metadataStatement; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php index f3eb724fd..8ad284c44 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php @@ -4,37 +4,39 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; use CBOR\Decoder; -use CBOR\MapObject; use CBOR\Normalizable; -use function ord; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use function Safe\unpack; -use Symfony\Component\Uid\Uuid; use Throwable; -use Webauthn\AttestedCredentialData; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputsLoader; -use Webauthn\AuthenticatorData; +use Webauthn\AuthenticatorDataLoader; +use Webauthn\Event\AttestationObjectLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\InvalidDataException; +use Webauthn\MetadataService\CanLogData; use Webauthn\StringStream; use Webauthn\Util\Base64; +use function array_key_exists; +use function is_array; -class AttestationObjectLoader +class AttestationObjectLoader implements CanDispatchEvents, CanLogData { - private const FLAG_AT = 0b01000000; - - private const FLAG_ED = 0b10000000; - - private readonly Decoder $decoder; - private LoggerInterface $logger; + private EventDispatcherInterface $dispatcher; + public function __construct( private readonly AttestationStatementSupportManager $attestationStatementSupportManager ) { - $this->decoder = Decoder::create(); $this->logger = new NullLogger(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; } public static function create(AttestationStatementSupportManager $attestationStatementSupportManager): self @@ -50,18 +52,35 @@ class AttestationObjectLoader ]); $decodedData = Base64::decode($data); $stream = new StringStream($decodedData); - $parsed = $this->decoder->decode($stream); + $parsed = Decoder::create()->decode($stream); $this->logger->info('Loading the Attestation Statement'); - Assertion::isInstanceOf($parsed, Normalizable::class, 'Invalid attestation object. Unexpected object.'); + $parsed instanceof Normalizable || throw InvalidDataException::create( + $parsed, + 'Invalid attestation object. Unexpected object.' + ); $attestationObject = $parsed->normalize(); - Assertion::true($stream->isEOF(), 'Invalid attestation object. Presence of extra bytes.'); + $stream->isEOF() || throw InvalidDataException::create( + null, + 'Invalid attestation object. Presence of extra bytes.' + ); $stream->close(); - Assertion::isArray($attestationObject, 'Invalid attestation object'); - Assertion::keyExists($attestationObject, 'authData', 'Invalid attestation object'); - Assertion::keyExists($attestationObject, 'fmt', 'Invalid attestation object'); - Assertion::keyExists($attestationObject, 'attStmt', 'Invalid attestation object'); - $authData = $attestationObject['authData']; + is_array($attestationObject) || throw InvalidDataException::create( + $attestationObject, + 'Invalid attestation object' + ); + array_key_exists('authData', $attestationObject) || throw InvalidDataException::create( + $attestationObject, + 'Invalid attestation object' + ); + array_key_exists('fmt', $attestationObject) || throw InvalidDataException::create( + $attestationObject, + 'Invalid attestation object' + ); + array_key_exists('attStmt', $attestationObject) || throw InvalidDataException::create( + $attestationObject, + 'Invalid attestation object' + ); $attestationStatementSupport = $this->attestationStatementSupportManager->get($attestationObject['fmt']); $attestationStatement = $attestationStatementSupport->load($attestationObject); @@ -69,64 +88,16 @@ class AttestationObjectLoader $this->logger->debug('Attestation Statement loaded', [ 'attestationStatement' => $attestationStatement, ]); + $authData = $attestationObject['authData']; + $authDataLoader = AuthenticatorDataLoader::create(); + $authenticatorData = $authDataLoader->load($authData); - $authDataStream = new StringStream($authData); - $rp_id_hash = $authDataStream->read(32); - $flags = $authDataStream->read(1); - $signCount = $authDataStream->read(4); - $signCount = unpack('N', $signCount); - $this->logger->debug(sprintf('Signature counter: %d', $signCount[1])); - - $attestedCredentialData = null; - if (0 !== (ord($flags) & self::FLAG_AT)) { - $this->logger->info('Attested Credential Data is present'); - $aaguid = Uuid::fromBinary($authDataStream->read(16)); - $credentialLength = $authDataStream->read(2); - $credentialLength = unpack('n', $credentialLength); - $credentialId = $authDataStream->read($credentialLength[1]); - $credentialPublicKey = $this->decoder->decode($authDataStream); - Assertion::isInstanceOf( - $credentialPublicKey, - MapObject::class, - 'The data does not contain a valid credential public key.' - ); - $attestedCredentialData = new AttestedCredentialData( - $aaguid, - $credentialId, - (string) $credentialPublicKey - ); - $this->logger->info('Attested Credential Data loaded'); - $this->logger->debug('Attested Credential Data loaded', [ - 'at' => $attestedCredentialData, - ]); - } - - $extension = null; - if (0 !== (ord($flags) & self::FLAG_ED)) { - $this->logger->info('Extension Data loaded'); - $extension = $this->decoder->decode($authDataStream); - $extension = AuthenticationExtensionsClientOutputsLoader::load($extension); - $this->logger->info('Extension Data loaded'); - $this->logger->debug('Extension Data loaded', [ - 'ed' => $extension, - ]); - } - Assertion::true($authDataStream->isEOF(), 'Invalid authentication data. Presence of extra bytes.'); - $authDataStream->close(); - - $authenticatorData = new AuthenticatorData( - $authData, - $rp_id_hash, - $flags, - $signCount[1], - $attestedCredentialData, - $extension - ); - $attestationObject = new AttestationObject($data, $attestationStatement, $authenticatorData); + $attestationObject = AttestationObject::create($data, $attestationStatement, $authenticatorData); $this->logger->info('Attestation Object loaded'); $this->logger->debug('Attestation Object', [ 'ed' => $attestationObject, ]); + $this->dispatcher->dispatch(AttestationObjectLoaded::create($attestationObject)); return $attestationObject; } catch (Throwable $throwable) { @@ -137,10 +108,8 @@ class AttestationObjectLoader } } - public function setLogger(LoggerInterface $logger): self + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; - - return $this; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php index fb21cf90b..8f45491c0 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php @@ -4,11 +4,12 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use function array_key_exists; -use Assert\Assertion; use JsonSerializable; +use Webauthn\Exception\InvalidDataException; use Webauthn\TrustPath\TrustPath; use Webauthn\TrustPath\TrustPathLoader; +use function array_key_exists; +use function sprintf; class AttestationStatement implements JsonSerializable { @@ -20,6 +21,10 @@ class AttestationStatement implements JsonSerializable final public const TYPE_ATTCA = 'attca'; + /** + * @deprecated since 4.2.0 and will be removed in 5.0.0. The ECDAA Trust Anchor does no longer exist in Webauthn specification. + * @infection-ignore-all + */ final public const TYPE_ECDAA = 'ecdaa'; final public const TYPE_ANONCA = 'anonca'; @@ -28,19 +33,24 @@ class AttestationStatement implements JsonSerializable * @param array $attStmt */ public function __construct( - private readonly string $fmt, - private readonly array $attStmt, - private readonly string $type, - private readonly TrustPath $trustPath + public readonly string $fmt, + public readonly array $attStmt, + public readonly string $type, + public readonly TrustPath $trustPath ) { } + public static function create(string $fmt, array $attStmt, string $type, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, $type, $trustPath); + } + /** * @param array $attStmt */ public static function createNone(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_NONE, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_NONE, $trustPath); } /** @@ -48,7 +58,7 @@ class AttestationStatement implements JsonSerializable */ public static function createBasic(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_BASIC, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_BASIC, $trustPath); } /** @@ -56,7 +66,7 @@ class AttestationStatement implements JsonSerializable */ public static function createSelf(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_SELF, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_SELF, $trustPath); } /** @@ -64,15 +74,18 @@ class AttestationStatement implements JsonSerializable */ public static function createAttCA(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_ATTCA, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_ATTCA, $trustPath); } /** * @param array $attStmt + * + * @deprecated since 4.2.0 and will be removed in 5.0.0. The ECDAA Trust Anchor does no longer exist in Webauthn specification. + * @infection-ignore-all */ public static function createEcdaa(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_ECDAA, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_ECDAA, $trustPath); } /** @@ -80,9 +93,13 @@ class AttestationStatement implements JsonSerializable */ public static function createAnonymizationCA(string $fmt, array $attStmt, TrustPath $trustPath): self { - return new self($fmt, $attStmt, self::TYPE_ANONCA, $trustPath); + return self::create($fmt, $attStmt, self::TYPE_ANONCA, $trustPath); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getFmt(): string { return $this->fmt; @@ -90,6 +107,8 @@ class AttestationStatement implements JsonSerializable /** * @return mixed[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getAttStmt(): array { @@ -103,16 +122,27 @@ class AttestationStatement implements JsonSerializable public function get(string $key): mixed { - Assertion::true($this->has($key), sprintf('The attestation statement has no key "%s".', $key)); + $this->has($key) || throw InvalidDataException::create($this->attStmt, sprintf( + 'The attestation statement has no key "%s".', + $key + )); return $this->attStmt[$key]; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getTrustPath(): TrustPath { return $this->trustPath; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; @@ -120,14 +150,19 @@ class AttestationStatement implements JsonSerializable /** * @param mixed[] $data + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $data): self { foreach (['fmt', 'attStmt', 'trustPath', 'type'] as $key) { - Assertion::keyExists($data, $key, sprintf('The key "%s" is missing', $key)); + array_key_exists($key, $data) || throw InvalidDataException::create($data, sprintf( + 'The key "%s" is missing', + $key + )); } - return new self( + return self::create( $data['fmt'], $data['attStmt'], $data['type'], @@ -140,10 +175,16 @@ class AttestationStatement implements JsonSerializable */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); return [ 'fmt' => $this->fmt, 'attStmt' => $this->attStmt, - 'trustPath' => $this->trustPath->jsonSerialize(), + 'trustPath' => $this->trustPath, 'type' => $this->type, ]; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupportManager.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupportManager.php index 0858a5b15..7687d8d35 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupportManager.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupportManager.php @@ -4,19 +4,30 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; +use Webauthn\Exception\InvalidDataException; use function array_key_exists; -use Assert\Assertion; +use function sprintf; class AttestationStatementSupportManager { /** - * @var AttestationStatementSupport[] + * @param AttestationStatementSupport[] $attestationStatementSupports */ - private array $attestationStatementSupports = []; + public function __construct( + private array $attestationStatementSupports = [] + ) { + $this->add(new NoneAttestationStatementSupport()); + foreach ($attestationStatementSupports as $attestationStatementSupport) { + $this->add($attestationStatementSupport); + } + } - public static function create(): self + /** + * @param AttestationStatementSupport[] $attestationStatementSupports + */ + public static function create(array $attestationStatementSupports = []): self { - return new self(); + return new self($attestationStatementSupports); } public function add(AttestationStatementSupport $attestationStatementSupport): void @@ -31,7 +42,10 @@ class AttestationStatementSupportManager public function get(string $name): AttestationStatementSupport { - Assertion::true($this->has($name), sprintf('The attestation statement format "%s" is not supported.', $name)); + $this->has($name) || throw InvalidDataException::create($name, sprintf( + 'The attestation statement format "%s" is not supported.', + $name + )); return $this->attestationStatementSupports[$name]; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php index 23686ce03..c0d812b2f 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php @@ -4,27 +4,44 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; use CBOR\Decoder; use CBOR\MapObject; use Cose\Key\Ec2Key; -use InvalidArgumentException; -use const OPENSSL_ALGO_SHA256; -use function Safe\openssl_pkey_get_public; -use function Safe\openssl_verify; +use Psr\EventDispatcher\EventDispatcherInterface; use Throwable; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\StringStream; use Webauthn\TrustPath\CertificateTrustPath; +use function array_key_exists; +use function count; +use function is_array; +use function openssl_pkey_get_public; +use function openssl_verify; +use function sprintf; +use const OPENSSL_ALGO_SHA256; -final class FidoU2FAttestationStatementSupport implements AttestationStatementSupport +final class FidoU2FAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { private readonly Decoder $decoder; + private EventDispatcherInterface $dispatcher; + public function __construct() { $this->decoder = Decoder::create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; } public static function create(): self @@ -42,23 +59,23 @@ final class FidoU2FAttestationStatementSupport implements AttestationStatementSu */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + array_key_exists('attStmt', $attestation) || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); foreach (['sig', 'x5c'] as $key) { - Assertion::keyExists( - $attestation['attStmt'], - $key, + array_key_exists($key, $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, sprintf('The attestation statement value "%s" is missing.', $key) ); } $certificates = $attestation['attStmt']['x5c']; - Assertion::isArray($certificates, 'The attestation statement value "x5c" must be a list with one certificate.'); - Assertion::count( - $certificates, - 1, + is_array($certificates) || throw AttestationStatementLoadingException::create( + $attestation, 'The attestation statement value "x5c" must be a list with one certificate.' ); - Assertion::allString( - $certificates, + count($certificates) === 1 || throw AttestationStatementLoadingException::create( + $attestation, 'The attestation statement value "x5c" must be a list with one certificate.' ); @@ -66,11 +83,14 @@ final class FidoU2FAttestationStatementSupport implements AttestationStatementSu $certificates = CertificateToolbox::convertAllDERToPEM($certificates); $this->checkCertificate($certificates[0]); - return AttestationStatement::createBasic( + $attestationStatement = AttestationStatement::createBasic( $attestation['fmt'], $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -78,45 +98,45 @@ final class FidoU2FAttestationStatementSupport implements AttestationStatementSu AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - Assertion::eq( - $authenticatorData->getAttestedCredentialData() - ?->getAaguid() - ->__toString(), - '00000000-0000-0000-0000-000000000000', - 'Invalid AAGUID for fido-u2f attestation statement. Shall be "00000000-0000-0000-0000-000000000000"' + $authenticatorData->attestedCredentialData + ?->aaguid + ->__toString() === '00000000-0000-0000-0000-000000000000' || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid AAGUID for fido-u2f attestation statement. Shall be "00000000-0000-0000-0000-000000000000"' + ); + $trustPath = $attestationStatement->trustPath; + $trustPath instanceof CertificateTrustPath || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Invalid trust path' ); - $trustPath = $attestationStatement->getTrustPath(); - Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); $dataToVerify = "\0"; - $dataToVerify .= $authenticatorData->getRpIdHash(); + $dataToVerify .= $authenticatorData->rpIdHash; $dataToVerify .= $clientDataJSONHash; - $dataToVerify .= $authenticatorData->getAttestedCredentialData() - ?->getCredentialId() - ; - $dataToVerify .= $this->extractPublicKey( - $authenticatorData->getAttestedCredentialData() - ?->getCredentialPublicKey() - ); + $dataToVerify .= $authenticatorData->attestedCredentialData + ->credentialId; + $dataToVerify .= $this->extractPublicKey($authenticatorData->attestedCredentialData ->credentialPublicKey); return openssl_verify( $dataToVerify, $attestationStatement->get('sig'), - $trustPath->getCertificates()[0], + $trustPath->certificates[0], OPENSSL_ALGO_SHA256 ) === 1; } private function extractPublicKey(?string $publicKey): string { - Assertion::notNull($publicKey, 'The attested credential data does not contain a valid public key.'); + $publicKey !== null || throw AttestationStatementVerificationException::create( + 'The attested credential data does not contain a valid public key.' + ); $publicKeyStream = new StringStream($publicKey); $coseKey = $this->decoder->decode($publicKeyStream); - Assertion::true($publicKeyStream->isEOF(), 'Invalid public key. Presence of extra bytes.'); + $publicKeyStream->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid public key. Presence of extra bytes.' + ); $publicKeyStream->close(); - Assertion::isInstanceOf( - $coseKey, - MapObject::class, + $coseKey instanceof MapObject || throw AttestationStatementVerificationException::create( 'The attested credential data does not contain a valid public key.' ); @@ -135,13 +155,28 @@ final class FidoU2FAttestationStatementSupport implements AttestationStatementSu $resource = openssl_pkey_get_public($publicKey); $details = openssl_pkey_get_details($resource); } catch (Throwable $throwable) { - throw new InvalidArgumentException('Invalid certificate or certificate chain', 0, $throwable); + throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain', + $throwable + ); } - Assertion::isArray($details, 'Invalid certificate or certificate chain'); - Assertion::keyExists($details, 'ec', 'Invalid certificate or certificate chain'); - Assertion::keyExists($details['ec'], 'curve_name', 'Invalid certificate or certificate chain'); - Assertion::eq($details['ec']['curve_name'], 'prime256v1', 'Invalid certificate or certificate chain'); - Assertion::keyExists($details['ec'], 'curve_oid', 'Invalid certificate or certificate chain'); - Assertion::eq($details['ec']['curve_oid'], '1.2.840.10045.3.1.7', 'Invalid certificate or certificate chain'); + is_array($details) || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); + array_key_exists('ec', $details) || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); + array_key_exists('curve_name', $details['ec']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); + $details['ec']['curve_name'] === 'prime256v1' || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); + array_key_exists('curve_oid', $details['ec']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); + $details['ec']['curve_oid'] === '1.2.840.10045.3.1.7' || throw AttestationStatementVerificationException::create( + 'Invalid certificate or certificate chain' + ); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php index 58ee4c630..a28e3e6cc 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php @@ -4,13 +4,31 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; -use function count; +use Psr\EventDispatcher\EventDispatcherInterface; use Webauthn\AuthenticatorData; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; use Webauthn\TrustPath\EmptyTrustPath; +use function count; +use function is_array; +use function is_string; -final class NoneAttestationStatementSupport implements AttestationStatementSupport +final class NoneAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { + private EventDispatcherInterface $dispatcher; + + public function __construct() + { + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + public static function create(): self { return new self(); @@ -26,9 +44,28 @@ final class NoneAttestationStatementSupport implements AttestationStatementSuppo */ public function load(array $attestation): AttestationStatement { - Assertion::noContent($attestation['attStmt'], 'Invalid attestation object'); + $format = $attestation['fmt'] ?? null; + $attestationStatement = $attestation['attStmt'] ?? []; - return AttestationStatement::createNone($attestation['fmt'], $attestation['attStmt'], new EmptyTrustPath()); + (is_string($format) && $format !== '') || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); + (is_array( + $attestationStatement + ) && $attestationStatement === []) || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); + + $attestationStatement = AttestationStatement::createNone( + $format, + $attestationStatement, + EmptyTrustPath::create() + ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -36,6 +73,6 @@ final class NoneAttestationStatementSupport implements AttestationStatementSuppo AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - return count($attestationStatement->getAttStmt()) === 0; + return count($attestationStatement->attStmt) === 0; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php index 9548e6459..7af35f589 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php @@ -4,35 +4,51 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use function array_key_exists; -use Assert\Assertion; use CBOR\Decoder; use CBOR\MapObject; use Cose\Algorithm\Manager; use Cose\Algorithm\Signature\Signature; use Cose\Algorithms; use Cose\Key\Key; -use function in_array; -use InvalidArgumentException; -use function is_array; -use RuntimeException; -use function Safe\openssl_verify; +use Psr\EventDispatcher\EventDispatcherInterface; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\Exception\InvalidDataException; +use Webauthn\Exception\UnsupportedFeatureException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\StringStream; use Webauthn\TrustPath\CertificateTrustPath; use Webauthn\TrustPath\EcdaaKeyIdTrustPath; use Webauthn\TrustPath\EmptyTrustPath; use Webauthn\Util\CoseSignatureFixer; +use function array_key_exists; +use function count; +use function in_array; +use function is_array; +use function is_string; +use function openssl_verify; -final class PackedAttestationStatementSupport implements AttestationStatementSupport +final class PackedAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { private readonly Decoder $decoder; + private EventDispatcherInterface $dispatcher; + public function __construct( private readonly Manager $algorithmManager ) { $this->decoder = Decoder::create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; } public static function create(Manager $algorithmManager): self @@ -50,9 +66,18 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation['attStmt'], 'sig', 'The attestation statement value "sig" is missing.'); - Assertion::keyExists($attestation['attStmt'], 'alg', 'The attestation statement value "alg" is missing.'); - Assertion::string($attestation['attStmt']['sig'], 'The attestation statement value "sig" is missing.'); + array_key_exists('sig', $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, + 'The attestation statement value "sig" is missing.' + ); + array_key_exists('alg', $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, + 'The attestation statement value "alg" is missing.' + ); + is_string($attestation['attStmt']['sig']) || throw AttestationStatementLoadingException::create( + $attestation, + 'The attestation statement value "sig" is missing.' + ); return match (true) { array_key_exists('x5c', $attestation['attStmt']) => $this->loadBasicType($attestation), @@ -66,7 +91,7 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $trustPath = $attestationStatement->getTrustPath(); + $trustPath = $attestationStatement->trustPath; return match (true) { $trustPath instanceof CertificateTrustPath => $this->processWithCertificate( @@ -81,7 +106,10 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup $attestationStatement, $authenticatorData ), - default => throw new InvalidArgumentException('Unsupported attestation statement'), + default => throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Unsupported attestation statement' + ), }; } @@ -91,22 +119,22 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup private function loadBasicType(array $attestation): AttestationStatement { $certificates = $attestation['attStmt']['x5c']; - Assertion::isArray( - $certificates, + is_array($certificates) || throw AttestationStatementVerificationException::create( 'The attestation statement value "x5c" must be a list with at least one certificate.' ); - Assertion::minCount( - $certificates, - 1, + count($certificates) > 0 || throw AttestationStatementVerificationException::create( 'The attestation statement value "x5c" must be a list with at least one certificate.' ); $certificates = CertificateToolbox::convertAllDERToPEM($certificates); - return AttestationStatement::createBasic( + $attestationStatement = AttestationStatement::createBasic( $attestation['fmt'], $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } /** @@ -115,13 +143,18 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup private function loadEcdaaType(array $attestation): AttestationStatement { $ecdaaKeyId = $attestation['attStmt']['ecdaaKeyId']; - Assertion::string($ecdaaKeyId, 'The attestation statement value "ecdaaKeyId" is invalid.'); + is_string($ecdaaKeyId) || throw AttestationStatementVerificationException::create( + 'The attestation statement value "ecdaaKeyId" is invalid.' + ); - return AttestationStatement::createEcdaa( + $attestationStatement = AttestationStatement::createEcdaa( $attestation['fmt'], $attestation['attStmt'], new EcdaaKeyIdTrustPath($attestation['ecdaaKeyId']) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } /** @@ -129,47 +162,71 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup */ private function loadEmptyType(array $attestation): AttestationStatement { - return AttestationStatement::createSelf($attestation['fmt'], $attestation['attStmt'], new EmptyTrustPath()); + $attestationStatement = AttestationStatement::createSelf( + $attestation['fmt'], + $attestation['attStmt'], + EmptyTrustPath::create() + ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } private function checkCertificate(string $attestnCert, AuthenticatorData $authenticatorData): void { $parsed = openssl_x509_parse($attestnCert); - Assertion::isArray($parsed, 'Invalid certificate'); + is_array($parsed) || throw AttestationStatementVerificationException::create('Invalid certificate'); //Check version - Assertion::false(! isset($parsed['version']) || $parsed['version'] !== 2, 'Invalid certificate version'); + isset($parsed['version']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate version' + ); + $parsed['version'] === 2 || throw AttestationStatementVerificationException::create( + 'Invalid certificate version' + ); //Check subject field - Assertion::false( - ! isset($parsed['name']) || ! str_contains((string) $parsed['name'], '/OU=Authenticator Attestation'), + isset($parsed['name']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate name. The Subject Organization Unit must be "Authenticator Attestation"' + ); + str_contains( + (string) $parsed['name'], + '/OU=Authenticator Attestation' + ) || throw AttestationStatementVerificationException::create( 'Invalid certificate name. The Subject Organization Unit must be "Authenticator Attestation"' ); //Check extensions - Assertion::false( - ! isset($parsed['extensions']) || ! is_array($parsed['extensions']), + isset($parsed['extensions']) || throw AttestationStatementVerificationException::create( + 'Certificate extensions are missing' + ); + is_array($parsed['extensions']) || throw AttestationStatementVerificationException::create( 'Certificate extensions are missing' ); //Check certificate is not a CA cert - Assertion::false( - ! isset($parsed['extensions']['basicConstraints']) || $parsed['extensions']['basicConstraints'] !== 'CA:FALSE', + isset($parsed['extensions']['basicConstraints']) || throw AttestationStatementVerificationException::create( + 'The Basic Constraints extension must have the CA component set to false' + ); + $parsed['extensions']['basicConstraints'] === 'CA:FALSE' || throw AttestationStatementVerificationException::create( 'The Basic Constraints extension must have the CA component set to false' ); - $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); - Assertion::notNull($attestedCredentialData, 'No attested credential available'); + $attestedCredentialData = $authenticatorData->attestedCredentialData; + $attestedCredentialData !== null || throw AttestationStatementVerificationException::create( + 'No attested credential available' + ); // id-fido-gen-ce-aaguid OID check - Assertion::false( - in_array('1.3.6.1.4.1.45724.1.1.4', $parsed['extensions'], true) && ! hash_equals( - $attestedCredentialData->getAaguid() + if (in_array('1.3.6.1.4.1.45724.1.1.4', $parsed['extensions'], true)) { + hash_equals( + $attestedCredentialData->aaguid ->toBinary(), $parsed['extensions']['1.3.6.1.4.1.45724.1.1.4'] - ), - 'The value of the "aaguid" does not match with the certificate' - ); + ) || throw AttestationStatementVerificationException::create( + 'The value of the "aaguid" does not match with the certificate' + ); + } } private function processWithCertificate( @@ -178,7 +235,7 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup AuthenticatorData $authenticatorData, CertificateTrustPath $trustPath ): bool { - $certificates = $trustPath->getCertificates(); + $certificates = $trustPath->certificates; // Check leaf certificate $this->checkCertificate($certificates[0], $authenticatorData); @@ -188,7 +245,7 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup $opensslAlgorithmIdentifier = Algorithms::getOpensslAlgorithmFor($coseAlgorithmIdentifier); // Verification of the signature - $signedData = $authenticatorData->getAuthData() . $clientDataJSONHash; + $signedData = $authenticatorData->authData . $clientDataJSONHash; $result = openssl_verify( $signedData, $attestationStatement->get('sig'), @@ -201,7 +258,7 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup private function processWithECDAA(): never { - throw new RuntimeException('ECDAA not supported'); + throw UnsupportedFeatureException::create('ECDAA not supported'); } private function processWithSelfAttestation( @@ -209,31 +266,35 @@ final class PackedAttestationStatementSupport implements AttestationStatementSup AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); - Assertion::notNull($attestedCredentialData, 'No attested credential available'); - $credentialPublicKey = $attestedCredentialData->getCredentialPublicKey(); - Assertion::notNull($credentialPublicKey, 'No credential public key available'); + $attestedCredentialData = $authenticatorData->attestedCredentialData; + $attestedCredentialData !== null || throw AttestationStatementVerificationException::create( + 'No attested credential available' + ); + $credentialPublicKey = $attestedCredentialData->credentialPublicKey; + $credentialPublicKey !== null || throw AttestationStatementVerificationException::create( + 'No credential public key available' + ); $publicKeyStream = new StringStream($credentialPublicKey); $publicKey = $this->decoder->decode($publicKeyStream); - Assertion::true($publicKeyStream->isEOF(), 'Invalid public key. Presence of extra bytes.'); + $publicKeyStream->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid public key. Presence of extra bytes.' + ); $publicKeyStream->close(); - Assertion::isInstanceOf( - $publicKey, - MapObject::class, + $publicKey instanceof MapObject || throw AttestationStatementVerificationException::create( 'The attested credential data does not contain a valid public key.' ); $publicKey = $publicKey->normalize(); $publicKey = new Key($publicKey); - Assertion::eq( - $publicKey->alg(), - (int) $attestationStatement->get('alg'), + $publicKey->alg() === (int) $attestationStatement->get( + 'alg' + ) || throw AttestationStatementVerificationException::create( 'The algorithm of the attestation statement and the key are not identical.' ); - $dataToVerify = $authenticatorData->getAuthData() . $clientDataJSONHash; + $dataToVerify = $authenticatorData->authData . $clientDataJSONHash; $algorithm = $this->algorithmManager->get((int) $attestationStatement->get('alg')); if (! $algorithm instanceof Signature) { - throw new RuntimeException('Invalid algorithm'); + throw InvalidDataException::create($algorithm, 'Invalid algorithm'); } $signature = CoseSignatureFixer::fix($attestationStatement->get('sig'), $algorithm); diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php index 1d81eff8c..7f027ef83 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Webauthn\AttestationStatement; -use Assert\Assertion; use CBOR\Decoder; use CBOR\MapObject; use Cose\Algorithms; @@ -12,26 +11,62 @@ use Cose\Key\Ec2Key; use Cose\Key\Key; use Cose\Key\OkpKey; use Cose\Key\RsaKey; -use function count; -use function in_array; -use InvalidArgumentException; -use function is_array; -use RuntimeException; -use Safe\DateTimeImmutable; -use function Safe\openssl_verify; -use function Safe\unpack; +use DateTimeImmutable; +use DateTimeZone; +use Lcobucci\Clock\Clock; +use Lcobucci\Clock\SystemClock; +use ParagonIE\ConstantTime\Base64UrlSafe; +use Psr\Clock\ClockInterface; +use Psr\EventDispatcher\EventDispatcherInterface; use Webauthn\AuthenticatorData; -use Webauthn\CertificateToolbox; +use Webauthn\Event\AttestationStatementLoaded; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AttestationStatementLoadingException; +use Webauthn\Exception\AttestationStatementVerificationException; +use Webauthn\Exception\InvalidAttestationStatementException; +use Webauthn\Exception\UnsupportedFeatureException; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox; use Webauthn\StringStream; use Webauthn\TrustPath\CertificateTrustPath; use Webauthn\TrustPath\EcdaaKeyIdTrustPath; -use Webauthn\Util\Base64; +use function array_key_exists; +use function count; +use function in_array; +use function is_array; +use function is_int; +use function openssl_verify; +use function sprintf; +use function unpack; -final class TPMAttestationStatementSupport implements AttestationStatementSupport +final class TPMAttestationStatementSupport implements AttestationStatementSupport, CanDispatchEvents { - public static function create(): self + private readonly Clock|ClockInterface $clock; + + private EventDispatcherInterface $dispatcher; + + public function __construct(null|Clock|ClockInterface $clock = null) { - return new self(); + if ($clock === null) { + trigger_deprecation( + 'web-auth/metadata-service', + '4.5.0', + 'The parameter "$clock" will become mandatory in 5.0.0. Please set a valid PSR Clock implementation instead of "null".' + ); + $clock = new SystemClock(new DateTimeZone('UTC')); + } + $this->clock = $clock; + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + public static function create(null|Clock|ClockInterface $clock = null): self + { + return new self($clock); } public function name(): string @@ -44,19 +79,30 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor */ public function load(array $attestation): AttestationStatement { - Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); - Assertion::keyNotExists($attestation['attStmt'], 'ecdaaKeyId', 'ECDAA not supported'); + array_key_exists('attStmt', $attestation) || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); + ! array_key_exists( + 'ecdaaKeyId', + $attestation['attStmt'] + ) || throw AttestationStatementLoadingException::create($attestation, 'ECDAA not supported'); foreach (['ver', 'ver', 'sig', 'alg', 'certInfo', 'pubArea'] as $key) { - Assertion::keyExists( - $attestation['attStmt'], - $key, + array_key_exists($key, $attestation['attStmt']) || throw AttestationStatementLoadingException::create( + $attestation, sprintf('The attestation statement value "%s" is missing.', $key) ); } - Assertion::eq('2.0', $attestation['attStmt']['ver'], 'Invalid attestation object'); + $attestation['attStmt']['ver'] === '2.0' || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); $certInfo = $this->checkCertInfo($attestation['attStmt']['certInfo']); - Assertion::eq('8017', bin2hex((string) $certInfo['type']), 'Invalid attestation object'); + bin2hex((string) $certInfo['type']) === '8017' || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attestation object' + ); $pubArea = $this->checkPubArea($attestation['attStmt']['pubArea']); $pubAreaAttestedNameAlg = mb_substr((string) $certInfo['attestedName'], 0, 2, '8bit'); @@ -66,23 +112,28 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor true ); $attestedName = $pubAreaAttestedNameAlg . $pubAreaHash; - Assertion::eq($attestedName, $certInfo['attestedName'], 'Invalid attested name'); + $attestedName === $certInfo['attestedName'] || throw AttestationStatementLoadingException::create( + $attestation, + 'Invalid attested name' + ); $attestation['attStmt']['parsedCertInfo'] = $certInfo; $attestation['attStmt']['parsedPubArea'] = $pubArea; $certificates = CertificateToolbox::convertAllDERToPEM($attestation['attStmt']['x5c']); - Assertion::minCount( - $certificates, - 1, + count($certificates) > 0 || throw AttestationStatementLoadingException::create( + $attestation, 'The attestation statement value "x5c" must be a list with at least one certificate.' ); - return AttestationStatement::createAttCA( + $attestationStatement = AttestationStatement::createAttCA( $this->name(), $attestation['attStmt'], - new CertificateTrustPath($certificates) + CertificateTrustPath::create($certificates) ); + $this->dispatcher->dispatch(AttestationStatementLoaded::create($attestationStatement)); + + return $attestationStatement; } public function isValid( @@ -90,28 +141,35 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $attToBeSigned = $authenticatorData->getAuthData() . $clientDataJSONHash; + $attToBeSigned = $authenticatorData->authData . $clientDataJSONHash; $attToBeSignedHash = hash( Algorithms::getHashAlgorithmFor((int) $attestationStatement->get('alg')), $attToBeSigned, true ); - Assertion::eq( - $attestationStatement->get('parsedCertInfo')['extraData'], - $attToBeSignedHash, + $attestationStatement->get( + 'parsedCertInfo' + )['extraData'] === $attToBeSignedHash || throw InvalidAttestationStatementException::create( + $attestationStatement, 'Invalid attestation hash' ); - $credentialPublicKey = $authenticatorData->getAttestedCredentialData()?->getCredentialPublicKey(); - Assertion::notNull($credentialPublicKey, 'Not credential public key available in the attested credential data'); + $credentialPublicKey = $authenticatorData->attestedCredentialData?->credentialPublicKey; + $credentialPublicKey !== null || throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Not credential public key available in the attested credential data' + ); $this->checkUniquePublicKey($attestationStatement->get('parsedPubArea')['unique'], $credentialPublicKey); return match (true) { - $attestationStatement->getTrustPath() instanceof CertificateTrustPath => $this->processWithCertificate( + $attestationStatement->trustPath instanceof CertificateTrustPath => $this->processWithCertificate( $attestationStatement, $authenticatorData ), - $attestationStatement->getTrustPath() instanceof EcdaaKeyIdTrustPath => $this->processWithECDAA(), - default => throw new InvalidArgumentException('Unsupported attestation statement'), + $attestationStatement->trustPath instanceof EcdaaKeyIdTrustPath => $this->processWithECDAA(), + default => throw InvalidAttestationStatementException::create( + $attestationStatement, + 'Unsupported attestation statement' + ), }; } @@ -119,7 +177,9 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor { $cborDecoder = Decoder::create(); $publicKey = $cborDecoder->decode(new StringStream($cborPublicKey)); - Assertion::isInstanceOf($publicKey, MapObject::class, 'Invalid public key'); + $publicKey instanceof MapObject || throw AttestationStatementVerificationException::create( + 'Invalid public key' + ); $key = Key::create($publicKey->normalize()); switch ($key->type()) { @@ -134,10 +194,12 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor $uniqueFromKey = (new RsaKey($key->getData()))->n(); break; default: - throw new InvalidArgumentException('Invalid or unsupported key type.'); + throw AttestationStatementVerificationException::create('Invalid or unsupported key type.'); } - Assertion::eq($unique, $uniqueFromKey, 'Invalid pubArea.unique value'); + $unique === $uniqueFromKey || throw AttestationStatementVerificationException::create( + 'Invalid pubArea.unique value' + ); } /** @@ -148,7 +210,9 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor $certInfo = new StringStream($data); $magic = $certInfo->read(4); - Assertion::eq('ff544347', bin2hex($magic), 'Invalid attestation object'); + bin2hex($magic) === 'ff544347' || throw AttestationStatementVerificationException::create( + 'Invalid attestation object' + ); $type = $certInfo->read(2); @@ -167,7 +231,9 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor $attestedQualifiedNameLength = unpack('n', $certInfo->read(2))[1]; $attestedQualifiedName = $certInfo->read($attestedQualifiedNameLength); //Ignore - Assertion::true($certInfo->isEOF(), 'Invalid certificate information. Presence of extra bytes.'); + $certInfo->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid certificate information. Presence of extra bytes.' + ); $certInfo->close(); return [ @@ -200,9 +266,10 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor $parameters = $this->getParameters($type, $pubArea); - $uniqueLength = unpack('n', $pubArea->read(2))[1]; - $unique = $pubArea->read($uniqueLength); - Assertion::true($pubArea->isEOF(), 'Invalid public area. Presence of extra bytes.'); + $unique = $this->getUnique($type, $pubArea); + $pubArea->isEOF() || throw AttestationStatementVerificationException::create( + 'Invalid public area. Presence of extra bytes.' + ); $pubArea->close(); return [ @@ -221,25 +288,42 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor private function getParameters(string $type, StringStream $stream): array { return match (bin2hex($type)) { - '0001', '0014', '0016' => [ + '0001' => [ 'symmetric' => $stream->read(2), 'scheme' => $stream->read(2), 'keyBits' => unpack('n', $stream->read(2))[1], 'exponent' => $this->getExponent($stream->read(4)), ], - '0018' => [ + '0023' => [ 'symmetric' => $stream->read(2), 'scheme' => $stream->read(2), 'curveId' => $stream->read(2), 'kdf' => $stream->read(2), ], - default => throw new InvalidArgumentException('Unsupported type'), + default => throw AttestationStatementVerificationException::create('Unsupported type'), }; } + private function getUnique(string $type, StringStream $stream): string + { + switch (bin2hex($type)) { + case '0001': + $uniqueLength = unpack('n', $stream->read(2))[1]; + return $stream->read($uniqueLength); + case '0023': + $xLen = unpack('n', $stream->read(2))[1]; + $x = $stream->read($xLen); + $yLen = unpack('n', $stream->read(2))[1]; + $y = $stream->read($yLen); + return "\04" . $x . $y; + default: + throw AttestationStatementVerificationException::create('Unsupported type'); + } + } + private function getExponent(string $exponent): string { - return bin2hex($exponent) === '00000000' ? Base64::decodeUrlSafe('AQAB') : $exponent; + return bin2hex($exponent) === '00000000' ? Base64UrlSafe::decodeNoPadding('AQAB') : $exponent; } private function getTPMHash(string $nameAlg): string @@ -249,7 +333,7 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor '000b' => 'sha256', '000c' => 'sha384', '000d' => 'sha512', - default => throw new InvalidArgumentException('Unsupported hash algorithm'), + default => throw AttestationStatementVerificationException::create('Unsupported hash algorithm'), }; } @@ -257,10 +341,12 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData ): bool { - $trustPath = $attestationStatement->getTrustPath(); - Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + $trustPath = $attestationStatement->trustPath; + $trustPath instanceof CertificateTrustPath || throw AttestationStatementVerificationException::create( + 'Invalid trust path' + ); - $certificates = $trustPath->getCertificates(); + $certificates = $trustPath->certificates; // Check certificate CA chain and returns the Attestation Certificate $this->checkCertificate($certificates[0], $authenticatorData); @@ -282,55 +368,79 @@ final class TPMAttestationStatementSupport implements AttestationStatementSuppor private function checkCertificate(string $attestnCert, AuthenticatorData $authenticatorData): void { $parsed = openssl_x509_parse($attestnCert); - Assertion::isArray($parsed, 'Invalid certificate'); + is_array($parsed) || throw AttestationStatementVerificationException::create('Invalid certificate'); //Check version - Assertion::false(! isset($parsed['version']) || $parsed['version'] !== 2, 'Invalid certificate version'); + (isset($parsed['version']) && $parsed['version'] === 2) || throw AttestationStatementVerificationException::create( + 'Invalid certificate version' + ); //Check subject field is empty - Assertion::false( - ! isset($parsed['subject']) || ! is_array($parsed['subject']) || count($parsed['subject']) !== 0, + isset($parsed['subject']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate name. The Subject should be empty' + ); + is_array($parsed['subject']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate name. The Subject should be empty' + ); + count($parsed['subject']) === 0 || throw AttestationStatementVerificationException::create( 'Invalid certificate name. The Subject should be empty' ); // Check period of validity - Assertion::keyExists($parsed, 'validFrom_time_t', 'Invalid certificate start date.'); - Assertion::integer($parsed['validFrom_time_t'], 'Invalid certificate start date.'); + array_key_exists( + 'validFrom_time_t', + $parsed + ) || throw AttestationStatementVerificationException::create('Invalid certificate start date.'); + is_int($parsed['validFrom_time_t']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate start date.' + ); $startDate = (new DateTimeImmutable())->setTimestamp($parsed['validFrom_time_t']); - Assertion::true($startDate < new DateTimeImmutable(), 'Invalid certificate start date.'); - - Assertion::keyExists($parsed, 'validTo_time_t', 'Invalid certificate end date.'); - Assertion::integer($parsed['validTo_time_t'], 'Invalid certificate end date.'); - $endDate = (new DateTimeImmutable())->setTimestamp($parsed['validTo_time_t']); - Assertion::true($endDate > new DateTimeImmutable(), 'Invalid certificate end date.'); - - //Check extensions - Assertion::false( - ! isset($parsed['extensions']) || ! is_array($parsed['extensions']), - 'Certificate extensions are missing' + $startDate < $this->clock->now() || throw AttestationStatementVerificationException::create( + 'Invalid certificate start date.' ); + array_key_exists('validTo_time_t', $parsed) || throw AttestationStatementVerificationException::create( + 'Invalid certificate end date.' + ); + is_int($parsed['validTo_time_t']) || throw AttestationStatementVerificationException::create( + 'Invalid certificate end date.' + ); + $endDate = (new DateTimeImmutable())->setTimestamp($parsed['validTo_time_t']); + $endDate > $this->clock->now() || throw AttestationStatementVerificationException::create( + 'Invalid certificate end date.' + ); + + //Check extensions + (isset($parsed['extensions']) && is_array( + $parsed['extensions'] + )) || throw AttestationStatementVerificationException::create('Certificate extensions are missing'); + //Check subjectAltName - Assertion::false(! isset($parsed['extensions']['subjectAltName']), 'The "subjectAltName" is missing'); + isset($parsed['extensions']['subjectAltName']) || throw AttestationStatementVerificationException::create( + 'The "subjectAltName" is missing' + ); //Check extendedKeyUsage - Assertion::false(! isset($parsed['extensions']['extendedKeyUsage']), 'The "subjectAltName" is missing'); - Assertion::eq($parsed['extensions']['extendedKeyUsage'], '2.23.133.8.3', 'The "extendedKeyUsage" is invalid'); + isset($parsed['extensions']['extendedKeyUsage']) || throw AttestationStatementVerificationException::create( + 'The "subjectAltName" is missing' + ); + $parsed['extensions']['extendedKeyUsage'] === '2.23.133.8.3' || throw AttestationStatementVerificationException::create( + 'The "extendedKeyUsage" is invalid' + ); // id-fido-gen-ce-aaguid OID check - Assertion::false( - in_array('1.3.6.1.4.1.45724.1.1.4', $parsed['extensions'], true) && ! hash_equals( - $authenticatorData->getAttestedCredentialData() - ?->getAaguid() - ->toBinary() ?? '', - $parsed['extensions']['1.3.6.1.4.1.45724.1.1.4'] - ), + in_array('1.3.6.1.4.1.45724.1.1.4', $parsed['extensions'], true) && ! hash_equals( + $authenticatorData->attestedCredentialData + ?->aaguid + ->toBinary() ?? '', + $parsed['extensions']['1.3.6.1.4.1.45724.1.1.4'] + ) && throw AttestationStatementVerificationException::create( 'The value of the "aaguid" does not match with the certificate' ); } private function processWithECDAA(): never { - throw new RuntimeException('ECDAA not supported'); + throw UnsupportedFeatureException::create('ECDAA not supported'); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php index ca8724ed9..a97f3fa49 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php @@ -4,11 +4,12 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; use JsonSerializable; use ParagonIE\ConstantTime\Base64; -use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Uuid; +use Webauthn\Exception\InvalidDataException; +use function array_key_exists; +use function is_string; /** * @see https://www.w3.org/TR/webauthn/#sec-attested-credential-data @@ -16,27 +17,48 @@ use Symfony\Component\Uid\Uuid; class AttestedCredentialData implements JsonSerializable { public function __construct( - private AbstractUid $aaguid, - private readonly string $credentialId, - private readonly ?string $credentialPublicKey + public Uuid $aaguid, + public readonly string $credentialId, + public readonly ?string $credentialPublicKey ) { } - public function getAaguid(): AbstractUid + public static function create(Uuid $aaguid, string $credentialId, ?string $credentialPublicKey = null): self + { + return new self($aaguid, $credentialId, $credentialPublicKey); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAaguid(): Uuid { return $this->aaguid; } - public function setAaguid(AbstractUid $aaguid): void + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function setAaguid(Uuid $aaguid): void { $this->aaguid = $aaguid; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getCredentialId(): string { return $this->credentialId; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getCredentialPublicKey(): ?string { return $this->credentialPublicKey; @@ -44,18 +66,34 @@ class AttestedCredentialData implements JsonSerializable /** * @param mixed[] $json + * @deprecated since 4.9.0 and will be removed in 5.0.0. Please use the serializer instead. */ public static function createFromArray(array $json): self { - Assertion::keyExists($json, 'aaguid', 'Invalid input. "aaguid" is missing.'); + array_key_exists('aaguid', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "aaguid" is missing.' + ); $aaguid = $json['aaguid']; - Assertion::string($aaguid, 'Invalid input. "aaguid" shall be a string of 36 characters'); - Assertion::length($aaguid, 36, 'Invalid input. "aaguid" shall be a string of 36 characters'); - $uuid = Uuid::fromString($json['aaguid']); + is_string($aaguid) || throw InvalidDataException::create( + $json, + 'Invalid input. "aaguid" shall be a string of 36 characters' + ); + mb_strlen($aaguid, '8bit') === 36 || throw InvalidDataException::create( + $json, + 'Invalid input. "aaguid" shall be a string of 36 characters' + ); + $uuid = Uuid::fromString($aaguid); - Assertion::keyExists($json, 'credentialId', 'Invalid input. "credentialId" is missing.'); + array_key_exists('credentialId', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "credentialId" is missing.' + ); $credentialId = $json['credentialId']; - Assertion::string($credentialId, 'Invalid input. "credentialId" shall be a string'); + is_string($credentialId) || throw InvalidDataException::create( + $json, + 'Invalid input. "credentialId" shall be a string' + ); $credentialId = Base64::decode($credentialId, true); $credentialPublicKey = null; @@ -63,7 +101,7 @@ class AttestedCredentialData implements JsonSerializable $credentialPublicKey = Base64::decode($json['credentialPublicKey'], true); } - return new self($uuid, $credentialId, $credentialPublicKey); + return self::create($uuid, $credentialId, $credentialPublicKey); } /** @@ -71,6 +109,12 @@ class AttestedCredentialData implements JsonSerializable */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $result = [ 'aaguid' => $this->aaguid->__toString(), 'credentialId' => base64_encode($this->credentialId), diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php index a2a4c1e1c..384476a1e 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php @@ -9,8 +9,8 @@ use JsonSerializable; class AuthenticationExtension implements JsonSerializable { public function __construct( - private readonly string $name, - private readonly mixed $value + public readonly string $name, + public readonly mixed $value ) { } @@ -19,11 +19,19 @@ class AuthenticationExtension implements JsonSerializable return new self($name, $value); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function name(): string { return $this->name; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function value(): mixed { return $this->value; @@ -31,6 +39,12 @@ class AuthenticationExtension implements JsonSerializable public function jsonSerialize(): mixed { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); return $this->value; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensions.php new file mode 100644 index 000000000..5315524e9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensions.php @@ -0,0 +1,165 @@ + + * @final + */ +class AuthenticationExtensions implements JsonSerializable, Countable, IteratorAggregate, ArrayAccess +{ + /** + * @var array + * @readonly + */ + public array $extensions; + + /** + * @param array $extensions + */ + public function __construct(array $extensions = []) + { + $list = []; + foreach ($extensions as $key => $extension) { + if ($extension instanceof AuthenticationExtension) { + $list[$extension->name] = $extension; + + continue; + } + if (is_string($key)) { + $list[$key] = AuthenticationExtension::create($key, $extension); + continue; + } + throw new AuthenticationExtensionException('Invalid extension'); + } + $this->extensions = $list; + } + + /** + * @param array $extensions + */ + public static function create(array $extensions = []): static + { + return new static($extensions); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function add(AuthenticationExtension ...$extensions): static + { + foreach ($extensions as $extension) { + $this->extensions[$extension->name] = $extension; + } + + return $this; + } + + /** + * @param array $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $json): static + { + return static::create( + array_map( + static fn (string $key, mixed $value): AuthenticationExtension => AuthenticationExtension::create( + $key, + $value + ), + array_keys($json), + $json + ) + ); + } + + public function has(string $key): bool + { + return array_key_exists($key, $this->extensions); + } + + public function get(string $key): AuthenticationExtension + { + $this->has($key) || throw AuthenticationExtensionException::create(sprintf( + 'The extension with key "%s" is not available', + $key + )); + + return $this->extensions[$key]; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return $this->extensions; + } + + /** + * @return Iterator + */ + public function getIterator(): Iterator + { + return new ArrayIterator($this->extensions); + } + + public function count(int $mode = COUNT_NORMAL): int + { + return count($this->extensions, $mode); + } + + public function offsetExists(mixed $offset): bool + { + return array_key_exists($offset, $this->extensions); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->extensions[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if ($value === null) { + return; + } + if ($value instanceof AuthenticationExtension) { + $this->extensions[$value->name] = $value; + return; + } + if (is_string($offset)) { + $this->extensions[$offset] = AuthenticationExtension::create($offset, $value); + return; + } + throw new AuthenticationExtensionException('Invalid extension'); + } + + public function offsetUnset(mixed $offset): void + { + unset($this->extensions[$offset]); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php index 2febddb6b..5e0548405 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php @@ -4,83 +4,9 @@ declare(strict_types=1); namespace Webauthn\AuthenticationExtensions; -use function array_key_exists; -use ArrayIterator; -use Assert\Assertion; -use function count; -use const COUNT_NORMAL; -use Countable; -use Iterator; -use IteratorAggregate; -use JsonSerializable; - /** - * @implements IteratorAggregate + * @deprecated since 4.8.0. Use {Webauthn\AuthenticationExtensions\AuthenticationExtensions} instead. */ -class AuthenticationExtensionsClientInputs implements JsonSerializable, Countable, IteratorAggregate +class AuthenticationExtensionsClientInputs extends AuthenticationExtensions { - /** - * @var AuthenticationExtension[] - */ - private array $extensions = []; - - public static function create(): self - { - return new self(); - } - - public function add(AuthenticationExtension ...$extensions): self - { - foreach ($extensions as $extension) { - $this->extensions[$extension->name()] = $extension; - } - - return $this; - } - - /** - * @param array $json - */ - public static function createFromArray(array $json): self - { - $object = new self(); - foreach ($json as $k => $v) { - $object->add(AuthenticationExtension::create($k, $v)); - } - - return $object; - } - - public function has(string $key): bool - { - return array_key_exists($key, $this->extensions); - } - - public function get(string $key): AuthenticationExtension - { - Assertion::true($this->has($key), sprintf('The extension with key "%s" is not available', $key)); - - return $this->extensions[$key]; - } - - /** - * @return AuthenticationExtension[] - */ - public function jsonSerialize(): array - { - return array_map(static fn (AuthenticationExtension $object) => $object->jsonSerialize(), $this->extensions); - } - - /** - * @return Iterator - */ - public function getIterator(): Iterator - { - return new ArrayIterator($this->extensions); - } - - public function count(int $mode = COUNT_NORMAL): int - { - return count($this->extensions, $mode); - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php index 7943199b1..fdfe12994 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php @@ -4,90 +4,9 @@ declare(strict_types=1); namespace Webauthn\AuthenticationExtensions; -use function array_key_exists; -use ArrayIterator; -use Assert\Assertion; -use function count; -use const COUNT_NORMAL; -use Countable; -use Iterator; -use IteratorAggregate; -use const JSON_THROW_ON_ERROR; -use JsonSerializable; - /** - * @implements IteratorAggregate + * @deprecated since 4.8.0. Use {Webauthn\AuthenticationExtensions\AuthenticationExtensions} instead. */ -class AuthenticationExtensionsClientOutputs implements JsonSerializable, Countable, IteratorAggregate +class AuthenticationExtensionsClientOutputs extends AuthenticationExtensions { - /** - * @var AuthenticationExtension[] - */ - private array $extensions = []; - - public static function create(): self - { - return new self(); - } - - public function add(AuthenticationExtension ...$extensions): void - { - foreach ($extensions as $extension) { - $this->extensions[$extension->name()] = $extension; - } - } - - public static function createFromString(string $data): self - { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); - - return self::createFromArray($data); - } - - /** - * @param array $json - */ - public static function createFromArray(array $json): self - { - $object = new self(); - foreach ($json as $k => $v) { - $object->add(AuthenticationExtension::create($k, $v)); - } - - return $object; - } - - public function has(string $key): bool - { - return array_key_exists($key, $this->extensions); - } - - public function get(string $key): AuthenticationExtension - { - Assertion::true($this->has($key), sprintf('The extension with key "%s" is not available', $key)); - - return $this->extensions[$key]; - } - - /** - * @return AuthenticationExtension[] - */ - public function jsonSerialize(): array - { - return array_map(static fn (AuthenticationExtension $object) => $object->jsonSerialize(), $this->extensions); - } - - /** - * @return Iterator - */ - public function getIterator(): Iterator - { - return new ArrayIterator($this->extensions); - } - - public function count(int $mode = COUNT_NORMAL): int - { - return count($this->extensions, $mode); - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php index 70702a5ca..ddf5e49f6 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php @@ -4,22 +4,22 @@ declare(strict_types=1); namespace Webauthn\AuthenticationExtensions; -use Assert\Assertion; use CBOR\CBORObject; use CBOR\MapObject; +use Webauthn\Exception\AuthenticationExtensionException; abstract class AuthenticationExtensionsClientOutputsLoader { - public static function load(CBORObject $object): AuthenticationExtensionsClientOutputs + public static function load(CBORObject $object): AuthenticationExtensions { - Assertion::isInstanceOf($object, MapObject::class, 'Invalid extension object'); + $object instanceof MapObject || throw AuthenticationExtensionException::create('Invalid extension object'); $data = $object->normalize(); - $extensions = AuthenticationExtensionsClientOutputs::create(); - foreach ($data as $key => $value) { - Assertion::string($key, 'Invalid extension key'); - $extensions->add(AuthenticationExtension::create($key, $value)); - } - - return $extensions; + return AuthenticationExtensionsClientOutputs::create( + array_map( + fn (mixed $value, string $key) => AuthenticationExtension::create($key, $value), + $data, + array_keys($data) + ) + ); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php index e5a99ff94..7dda0796b 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php @@ -6,8 +6,5 @@ namespace Webauthn\AuthenticationExtensions; interface ExtensionOutputChecker { - public function check( - AuthenticationExtensionsClientInputs $inputs, - AuthenticationExtensionsClientOutputs $outputs - ): void; + public function check(AuthenticationExtensions $inputs, AuthenticationExtensions $outputs): void; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputCheckerHandler.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputCheckerHandler.php index 1ccd6c1cf..d50887d40 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputCheckerHandler.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputCheckerHandler.php @@ -21,10 +21,8 @@ class ExtensionOutputCheckerHandler $this->checkers[] = $checker; } - public function check( - AuthenticationExtensionsClientInputs $inputs, - AuthenticationExtensionsClientOutputs $outputs - ): void { + public function check(AuthenticationExtensions $inputs, AuthenticationExtensions $outputs): void + { foreach ($this->checkers as $checker) { $checker->check($inputs, $outputs); } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php index 238311337..9310befa5 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php @@ -10,14 +10,18 @@ use Throwable; class ExtensionOutputError extends Exception { public function __construct( - private readonly AuthenticationExtension $authenticationExtension, + public readonly AuthenticationExtension $authenticationExtension, string $message = '', int $code = 0, - Throwable $previous = null + ?Throwable $previous = null ) { parent::__construct($message, $code, $previous); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAuthenticationExtension(): AuthenticationExtension { return $this->authenticationExtension; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php index c815cccff..8b105a429 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Webauthn; -use ParagonIE\ConstantTime\Base64; +use Webauthn\AttestationStatement\AttestationObject; /** * @see https://www.w3.org/TR/webauthn/#authenticatorassertionresponse @@ -13,29 +13,39 @@ class AuthenticatorAssertionResponse extends AuthenticatorResponse { public function __construct( CollectedClientData $clientDataJSON, - private readonly AuthenticatorData $authenticatorData, - private readonly string $signature, - private readonly ?string $userHandle + public readonly AuthenticatorData $authenticatorData, + public readonly string $signature, + public readonly ?string $userHandle, + public readonly null|AttestationObject $attestationObject = null, ) { parent::__construct($clientDataJSON); } - public function getAuthenticatorData(): AuthenticatorData - { - return $this->authenticatorData; + public static function create( + CollectedClientData $clientDataJSON, + AuthenticatorData $authenticatorData, + string $signature, + ?string $userHandle = null, + null|AttestationObject $attestationObject = null, + ): self { + return new self($clientDataJSON, $authenticatorData, $signature, $userHandle, $attestationObject); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getSignature(): string { return $this->signature; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getUserHandle(): ?string { - if ($this->userHandle === null || $this->userHandle === '') { - return $this->userHandle; - } - - return Base64::decode($this->userHandle, true); + return $this->userHandle; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php index 7d85a092c..d6923b724 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php @@ -4,58 +4,111 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use CBOR\Decoder; -use CBOR\Normalizable; use Cose\Algorithm\Manager; -use Cose\Algorithm\Signature\Signature; -use Cose\Key\Key; -use function count; -use function in_array; -use function is_string; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use function Safe\parse_url; use Throwable; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputs; use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler; +use Webauthn\CeremonyStep\CeremonyStepManager; +use Webauthn\CeremonyStep\CeremonyStepManagerFactory; use Webauthn\Counter\CounterChecker; -use Webauthn\Counter\ThrowExceptionIfInvalid; +use Webauthn\Event\AuthenticatorAssertionResponseValidationFailedEvent; +use Webauthn\Event\AuthenticatorAssertionResponseValidationSucceededEvent; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AuthenticatorResponseVerificationException; +use Webauthn\MetadataService\CanLogData; use Webauthn\TokenBinding\TokenBindingHandler; -use Webauthn\Util\CoseSignatureFixer; +use function is_string; +use function sprintf; -class AuthenticatorAssertionResponseValidator +class AuthenticatorAssertionResponseValidator implements CanLogData, CanDispatchEvents { - private readonly Decoder $decoder; - - private CounterChecker $counterChecker; - private LoggerInterface $logger; + private readonly CeremonyStepManagerFactory $ceremonyStepManagerFactory; + + private EventDispatcherInterface $eventDispatcher; + public function __construct( - private readonly PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository, - private readonly TokenBindingHandler $tokenBindingHandler, - private readonly ExtensionOutputCheckerHandler $extensionOutputCheckerHandler, - private readonly ?Manager $algorithmManager, + private readonly null|PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository = null, + private readonly null|TokenBindingHandler $tokenBindingHandler = null, + null|ExtensionOutputCheckerHandler $extensionOutputCheckerHandler = null, + null|Manager $algorithmManager = null, + null|EventDispatcherInterface $eventDispatcher = null, + private null|CeremonyStepManager $ceremonyStepManager = null ) { - $this->decoder = Decoder::create(); - $this->counterChecker = new ThrowExceptionIfInvalid(); + if ($this->publicKeyCredentialSourceRepository !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.6.0', + 'The parameter "$publicKeyCredentialSourceRepository" is deprecated since 4.6.0 and will be removed in 5.0.0. Please set "null" instead.' + ); + } + if ($this->tokenBindingHandler !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.3.0', + 'The parameter "$tokenBindingHandler" is deprecated since 4.3.0 and will be removed in 5.0.0. Please set "null" instead.' + ); + } + if ($extensionOutputCheckerHandler !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$extensionOutputCheckerHandler" is deprecated since 4.8.0 and will be removed in 5.0.0. Please set "null" instead and inject a CheckExtensions object into the CeremonyStepManager.' + ); + } + if ($algorithmManager !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$algorithmManager" is deprecated since 4.8.0 and will be removed in 5.0.0. Please set "null" instead and inject a CheckSignature object into the CeremonyStepManager.' + ); + } + $this->eventDispatcher = $eventDispatcher ?? new NullEventDispatcher(); + if ($eventDispatcher !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + 'The parameter "$eventDispatcher" is deprecated since 4.5.0 will be removed in 5.0.0. Please use `setEventDispatcher` instead.' + ); + } + if ($this->ceremonyStepManager === null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$ceremonyStepManager" will mandatory in 5.0.0. Please set a CeremonyStepManager object instead and set null for $algorithmManager and $extensionOutputCheckerHandler.' + ); + } $this->logger = new NullLogger(); + + $this->ceremonyStepManagerFactory = new CeremonyStepManagerFactory(); + if ($extensionOutputCheckerHandler !== null) { + $this->ceremonyStepManagerFactory->setExtensionOutputCheckerHandler($extensionOutputCheckerHandler); + } + if ($algorithmManager !== null) { + $this->ceremonyStepManagerFactory->setAlgorithmManager($algorithmManager); + } } public static function create( - PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository, - TokenBindingHandler $tokenBindingHandler, - ExtensionOutputCheckerHandler $extensionOutputCheckerHandler, - ?Manager $algorithmManager, + null|PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository = null, + null|TokenBindingHandler $tokenBindingHandler = null, + null|ExtensionOutputCheckerHandler $extensionOutputCheckerHandler = null, + null|Manager $algorithmManager = null, + null|EventDispatcherInterface $eventDispatcher = null, + null|CeremonyStepManager $ceremonyStepManager = null ): self { return new self( $publicKeyCredentialSourceRepository, $tokenBindingHandler, $extensionOutputCheckerHandler, - $algorithmManager + $algorithmManager, + $eventDispatcher, + $ceremonyStepManager ); } @@ -65,222 +118,209 @@ class AuthenticatorAssertionResponseValidator * @see https://www.w3.org/TR/webauthn/#verifying-assertion */ public function check( - string $credentialId, + string|PublicKeyCredentialSource $credentialId, AuthenticatorAssertionResponse $authenticatorAssertionResponse, PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, - ServerRequestInterface $request, + ServerRequestInterface|string $request, ?string $userHandle, - array $securedRelyingPartyId = [] + null|array $securedRelyingPartyId = null ): PublicKeyCredentialSource { - try { - $this->logger->info('Checking the authenticator assertion response', [ - 'credentialId' => $credentialId, - 'authenticatorAssertionResponse' => $authenticatorAssertionResponse, - 'publicKeyCredentialRequestOptions' => $publicKeyCredentialRequestOptions, - 'host' => $request->getUri() - ->getHost(), - 'userHandle' => $userHandle, - ]); - if (count($publicKeyCredentialRequestOptions->getAllowCredentials()) !== 0) { - Assertion::true( - $this->isCredentialIdAllowed( - $credentialId, - $publicKeyCredentialRequestOptions->getAllowCredentials() - ), - 'The credential ID is not allowed.' - ); - } + if ($request instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + sprintf( + 'Passing a %s to the method `check` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class + ) + ); + } + if (is_string($credentialId)) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.6.0', + sprintf( + 'Passing a string as first to the method `check` of the class "%s" is deprecated since 4.6.0. Please inject a %s object instead.', + self::class, + PublicKeyCredentialSource::class + ) + ); + } + if ($securedRelyingPartyId !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + sprintf( + 'Passing a list or secured relying party IDs to the method `check` of the class "%s" is deprecated since 4.8.0 and will be removed in 5.0.0. Please inject a CheckOrigin into the CeremonyStepManager instead.', + self::class + ) + ); + } + if ($credentialId instanceof PublicKeyCredentialSource) { + $publicKeyCredentialSource = $credentialId; + } else { + $this->publicKeyCredentialSourceRepository instanceof PublicKeyCredentialSourceRepository || throw AuthenticatorResponseVerificationException::create( + 'Please pass the Public Key Credential Source to the method "check".' + ); $publicKeyCredentialSource = $this->publicKeyCredentialSourceRepository->findOneByCredentialId( $credentialId ); - Assertion::notNull($publicKeyCredentialSource, 'The credential ID is invalid.'); + } + $publicKeyCredentialSource !== null || throw AuthenticatorResponseVerificationException::create( + 'The credential ID is invalid.' + ); + $host = is_string($request) ? $request : $request->getUri() + ->getHost(); - $attestedCredentialData = $publicKeyCredentialSource->getAttestedCredentialData(); - $credentialUserHandle = $publicKeyCredentialSource->getUserHandle(); - $responseUserHandle = $authenticatorAssertionResponse->getUserHandle(); + if ($this->ceremonyStepManager === null) { + $this->ceremonyStepManager = $this->ceremonyStepManagerFactory->requestCeremony($securedRelyingPartyId); + } - if ($userHandle !== null) { //If the user was identified before the authentication ceremony was initiated, - Assertion::eq($credentialUserHandle, $userHandle, 'Invalid user handle'); - if ($responseUserHandle !== null && $responseUserHandle !== '') { - Assertion::eq($credentialUserHandle, $responseUserHandle, 'Invalid user handle'); - } - } else { - Assertion::notEmpty($responseUserHandle, 'User handle is mandatory'); - Assertion::eq($credentialUserHandle, $responseUserHandle, 'Invalid user handle'); - } + try { + $this->logger->info('Checking the authenticator assertion response', [ + 'credentialId' => $credentialId, + 'publicKeyCredentialSource' => $publicKeyCredentialSource, + 'authenticatorAssertionResponse' => $authenticatorAssertionResponse, + 'publicKeyCredentialRequestOptions' => $publicKeyCredentialRequestOptions, + 'host' => $host, + 'userHandle' => $userHandle, + ]); - $credentialPublicKey = $attestedCredentialData->getCredentialPublicKey(); - Assertion::notNull($credentialPublicKey, 'No public key available.'); - $isU2F = U2FPublicKey::isU2FKey($credentialPublicKey); - if ($isU2F === true) { - $credentialPublicKey = U2FPublicKey::convertToCoseKey($credentialPublicKey); - } - $stream = new StringStream($credentialPublicKey); - $credentialPublicKeyStream = $this->decoder->decode($stream); - Assertion::true($stream->isEOF(), 'Invalid key. Presence of extra bytes.'); - $stream->close(); - - $C = $authenticatorAssertionResponse->getClientDataJSON(); - - Assertion::eq('webauthn.get', $C->getType(), 'The client data type is not "webauthn.get".'); - - Assertion::true( - hash_equals($publicKeyCredentialRequestOptions->getChallenge(), $C->getChallenge()), - 'Invalid challenge.' + $this->ceremonyStepManager->process( + $publicKeyCredentialSource, + $authenticatorAssertionResponse, + $publicKeyCredentialRequestOptions, + $userHandle, + $host ); - $rpId = $publicKeyCredentialRequestOptions->getRpId() ?? $request->getUri() - ->getHost() - ; - $facetId = $this->getFacetId( - $rpId, - $publicKeyCredentialRequestOptions->getExtensions(), - $authenticatorAssertionResponse->getAuthenticatorData() - ->getExtensions() - ); - $parsedRelyingPartyId = parse_url($C->getOrigin()); - Assertion::isArray($parsedRelyingPartyId, 'Invalid origin'); - if (! in_array($facetId, $securedRelyingPartyId, true)) { - $scheme = $parsedRelyingPartyId['scheme'] ?? ''; - Assertion::eq('https', $scheme, 'Invalid scheme. HTTPS required.'); + $publicKeyCredentialSource->counter = $authenticatorAssertionResponse->authenticatorData->signCount; //26.1. + $publicKeyCredentialSource->backupEligible = $authenticatorAssertionResponse->authenticatorData->isBackupEligible(); //26.2. + $publicKeyCredentialSource->backupStatus = $authenticatorAssertionResponse->authenticatorData->isBackedUp(); //26.2. + if ($publicKeyCredentialSource->uvInitialized === false) { + $publicKeyCredentialSource->uvInitialized = $authenticatorAssertionResponse->authenticatorData->isUserVerified(); //26.3. } - $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; - Assertion::notEmpty($clientDataRpId, 'Invalid origin rpId.'); - $rpIdLength = mb_strlen($facetId); - Assertion::eq(mb_substr('.' . $clientDataRpId, -($rpIdLength + 1)), '.' . $facetId, 'rpId mismatch.'); + /* + * 26.3. + * OPTIONALLY, if response.attestationObject is present, update credentialRecord.attestationObject to the value of response.attestationObject and update credentialRecord.attestationClientDataJSON to the value of response.clientDataJSON. + */ - if ($C->getTokenBinding() !== null) { - $this->tokenBindingHandler->check($C->getTokenBinding(), $request); + if (is_string( + $credentialId + ) && ($this->publicKeyCredentialSourceRepository instanceof PublicKeyCredentialSourceRepository)) { + $this->publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource); } - - $rpIdHash = hash('sha256', $isU2F ? $C->getOrigin() : $facetId, true); - Assertion::true( - hash_equals($rpIdHash, $authenticatorAssertionResponse->getAuthenticatorData()->getRpIdHash()), - 'rpId hash mismatch.' - ); - - if ($publicKeyCredentialRequestOptions->getUserVerification() === AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED) { - Assertion::true( - $authenticatorAssertionResponse->getAuthenticatorData() - ->isUserPresent(), - 'User was not present' - ); - Assertion::true( - $authenticatorAssertionResponse->getAuthenticatorData() - ->isUserVerified(), - 'User authentication required.' - ); - } - - $extensionsClientOutputs = $authenticatorAssertionResponse->getAuthenticatorData() - ->getExtensions() - ; - if ($extensionsClientOutputs !== null) { - $this->extensionOutputCheckerHandler->check( - $publicKeyCredentialRequestOptions->getExtensions(), - $extensionsClientOutputs - ); - } - - $getClientDataJSONHash = hash( - 'sha256', - $authenticatorAssertionResponse->getClientDataJSON() - ->getRawData(), - true - ); - - $dataToVerify = $authenticatorAssertionResponse->getAuthenticatorData() - ->getAuthData() . $getClientDataJSONHash; - $signature = $authenticatorAssertionResponse->getSignature(); - Assertion::isInstanceOf( - $credentialPublicKeyStream, - Normalizable::class, - 'Invalid attestation object. Unexpected object.' - ); - $coseKey = Key::create($credentialPublicKeyStream->normalize()); - $algorithm = $this->algorithmManager?->get($coseKey->alg()); - Assertion::isInstanceOf( - $algorithm, - Signature::class, - 'Invalid algorithm identifier. Should refer to a signature algorithm' - ); - $signature = CoseSignatureFixer::fix($signature, $algorithm); - Assertion::true($algorithm->verify($dataToVerify, $coseKey, $signature), 'Invalid signature.'); - - $storedCounter = $publicKeyCredentialSource->getCounter(); - $responseCounter = $authenticatorAssertionResponse->getAuthenticatorData() - ->getSignCount() - ; - if ($responseCounter !== 0 || $storedCounter !== 0) { - $this->counterChecker->check($publicKeyCredentialSource, $responseCounter); - } - $publicKeyCredentialSource->setCounter($responseCounter); - $this->publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource); - //All good. We can continue. $this->logger->info('The assertion is valid'); $this->logger->debug('Public Key Credential Source', [ 'publicKeyCredentialSource' => $publicKeyCredentialSource, ]); - + $this->eventDispatcher->dispatch( + $this->createAuthenticatorAssertionResponseValidationSucceededEvent( + null, + $authenticatorAssertionResponse, + $publicKeyCredentialRequestOptions, + $host, + $userHandle, + $publicKeyCredentialSource + ) + ); + // 27. return $publicKeyCredentialSource; - } catch (Throwable $throwable) { + } catch (AuthenticatorResponseVerificationException $throwable) { $this->logger->error('An error occurred', [ 'exception' => $throwable, ]); + $this->eventDispatcher->dispatch( + $this->createAuthenticatorAssertionResponseValidationFailedEvent( + $publicKeyCredentialSource, + $authenticatorAssertionResponse, + $publicKeyCredentialRequestOptions, + $host, + $userHandle, + $throwable + ) + ); throw $throwable; } } - public function setLogger(LoggerInterface $logger): self + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; - - return $this; } - public function setCounterChecker(CounterChecker $counterChecker): self + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void { - $this->counterChecker = $counterChecker; - - return $this; + $this->eventDispatcher = $eventDispatcher; } /** - * @param array $allowedCredentials + * @deprecated since 4.8.0 and will be removed in 5.0.0. Please inject a CheckCounter object into a CeremonyStepManager instead. */ - private function isCredentialIdAllowed(string $credentialId, array $allowedCredentials): bool + public function setCounterChecker(CounterChecker $counterChecker): self { - foreach ($allowedCredentials as $allowedCredential) { - if (hash_equals($allowedCredential->getId(), $credentialId)) { - return true; - } - } - - return false; + $this->ceremonyStepManagerFactory->setCounterChecker($counterChecker); + return $this; } - private function getFacetId( - string $rpId, - AuthenticationExtensionsClientInputs $authenticationExtensionsClientInputs, - ?AuthenticationExtensionsClientOutputs $authenticationExtensionsClientOutputs - ): string { - if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has( - 'appid' - ) || ! $authenticationExtensionsClientOutputs->has('appid')) { - return $rpId; - } - $appId = $authenticationExtensionsClientInputs->get('appid') - ->value() - ; - $wasUsed = $authenticationExtensionsClientOutputs->get('appid') - ->value() - ; - if (! is_string($appId) || $wasUsed !== true) { - return $rpId; + protected function createAuthenticatorAssertionResponseValidationSucceededEvent( + null|string $credentialId, + AuthenticatorAssertionResponse $authenticatorAssertionResponse, + PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, + ServerRequestInterface|string $host, + ?string $userHandle, + PublicKeyCredentialSource $publicKeyCredentialSource + ): AuthenticatorAssertionResponseValidationSucceededEvent { + if ($host instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + sprintf( + 'Passing a %s to the method `createAuthenticatorAssertionResponseValidationSucceededEvent` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class + ) + ); } + return new AuthenticatorAssertionResponseValidationSucceededEvent( + $credentialId, + $authenticatorAssertionResponse, + $publicKeyCredentialRequestOptions, + $host, + $userHandle, + $publicKeyCredentialSource + ); + } - return $appId; + protected function createAuthenticatorAssertionResponseValidationFailedEvent( + string|PublicKeyCredentialSource $publicKeyCredentialSource, + AuthenticatorAssertionResponse $authenticatorAssertionResponse, + PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, + ServerRequestInterface|string $host, + ?string $userHandle, + Throwable $throwable + ): AuthenticatorAssertionResponseValidationFailedEvent { + if ($host instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + sprintf( + 'Passing a %s to the method `createAuthenticatorAssertionResponseValidationFailedEvent` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class + ) + ); + } + return new AuthenticatorAssertionResponseValidationFailedEvent( + $publicKeyCredentialSource, + $authenticatorAssertionResponse, + $publicKeyCredentialRequestOptions, + $host, + $userHandle, + $throwable + ); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php index a2dd039e0..875bc5257 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php @@ -11,15 +11,45 @@ use Webauthn\AttestationStatement\AttestationObject; */ class AuthenticatorAttestationResponse extends AuthenticatorResponse { + /** + * @param string[] $transports + */ public function __construct( CollectedClientData $clientDataJSON, - private readonly AttestationObject $attestationObject + public readonly AttestationObject $attestationObject, + public readonly array $transports = [] ) { parent::__construct($clientDataJSON); } + /** + * @param string[] $transports + */ + public static function create( + CollectedClientData $clientDataJSON, + AttestationObject $attestationObject, + array $transports = [] + ): self { + return new self($clientDataJSON, $attestationObject, $transports); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAttestationObject(): AttestationObject { return $this->attestationObject; } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + * + * @return string[] + */ + public function getTransports(): array + { + return $this->transports; + } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php index d6a3417f8..71fc82f6b 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php @@ -4,86 +4,150 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use function count; -use function in_array; -use InvalidArgumentException; -use function is_string; -use LogicException; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use function Safe\parse_url; -use Symfony\Component\Uid\Uuid; use Throwable; -use Webauthn\AttestationStatement\AttestationObject; -use Webauthn\AttestationStatement\AttestationStatement; use Webauthn\AttestationStatement\AttestationStatementSupportManager; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputs; use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler; -use Webauthn\CertificateChainChecker\CertificateChainChecker; +use Webauthn\CeremonyStep\CeremonyStepManager; +use Webauthn\CeremonyStep\CeremonyStepManagerFactory; +use Webauthn\Event\AuthenticatorAttestationResponseValidationFailedEvent; +use Webauthn\Event\AuthenticatorAttestationResponseValidationSucceededEvent; +use Webauthn\Event\CanDispatchEvents; +use Webauthn\Event\NullEventDispatcher; +use Webauthn\Exception\AuthenticatorResponseVerificationException; +use Webauthn\MetadataService\CanLogData; +use Webauthn\MetadataService\CertificateChain\CertificateChainValidator; use Webauthn\MetadataService\MetadataStatementRepository; -use Webauthn\MetadataService\Statement\MetadataStatement; use Webauthn\MetadataService\StatusReportRepository; use Webauthn\TokenBinding\TokenBindingHandler; -use Webauthn\TrustPath\CertificateTrustPath; -use Webauthn\TrustPath\EmptyTrustPath; +use function is_string; +use function sprintf; -class AuthenticatorAttestationResponseValidator +class AuthenticatorAttestationResponseValidator implements CanLogData, CanDispatchEvents { private LoggerInterface $logger; - private ?MetadataStatementRepository $metadataStatementRepository = null; + private EventDispatcherInterface $eventDispatcher; - private ?StatusReportRepository $statusReportRepository = null; - - private ?CertificateChainChecker $certificateChainChecker = null; + private readonly CeremonyStepManagerFactory $ceremonyStepManagerFactory; public function __construct( - private readonly AttestationStatementSupportManager $attestationStatementSupportManager, - private readonly PublicKeyCredentialSourceRepository $publicKeyCredentialSource, - private readonly TokenBindingHandler $tokenBindingHandler, - private readonly ExtensionOutputCheckerHandler $extensionOutputCheckerHandler + null|AttestationStatementSupportManager $attestationStatementSupportManager = null, + private readonly null|PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository = null, + private readonly null|TokenBindingHandler $tokenBindingHandler = null, + null|ExtensionOutputCheckerHandler $extensionOutputCheckerHandler = null, + null|EventDispatcherInterface $eventDispatcher = null, + private null|CeremonyStepManager $ceremonyStepManager = null ) { + if ($this->publicKeyCredentialSourceRepository !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.6.0', + 'The parameter "$publicKeyCredentialSourceRepository" is deprecated since 4.6.0 and will be removed in 5.0.0. Please set "null" instead.' + ); + } + if ($this->tokenBindingHandler !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.3.0', + 'The parameter "$tokenBindingHandler" is deprecated since 4.3.0 and will be removed in 5.0.0. Please set "null" instead.' + ); + } + if ($extensionOutputCheckerHandler !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$extensionOutputCheckerHandler" is deprecated since 4.8.0 and will be removed in 5.0.0. Please set "null" instead and inject a CheckExtensions object into the CeremonyStepManager.' + ); + } + $this->eventDispatcher = $eventDispatcher ?? new NullEventDispatcher(); + if ($eventDispatcher !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + 'The parameter "$eventDispatcher" is deprecated since 4.5.0 will be removed in 5.0.0. Please use `setEventDispatcher` instead.' + ); + } + if ($this->ceremonyStepManager === null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$ceremonyStepManager" will mandatory in 5.0.0. Please set a CeremonyStepManager object instead and set null for $attestationStatementSupportManager and $extensionOutputCheckerHandler.' + ); + } $this->logger = new NullLogger(); + $this->ceremonyStepManagerFactory = new CeremonyStepManagerFactory(); + if ($attestationStatementSupportManager !== null) { + $this->ceremonyStepManagerFactory->setAttestationStatementSupportManager( + $attestationStatementSupportManager + ); + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$attestationStatementSupportManager" is deprecated since 4.8.0 will be removed in 5.0.0. Please set a CheckAttestationFormatIsKnownAndValid object into CeremonyStepManager object instead.' + ); + } + if ($extensionOutputCheckerHandler !== null) { + $this->ceremonyStepManagerFactory->setExtensionOutputCheckerHandler($extensionOutputCheckerHandler); + } } + /** + * @private Will become private in 5.0.0 + */ public static function create( - AttestationStatementSupportManager $attestationStatementSupportManager, - PublicKeyCredentialSourceRepository $publicKeyCredentialSource, - TokenBindingHandler $tokenBindingHandler, - ExtensionOutputCheckerHandler $extensionOutputCheckerHandler + null|AttestationStatementSupportManager $attestationStatementSupportManager = null, + null|PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository = null, + null|TokenBindingHandler $tokenBindingHandler = null, + null|ExtensionOutputCheckerHandler $extensionOutputCheckerHandler = null, + null|EventDispatcherInterface $eventDispatcher = null, + null|CeremonyStepManager $ceremonyStepManager = null, ): self { return new self( $attestationStatementSupportManager, - $publicKeyCredentialSource, + $publicKeyCredentialSourceRepository, $tokenBindingHandler, - $extensionOutputCheckerHandler + $extensionOutputCheckerHandler, + $eventDispatcher, + $ceremonyStepManager ); } - public function setLogger(LoggerInterface $logger): self + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; - - return $this; } - public function setCertificateChainChecker(): self + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void { + $this->eventDispatcher = $eventDispatcher; + } + + /** + * @deprecated since 4.8.0 and will be removed in 5.0.0. Please use the CheckMetadataStatement object from the CeremonyStepManager instead. + */ + public function setCertificateChainValidator(CertificateChainValidator $certificateChainValidator): self + { + $this->ceremonyStepManagerFactory->enableCertificateChainValidator($certificateChainValidator); return $this; } + /** + * @deprecated since 4.8.0 and will be removed in 5.0.0. Please use the CheckMetadataStatement object from the CeremonyStepManager instead. + */ public function enableMetadataStatementSupport( MetadataStatementRepository $metadataStatementRepository, StatusReportRepository $statusReportRepository, - CertificateChainChecker $certificateChainChecker, + CertificateChainValidator $certificateChainValidator ): self { - $this->metadataStatementRepository = $metadataStatementRepository; - $this->certificateChainChecker = $certificateChainChecker; - $this->statusReportRepository = $statusReportRepository; - + $this->ceremonyStepManagerFactory->enableMetadataStatementSupport( + $metadataStatementRepository, + $statusReportRepository, + $certificateChainValidator + ); return $this; } @@ -95,325 +159,171 @@ class AuthenticatorAttestationResponseValidator public function check( AuthenticatorAttestationResponse $authenticatorAttestationResponse, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, - ServerRequestInterface $request, - array $securedRelyingPartyId = [] + ServerRequestInterface|string $request, + null|array $securedRelyingPartyId = null, ): PublicKeyCredentialSource { + if ($request instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + sprintf( + 'Passing a %s to the method `check` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class + ) + ); + } + if ($securedRelyingPartyId !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + sprintf( + 'Passing a list or secured relying party IDs to the method `check` of the class "%s" is deprecated since 4.8.0 and will be removed in 5.0.0. Please inject the list instead.', + self::class + ) + ); + } + $host = is_string($request) ? $request : $request->getUri() + ->getHost(); try { $this->logger->info('Checking the authenticator attestation response', [ 'authenticatorAttestationResponse' => $authenticatorAttestationResponse, 'publicKeyCredentialCreationOptions' => $publicKeyCredentialCreationOptions, - 'host' => $request->getUri() - ->getHost(), + 'host' => $host, ]); - //Nothing to do - - $C = $authenticatorAttestationResponse->getClientDataJSON(); - - Assertion::eq('webauthn.create', $C->getType(), 'The client data type is not "webauthn.create".'); - - Assertion::true( - hash_equals($publicKeyCredentialCreationOptions->getChallenge(), $C->getChallenge()), - 'Invalid challenge.' - ); - - $rpId = $publicKeyCredentialCreationOptions->getRp() - ->getId() ?? $request->getUri() - ->getHost() - ; - $facetId = $this->getFacetId( - $rpId, - $publicKeyCredentialCreationOptions->getExtensions(), - $authenticatorAttestationResponse->getAttestationObject() - ->getAuthData() - ->getExtensions() - ); - - $parsedRelyingPartyId = parse_url($C->getOrigin()); - Assertion::isArray($parsedRelyingPartyId, sprintf('The origin URI "%s" is not valid', $C->getOrigin())); - Assertion::keyExists($parsedRelyingPartyId, 'scheme', 'Invalid origin rpId.'); - $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; - Assertion::notEmpty($clientDataRpId, 'Invalid origin rpId.'); - $rpIdLength = mb_strlen($facetId); - Assertion::eq(mb_substr('.' . $clientDataRpId, -($rpIdLength + 1)), '.' . $facetId, 'rpId mismatch.'); - - if (! in_array($facetId, $securedRelyingPartyId, true)) { - $scheme = $parsedRelyingPartyId['scheme']; - Assertion::eq('https', $scheme, 'Invalid scheme. HTTPS required.'); - } - - if ($C->getTokenBinding() !== null) { - $this->tokenBindingHandler->check($C->getTokenBinding(), $request); - } - - $clientDataJSONHash = hash( - 'sha256', - $authenticatorAttestationResponse->getClientDataJSON() - ->getRawData(), - true - ); - - $attestationObject = $authenticatorAttestationResponse->getAttestationObject(); - - $rpIdHash = hash('sha256', $facetId, true); - Assertion::true( - hash_equals($rpIdHash, $attestationObject->getAuthData()->getRpIdHash()), - 'rpId hash mismatch.' - ); - - if ($publicKeyCredentialCreationOptions->getAuthenticatorSelection()->getUserVerification() === AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED) { - Assertion::true($attestationObject->getAuthData()->isUserPresent(), 'User was not present'); - Assertion::true($attestationObject->getAuthData()->isUserVerified(), 'User authentication required.'); - } - - $extensionsClientOutputs = $attestationObject->getAuthData() - ->getExtensions() - ; - if ($extensionsClientOutputs !== null) { - $this->extensionOutputCheckerHandler->check( - $publicKeyCredentialCreationOptions->getExtensions(), - $extensionsClientOutputs + if ($this->ceremonyStepManager === null) { + $this->ceremonyStepManager = $this->ceremonyStepManagerFactory->creationCeremony( + $securedRelyingPartyId ); } - $this->checkMetadataStatement($publicKeyCredentialCreationOptions, $attestationObject); - $fmt = $attestationObject->getAttStmt() - ->getFmt() - ; - Assertion::true( - $this->attestationStatementSupportManager->has($fmt), - 'Unsupported attestation statement format.' - ); - - $attestationStatementSupport = $this->attestationStatementSupportManager->get($fmt); - Assertion::true( - $attestationStatementSupport->isValid( - $clientDataJSONHash, - $attestationObject->getAttStmt(), - $attestationObject->getAuthData() - ), - 'Invalid attestation statement.' - ); - - Assertion::true( - $attestationObject->getAuthData() - ->hasAttestedCredentialData(), - 'There is no attested credential data.' - ); - $attestedCredentialData = $attestationObject->getAuthData() - ->getAttestedCredentialData() - ; - Assertion::notNull($attestedCredentialData, 'There is no attested credential data.'); - $credentialId = $attestedCredentialData->getCredentialId(); - Assertion::null( - $this->publicKeyCredentialSource->findOneByCredentialId($credentialId), - 'The credential ID already exists.' - ); - $publicKeyCredentialSource = $this->createPublicKeyCredentialSource( - $credentialId, - $attestedCredentialData, - $attestationObject, - $publicKeyCredentialCreationOptions->getUser() - ->getId() + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions ); + + $this->ceremonyStepManager->process( + $publicKeyCredentialSource, + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions, + $publicKeyCredentialCreationOptions->user->id, + $host + ); + + $publicKeyCredentialSource->counter = $authenticatorAttestationResponse->attestationObject->authData->signCount; + $publicKeyCredentialSource->backupEligible = $authenticatorAttestationResponse->attestationObject->authData->isBackupEligible(); + $publicKeyCredentialSource->backupStatus = $authenticatorAttestationResponse->attestationObject->authData->isBackedUp(); + $publicKeyCredentialSource->uvInitialized = $authenticatorAttestationResponse->attestationObject->authData->isUserVerified(); + $this->logger->info('The attestation is valid'); $this->logger->debug('Public Key Credential Source', [ 'publicKeyCredentialSource' => $publicKeyCredentialSource, ]); - + $this->eventDispatcher->dispatch( + $this->createAuthenticatorAttestationResponseValidationSucceededEvent( + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions, + $host, + $publicKeyCredentialSource + ) + ); return $publicKeyCredentialSource; } catch (Throwable $throwable) { $this->logger->error('An error occurred', [ 'exception' => $throwable, ]); + $this->eventDispatcher->dispatch( + $this->createAuthenticatorAttestationResponseValidationFailedEvent( + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions, + $host, + $throwable + ) + ); throw $throwable; } } - private function checkCertificateChain( - AttestationStatement $attestationStatement, - ?MetadataStatement $metadataStatement - ): void { - $trustPath = $attestationStatement->getTrustPath(); - if (! $trustPath instanceof CertificateTrustPath) { - return; - } - $authenticatorCertificates = $trustPath->getCertificates(); - - if ($metadataStatement === null) { - $this->certificateChainChecker?->check($authenticatorCertificates, []); - - return; - } - - $trustedCertificates = array_merge( - $metadataStatement->getAttestationRootCertificates(), - $metadataStatement->getRootCertificates() - ); - $trustedCertificates = CertificateToolbox::fixPEMStructures($trustedCertificates); - - $this->certificateChainChecker?->check($authenticatorCertificates, $trustedCertificates); - } - - private function checkMetadataStatement( + protected function createAuthenticatorAttestationResponseValidationSucceededEvent( + AuthenticatorAttestationResponse $authenticatorAttestationResponse, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, - AttestationObject $attestationObject - ): void { - $attestationStatement = $attestationObject->getAttStmt(); - $attestedCredentialData = $attestationObject->getAuthData() - ->getAttestedCredentialData() - ; - Assertion::notNull($attestedCredentialData, 'No attested credential data found'); - $aaguid = $attestedCredentialData->getAaguid() - ->__toString() - ; - if ($publicKeyCredentialCreationOptions->getAttestation() === PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE) { - $this->logger->debug('No attestation is asked.'); - //No attestation is asked. We shall ensure that the data is anonymous. - if ( - $aaguid === '00000000-0000-0000-0000-000000000000' - && ($attestationStatement->getType() === AttestationStatement::TYPE_NONE || $attestationStatement->getType() === AttestationStatement::TYPE_SELF)) { - $this->logger->debug('The Attestation Statement is anonymous.'); - $this->checkCertificateChain($attestationStatement, null); - - return; - } - $this->logger->debug('Anonymization required. AAGUID and Attestation Statement changed.', [ - 'aaguid' => $aaguid, - 'AttestationStatement' => $attestationStatement, - ]); - $attestedCredentialData->setAaguid(Uuid::fromString('00000000-0000-0000-0000-000000000000')); - $attestationObject->setAttStmt(AttestationStatement::createNone('none', [], new EmptyTrustPath())); - - return; - } - - // If no Attestation Statement has been returned or if null AAGUID (=00000000-0000-0000-0000-000000000000) - // => nothing to check - if ($attestationStatement->getType() === AttestationStatement::TYPE_NONE) { - $this->logger->debug('No attestation returned.'); - //No attestation is returned. We shall ensure that the AAGUID is a null one. - if ($aaguid !== '00000000-0000-0000-0000-000000000000') { - $this->logger->debug('Anonymization required. AAGUID and Attestation Statement changed.', [ - 'aaguid' => $aaguid, - 'AttestationStatement' => $attestationStatement, - ]); - $attestedCredentialData->setAaguid(Uuid::fromString('00000000-0000-0000-0000-000000000000')); - - return; - } - - return; - } - - if ($aaguid === '00000000-0000-0000-0000-000000000000') { - //No need to continue if the AAGUID is null. - // This could be the case e.g. with AnonCA type - return; - } - - //The MDS Repository is mandatory here - Assertion::notNull( - $this->metadataStatementRepository, - 'The Metadata Statement Repository is mandatory when requesting attestation objects.' - ); - $metadataStatement = $this->metadataStatementRepository->findOneByAAGUID($aaguid); - - // We check the last status report - $this->checkStatusReport($aaguid); - - // We check the certificate chain (if any) - $this->checkCertificateChain($attestationStatement, $metadataStatement); - - // At this point, the Metadata Statement is mandatory - Assertion::notNull( - $metadataStatement, - sprintf('The Metadata Statement for the AAGUID "%s" is missing', $aaguid) - ); - - // Check Attestation Type is allowed - if (count($metadataStatement->getAttestationTypes()) !== 0) { - $type = $this->getAttestationType($attestationStatement); - Assertion::inArray( - $type, - $metadataStatement->getAttestationTypes(), + ServerRequestInterface|string $host, + PublicKeyCredentialSource $publicKeyCredentialSource + ): AuthenticatorAttestationResponseValidationSucceededEvent { + if ($host instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', sprintf( - 'Invalid attestation statement. The attestation type "%s" is not allowed for this authenticator.', - $type + 'Passing a %s to the method `createAuthenticatorAttestationResponseValidationSucceededEvent` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class ) ); } - } - - private function getAttestationType(AttestationStatement $attestationStatement): string - { - return match ($attestationStatement->getType()) { - AttestationStatement::TYPE_BASIC => MetadataStatement::ATTESTATION_BASIC_FULL, - AttestationStatement::TYPE_SELF => MetadataStatement::ATTESTATION_BASIC_SURROGATE, - AttestationStatement::TYPE_ATTCA => MetadataStatement::ATTESTATION_ATTCA, - AttestationStatement::TYPE_ECDAA => MetadataStatement::ATTESTATION_ECDAA, - default => throw new InvalidArgumentException('Invalid attestation type'), - }; - } - - private function checkStatusReport(string $aaguid): void - { - $statusReports = $this->statusReportRepository === null ? [] : $this->statusReportRepository->findStatusReportsByAAGUID( - $aaguid + return new AuthenticatorAttestationResponseValidationSucceededEvent( + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions, + $host, + $publicKeyCredentialSource ); - if (count($statusReports) !== 0) { - $lastStatusReport = end($statusReports); - if ($lastStatusReport->isCompromised()) { - throw new LogicException('The authenticator is compromised and cannot be used'); - } + } + + protected function createAuthenticatorAttestationResponseValidationFailedEvent( + AuthenticatorAttestationResponse $authenticatorAttestationResponse, + PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, + ServerRequestInterface|string $host, + Throwable $throwable + ): AuthenticatorAttestationResponseValidationFailedEvent { + if ($host instanceof ServerRequestInterface) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.5.0', + sprintf( + 'Passing a %s to the method `createAuthenticatorAttestationResponseValidationFailedEvent` of the class "%s" is deprecated since 4.5.0 and will be removed in 5.0.0. Please inject the host as a string instead.', + ServerRequestInterface::class, + self::class + ) + ); } + return new AuthenticatorAttestationResponseValidationFailedEvent( + $authenticatorAttestationResponse, + $publicKeyCredentialCreationOptions, + $host, + $throwable + ); } private function createPublicKeyCredentialSource( - string $credentialId, - AttestedCredentialData $attestedCredentialData, - AttestationObject $attestationObject, - string $userHandle + AuthenticatorAttestationResponse $authenticatorAttestationResponse, + PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ): PublicKeyCredentialSource { - $credentialPublicKey = $attestedCredentialData->getCredentialPublicKey(); - Assertion::notNull($credentialPublicKey, 'Not credential public key available in the attested credential data'); + $attestationObject = $authenticatorAttestationResponse->attestationObject; + $attestedCredentialData = $attestationObject->authData->attestedCredentialData; + $attestedCredentialData !== null || throw AuthenticatorResponseVerificationException::create( + 'Not attested credential data' + ); + $credentialId = $attestedCredentialData->credentialId; + $credentialPublicKey = $attestedCredentialData->credentialPublicKey; + $credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create( + 'Not credential public key available in the attested credential data' + ); + $userHandle = $publicKeyCredentialCreationOptions->user->id; + $transports = $authenticatorAttestationResponse->transports; - return new PublicKeyCredentialSource( + return PublicKeyCredentialSource::create( $credentialId, PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, - [], - $attestationObject->getAttStmt() - ->getType(), - $attestationObject->getAttStmt() - ->getTrustPath(), - $attestedCredentialData->getAaguid(), + $transports, + $attestationObject->attStmt + ->type, + $attestationObject->attStmt + ->trustPath, + $attestedCredentialData->aaguid, $credentialPublicKey, $userHandle, - $attestationObject->getAuthData() - ->getSignCount() + $attestationObject->authData + ->signCount, ); } - - private function getFacetId( - string $rpId, - AuthenticationExtensionsClientInputs $authenticationExtensionsClientInputs, - ?AuthenticationExtensionsClientOutputs $authenticationExtensionsClientOutputs - ): string { - if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has( - 'appid' - ) || ! $authenticationExtensionsClientOutputs->has('appid')) { - return $rpId; - } - $appId = $authenticationExtensionsClientInputs->get('appid') - ->value() - ; - $wasUsed = $authenticationExtensionsClientOutputs->get('appid') - ->value() - ; - if (! is_string($appId) || $wasUsed !== true) { - return $rpId; - } - - return $appId; - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php index 89e241343..f21ff0629 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php @@ -4,41 +4,68 @@ declare(strict_types=1); namespace Webauthn; +use Webauthn\AuthenticationExtensions\AuthenticationExtensions; use function ord; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputs; /** * @see https://www.w3.org/TR/webauthn/#sec-authenticator-data + * @see https://www.w3.org/TR/webauthn/#flags */ class AuthenticatorData { - private const FLAG_UP = 0b00000001; + final public const FLAG_UP = 0b00000001; - private const FLAG_RFU1 = 0b00000010; + final public const FLAG_RFU1 = 0b00000010; - private const FLAG_UV = 0b00000100; + final public const FLAG_UV = 0b00000100; - private const FLAG_RFU2 = 0b00111000; + final public const FLAG_BE = 0b00001000; - private const FLAG_AT = 0b01000000; + final public const FLAG_BS = 0b00010000; - private const FLAG_ED = 0b10000000; + /** + * TODO: remove bits 3 and 4 as they have been assigned to BE and BS in Webauthn level 3. + */ + final public const FLAG_RFU2 = 0b00111000; + + final public const FLAG_AT = 0b01000000; + + final public const FLAG_ED = 0b10000000; public function __construct( - protected string $authData, - protected string $rpIdHash, - protected string $flags, - protected int $signCount, - protected ?AttestedCredentialData $attestedCredentialData, - protected ?AuthenticationExtensionsClientOutputs $extensions + public readonly string $authData, + public readonly string $rpIdHash, + public readonly string $flags, + public readonly int $signCount, + public readonly null|AttestedCredentialData $attestedCredentialData, + public readonly null|AuthenticationExtensions $extensions ) { } + public static function create( + string $authData, + string $rpIdHash, + string $flags, + int $signCount, + null|AttestedCredentialData $attestedCredentialData = null, + null|AuthenticationExtensions $extensions = null + ): self { + return new self($authData, $rpIdHash, $flags, $signCount, $attestedCredentialData, $extensions); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAuthData(): string { return $this->authData; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRpIdHash(): string { return $this->rpIdHash; @@ -54,6 +81,16 @@ class AuthenticatorData return 0 !== (ord($this->flags) & self::FLAG_UV); } + public function isBackupEligible(): bool + { + return 0 !== (ord($this->flags) & self::FLAG_BE); + } + + public function isBackedUp(): bool + { + return 0 !== (ord($this->flags) & self::FLAG_BS); + } + public function hasAttestedCredentialData(): bool { return 0 !== (ord($this->flags) & self::FLAG_AT); @@ -74,17 +111,29 @@ class AuthenticatorData return ord($this->flags) & self::FLAG_RFU2; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getSignCount(): int { return $this->signCount; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAttestedCredentialData(): ?AttestedCredentialData { return $this->attestedCredentialData; } - public function getExtensions(): ?AuthenticationExtensionsClientOutputs + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getExtensions(): ?AuthenticationExtensions { return $this->extensions !== null && $this->hasExtensions() ? $this->extensions : null; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorDataLoader.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorDataLoader.php new file mode 100644 index 000000000..e09e64373 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorDataLoader.php @@ -0,0 +1,117 @@ +decoder = Decoder::create(); + } + + public static function create(): self + { + return new self(); + } + + public function load(string $authData): AuthenticatorData + { + $authData = $this->fixIncorrectEdDSAKey($authData); + $authDataStream = new StringStream($authData); + $rp_id_hash = $authDataStream->read(32); + $flags = $authDataStream->read(1); + $signCount = $authDataStream->read(4); + $signCount = unpack('N', $signCount); + + $attestedCredentialData = null; + if (0 !== (ord($flags) & AuthenticatorData::FLAG_AT)) { + $aaguid = Uuid::fromBinary($authDataStream->read(16)); + $credentialLength = $authDataStream->read(2); + $credentialLength = unpack('n', $credentialLength); + $credentialId = $authDataStream->read($credentialLength[1]); + $credentialPublicKey = $this->decoder->decode($authDataStream); + $credentialPublicKey instanceof MapObject || throw InvalidDataException::create( + $authData, + 'The data does not contain a valid credential public key.' + ); + $attestedCredentialData = AttestedCredentialData::create( + $aaguid, + $credentialId, + (string) $credentialPublicKey + ); + } + + $extension = null; + if (0 !== (ord($flags) & AuthenticatorData::FLAG_ED)) { + $extension = $this->decoder->decode($authDataStream); + $extension = AuthenticationExtensionsClientOutputsLoader::load($extension); + } + $authDataStream->isEOF() || throw InvalidDataException::create( + $authData, + 'Invalid authentication data. Presence of extra bytes.' + ); + $authDataStream->close(); + + return AuthenticatorData::create( + $authData, + $rp_id_hash, + $flags, + $signCount[1], + $attestedCredentialData, + $extension + ); + } + + private function fixIncorrectEdDSAKey(string $data): string + { + $needle = hex2bin('a301634f4b500327206745643235353139'); + $correct = hex2bin('a401634f4b500327206745643235353139'); + $position = mb_strpos($data, $needle, 0, '8bit'); + if ($position === false) { + return $data; + } + + $begin = mb_substr($data, 0, $position, '8bit'); + $end = mb_substr($data, $position, null, '8bit'); + $end = str_replace($needle, $correct, $end); + $cbor = new StringStream($end); + $badKey = $this->decoder->decode($cbor); + + ($badKey instanceof MapObject && $cbor->isEOF()) || throw InvalidDataException::create( + $end, + 'Invalid authentication data. Presence of extra bytes.' + ); + $badX = $badKey->get(-2); + $badX instanceof ListObject || throw InvalidDataException::create($end, 'Invalid authentication data.'); + $keyBytes = array_reduce( + $badX->normalize(), + static fn (string $carry, string $item): string => $carry . chr((int) $item), + '' + ); + $correctX = ByteStringObject::create($keyBytes); + $correctKey = MapObject::create() + ->add(UnsignedIntegerObject::create(1), TextStringObject::create('OKP')) + ->add(UnsignedIntegerObject::create(3), NegativeIntegerObject::create(-8)) + ->add(NegativeIntegerObject::create(-1), TextStringObject::create('Ed25519')) + ->add(NegativeIntegerObject::create(-2), $correctX); + + return $begin . $correctKey; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php index 33c1e1920..162c24db6 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php @@ -10,10 +10,14 @@ namespace Webauthn; abstract class AuthenticatorResponse { public function __construct( - private readonly CollectedClientData $clientDataJSON + public readonly CollectedClientData $clientDataJSON ) { } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getClientDataJSON(): CollectedClientData { return $this->clientDataJSON; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php index 335c37f5e..ac794688c 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php @@ -4,9 +4,13 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use const JSON_THROW_ON_ERROR; +use InvalidArgumentException; use JsonSerializable; +use Webauthn\Exception\InvalidDataException; +use function in_array; +use function is_bool; +use function is_string; +use const JSON_THROW_ON_ERROR; class AuthenticatorSelectionCriteria implements JsonSerializable { @@ -16,12 +20,30 @@ class AuthenticatorSelectionCriteria implements JsonSerializable final public const AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM = 'cross-platform'; + final public const AUTHENTICATOR_ATTACHMENTS = [ + self::AUTHENTICATOR_ATTACHMENT_NO_PREFERENCE, + self::AUTHENTICATOR_ATTACHMENT_PLATFORM, + self::AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM, + ]; + final public const USER_VERIFICATION_REQUIREMENT_REQUIRED = 'required'; final public const USER_VERIFICATION_REQUIREMENT_PREFERRED = 'preferred'; final public const USER_VERIFICATION_REQUIREMENT_DISCOURAGED = 'discouraged'; + final public const USER_VERIFICATION_REQUIREMENTS = [ + self::USER_VERIFICATION_REQUIREMENT_REQUIRED, + self::USER_VERIFICATION_REQUIREMENT_PREFERRED, + self::USER_VERIFICATION_REQUIREMENT_DISCOURAGED, + ]; + + final public const RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE = null; + + /** + * @deprecated Please use AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE instead + * @infection-ignore-all + */ final public const RESIDENT_KEY_REQUIREMENT_NONE = null; final public const RESIDENT_KEY_REQUIREMENT_REQUIRED = 'required'; @@ -30,26 +52,53 @@ class AuthenticatorSelectionCriteria implements JsonSerializable final public const RESIDENT_KEY_REQUIREMENT_DISCOURAGED = 'discouraged'; - private ?string $authenticatorAttachment = null; + final public const RESIDENT_KEY_REQUIREMENTS = [ + self::RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE, + self::RESIDENT_KEY_REQUIREMENT_REQUIRED, + self::RESIDENT_KEY_REQUIREMENT_PREFERRED, + self::RESIDENT_KEY_REQUIREMENT_DISCOURAGED, + ]; - private bool $requireResidentKey; - - private string $userVerification; - - private ?string $residentKey; - - public function __construct() - { - $this->requireResidentKey = false; - $this->userVerification = self::USER_VERIFICATION_REQUIREMENT_PREFERRED; - $this->residentKey = self::RESIDENT_KEY_REQUIREMENT_NONE; + public function __construct( + public null|string $authenticatorAttachment = null, + public string $userVerification = self::USER_VERIFICATION_REQUIREMENT_PREFERRED, + public null|string $residentKey = self::RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE, + /** @deprecated Will be removed in 5.0. Please use residentKey instead**/ + public null|bool $requireResidentKey = null, + ) { + in_array($authenticatorAttachment, self::AUTHENTICATOR_ATTACHMENTS, true) || throw new InvalidArgumentException( + 'Invalid authenticator attachment' + ); + in_array($userVerification, self::USER_VERIFICATION_REQUIREMENTS, true) || throw new InvalidArgumentException( + 'Invalid user verification' + ); + in_array($residentKey, self::RESIDENT_KEY_REQUIREMENTS, true) || throw new InvalidArgumentException( + 'Invalid resident key' + ); + if ($requireResidentKey === true && $residentKey !== null && $residentKey !== self::RESIDENT_KEY_REQUIREMENT_REQUIRED) { + throw new InvalidArgumentException( + 'Invalid resident key requirement. Resident key is required but requireResidentKey is false' + ); + } + if ($this->residentKey === null && $this->requireResidentKey === true) { + $this->residentKey = self::RESIDENT_KEY_REQUIREMENT_REQUIRED; + } + $this->requireResidentKey = $requireResidentKey ?? ($residentKey === null ? null : $residentKey === self::RESIDENT_KEY_REQUIREMENT_REQUIRED); } - public static function create(): self - { - return new self(); + public static function create( + ?string $authenticatorAttachment = null, + string $userVerification = self::USER_VERIFICATION_REQUIREMENT_PREFERRED, + null|string $residentKey = self::RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE, + null|bool $requireResidentKey = null + ): self { + return new self($authenticatorAttachment, $userVerification, $residentKey, $requireResidentKey); } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function setAuthenticatorAttachment(?string $authenticatorAttachment): self { $this->authenticatorAttachment = $authenticatorAttachment; @@ -57,13 +106,24 @@ class AuthenticatorSelectionCriteria implements JsonSerializable return $this; } + /** + * @deprecated since v4.1. Please use the {self::create} instead. + * @infection-ignore-all + */ public function setRequireResidentKey(bool $requireResidentKey): self { $this->requireResidentKey = $requireResidentKey; + if ($requireResidentKey === true) { + $this->residentKey = self::RESIDENT_KEY_REQUIREMENT_REQUIRED; + } return $this; } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function setUserVerification(string $userVerification): self { $this->userVerification = $userVerification; @@ -71,52 +131,97 @@ class AuthenticatorSelectionCriteria implements JsonSerializable return $this; } - public function setResidentKey(?string $residentKey): self + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ + public function setResidentKey(null|string $residentKey): self { $this->residentKey = $residentKey; + $this->requireResidentKey = $residentKey === self::RESIDENT_KEY_REQUIREMENT_REQUIRED; return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAuthenticatorAttachment(): ?string { return $this->authenticatorAttachment; } + /** + * @deprecated Will be removed in 5.0. Please use the property directly. + * @infection-ignore-all + */ public function isRequireResidentKey(): bool { return $this->requireResidentKey; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getUserVerification(): string { return $this->userVerification; } - public function getResidentKey(): ?string + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getResidentKey(): null|string { return $this->residentKey; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromString(string $data): self { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $json): self { - return self::create() - ->setAuthenticatorAttachment($json['authenticatorAttachment'] ?? null) - ->setRequireResidentKey($json['requireResidentKey'] ?? false) - ->setUserVerification($json['userVerification'] ?? self::USER_VERIFICATION_REQUIREMENT_PREFERRED) - ->setResidentKey($json['residentKey'] ?? self::RESIDENT_KEY_REQUIREMENT_NONE) - ; + $authenticatorAttachment = $json['authenticatorAttachment'] ?? null; + $requireResidentKey = $json['requireResidentKey'] ?? null; + $userVerification = $json['userVerification'] ?? self::USER_VERIFICATION_REQUIREMENT_PREFERRED; + $residentKey = $json['residentKey'] ?? null; + + $authenticatorAttachment === null || is_string($authenticatorAttachment) || throw InvalidDataException::create( + $json, + 'Invalid "authenticatorAttachment" value' + ); + ($requireResidentKey === null || is_bool($requireResidentKey)) || throw InvalidDataException::create( + $json, + 'Invalid "requireResidentKey" value' + ); + is_string($userVerification) || throw InvalidDataException::create($json, 'Invalid "userVerification" value'); + ($residentKey === null || is_string($residentKey)) || throw InvalidDataException::create( + $json, + 'Invalid "residentKey" value' + ); + + return self::create( + $authenticatorAttachment ?? null, + $userVerification, + $residentKey, + $requireResidentKey, + ); } /** @@ -124,15 +229,22 @@ class AuthenticatorSelectionCriteria implements JsonSerializable */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = [ 'requireResidentKey' => $this->requireResidentKey, 'userVerification' => $this->userVerification, + 'residentKey' => $this->residentKey, + 'authenticatorAttachment' => $this->authenticatorAttachment, ]; - if ($this->authenticatorAttachment !== null) { - $json['authenticatorAttachment'] = $this->authenticatorAttachment; - } - if ($this->residentKey !== null) { - $json['residentKey'] = $this->residentKey; + foreach ($json as $key => $value) { + if ($value === null) { + unset($json[$key]); + } } return $json; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStep.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStep.php new file mode 100644 index 000000000..d015e00a0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStep.php @@ -0,0 +1,22 @@ +steps as $step) { + $step->process( + $publicKeyCredentialSource, + $authenticatorResponse, + $publicKeyCredentialOptions, + $userHandle, + $host + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStepManagerFactory.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStepManagerFactory.php new file mode 100644 index 000000000..cc58ae3bc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CeremonyStepManagerFactory.php @@ -0,0 +1,159 @@ +counterChecker = new ThrowExceptionIfInvalid(); + $this->algorithmManager = Manager::create()->add(ES256::create(), RS256::create()); + $this->attestationStatementSupportManager = new AttestationStatementSupportManager([ + new NoneAttestationStatementSupport(), + ]); + $this->extensionOutputCheckerHandler = new ExtensionOutputCheckerHandler(); + } + + public function setCounterChecker(CounterChecker $counterChecker): void + { + $this->counterChecker = $counterChecker; + } + + /** + * @param string[] $securedRelyingPartyId + */ + public function setSecuredRelyingPartyId(array $securedRelyingPartyId): void + { + $this->securedRelyingPartyId = $securedRelyingPartyId; + } + + public function setExtensionOutputCheckerHandler(ExtensionOutputCheckerHandler $extensionOutputCheckerHandler): void + { + $this->extensionOutputCheckerHandler = $extensionOutputCheckerHandler; + } + + public function setAttestationStatementSupportManager( + AttestationStatementSupportManager $attestationStatementSupportManager + ): void { + $this->attestationStatementSupportManager = $attestationStatementSupportManager; + } + + public function setAlgorithmManager(Manager $algorithmManager): void + { + $this->algorithmManager = $algorithmManager; + } + + public function enableMetadataStatementSupport( + MetadataStatementRepository $metadataStatementRepository, + StatusReportRepository $statusReportRepository, + CertificateChainValidator $certificateChainValidator + ): void { + $this->metadataStatementRepository = $metadataStatementRepository; + $this->statusReportRepository = $statusReportRepository; + $this->certificateChainValidator = $certificateChainValidator; + } + + public function enableCertificateChainValidator(CertificateChainValidator $certificateChainValidator): void + { + $this->certificateChainValidator = $certificateChainValidator; + } + + public function enableTopOriginValidator(TopOriginValidator $topOriginValidator): void + { + $this->topOriginValidator = $topOriginValidator; + } + + /** + * @param null|string[] $securedRelyingPartyId + */ + public function creationCeremony(null|array $securedRelyingPartyId = null): CeremonyStepManager + { + $metadataStatementChecker = new CheckMetadataStatement(); + if ($this->certificateChainValidator !== null) { + $metadataStatementChecker->enableCertificateChainValidator($this->certificateChainValidator); + } + if ($this->metadataStatementRepository !== null && $this->statusReportRepository !== null && $this->certificateChainValidator !== null) { + $metadataStatementChecker->enableMetadataStatementSupport( + $this->metadataStatementRepository, + $this->statusReportRepository, + $this->certificateChainValidator, + ); + } + + /* @see https://www.w3.org/TR/webauthn-3/#sctn-registering-a-new-credential */ + return new CeremonyStepManager([ + new CheckClientDataCollectorType(), + new CheckChallenge(), + new CheckOrigin($this->securedRelyingPartyId ?? $securedRelyingPartyId ?? []), + new CheckTopOrigin($this->topOriginValidator), + new CheckRelyingPartyIdIdHash(), + new CheckUserWasPresent(), + new CheckUserVerification(), + new CheckBackupBitsAreConsistent(), + new CheckAlgorithm(), + new CheckExtensions($this->extensionOutputCheckerHandler), + new CheckAttestationFormatIsKnownAndValid($this->attestationStatementSupportManager), + new CheckHasAttestedCredentialData(), + $metadataStatementChecker, + new CheckCredentialId(), + ]); + } + + /** + * @param null|string[] $securedRelyingPartyId + */ + public function requestCeremony(null|array $securedRelyingPartyId = null): CeremonyStepManager + { + /* @see https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion */ + return new CeremonyStepManager([ + new CheckAllowedCredentialList(), + new CheckUserHandle(), + new CheckClientDataCollectorType(), + new CheckChallenge(), + new CheckOrigin($this->securedRelyingPartyId ?? $securedRelyingPartyId ?? []), + new CheckTopOrigin(null), + new CheckRelyingPartyIdIdHash(), + new CheckUserWasPresent(), + new CheckUserVerification(), + new CheckBackupBitsAreConsistent(), + new CheckExtensions($this->extensionOutputCheckerHandler), + new CheckSignature($this->algorithmManager), + new CheckCounter($this->counterChecker), + ]); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAlgorithm.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAlgorithm.php new file mode 100644 index 000000000..74a221e14 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAlgorithm.php @@ -0,0 +1,77 @@ +getAttestedCredentialData() + ->credentialPublicKey; + $credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create( + 'No public key available.' + ); + $algorithms = array_map( + fn ($pubKeyCredParam) => $pubKeyCredParam->alg, + $publicKeyCredentialOptions->pubKeyCredParams + ); + if (count($algorithms) === 0) { + $algorithms = [Algorithms::COSE_ALGORITHM_ES256, Algorithms::COSE_ALGORITHM_RS256]; + } + $coseKey = $this->getCoseKey($credentialPublicKey); + in_array($coseKey->alg(), $algorithms, true) || throw AuthenticatorResponseVerificationException::create( + sprintf('Invalid algorithm. Expected one of %s but got %d', implode(', ', $algorithms), $coseKey->alg()) + ); + } + + private function getCoseKey(string $credentialPublicKey): Key + { + $isU2F = U2FPublicKey::isU2FKey($credentialPublicKey); + if ($isU2F === true) { + $credentialPublicKey = U2FPublicKey::convertToCoseKey($credentialPublicKey); + } + $stream = new StringStream($credentialPublicKey); + $credentialPublicKeyStream = Decoder::create()->decode($stream); + $stream->isEOF() || throw AuthenticatorResponseVerificationException::create( + 'Invalid key. Presence of extra bytes.' + ); + $stream->close(); + $credentialPublicKeyStream instanceof Normalizable || throw AuthenticatorResponseVerificationException::create( + 'Invalid attestation object. Unexpected object.' + ); + $normalizedData = $credentialPublicKeyStream->normalize(); + is_array($normalizedData) || throw AuthenticatorResponseVerificationException::create( + 'Invalid attestation object. Unexpected object.' + ); + /** @var array $normalizedData */ + + return Key::create($normalizedData); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAllowedCredentialList.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAllowedCredentialList.php new file mode 100644 index 000000000..bd51f61e6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAllowedCredentialList.php @@ -0,0 +1,38 @@ +allowCredentials) === 0) { + return; + } + + foreach ($publicKeyCredentialOptions->allowCredentials as $allowedCredential) { + if (hash_equals($allowedCredential->id, $publicKeyCredentialSource->publicKeyCredentialId)) { + return; + } + } + throw AuthenticatorResponseVerificationException::create('The credential ID is not allowed.'); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAttestationFormatIsKnownAndValid.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAttestationFormatIsKnownAndValid.php new file mode 100644 index 000000000..147ffcee7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckAttestationFormatIsKnownAndValid.php @@ -0,0 +1,48 @@ +attestationObject; + if ($attestationObject === null) { + return; + } + + $fmt = $attestationObject->attStmt + ->fmt; + $this->attestationStatementSupportManager->has( + $fmt + ) || throw AuthenticatorResponseVerificationException::create('Unsupported attestation statement format.'); + + $attestationStatementSupport = $this->attestationStatementSupportManager->get($fmt); + $clientDataJSONHash = hash('sha256', $authenticatorResponse->clientDataJSON ->rawData, true); + $attestationStatementSupport->isValid( + $clientDataJSONHash, + $attestationObject->attStmt, + $attestationObject->authData + ) || throw AuthenticatorResponseVerificationException::create('Invalid attestation statement.'); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckBackupBitsAreConsistent.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckBackupBitsAreConsistent.php new file mode 100644 index 000000000..dffa239c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckBackupBitsAreConsistent.php @@ -0,0 +1,31 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + if ($authData->isBackupEligible()) { + return; + } + $authData->isBackedUp() !== true || throw AuthenticatorResponseVerificationException::create( + 'Backup up bit is set but the backup is not eligible.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckChallenge.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckChallenge.php new file mode 100644 index 000000000..a1c059706 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckChallenge.php @@ -0,0 +1,31 @@ +challenge !== '' || throw AuthenticatorResponseVerificationException::create( + 'Invalid challenge.' + ); + hash_equals( + $publicKeyCredentialOptions->challenge, + $authenticatorResponse->clientDataJSON->challenge + ) || throw AuthenticatorResponseVerificationException::create('Invalid challenge.'); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckClientDataCollectorType.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckClientDataCollectorType.php new file mode 100644 index 000000000..645cb904d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckClientDataCollectorType.php @@ -0,0 +1,41 @@ +clientDataCollectorManager = $clientDataCollectorManager ?? new ClientDataCollectorManager([ + new WebauthnAuthenticationCollector(), + ]); + } + + public function process( + PublicKeyCredentialSource $publicKeyCredentialSource, + AuthenticatorAssertionResponse|AuthenticatorAttestationResponse $authenticatorResponse, + PublicKeyCredentialRequestOptions|PublicKeyCredentialCreationOptions $publicKeyCredentialOptions, + ?string $userHandle, + string $host + ): void { + $this->clientDataCollectorManager->collect( + $authenticatorResponse->clientDataJSON, + $publicKeyCredentialOptions, + $authenticatorResponse, + $host + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCounter.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCounter.php new file mode 100644 index 000000000..dcf84536c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCounter.php @@ -0,0 +1,36 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $storedCounter = $publicKeyCredentialSource->counter; + $responseCounter = $authData->signCount; + if ($responseCounter !== 0 || $storedCounter !== 0) { + $this->counterChecker->check($publicKeyCredentialSource, $responseCounter); + } + $publicKeyCredentialSource->counter = $responseCounter; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCredentialId.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCredentialId.php new file mode 100644 index 000000000..aeb202054 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckCredentialId.php @@ -0,0 +1,28 @@ +publicKeyCredentialId; + mb_strlen($credentialId) <= 1023 || throw new AuthenticatorResponseVerificationException( + 'Credential ID too long.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckExtensions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckExtensions.php new file mode 100644 index 000000000..b74aadea7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckExtensions.php @@ -0,0 +1,37 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $extensionsClientOutputs = $authData->extensions; + if ($extensionsClientOutputs !== null) { + $this->extensionOutputCheckerHandler->check( + $publicKeyCredentialOptions->extensions, + $extensionsClientOutputs + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckHasAttestedCredentialData.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckHasAttestedCredentialData.php new file mode 100644 index 000000000..cf1cd23dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckHasAttestedCredentialData.php @@ -0,0 +1,32 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $authData + ->hasAttestedCredentialData() || throw AuthenticatorResponseVerificationException::create( + 'There is no attested credential data.' + ); + $authData->attestedCredentialData !== null || throw AuthenticatorResponseVerificationException::create( + 'There is no attested credential data.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckMetadataStatement.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckMetadataStatement.php new file mode 100644 index 000000000..59c23c754 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckMetadataStatement.php @@ -0,0 +1,191 @@ +logger = new NullLogger(); + } + + public function enableMetadataStatementSupport( + MetadataStatementRepository $metadataStatementRepository, + StatusReportRepository $statusReportRepository, + CertificateChainValidator $certificateChainValidator + ): void { + $this->metadataStatementRepository = $metadataStatementRepository; + $this->statusReportRepository = $statusReportRepository; + $this->certificateChainValidator = $certificateChainValidator; + } + + public function enableCertificateChainValidator(CertificateChainValidator $certificateChainValidator): void + { + $this->certificateChainValidator = $certificateChainValidator; + } + + public function setLogger(LoggerInterface $logger): void + { + $this->logger = $logger; + } + + public function process( + PublicKeyCredentialSource $publicKeyCredentialSource, + AuthenticatorAssertionResponse|AuthenticatorAttestationResponse $authenticatorResponse, + PublicKeyCredentialRequestOptions|PublicKeyCredentialCreationOptions $publicKeyCredentialOptions, + ?string $userHandle, + string $host + ): void { + if ( + ! $publicKeyCredentialOptions instanceof PublicKeyCredentialCreationOptions + || ! $authenticatorResponse instanceof AuthenticatorAttestationResponse + ) { + return; + } + + $attestationStatement = $authenticatorResponse->attestationObject->attStmt; + $attestedCredentialData = $authenticatorResponse->attestationObject->authData + ->attestedCredentialData; + $attestedCredentialData !== null || throw AuthenticatorResponseVerificationException::create( + 'No attested credential data found' + ); + $aaguid = $attestedCredentialData->aaguid + ->__toString(); + if ($publicKeyCredentialOptions->attestation === null || $publicKeyCredentialOptions->attestation === PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE) { + $this->logger->debug('No attestation is asked.'); + if ($aaguid === '00000000-0000-0000-0000-000000000000' && in_array( + $attestationStatement->type, + [AttestationStatement::TYPE_NONE, AttestationStatement::TYPE_SELF], + true + )) { + $this->logger->debug('The Attestation Statement is anonymous.'); + $this->checkCertificateChain($attestationStatement, null); + return; + } + return; + } + // If no Attestation Statement has been returned or if null AAGUID (=00000000-0000-0000-0000-000000000000) + // => nothing to check + if ($attestationStatement->type === AttestationStatement::TYPE_NONE) { + $this->logger->debug('No attestation returned.'); + //No attestation is returned. We shall ensure that the AAGUID is a null one. + //if ($aaguid !== '00000000-0000-0000-0000-000000000000') { + //$this->logger->debug('Anonymization required. AAGUID and Attestation Statement changed.', [ + // 'aaguid' => $aaguid, + // 'AttestationStatement' => $attestationStatement, + //]); + //$attestedCredentialData->aaguid = Uuid::fromString('00000000-0000-0000-0000-000000000000'); + // return; + //} + return; + } + if ($aaguid === '00000000-0000-0000-0000-000000000000') { + //No need to continue if the AAGUID is null. + // This could be the case e.g. with AnonCA type + return; + } + //The MDS Repository is mandatory here + $this->metadataStatementRepository !== null || throw AuthenticatorResponseVerificationException::create( + 'The Metadata Statement Repository is mandatory when requesting attestation objects.' + ); + $metadataStatement = $this->metadataStatementRepository->findOneByAAGUID($aaguid); + // At this point, the Metadata Statement is mandatory + $metadataStatement !== null || throw AuthenticatorResponseVerificationException::create( + sprintf('The Metadata Statement for the AAGUID "%s" is missing', $aaguid) + ); + // We check the last status report + $this->checkStatusReport($aaguid); + // We check the certificate chain (if any) + $this->checkCertificateChain($attestationStatement, $metadataStatement); + // Check Attestation Type is allowed + if (count($metadataStatement->attestationTypes) !== 0) { + $type = $this->getAttestationType($attestationStatement); + in_array( + $type, + $metadataStatement->attestationTypes, + true + ) || throw AuthenticatorResponseVerificationException::create( + sprintf( + 'Invalid attestation statement. The attestation type "%s" is not allowed for this authenticator.', + $type + ) + ); + } + } + + private function getAttestationType(AttestationStatement $attestationStatement): string + { + return match ($attestationStatement->type) { + AttestationStatement::TYPE_BASIC => MetadataStatement::ATTESTATION_BASIC_FULL, + AttestationStatement::TYPE_SELF => MetadataStatement::ATTESTATION_BASIC_SURROGATE, + AttestationStatement::TYPE_ATTCA => MetadataStatement::ATTESTATION_ATTCA, + AttestationStatement::TYPE_ECDAA => MetadataStatement::ATTESTATION_ECDAA, + AttestationStatement::TYPE_ANONCA => MetadataStatement::ATTESTATION_ANONCA, + default => throw AuthenticatorResponseVerificationException::create('Invalid attestation type'), + }; + } + + private function checkStatusReport(string $aaguid): void + { + $statusReports = $this->statusReportRepository === null ? [] : $this->statusReportRepository->findStatusReportsByAAGUID( + $aaguid + ); + if (count($statusReports) !== 0) { + $lastStatusReport = end($statusReports); + if ($lastStatusReport->isCompromised()) { + throw AuthenticatorResponseVerificationException::create( + 'The authenticator is compromised and cannot be used' + ); + } + } + } + + private function checkCertificateChain( + AttestationStatement $attestationStatement, + ?MetadataStatement $metadataStatement + ): void { + $trustPath = $attestationStatement->trustPath; + if (! $trustPath instanceof CertificateTrustPath) { + return; + } + $authenticatorCertificates = $trustPath->certificates; + if ($metadataStatement === null) { + $this->certificateChainValidator?->check($authenticatorCertificates, []); + return; + } + $trustedCertificates = CertificateToolbox::fixPEMStructures( + $metadataStatement->attestationRootCertificates + ); + $this->certificateChainValidator?->check($authenticatorCertificates, $trustedCertificates); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckOrigin.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckOrigin.php new file mode 100644 index 000000000..950cf6f85 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckOrigin.php @@ -0,0 +1,78 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $C = $authenticatorResponse->clientDataJSON; + $rpId = $publicKeyCredentialOptions->rpId ?? $publicKeyCredentialOptions->rp->id ?? $host; + $facetId = $this->getFacetId($rpId, $publicKeyCredentialOptions->extensions, $authData->extensions); + $parsedRelyingPartyId = parse_url($C->origin); + is_array($parsedRelyingPartyId) || throw AuthenticatorResponseVerificationException::create( + 'Invalid origin' + ); + if (! in_array($facetId, $this->securedRelyingPartyId, true)) { + $scheme = $parsedRelyingPartyId['scheme'] ?? ''; + $scheme === 'https' || throw AuthenticatorResponseVerificationException::create( + 'Invalid scheme. HTTPS required.' + ); + } + $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; + $clientDataRpId !== '' || throw AuthenticatorResponseVerificationException::create('Invalid origin rpId.'); + $rpIdLength = mb_strlen($facetId); + + mb_substr( + '.' . $clientDataRpId, + -($rpIdLength + 1) + ) === '.' . $facetId || throw AuthenticatorResponseVerificationException::create('rpId mismatch.'); + } + + private function getFacetId( + string $rpId, + AuthenticationExtensions $authenticationExtensionsClientInputs, + null|AuthenticationExtensions $authenticationExtensionsClientOutputs + ): string { + if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has( + 'appid' + ) || ! $authenticationExtensionsClientOutputs->has('appid')) { + return $rpId; + } + $appId = $authenticationExtensionsClientInputs->get('appid') + ->value; + $wasUsed = $authenticationExtensionsClientOutputs->get('appid') + ->value; + if (! is_string($appId) || $wasUsed !== true) { + return $rpId; + } + return $appId; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckRelyingPartyIdIdHash.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckRelyingPartyIdIdHash.php new file mode 100644 index 000000000..de45b27b0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckRelyingPartyIdIdHash.php @@ -0,0 +1,63 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $C = $authenticatorResponse->clientDataJSON; + $attestedCredentialData = $publicKeyCredentialSource->getAttestedCredentialData(); + $credentialPublicKey = $attestedCredentialData->credentialPublicKey; + $credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create( + 'No public key available.' + ); + $isU2F = U2FPublicKey::isU2FKey($credentialPublicKey); + $rpId = $publicKeyCredentialOptions->rpId ?? $publicKeyCredentialOptions->rp->id ?? $host; + $facetId = $this->getFacetId($rpId, $publicKeyCredentialOptions->extensions, $authData ->extensions); + $rpIdHash = hash('sha256', $isU2F ? $C->origin : $facetId, true); + hash_equals( + $rpIdHash, + $authData + ->rpIdHash + ) || throw AuthenticatorResponseVerificationException::create('rpId hash mismatch.'); + } + + private function getFacetId( + string $rpId, + AuthenticationExtensions $authenticationExtensionsClientInputs, + null|AuthenticationExtensions $authenticationExtensionsClientOutputs + ): string { + if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has( + 'appid' + ) || ! $authenticationExtensionsClientOutputs->has('appid')) { + return $rpId; + } + $appId = $authenticationExtensionsClientInputs->get('appid') + ->value; + $wasUsed = $authenticationExtensionsClientOutputs->get('appid') + ->value; + if (! is_string($appId) || $wasUsed !== true) { + return $rpId; + } + return $appId; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckSignature.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckSignature.php new file mode 100644 index 000000000..20454dc83 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckSignature.php @@ -0,0 +1,90 @@ +algorithmManager = $algorithmManager ?? Manager::create()->add(ES256::create(), RS256::create()); + } + + public function process( + PublicKeyCredentialSource $publicKeyCredentialSource, + AuthenticatorAssertionResponse|AuthenticatorAttestationResponse $authenticatorResponse, + PublicKeyCredentialRequestOptions|PublicKeyCredentialCreationOptions $publicKeyCredentialOptions, + ?string $userHandle, + string $host + ): void { + if (! $authenticatorResponse instanceof AuthenticatorAssertionResponse) { + return; + } + $credentialPublicKey = $publicKeyCredentialSource->getAttestedCredentialData() + ->credentialPublicKey; + $credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create( + 'No public key available.' + ); + $coseKey = $this->getCoseKey($credentialPublicKey); + + $getClientDataJSONHash = hash('sha256', $authenticatorResponse->clientDataJSON->rawData, true); + $dataToVerify = $authenticatorResponse->authenticatorData->authData . $getClientDataJSONHash; + $signature = $authenticatorResponse->signature; + $algorithm = $this->algorithmManager->get($coseKey->alg()); + $algorithm instanceof Signature || throw AuthenticatorResponseVerificationException::create( + 'Invalid algorithm identifier. Should refer to a signature algorithm' + ); + $signature = CoseSignatureFixer::fix($signature, $algorithm); + $algorithm->verify( + $dataToVerify, + $coseKey, + $signature + ) || throw AuthenticatorResponseVerificationException::create('Invalid signature.'); + } + + private function getCoseKey(string $credentialPublicKey): Key + { + $isU2F = U2FPublicKey::isU2FKey($credentialPublicKey); + if ($isU2F === true) { + $credentialPublicKey = U2FPublicKey::convertToCoseKey($credentialPublicKey); + } + $stream = new StringStream($credentialPublicKey); + $credentialPublicKeyStream = Decoder::create()->decode($stream); + $stream->isEOF() || throw AuthenticatorResponseVerificationException::create( + 'Invalid key. Presence of extra bytes.' + ); + $stream->close(); + $credentialPublicKeyStream instanceof Normalizable || throw AuthenticatorResponseVerificationException::create( + 'Invalid attestation object. Unexpected object.' + ); + $normalizedData = $credentialPublicKeyStream->normalize(); + is_array($normalizedData) || throw AuthenticatorResponseVerificationException::create( + 'Invalid attestation object. Unexpected object.' + ); + /** @var array $normalizedData */ + + return Key::create($normalizedData); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckTopOrigin.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckTopOrigin.php new file mode 100644 index 000000000..bb9a55547 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckTopOrigin.php @@ -0,0 +1,41 @@ +clientDataJSON->topOrigin; + if ($topOrigin === null) { + return; + } + if ($authenticatorResponse->clientDataJSON->crossOrigin !== true) { + throw AuthenticatorResponseVerificationException::create('The response is not cross-origin.'); + } + if ($this->topOriginValidator === null) { + (new HostTopOriginValidator($host))->validate($topOrigin); + } else { + $this->topOriginValidator->validate($topOrigin); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserHandle.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserHandle.php new file mode 100644 index 000000000..27585754e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserHandle.php @@ -0,0 +1,37 @@ +userHandle; + $responseUserHandle = $authenticatorResponse->userHandle; + if ($userHandle !== null) { //If the user was identified before the authentication ceremony was initiated, + $credentialUserHandle === $userHandle || throw InvalidUserHandleException::create(); + if ($responseUserHandle !== null && $responseUserHandle !== '') { + $credentialUserHandle === $responseUserHandle || throw InvalidUserHandleException::create(); + } + } else { + ($responseUserHandle !== '' && $credentialUserHandle === $responseUserHandle) || throw InvalidUserHandleException::create(); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserVerification.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserVerification.php new file mode 100644 index 000000000..392eca8bb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserVerification.php @@ -0,0 +1,33 @@ +userVerification : $publicKeyCredentialOptions->authenticatorSelection?->userVerification; + if ($userVerification !== AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED) { + return; + } + $authData = $authenticatorResponse instanceof AuthenticatorAssertionResponse ? $authenticatorResponse->authenticatorData : $authenticatorResponse->attestationObject->authData; + $authData->isUserVerified() || throw AuthenticatorResponseVerificationException::create( + 'User authentication required.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserWasPresent.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserWasPresent.php new file mode 100644 index 000000000..32fd7fff6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/CheckUserWasPresent.php @@ -0,0 +1,26 @@ +authenticatorData : $authenticatorResponse->attestationObject->authData; + $authData->isUserPresent() || throw AuthenticatorResponseVerificationException::create('User was not present'); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/HostTopOriginValidator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/HostTopOriginValidator.php new file mode 100644 index 000000000..dfccbcccc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/HostTopOriginValidator.php @@ -0,0 +1,22 @@ +host || throw AuthenticatorResponseVerificationException::create( + 'The top origin does not correspond to the host.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/TopOriginValidator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/TopOriginValidator.php new file mode 100644 index 000000000..d189a6118 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CeremonyStep/TopOriginValidator.php @@ -0,0 +1,10 @@ +checkCertificatesValidity($authenticatorCertificates, true); - - return; - } - $this->checkCertificatesValidity($authenticatorCertificates, false); - - $trustedCertificatesFilenames = []; - foreach ($trustedCertificates as $trustedCertificate) { - $trustedCertificatesFilenames[] = $this->saveToTemporaryFile( - $trustedCertificate, - 'webauthn-trusted-', - '.pem' - ); - } - - $leafCertificate = array_shift($authenticatorCertificates); - Assertion::notNull($leafCertificate, 'No leaf certificate from the authenticator certificate list.'); - $untrustedCertificatesFilename = null; - if (count($authenticatorCertificates) !== 0) { - $untrustedCertificatesFilename = $this->saveToTemporaryFile( - implode(PHP_EOL, $authenticatorCertificates), - 'webauthn-untrusted-', - '.pem' - ); - } - - $result = openssl_x509_checkpurpose( - $leafCertificate, - X509_PURPOSE_ANY, - $trustedCertificatesFilenames, - $untrustedCertificatesFilename - ); - if ($result === false) { - throw new RuntimeException('Unable to verify the certificate chain'); - } - $crls = []; - foreach ($trustedCertificates as $certificate) { - $crl = $this->getCrls($certificate); - if ($crl !== '') { - $crls[] = $crl; - } - } - foreach ($authenticatorCertificates as $certificate) { - $crl = $this->getCrls($certificate); - if ($crl !== '') { - $crls[] = $crl; - } - } - $revokedCertificates = []; - foreach ($crls as $crl) { - $crl = CertificateToolbox::convertPEMToDER($crl); - $asn = ASNObject::fromBinary($crl); - Assertion::isInstanceOf($asn, Sequence::class, 'Invalid CRL(1)'); - $asn = $asn->getFirstChild(); - Assertion::isInstanceOf($asn, Sequence::class, 'Invalid CRL(2)'); - Assertion::minCount($asn->getChildren(), 5); - $list = $asn->getChildren()[5]; - Assertion::isInstanceOf($list, Sequence::class, 'Invalid CRL(3)'); - Assertion::allIsInstanceOf($list->getChildren(), Sequence::class, 'Invalid CRL(3)'); - $revokedCertificates = array_merge($revokedCertificates, array_map(static function (Sequence $r): string { - $sn = $r->getFirstChild(); - Assertion::isInstanceOf($sn, Integer::class, 'Invalid CRL(4)'); - - return $sn->getContent(); - }, $list->getChildren())); - } - $certificatesIds = $this->getCertificatesIds(...$trustedCertificates, ...$authenticatorCertificates); - foreach ($certificatesIds as $certificatesId) { - if (in_array($certificatesId, $revokedCertificates, true)) { - throw new RuntimeException(sprintf( - 'The certificate with the serial number "%s" is revoked', - $certificatesId - )); - } - } - - foreach ($trustedCertificatesFilenames as $filename) { - unlink($filename); - } - if ($untrustedCertificatesFilename !== null) { - unlink($untrustedCertificatesFilename); - } - } - - /** - * @param string[] $certificates - */ - private function checkCertificatesValidity(array $certificates, bool $allowRootCertificate): void - { - foreach ($certificates as $certificate) { - $parsed = openssl_x509_parse($certificate); - Assertion::isArray($parsed, 'Unable to read the certificate. Submitted data was: ' . $certificate); - if ($allowRootCertificate === false) { - $this->checkRootCertificate($parsed); - } - - Assertion::keyExists($parsed, 'validTo_time_t', 'The certificate has no validity period'); - Assertion::keyExists($parsed, 'validFrom_time_t', 'The certificate has no validity period'); - Assertion::lessOrEqualThan(time(), $parsed['validTo_time_t'], 'The certificate expired'); - Assertion::greaterOrEqualThan(time(), $parsed['validFrom_time_t'], 'The certificate is not usable yet'); - } - } - - /** - * @param array $parsed - */ - private function checkRootCertificate(array $parsed): void - { - Assertion::keyExists($parsed, 'subject', 'The certificate has no subject'); - Assertion::keyExists($parsed, 'issuer', 'The certificate has no issuer'); - $subject = $parsed['subject']; - $issuer = $parsed['issuer']; - ksort($subject); - ksort($issuer); - Assertion::notEq($subject, $issuer, 'Root certificates are not allowed'); - } - - private function saveToTemporaryFile(string $certificate, string $prefix, string $suffix): string - { - $filename = tempnam(sys_get_temp_dir(), $prefix); - rename($filename, $filename . $suffix); - file_put_contents($filename . $suffix, $certificate, FILE_APPEND); - - return $filename . $suffix; - } - - private function getCrls(string $certificate): string - { - $parsed = openssl_x509_parse($certificate); - if ($parsed === false || ! isset($parsed['extensions']['crlDistributionPoints'])) { - return ''; - } - $endpoint = $parsed['extensions']['crlDistributionPoints']; - $pos = mb_strpos((string) $endpoint, 'URI:'); - if (! is_int($pos)) { - return ''; - } - $endpoint = trim(mb_substr((string) $endpoint, $pos + 4)); - - $request = $this->requestFactory->createRequest('GET', $endpoint); - try { - $response = $this->client->sendRequest($request); - if ($response->getStatusCode() !== 200) { - return ''; - } - - return $response->getBody() - ->getContents() - ; - } catch (Throwable) { - return ''; - } - } - - /** - * @return string[] - */ - private function getCertificatesIds(string ...$certificates): iterable - { - return array_map(static function (string $cert): string { - $details = openssl_x509_parse($cert); - Assertion::isArray($details, 'Unable to parse the X509 certificate'); - - return $details['serialNumber']; - }, $certificates); - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php index 22693fe36..18b07aa9d 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php @@ -4,92 +4,12 @@ declare(strict_types=1); namespace Webauthn; -use function in_array; -use ParagonIE\ConstantTime\Base64; -use const PHP_EOL; -use function Safe\preg_replace; +use Webauthn\MetadataService\CertificateChain\CertificateToolbox as BaseCertificateToolbox; -class CertificateToolbox +/** + * @deprecated since v4.1. Please use Webauthn\MetadataService\CertificateChainChecker\PhpCertificateChainValidator instead + * @infection-ignore-all + */ +class CertificateToolbox extends BaseCertificateToolbox { - /** - * @param string[] $data - * - * @return string[] - */ - public static function fixPEMStructures(array $data, string $type = 'CERTIFICATE'): array - { - return array_map(static fn ($d): string => self::fixPEMStructure($d, $type), $data); - } - - public static function fixPEMStructure(string $data, string $type = 'CERTIFICATE'): string - { - if (str_contains($data, '-----BEGIN')) { - return $data; - } - $pem = '-----BEGIN ' . $type . '-----' . PHP_EOL; - $pem .= chunk_split($data, 64, PHP_EOL); - - return $pem . ('-----END ' . $type . '-----' . PHP_EOL); - } - - public static function convertPEMToDER(string $data): string - { - if (! str_contains($data, '-----BEGIN')) { - return $data; - } - $data = preg_replace('/[\-]{5}.*[\-]{5}[\r\n]*/', '', $data); - $data = preg_replace("/[\r\n]*/", '', $data); - - return Base64::decode(trim($data), true); - } - - public static function convertDERToPEM(string $data, string $type = 'CERTIFICATE'): string - { - if (str_contains($data, '-----BEGIN')) { - return $data; - } - $der = self::unusedBytesFix($data); - - return self::fixPEMStructure(base64_encode($der), $type); - } - - /** - * @param string[] $data - * - * @return string[] - */ - public static function convertAllDERToPEM(iterable $data, string $type = 'CERTIFICATE'): array - { - $certificates = []; - foreach ($data as $d) { - $certificates[] = self::convertDERToPEM($d, $type); - } - - return $certificates; - } - - private static function unusedBytesFix(string $data): string - { - $hash = hash('sha256', $data); - if (in_array($hash, self::getCertificateHashes(), true)) { - $data[mb_strlen($data, '8bit') - 257] = "\0"; - } - - return $data; - } - - /** - * @return string[] - */ - private static function getCertificateHashes(): array - { - return [ - '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8', - 'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f', - '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae', - 'd0edc9a91a1677435a953390865d208c55b3183c6759c9b5a7ff494c322558eb', - '6073c436dcd064a48127ddbf6032ac1a66fd59a0c24434f070d4e564c124c897', - 'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511', - ]; - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/ClientDataCollector.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/ClientDataCollector.php new file mode 100644 index 000000000..7da6dc7f0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/ClientDataCollector.php @@ -0,0 +1,24 @@ +clientDataCollectors as $clientDataCollector) { + if (in_array($collectedClientData->type, $clientDataCollector->supportedTypes(), true)) { + $clientDataCollector->verifyCollectedClientData( + $collectedClientData, + $publicKeyCredentialOptions, + $authenticatorResponse, + $host + ); + return; + } + } + + throw AuthenticatorResponseVerificationException::create('No client data collector found.'); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/WebauthnAuthenticationCollector.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/WebauthnAuthenticationCollector.php new file mode 100644 index 000000000..ea97fdf1e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/ClientDataCollector/WebauthnAuthenticationCollector.php @@ -0,0 +1,35 @@ +type, + $this->supportedTypes(), + true + ) || throw AuthenticatorResponseVerificationException::create( + sprintf('The client data type is not "%s" supported.', implode('", "', $this->supportedTypes())) + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php index d2bb54728..f7c14b531 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php @@ -4,105 +4,151 @@ declare(strict_types=1); namespace Webauthn; -use function array_key_exists; -use Assert\Assertion; -use InvalidArgumentException; -use const JSON_THROW_ON_ERROR; -use Throwable; +use ParagonIE\ConstantTime\Base64UrlSafe; +use Webauthn\Exception\InvalidDataException; use Webauthn\TokenBinding\TokenBinding; -use Webauthn\Util\Base64; +use function array_key_exists; +use function is_array; +use function is_string; +use function sprintf; +use const JSON_THROW_ON_ERROR; class CollectedClientData { /** * @var mixed[] */ - private readonly array $data; + public readonly array $data; - private readonly string $type; + public readonly string $type; - private readonly string $challenge; + public readonly string $challenge; - private readonly string $origin; + public readonly string $origin; + + public readonly null|string $topOrigin; + + public readonly bool $crossOrigin; /** * @var mixed[]|null + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all */ - private readonly ?array $tokenBinding; + public readonly ?array $tokenBinding; /** * @param mixed[] $data */ public function __construct( - private readonly string $rawData, + public readonly string $rawData, array $data ) { - $this->type = $this->findData( + $type = $data['type'] ?? ''; + (is_string($type) && $type !== '') || throw InvalidDataException::create( $data, - 'type', - static function ($d): void { - Assertion::string($d, 'Invalid parameter "type". Shall be a string.'); - Assertion::notEmpty($d, 'Invalid parameter "type". Shall not be empty.'); - } + 'Invalid parameter "type". Shall be a non-empty string.' ); - $this->challenge = $this->findData( + $this->type = $type; + + $challenge = $data['challenge'] ?? ''; + is_string($challenge) || throw InvalidDataException::create( $data, - 'challenge', - static function ($d): void { - Assertion::string($d, 'Invalid parameter "challenge". Shall be a string.'); - Assertion::notEmpty($d, 'Invalid parameter "challenge". Shall not be empty.'); - }, - true, - true + 'Invalid parameter "challenge". Shall be a string.' ); - $this->origin = $this->findData( + $challenge = Base64UrlSafe::decodeNoPadding($challenge); + $challenge !== '' || throw InvalidDataException::create( $data, - 'origin', - static function ($d): void { - Assertion::string($d, 'Invalid parameter "origin". Shall be a string.'); - Assertion::notEmpty($d, 'Invalid parameter "origin". Shall not be empty.'); - } + 'Invalid parameter "challenge". Shall not be empty.' ); - $this->tokenBinding = $this->findData( + $this->challenge = $challenge; + + $origin = $data['origin'] ?? ''; + (is_string($origin) && $origin !== '') || throw InvalidDataException::create( $data, - 'tokenBinding', - static function ($d): void { - Assertion::isArray($d, 'Invalid parameter "tokenBinding". Shall be an object.'); - }, - false + 'Invalid parameter "origin". Shall be a non-empty string.' ); + $this->origin = $origin; + + $this->topOrigin = $data['topOrigin'] ?? null; + $this->crossOrigin = $data['crossOrigin'] ?? false; + + $tokenBinding = $data['tokenBinding'] ?? null; + $tokenBinding === null || is_array($tokenBinding) || throw InvalidDataException::create( + $data, + 'Invalid parameter "tokenBinding". Shall be an object or .' + ); + $this->tokenBinding = $tokenBinding; + $this->data = $data; } + /** + * @param mixed[] $data + */ + public static function create(string $rawData, array $data): self + { + return new self($rawData, $data); + } + public static function createFormJson(string $data): self { - $rawData = Base64::decodeUrlSafe($data); - $json = json_decode($rawData, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($json, 'Invalid collected client data'); + $rawData = Base64UrlSafe::decodeNoPadding($data); + $json = json_decode($rawData, true, flags: JSON_THROW_ON_ERROR); + is_array($json) || throw InvalidDataException::create($data, 'Invalid JSON data.'); - return new self($rawData, $json); + return self::create($rawData, $json); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getChallenge(): string { return $this->challenge; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getOrigin(): string { return $this->origin; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCrossOrigin(): bool + { + return $this->crossOrigin; + } + + /** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ public function getTokenBinding(): ?TokenBinding { return $this->tokenBinding === null ? null : TokenBinding::createFormArray($this->tokenBinding); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRawData(): string { return $this->rawData; @@ -124,42 +170,9 @@ class CollectedClientData public function get(string $key): mixed { if (! $this->has($key)) { - throw new InvalidArgumentException(sprintf('The key "%s" is missing', $key)); + throw InvalidDataException::create($this->data, sprintf('The key "%s" is missing', $key)); } return $this->data[$key]; } - - /** - * @param mixed[] $json - * - * @return mixed|null - */ - private function findData( - array $json, - string $key, - callable $check, - bool $isRequired = true, - bool $isB64 = false - ): mixed { - if (! array_key_exists($key, $json)) { - if ($isRequired) { - throw new InvalidArgumentException(sprintf('The key "%s" is missing', $key)); - } - - return null; - } - - $check($json[$key]); - try { - $data = $isB64 ? Base64::decodeUrlSafe($json[$key]) : $json[$key]; - } catch (Throwable $e) { - throw new InvalidArgumentException(sprintf( - 'The parameter "%s" shall be Base64 Url Safe encoded', - $key - ), 0, $e); - } - - return $data; - } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Counter/ThrowExceptionIfInvalid.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Counter/ThrowExceptionIfInvalid.php index 71df86677..bf411d2a4 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Counter/ThrowExceptionIfInvalid.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Counter/ThrowExceptionIfInvalid.php @@ -4,16 +4,17 @@ declare(strict_types=1); namespace Webauthn\Counter; -use Assert\Assertion; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use Throwable; +use Webauthn\Exception\CounterException; +use Webauthn\MetadataService\CanLogData; use Webauthn\PublicKeyCredentialSource; -final class ThrowExceptionIfInvalid implements CounterChecker +final class ThrowExceptionIfInvalid implements CounterChecker, CanLogData { - public function __construct(private LoggerInterface $logger = new NullLogger()) - { + public function __construct( + private LoggerInterface $logger = new NullLogger() + ) { } public function setLogger(LoggerInterface $logger): void @@ -24,11 +25,15 @@ final class ThrowExceptionIfInvalid implements CounterChecker public function check(PublicKeyCredentialSource $publicKeyCredentialSource, int $currentCounter): void { try { - Assertion::greaterThan($currentCounter, $publicKeyCredentialSource->getCounter(), 'Invalid counter.'); - } catch (Throwable $throwable) { + $currentCounter > $publicKeyCredentialSource->counter || throw CounterException::create( + $currentCounter, + $publicKeyCredentialSource->counter, + 'Invalid counter.' + ); + } catch (CounterException $throwable) { $this->logger->error('The counter is invalid', [ 'current' => $currentCounter, - 'new' => $publicKeyCredentialSource->getCounter(), + 'new' => $publicKeyCredentialSource->counter, ]); throw $throwable; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php index 075226449..7b0e7b28b 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php @@ -4,22 +4,55 @@ declare(strict_types=1); namespace Webauthn; +use InvalidArgumentException; +use ParagonIE\ConstantTime\Base64UrlSafe; + /** * @see https://w3c.github.io/webappsec-credential-management/#credential */ abstract class Credential { + /** + * @deprecated since 4.9.0. Please use the property rawId instead. + */ + public readonly string $id; + + public readonly string $rawId; + public function __construct( - protected string $id, - protected string $type + null|string $id, + public readonly string $type, + null|string $rawId = null, ) { + if ($id === null && $rawId === null) { + throw new InvalidArgumentException('You must provide a valid raw ID'); + } + if ($id !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.9.0', + 'The property "$id" is deprecated and will be removed in 5.0.0. Please set null use "rawId" instead.' + ); + } else { + $id = Base64UrlSafe::encodeUnpadded($rawId); + } + $this->id = $id; + $this->rawId = $rawId ?? Base64UrlSafe::decodeNoPadding($id); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getId(): string { return $this->id; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationObjectDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationObjectDenormalizer.php new file mode 100644 index 000000000..eae463088 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationObjectDenormalizer.php @@ -0,0 +1,67 @@ +decode($stream); + + $parsed instanceof Normalizable || throw InvalidDataException::create( + $parsed, + 'Invalid attestation object. Unexpected object.' + ); + $attestationObject = $parsed->normalize(); + $stream->isEOF() || throw InvalidDataException::create( + null, + 'Invalid attestation object. Presence of extra bytes.' + ); + $stream->close(); + $authData = $attestationObject['authData'] ?? throw InvalidDataException::create( + $attestationObject, + 'Invalid attestation object. Missing "authData" field.' + ); + + return AttestationObject::create( + $data, + $this->denormalizer->denormalize($attestationObject, AttestationStatement::class, $format, $context), + $this->denormalizer->denormalize($authData, AuthenticatorData::class, $format, $context), + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AttestationObject::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AttestationObject::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationStatementDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationStatementDenormalizer.php new file mode 100644 index 000000000..fc3d0be0a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestationStatementDenormalizer.php @@ -0,0 +1,43 @@ +attestationStatementSupportManager->get($data['fmt']); + + return $attestationStatementSupport->load($data); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AttestationStatement::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AttestationStatement::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestedCredentialDataNormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestedCredentialDataNormalizer.php new file mode 100644 index 000000000..05bd09100 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AttestedCredentialDataNormalizer.php @@ -0,0 +1,45 @@ + + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof AttestedCredentialData); + $result = [ + 'aaguid' => $this->normalizer->normalize($data->aaguid, $format, $context), + 'credentialId' => base64_encode($data->credentialId), + ]; + if ($data->credentialPublicKey !== null) { + $result['credentialPublicKey'] = base64_encode($data->credentialPublicKey); + } + + return $result; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof AttestedCredentialData; + } + + public function getSupportedTypes(?string $format): array + { + return [ + AttestedCredentialData::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionNormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionNormalizer.php new file mode 100644 index 000000000..b34d29dea --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionNormalizer.php @@ -0,0 +1,37 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticationExtension::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof AuthenticationExtension); + + return $data->value; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof AuthenticationExtension; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionsDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionsDenormalizer.php new file mode 100644 index 000000000..9c2e80a5d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticationExtensionsDenormalizer.php @@ -0,0 +1,83 @@ +extensions); + } + assert(is_array($data), 'The data should be an array.'); + foreach ($data as $key => $value) { + if (! is_string($key)) { + continue; + } + $data[$key] = AuthenticationExtension::create($key, $value); + } + + return AuthenticationExtensions::create($data); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return in_array( + $type, + [ + AuthenticationExtensions::class, + AuthenticationExtensionsClientOutputs::class, + AuthenticationExtensionsClientInputs::class, + ], + true + ); + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticationExtensions::class => true, + AuthenticationExtensionsClientInputs::class => true, + AuthenticationExtensionsClientOutputs::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof AuthenticationExtensions); + $extensions = []; + foreach ($data->extensions as $extension) { + $extensions[$extension->name] = $extension->value; + } + + return $extensions; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof AuthenticationExtensions; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php new file mode 100644 index 000000000..fd8927ff2 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php @@ -0,0 +1,63 @@ +denormalizer->denormalize($data['clientDataJSON'], CollectedClientData::class, $format, $context), + $this->denormalizer->denormalize($data['authenticatorData'], AuthenticatorData::class, $format, $context), + $data['signature'], + $userHandle ?? null, + ! isset($data['attestationObject']) ? null : $this->denormalizer->denormalize( + $data['attestationObject'], + AttestationObject::class, + $format, + $context + ), + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AuthenticatorAssertionResponse::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticatorAssertionResponse::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAttestationResponseDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAttestationResponseDenormalizer.php new file mode 100644 index 000000000..a634fb6a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorAttestationResponseDenormalizer.php @@ -0,0 +1,63 @@ +denormalizer->denormalize( + $data['clientDataJSON'], + CollectedClientData::class, + $format, + $context + ); + $attestationObject = $this->denormalizer->denormalize( + $data['attestationObject'], + AttestationObject::class, + $format, + $context + ); + + return AuthenticatorAttestationResponse::create( + $clientDataJSON, + $attestationObject, + $data['transports'] ?? [], + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AuthenticatorAttestationResponse::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticatorAttestationResponse::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorDataDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorDataDenormalizer.php new file mode 100644 index 000000000..12aa21e06 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorDataDenormalizer.php @@ -0,0 +1,144 @@ +decoder = Decoder::create(); + } + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed + { + $authData = $this->fixIncorrectEdDSAKey($data); + $authDataStream = new StringStream($authData); + $rp_id_hash = $authDataStream->read(32); + $flags = $authDataStream->read(1); + $signCount = $authDataStream->read(4); + $signCount = unpack('N', $signCount); + + $attestedCredentialData = null; + if (0 !== (ord($flags) & AuthenticatorData::FLAG_AT)) { + $aaguid = Uuid::fromBinary($authDataStream->read(16)); + $credentialLength = $authDataStream->read(2); + $credentialLength = unpack('n', $credentialLength); + $credentialId = $authDataStream->read($credentialLength[1]); + $credentialPublicKey = $this->decoder->decode($authDataStream); + $credentialPublicKey instanceof MapObject || throw InvalidDataException::create( + $authData, + 'The data does not contain a valid credential public key.' + ); + $attestedCredentialData = AttestedCredentialData::create( + $aaguid, + $credentialId, + (string) $credentialPublicKey, + ); + } + $extension = null; + if (0 !== (ord($flags) & AuthenticatorData::FLAG_ED)) { + $extension = $this->decoder->decode($authDataStream); + $extension = AuthenticationExtensionsClientOutputsLoader::load($extension); + } + $authDataStream->isEOF() || throw InvalidDataException::create( + $authData, + 'Invalid authentication data. Presence of extra bytes.' + ); + $authDataStream->close(); + + return AuthenticatorData::create( + $authData, + $rp_id_hash, + $flags, + $signCount[1], + $attestedCredentialData, + $extension === null ? null : $this->denormalizer->denormalize( + $extension, + AuthenticationExtensions::class, + $format, + $context + ), + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AuthenticatorData::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticatorData::class => true, + ]; + } + + private function fixIncorrectEdDSAKey(string $data): string + { + $needle = hex2bin('a301634f4b500327206745643235353139'); + $correct = hex2bin('a401634f4b500327206745643235353139'); + $position = mb_strpos($data, $needle, 0, '8bit'); + if ($position === false) { + return $data; + } + + $begin = mb_substr($data, 0, $position, '8bit'); + $end = mb_substr($data, $position, null, '8bit'); + $end = str_replace($needle, $correct, $end); + $cbor = new StringStream($end); + $badKey = $this->decoder->decode($cbor); + + ($badKey instanceof MapObject && $cbor->isEOF()) || throw InvalidDataException::create( + $end, + 'Invalid authentication data. Presence of extra bytes.' + ); + $badX = $badKey->get(-2); + $badX instanceof ListObject || throw InvalidDataException::create($end, 'Invalid authentication data.'); + $keyBytes = array_reduce( + $badX->normalize(), + static fn (string $carry, string $item): string => $carry . chr((int) $item), + '' + ); + $correctX = ByteStringObject::create($keyBytes); + $correctKey = MapObject::create() + ->add(UnsignedIntegerObject::create(1), TextStringObject::create('OKP')) + ->add(UnsignedIntegerObject::create(3), NegativeIntegerObject::create(-8)) + ->add(NegativeIntegerObject::create(-1), TextStringObject::create('Ed25519')) + ->add(NegativeIntegerObject::create(-2), $correctX); + + return $begin . $correctKey; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorResponseDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorResponseDenormalizer.php new file mode 100644 index 000000000..63d152def --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/AuthenticatorResponseDenormalizer.php @@ -0,0 +1,49 @@ + AuthenticatorAttestationResponse::class, + array_key_exists('signature', $data) => AuthenticatorAssertionResponse::class, + default => throw InvalidDataException::create($data, 'Unable to create the response object'), + }; + + return $this->denormalizer->denormalize($data, $realType, $format, $context); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === AuthenticatorResponse::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticatorResponse::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/CollectedClientDataDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/CollectedClientDataDenormalizer.php new file mode 100644 index 000000000..fec3a7481 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/CollectedClientDataDenormalizer.php @@ -0,0 +1,40 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + CollectedClientData::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/ExtensionDescriptorDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/ExtensionDescriptorDenormalizer.php new file mode 100644 index 000000000..d67afd910 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/ExtensionDescriptorDenormalizer.php @@ -0,0 +1,56 @@ +denormalizer->denormalize($data, $type, $format, $context); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + if ($context[self::ALREADY_CALLED] ?? false) { + return false; + } + + return $type === ExtensionDescriptor::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + ExtensionDescriptor::class => false, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDenormalizer.php new file mode 100644 index 000000000..ba5508927 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDenormalizer.php @@ -0,0 +1,57 @@ +denormalizer->denormalize($data['response'], AuthenticatorResponse::class, $format, $context), + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === PublicKeyCredential::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredential::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php new file mode 100644 index 000000000..ec6a4b3d2 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php @@ -0,0 +1,47 @@ + + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof PublicKeyCredentialDescriptor); + $result = [ + 'type' => $data->type, + 'id' => Base64UrlSafe::encodeUnpadded($data->id), + ]; + if (count($data->transports) !== 0) { + $result['transports'] = $data->transports; + } + + return $result; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialDescriptor; + } + + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialDescriptor::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php new file mode 100644 index 000000000..326a37378 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php @@ -0,0 +1,183 @@ + $allowCredential) { + $data[$key][$item]['id'] = Base64UrlSafe::decodeNoPadding($allowCredential['id']); + } + } + } + if ($type === PublicKeyCredentialCreationOptions::class) { + return PublicKeyCredentialCreationOptions::create( + $this->denormalizer->denormalize($data['rp'], PublicKeyCredentialRpEntity::class, $format, $context), + $this->denormalizer->denormalize( + $data['user'], + PublicKeyCredentialUserEntity::class, + $format, + $context + ), + $data['challenge'], + ! isset($data['pubKeyCredParams']) ? [] : $this->denormalizer->denormalize( + $data['pubKeyCredParams'], + PublicKeyCredentialParameters::class . '[]', + $format, + $context + ), + ! isset($data['authenticatorSelection']) ? null : $this->denormalizer->denormalize( + $data['authenticatorSelection'], + AuthenticatorSelectionCriteria::class, + $format, + $context + ), + $data['attestation'] ?? null, + ! isset($data['excludeCredentials']) ? [] : $this->denormalizer->denormalize( + $data['excludeCredentials'], + PublicKeyCredentialDescriptor::class . '[]', + $format, + $context + ), + $data['timeout'] ?? null, + ! isset($data['extensions']) ? null : $this->denormalizer->denormalize( + $data['extensions'], + AuthenticationExtensions::class, + $format, + $context + ), + ); + } + if ($type === PublicKeyCredentialRequestOptions::class) { + return PublicKeyCredentialRequestOptions::create( + $data['challenge'], + $data['rpId'] ?? null, + ! isset($data['allowCredentials']) ? [] : $this->denormalizer->denormalize( + $data['allowCredentials'], + PublicKeyCredentialDescriptor::class . '[]', + $format, + $context + ), + $data['userVerification'] ?? null, + $data['timeout'] ?? null, + ! isset($data['extensions']) ? null : $this->denormalizer->denormalize( + $data['extensions'], + AuthenticationExtensions::class, + $format, + $context + ), + ); + } + throw new BadMethodCallException('Unsupported type'); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return in_array( + $type, + [PublicKeyCredentialCreationOptions::class, PublicKeyCredentialRequestOptions::class], + true + ); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialCreationOptions || $data instanceof PublicKeyCredentialRequestOptions; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialCreationOptions::class => true, + PublicKeyCredentialRequestOptions::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert( + $data instanceof PublicKeyCredentialCreationOptions || $data instanceof PublicKeyCredentialRequestOptions + ); + $json = [ + 'challenge' => Base64UrlSafe::encodeUnpadded($data->challenge), + 'timeout' => $data->timeout, + 'extensions' => $data->extensions->count() === 0 ? null : $this->normalizer->normalize( + $data->extensions, + $format, + $context + ), + ]; + + if ($data instanceof PublicKeyCredentialCreationOptions) { + $json = [ + ...$json, + 'rp' => $this->normalizer->normalize($data->rp, $format, $context), + 'user' => $this->normalizer->normalize($data->user, $format, $context), + 'pubKeyCredParams' => $this->normalizer->normalize( + $data->pubKeyCredParams, + PublicKeyCredentialParameters::class . '[]', + $context + ), + 'authenticatorSelection' => $data->authenticatorSelection === null ? null : $this->normalizer->normalize( + $data->authenticatorSelection, + $format, + $context + ), + 'attestation' => $data->attestation, + 'excludeCredentials' => $this->normalizer->normalize($data->excludeCredentials, $format, $context), + ]; + } + if ($data instanceof PublicKeyCredentialRequestOptions) { + $json = [ + ...$json, + 'rpId' => $data->rpId, + 'allowCredentials' => $this->normalizer->normalize($data->allowCredentials, $format, $context), + 'userVerification' => $data->userVerification, + ]; + } + + return array_filter($json, static fn ($value) => $value !== null && $value !== []); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialParametersDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialParametersDenormalizer.php new file mode 100644 index 000000000..0114c3a6a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialParametersDenormalizer.php @@ -0,0 +1,41 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialParameters::class => true, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php new file mode 100644 index 000000000..3a963afa6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php @@ -0,0 +1,100 @@ +denormalizer->denormalize($data['trustPath'], TrustPath::class, $format, $context), + Uuid::fromString($data['aaguid']), + $data['credentialPublicKey'], + $data['userHandle'], + $data['counter'], + $data['otherUI'] ?? null, + $data['backupEligible'] ?? null, + $data['backupStatus'] ?? null, + $data['uvInitialized'] ?? null, + ); + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === PublicKeyCredentialSource::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialSource::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof PublicKeyCredentialSource); + $result = [ + 'publicKeyCredentialId' => Base64UrlSafe::encodeUnpadded($data->publicKeyCredentialId), + 'type' => $data->type, + 'transports' => $data->transports, + 'attestationType' => $data->attestationType, + 'trustPath' => $this->normalizer->normalize($data->trustPath, $format, $context), + 'aaguid' => $this->normalizer->normalize($data->aaguid, $format, $context), + 'credentialPublicKey' => Base64UrlSafe::encodeUnpadded($data->credentialPublicKey), + 'userHandle' => Base64UrlSafe::encodeUnpadded($data->userHandle), + 'counter' => $data->counter, + 'otherUI' => $data->otherUI, + 'backupEligible' => $data->backupEligible, + 'backupStatus' => $data->backupStatus, + 'uvInitialized' => $data->uvInitialized, + ]; + + return array_filter($result, static fn ($value): bool => $value !== null); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialSource; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialUserEntityDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialUserEntityDenormalizer.php new file mode 100644 index 000000000..0ac7f5d12 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/PublicKeyCredentialUserEntityDenormalizer.php @@ -0,0 +1,71 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialUserEntity::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof PublicKeyCredentialUserEntity); + $normalized = [ + 'id' => Base64UrlSafe::encodeUnpadded($data->id), + 'name' => $data->name, + 'displayName' => $data->displayName, + 'icon' => $data->icon, + ]; + + return array_filter($normalized, fn ($value) => $value !== null); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialUserEntity; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/TrustPathDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/TrustPathDenormalizer.php new file mode 100644 index 000000000..4a565ed88 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/TrustPathDenormalizer.php @@ -0,0 +1,70 @@ + new EcdaaKeyIdTrustPath($data), + array_key_exists('x5c', $data) => CertificateTrustPath::create($data), + $data === [], isset($data['type']) && $data['type'] === EmptyTrustPath::class => EmptyTrustPath::create(), + default => throw new InvalidTrustPathException('Unsupported trust path type'), + }; + } + + public function supportsDenormalization( + mixed $data, + string $type, + ?string $format = null, + array $context = [] + ): bool { + return $type === TrustPath::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + TrustPath::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof TrustPath); + return match (true) { + $data instanceof EcdaaKeyIdTrustPath => [ + 'ecdaaKeyId' => $data->getEcdaaKeyId(), + ], + $data instanceof CertificateTrustPath => [ + 'x5c' => $data->certificates, + ], + $data instanceof EmptyTrustPath => [], + default => throw new InvalidTrustPathException('Unsupported trust path type'), + }; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof TrustPath; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/VerificationMethodANDCombinationsDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/VerificationMethodANDCombinationsDenormalizer.php new file mode 100644 index 000000000..64f69439e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/VerificationMethodANDCombinationsDenormalizer.php @@ -0,0 +1,45 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + VerificationMethodANDCombinations::class => true, + ]; + } + + /** + * @return array + */ + public function normalize(mixed $object, ?string $format = null, array $context = []): array + { + assert($object instanceof VerificationMethodANDCombinations); + + return array_map( + fn ($verificationMethod) => $this->normalizer->normalize($verificationMethod, $format, $context), + $object->verificationMethods + ); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof VerificationMethodANDCombinations; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/WebauthnSerializerFactory.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/WebauthnSerializerFactory.php new file mode 100644 index 000000000..f7dc10915 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Denormalizer/WebauthnSerializerFactory.php @@ -0,0 +1,93 @@ + $package) { + if (! class_exists($class)) { + throw new RuntimeException(sprintf( + 'The class "%s" is required. Please install the package "%s" to use this feature.', + $class, + $package + )); + } + } + + $denormalizers = [ + new ExtensionDescriptorDenormalizer(), + new VerificationMethodANDCombinationsDenormalizer(), + new AuthenticationExtensionNormalizer(), + new PublicKeyCredentialDescriptorNormalizer(), + new AttestedCredentialDataNormalizer(), + new AttestationObjectDenormalizer(), + new AttestationStatementDenormalizer($this->attestationStatementSupportManager), + new AuthenticationExtensionsDenormalizer(), + new AuthenticatorAssertionResponseDenormalizer(), + new AuthenticatorAttestationResponseDenormalizer(), + new AuthenticatorDataDenormalizer(), + new AuthenticatorResponseDenormalizer(), + new CollectedClientDataDenormalizer(), + new PublicKeyCredentialDenormalizer(), + new PublicKeyCredentialOptionsDenormalizer(), + new PublicKeyCredentialSourceDenormalizer(), + new PublicKeyCredentialUserEntityDenormalizer(), + new TrustPathDenormalizer(), + new UidNormalizer(), + new ArrayDenormalizer(), + new ObjectNormalizer( + propertyTypeExtractor: new PropertyInfoExtractor(typeExtractors: [ + new PhpDocExtractor(), + new ReflectionExtractor(), + ]) + ), + ]; + + return new Serializer($denormalizers, [new JsonEncoder()]); + } + + /** + * @return array + */ + private static function getRequiredSerializerClasses(): array + { + return [ + UidNormalizer::class => self::PACKAGE_SYMFONY_SERIALIZER, + ArrayDenormalizer::class => self::PACKAGE_SYMFONY_SERIALIZER, + ObjectNormalizer::class => self::PACKAGE_SYMFONY_SERIALIZER, + PropertyInfoExtractor::class => self::PACKAGE_SYMFONY_PROPERTY_INFO, + PhpDocExtractor::class => self::PACKAGE_PHPDOCUMENTOR_REFLECTION_DOCBLOCK, + ReflectionExtractor::class => self::PACKAGE_SYMFONY_PROPERTY_INFO, + JsonEncoder::class => self::PACKAGE_SYMFONY_SERIALIZER, + Serializer::class => self::PACKAGE_SYMFONY_SERIALIZER, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AttestationObjectLoaded.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AttestationObjectLoaded.php new file mode 100644 index 000000000..f3cbb14bc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AttestationObjectLoaded.php @@ -0,0 +1,20 @@ +credentialId instanceof PublicKeyCredentialSource) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.6.0', + 'Passing a string for the argument "$credentialId" is deprecated since 4.6.0. Please set the PublicKeyCredentialSource instead.' + ); + } + } + + /** + * @deprecated since 4.7.0 and will be removed in 5.0.0. Please use the `getCredential()` method instead + * @infection-ignore-all + */ + public function getCredentialId(): string + { + return $this->credentialId instanceof PublicKeyCredentialSource ? $this->credentialId->publicKeyCredentialId : $this->credentialId; + } + + public function getCredential(): ?PublicKeyCredentialSource + { + return $this->credentialId instanceof PublicKeyCredentialSource ? $this->credentialId : null; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getAuthenticatorAssertionResponse(): AuthenticatorAssertionResponse + { + return $this->authenticatorAssertionResponse; + } + + public function getPublicKeyCredentialRequestOptions(): PublicKeyCredentialRequestOptions + { + return $this->publicKeyCredentialRequestOptions; + } + + /** + * @deprecated since 4.5.0 and will be removed in 5.0.0. Please use the `host` property instead + * @infection-ignore-all + */ + public function getRequest(): ServerRequestInterface|string + { + return $this->host; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getUserHandle(): ?string + { + return $this->userHandle; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getThrowable(): Throwable + { + return $this->throwable; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAssertionResponseValidationSucceededEvent.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAssertionResponseValidationSucceededEvent.php new file mode 100644 index 000000000..75925582a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAssertionResponseValidationSucceededEvent.php @@ -0,0 +1,91 @@ +credentialId !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.6.0', + 'The argument "$credentialId" is deprecated since 4.6.0 and will be removed in 5.0.0. Please set null instead.' + ); + } + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getCredentialId(): string + { + return $this->publicKeyCredentialSource->publicKeyCredentialId; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getAuthenticatorAssertionResponse(): AuthenticatorAssertionResponse + { + return $this->authenticatorAssertionResponse; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getPublicKeyCredentialRequestOptions(): PublicKeyCredentialRequestOptions + { + return $this->publicKeyCredentialRequestOptions; + } + + /** + * @deprecated since 4.5.0 and will be removed in 5.0.0. Please use the `host` property instead + * @infection-ignore-all + */ + public function getRequest(): ServerRequestInterface|string + { + return $this->host; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getUserHandle(): ?string + { + return $this->userHandle; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getPublicKeyCredentialSource(): PublicKeyCredentialSource + { + return $this->publicKeyCredentialSource; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationFailedEvent.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationFailedEvent.php new file mode 100644 index 000000000..3c8168d5c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationFailedEvent.php @@ -0,0 +1,66 @@ +authenticatorAttestationResponse; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getPublicKeyCredentialCreationOptions(): PublicKeyCredentialCreationOptions + { + return $this->publicKeyCredentialCreationOptions; + } + + /** + * @deprecated since 4.5.0 and will be removed in 5.0.0. Please use the `host` property instead + * @infection-ignore-all + */ + public function getRequest(): ServerRequestInterface|string + { + return $this->host; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getThrowable(): Throwable + { + return $this->throwable; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationSucceededEvent.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationSucceededEvent.php new file mode 100644 index 000000000..6145464ec --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/AuthenticatorAttestationResponseValidationSucceededEvent.php @@ -0,0 +1,66 @@ +authenticatorAttestationResponse; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getPublicKeyCredentialCreationOptions(): PublicKeyCredentialCreationOptions + { + return $this->publicKeyCredentialCreationOptions; + } + + /** + * @deprecated since 4.5.0 and will be removed in 5.0.0. Please use the `host` property instead + * @infection-ignore-all + */ + public function getRequest(): ServerRequestInterface|string + { + return $this->host; + } + + /** + * @deprecated since 4.8.0. Will be removed in 5.0.0. Please use the property instead. + */ + public function getPublicKeyCredentialSource(): PublicKeyCredentialSource + { + return $this->publicKeyCredentialSource; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/BeforeCertificateChainValidation.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/BeforeCertificateChainValidation.php new file mode 100644 index 000000000..f871ae039 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Event/BeforeCertificateChainValidation.php @@ -0,0 +1,28 @@ + $attestation + */ + public function __construct( + public readonly array $attestation, + string $message, + ?Throwable $previous = null + ) { + parent::__construct($message, $previous); + } + + /** + * @param array $attestation + */ + public static function create( + array $attestation, + string $message = 'Invalid attestation object', + ?Throwable $previous = null + ): self { + return new self($attestation, $message, $previous); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/AttestationStatementVerificationException.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/AttestationStatementVerificationException.php new file mode 100644 index 000000000..763e2fed5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/AttestationStatementVerificationException.php @@ -0,0 +1,15 @@ + $untrustedCertificates + * @param array $trustedCertificates + */ + public function __construct( + public readonly array $untrustedCertificates, + public readonly array $trustedCertificates, + string $message, + ?Throwable $previous = null + ) { + parent::__construct($message, $previous); + } + + /** + * @param array $untrustedCertificates + * @param array $trustedCertificates + */ + public static function create( + array $untrustedCertificates, + array $trustedCertificates, + string $message = 'Unable to validate the certificate chain.', + ?Throwable $previous = null + ): self { + return new self($untrustedCertificates, $trustedCertificates, $message, $previous); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/CertificateException.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/CertificateException.php new file mode 100644 index 000000000..259277627 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Exception/CertificateException.php @@ -0,0 +1,18 @@ + self::fixPEMStructure($d, $type), $data); + } + + public static function fixPEMStructure(string $data, string $type = 'CERTIFICATE'): string + { + if (str_contains($data, self::PEM_HEADER)) { + return trim($data); + } + $pem = self::PEM_HEADER . $type . '-----' . PHP_EOL; + $pem .= chunk_split($data, 64, PHP_EOL); + + return $pem . (self::PEM_FOOTER . $type . '-----' . PHP_EOL); + } + + /** + * @deprecated since 4.7.0 and will be removed in 5.0.0. No replacement as not used internally. + * @infection-ignore-all + */ + public static function convertPEMToDER(string $data): string + { + if (! str_contains($data, self::PEM_HEADER)) { + return $data; + } + $data = preg_replace('/\-{5}.*\-{5}[\r\n]*/', '', $data); + $data = preg_replace("/[\r\n]*/", '', (string) $data); + + return Base64::decode(trim((string) $data), true); + } + + public static function convertDERToPEM(string $data, string $type = 'CERTIFICATE'): string + { + if (str_contains($data, self::PEM_HEADER)) { + return $data; + } + + return self::fixPEMStructure(base64_encode($data), $type); + } + + /** + * @param string[] $data + * + * @return string[] + */ + public static function convertAllDERToPEM(iterable $data, string $type = 'CERTIFICATE'): array + { + return array_map(static fn ($d): string => self::convertDERToPEM($d, $type), $data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/CertificateChain/PhpCertificateChainValidator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/CertificateChain/PhpCertificateChainValidator.php new file mode 100644 index 000000000..ff50e7e7d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/CertificateChain/PhpCertificateChainValidator.php @@ -0,0 +1,296 @@ +clock = $clock; + $this->dispatcher = new NullEventDispatcher(); + } + + public static function create( + HttpClientInterface $client, + null|Clock|ClockInterface $clock = null, + bool $allowFailures = true + ): self { + return new self($client, null, $clock, $allowFailures); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + /** + * @param string[] $untrustedCertificates + * @param string[] $trustedCertificates + */ + public function check(array $untrustedCertificates, array $trustedCertificates): void + { + foreach ($trustedCertificates as $trustedCertificate) { + $this->dispatcher->dispatch( + BeforeCertificateChainValidation::create($untrustedCertificates, $trustedCertificate) + ); + try { + if ($this->validateChain($untrustedCertificates, $trustedCertificate)) { + $this->dispatcher->dispatch( + CertificateChainValidationSucceeded::create($untrustedCertificates, $trustedCertificate) + ); + return; + } + } catch (Throwable $exception) { + $this->dispatcher->dispatch( + CertificateChainValidationFailed::create($untrustedCertificates, $trustedCertificate) + ); + throw $exception; + } + } + + throw CertificateChainException::create($untrustedCertificates, $trustedCertificates); + } + + /** + * @param string[] $untrustedCertificates + */ + private function validateChain(array $untrustedCertificates, string $trustedCertificate): bool + { + $untrustedCertificates = array_map( + static fn (string $cert): Certificate => Certificate::fromPEM(PEM::fromString($cert)), + array_reverse($untrustedCertificates) + ); + $trustedCertificate = Certificate::fromPEM(PEM::fromString($trustedCertificate)); + + // The trust path and the authenticator certificate are the same + if (count( + $untrustedCertificates + ) === 1 && $untrustedCertificates[0]->toPEM()->string() === $trustedCertificate->toPEM()->string()) { + return true; + } + $uniqueCertificates = array_map( + static fn (Certificate $cert): string => $cert->toPEM() + ->string(), + [...$untrustedCertificates, $trustedCertificate] + ); + count(array_unique($uniqueCertificates)) === count( + $uniqueCertificates + ) || throw CertificateChainException::create( + $untrustedCertificates, + [$trustedCertificate], + 'Invalid certificate chain with duplicated certificates.' + ); + + if (! $this->validateCertificates($trustedCertificate, ...$untrustedCertificates)) { + return false; + } + + $certificates = [$trustedCertificate, ...$untrustedCertificates]; + $numCerts = count($certificates); + for ($i = 1; $i < $numCerts; $i++) { + if ($this->isRevoked($certificates[$i])) { + throw CertificateChainException::create( + $untrustedCertificates, + [$trustedCertificate], + 'Unable to validate the certificate chain. Revoked certificate found.' + ); + } + } + + return true; + } + + private function isRevoked(Certificate $subject): bool + { + try { + $csn = $subject->tbsCertificate() + ->serialNumber(); + } catch (Throwable $e) { + throw InvalidCertificateException::create( + $subject->toPEM() + ->string(), + sprintf('Failed to parse certificate: %s', $e->getMessage()), + $e + ); + } + + try { + $urls = $this->getCrlUrlList($subject); + } catch (Throwable $e) { + if ($this->allowFailures) { + return false; + } + throw InvalidCertificateException::create( + $subject->toPEM() + ->string(), + 'Failed to get CRL distribution points: ' . $e->getMessage(), + $e + ); + } + + foreach ($urls as $url) { + try { + $revokedCertificates = $this->retrieveRevokedSerialNumbers($url); + + if (in_array($csn, $revokedCertificates, true)) { + return true; + } + } catch (Throwable $e) { + if ($this->allowFailures) { + return false; + } + throw CertificateRevocationListException::create($url, sprintf( + 'Failed to retrieve the CRL:' . PHP_EOL . '%s', + $e->getMessage() + ), $e); + } + } + return false; + } + + private function validateCertificates(Certificate ...$certificates): bool + { + try { + $config = PathValidationConfig::create($this->clock->now(), self::MAX_VALIDATION_LENGTH); + CertificationPath::create(...$certificates)->validate($config); + + return true; + } catch (Throwable) { + return false; + } + } + + /** + * @return string[] + */ + private function retrieveRevokedSerialNumbers(string $url): array + { + try { + if ($this->client instanceof HttpClientInterface) { + $crlData = $this->client->request('GET', $url) + ->getContent(); + } else { + $crlData = $this->sendPsrRequest($url); + } + $crl = UnspecifiedType::fromDER($crlData)->asSequence(); + count($crl) === 3 || throw CertificateRevocationListException::create($url); + $tbsCertList = $crl->at(0) + ->asSequence(); + count($tbsCertList) >= 6 || throw CertificateRevocationListException::create($url); + $list = $tbsCertList->at(5) + ->asSequence(); + + return array_map(static function (UnspecifiedType $r) use ($url): string { + $sequence = $r->asSequence(); + count($sequence) >= 1 || throw CertificateRevocationListException::create($url); + return $sequence->at(0) + ->asInteger() + ->number(); + }, $list->elements()); + } catch (Throwable $e) { + throw CertificateRevocationListException::create($url, 'Failed to download the CRL', $e); + } + } + + /** + * @return string[] + */ + private function getCrlUrlList(Certificate $subject): array + { + try { + $urls = []; + + $extensions = $subject->tbsCertificate() + ->extensions(); + if ($extensions->hasCRLDistributionPoints()) { + $crlDists = $extensions->crlDistributionPoints(); + foreach ($crlDists->distributionPoints() as $dist) { + $url = $dist->fullName() + ->names() + ->firstURI(); + $scheme = parse_url($url, PHP_URL_SCHEME); + if (! in_array($scheme, ['http', 'https'], true)) { + continue; + } + $urls[] = $url; + } + } + return $urls; + } catch (Throwable $e) { + throw InvalidCertificateException::create( + $subject->toPEM() + ->string(), + 'Failed to get CRL distribution points from certificate: ' . $e->getMessage(), + $e + ); + } + } + + private function sendPsrRequest(string $url): string + { + $request = $this->requestFactory->createRequest('GET', $url); + $response = $this->client->sendRequest($request); + if ($response->getStatusCode() !== 200) { + throw CertificateRevocationListException::create($url, 'Failed to download the CRL'); + } + + return $response->getBody() + ->getContents(); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Denormalizer/ExtensionDescriptorDenormalizer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Denormalizer/ExtensionDescriptorDenormalizer.php new file mode 100644 index 000000000..b31eec3dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Denormalizer/ExtensionDescriptorDenormalizer.php @@ -0,0 +1,14 @@ +create(); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Event/BeforeCertificateChainValidation.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Event/BeforeCertificateChainValidation.php new file mode 100644 index 000000000..bf6f5f910 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Event/BeforeCertificateChainValidation.php @@ -0,0 +1,14 @@ +requestFactory->createRequest($method, $baseUri . $url); + $body = $options['body'] ?? null; + if ($body !== null) { + $request = $request->withBody($this->streamFactory->createStream($body)); + } + foreach ($this->options as $name => $value) { + $request = $request->withHeader($name, $value); + } + foreach ($options['headers'] ?? [] as $name => $value) { + $request = $request->withHeader($name, $value); + } + $response = $this->client->sendRequest($request); + + return static::fromPsr17($response); + } + + /** + * @param ResponseInterface|iterable $responses + */ + public function stream(iterable|ResponseInterface $responses, ?float $timeout = null): ResponseStreamInterface + { + throw new LogicException('Not implemented'); + } + + public function withOptions(array $options): static + { + $this->options = $options; + return $this; + } + + protected static function fromPsr17(Psr17ResponseInterface $response): ResponseInterface + { + $headers = $response->getHeaders(); + $content = $response->getBody() + ->getContents(); + $status = $response->getStatusCode(); + + return new class($status, $headers, $content) implements ResponseInterface { + /** + * @param array $headers + */ + public function __construct( + private readonly int $status, + private readonly array $headers, + private readonly string $content, + ) { + } + + public function getStatusCode(): int + { + return $this->status; + } + + /** + * @return array + */ + public function getHeaders(bool $throw = true): array + { + return $this->headers; + } + + public function getContent(bool $throw = true): string + { + return $this->content; + } + + /** + * @return array + */ + public function toArray(bool $throw = true): array + { + $result = json_decode($this->content, true); + if (! is_array($result) || json_last_error() !== JSON_ERROR_NONE) { + throw new JsonException('Failed to decode JSON response: ' . json_last_error_msg()); + } + + return $result; + } + + public function cancel(): void + { + // noop + } + + public function getInfo(?string $type = null): mixed + { + return null; + } + }; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/ChainedMetadataServices.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/ChainedMetadataServices.php similarity index 89% rename from lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/ChainedMetadataServices.php rename to lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/ChainedMetadataServices.php index 660ac372c..f6cae8b72 100644 --- a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/ChainedMetadataServices.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/ChainedMetadataServices.php @@ -4,8 +4,7 @@ declare(strict_types=1); namespace Webauthn\MetadataService\Service; -use InvalidArgumentException; -use function sprintf; +use Webauthn\Exception\MissingMetadataStatementException; use Webauthn\MetadataService\Statement\MetadataStatement; final class ChainedMetadataServices implements MetadataService @@ -62,6 +61,6 @@ final class ChainedMetadataServices implements MetadataService } } - throw new InvalidArgumentException(sprintf('The Metadata Statement with AAGUID "%s" is missing', $aaguid)); + throw MissingMetadataStatementException::create($aaguid); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/DistantResourceMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/DistantResourceMetadataService.php new file mode 100644 index 000000000..e81006940 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/DistantResourceMetadataService.php @@ -0,0 +1,170 @@ + $additionalHeaderParameters + */ + public function __construct( + private readonly ?RequestFactoryInterface $requestFactory, + private readonly ClientInterface|HttpClientInterface $httpClient, + private readonly string $uri, + private readonly bool $isBase64Encoded = false, + private readonly array $additionalHeaderParameters = [], + ?SerializerInterface $serializer = null, + ) { + if ($requestFactory !== null && ! $httpClient instanceof HttpClientInterface) { + trigger_deprecation( + 'web-auth/metadata-service', + '4.7.0', + 'The parameter "$requestFactory" will be removed in 5.0.0. Please set it to null and set an Symfony\Contracts\HttpClient\HttpClientInterface as "$httpClient" argument.' + ); + } + $this->serializer = $serializer ?? (new WebauthnSerializerFactory( + AttestationStatementSupportManager::create() + ))->create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + /** + * @param array $additionalHeaderParameters + */ + public static function create( + ?RequestFactoryInterface $requestFactory, + ClientInterface|HttpClientInterface $httpClient, + string $uri, + bool $isBase64Encoded = false, + array $additionalHeaderParameters = [], + ?SerializerInterface $serializer = null + ): self { + return new self($requestFactory, $httpClient, $uri, $isBase64Encoded, $additionalHeaderParameters, $serializer); + } + + public function list(): iterable + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + $aaguid = $this->statement->aaguid; + if ($aaguid === null) { + yield from []; + } else { + yield from [$aaguid]; + } + } + + public function has(string $aaguid): bool + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + + return $aaguid === $this->statement->aaguid; + } + + public function get(string $aaguid): MetadataStatement + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + + if ($aaguid === $this->statement->aaguid) { + $this->dispatcher->dispatch(MetadataStatementFound::create($this->statement)); + + return $this->statement; + } + + throw MissingMetadataStatementException::create($aaguid); + } + + private function loadData(): void + { + if ($this->statement !== null) { + return; + } + + $content = $this->fetch(); + if ($this->isBase64Encoded) { + $content = Base64::decode($content, true); + } + if ($this->serializer !== null) { + $this->statement = $this->serializer->deserialize($content, MetadataStatement::class, 'json'); + return; + } + + $this->statement = MetadataStatement::createFromString($content); + } + + private function fetch(): string + { + if ($this->httpClient instanceof HttpClientInterface) { + $content = $this->sendSymfonyRequest(); + } else { + $content = $this->sendPsrRequest(); + } + $content !== '' || throw MetadataStatementLoadingException::create( + 'Unable to contact the server. The response has no content' + ); + + return $content; + } + + private function sendPsrRequest(): string + { + $request = $this->requestFactory->createRequest('GET', $this->uri); + foreach ($this->additionalHeaderParameters as $k => $v) { + $request = $request->withHeader($k, $v); + } + $response = $this->httpClient->sendRequest($request); + $response->getStatusCode() === 200 || throw MetadataStatementLoadingException::create(sprintf( + 'Unable to contact the server. Response code is %d', + $response->getStatusCode() + )); + $response->getBody() + ->rewind(); + + return $response->getBody() + ->getContents(); + } + + private function sendSymfonyRequest(): string + { + $response = $this->httpClient->request('GET', $this->uri, [ + 'headers' => $this->additionalHeaderParameters, + ]); + $response->getStatusCode() === 200 || throw MetadataStatementLoadingException::create(sprintf( + 'Unable to contact the server. Response code is %d', + $response->getStatusCode() + )); + + return $response->getContent(); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FidoAllianceCompliantMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FidoAllianceCompliantMetadataService.php new file mode 100644 index 000000000..5182a8109 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FidoAllianceCompliantMetadataService.php @@ -0,0 +1,286 @@ +> + */ + private array $statusReports = []; + + private EventDispatcherInterface $dispatcher; + + private readonly ?SerializerInterface $serializer; + + /** + * @param array $additionalHeaderParameters + */ + public function __construct( + private readonly ?RequestFactoryInterface $requestFactory, + private readonly ClientInterface|HttpClientInterface $httpClient, + private readonly string $uri, + private readonly array $additionalHeaderParameters = [], + private readonly ?CertificateChainValidator $certificateChainValidator = null, + private readonly ?string $rootCertificateUri = null, + ?SerializerInterface $serializer = null, + ) { + if ($requestFactory !== null && ! $httpClient instanceof HttpClientInterface) { + trigger_deprecation( + 'web-auth/metadata-service', + '4.7.0', + 'The parameter "$requestFactory" will be removed in 5.0.0. Please set it to null and set an Symfony\Contracts\HttpClient\HttpClientInterface as "$httpClient" argument.' + ); + } + $this->serializer = $serializer ?? (new WebauthnSerializerFactory( + AttestationStatementSupportManager::create() + ))->create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + /** + * @param array $additionalHeaderParameters + */ + public static function create( + ?RequestFactoryInterface $requestFactory, + ClientInterface|HttpClientInterface $httpClient, + string $uri, + array $additionalHeaderParameters = [], + ?CertificateChainValidator $certificateChainValidator = null, + ?string $rootCertificateUri = null, + ?SerializerInterface $serializer = null, + ): self { + return new self( + $requestFactory, + $httpClient, + $uri, + $additionalHeaderParameters, + $certificateChainValidator, + $rootCertificateUri, + $serializer, + ); + } + + /** + * @return string[] + */ + public function list(): iterable + { + $this->loadData(); + + yield from array_keys($this->statements); + } + + public function has(string $aaguid): bool + { + $this->loadData(); + + return array_key_exists($aaguid, $this->statements); + } + + public function get(string $aaguid): MetadataStatement + { + $this->loadData(); + array_key_exists($aaguid, $this->statements) || throw MissingMetadataStatementException::create($aaguid); + $mds = $this->statements[$aaguid]; + $this->dispatcher->dispatch(MetadataStatementFound::create($mds)); + + return $mds; + } + + /** + * @return StatusReport[] + */ + public function getStatusReports(string $aaguid): iterable + { + $this->loadData(); + + return $this->statusReports[$aaguid] ?? []; + } + + private function loadData(): void + { + if ($this->loaded) { + return; + } + + $content = $this->fetch($this->uri, $this->additionalHeaderParameters); + $jwtCertificates = []; + try { + $payload = $this->getJwsPayload($content, $jwtCertificates); + $this->validateCertificates(...$jwtCertificates); + if ($this->serializer !== null) { + $blob = $this->serializer->deserialize($payload, MetadataBLOBPayload::class, 'json'); + foreach ($blob->entries as $entry) { + $mds = $entry->metadataStatement; + if ($mds !== null && $entry->aaguid !== null) { + $this->statements[$entry->aaguid] = $mds; + $this->statusReports[$entry->aaguid] = $entry->statusReports; + } + } + $this->loaded = true; + return; + } + $data = json_decode($payload, true, flags: JSON_THROW_ON_ERROR); + + foreach ($data['entries'] as $datum) { + $entry = MetadataBLOBPayloadEntry::createFromArray($datum); + + $mds = $entry->metadataStatement; + if ($mds !== null && $entry->aaguid !== null) { + $this->statements[$entry->aaguid] = $mds; + $this->statusReports[$entry->aaguid] = $entry->statusReports; + } + } + } catch (Throwable) { + // Nothing to do + } + + $this->loaded = true; + } + + /** + * @param array $headerParameters + */ + private function fetch(string $uri, array $headerParameters): string + { + if ($this->httpClient instanceof HttpClientInterface) { + $content = $this->sendSymfonyRequest($uri, $headerParameters); + } else { + $content = $this->sendPsrRequest($uri, $headerParameters); + } + $content !== '' || throw MetadataStatementLoadingException::create( + 'Unable to contact the server. The response has no content' + ); + + return $content; + } + + /** + * @param string[] $rootCertificates + */ + private function getJwsPayload(string $token, array &$rootCertificates): string + { + $jws = (new CompactSerializer())->unserialize($token); + $jws->countSignatures() === 1 || throw MetadataStatementLoadingException::create( + 'Invalid response from the metadata service. Only one signature shall be present.' + ); + $signature = $jws->getSignature(0); + $payload = $jws->getPayload(); + $payload !== '' || throw MetadataStatementLoadingException::create( + 'Invalid response from the metadata service. The token payload is empty.' + ); + $header = $signature->getProtectedHeader(); + array_key_exists('alg', $header) || throw MetadataStatementLoadingException::create( + 'The "alg" parameter is missing.' + ); + array_key_exists('x5c', $header) || throw MetadataStatementLoadingException::create( + 'The "x5c" parameter is missing.' + ); + is_array($header['x5c']) || throw MetadataStatementLoadingException::create( + 'The "x5c" parameter should be an array.' + ); + $key = JWKFactory::createFromX5C($header['x5c']); + $rootCertificates = $header['x5c']; + + $verifier = new JWSVerifier(new AlgorithmManager([new ES256(), new RS256()])); + $isValid = $verifier->verifyWithKey($jws, $key, 0); + $isValid || throw MetadataStatementLoadingException::create( + 'Invalid response from the metadata service. The token signature is invalid.' + ); + $payload = $jws->getPayload(); + $payload !== null || throw MetadataStatementLoadingException::create( + 'Invalid response from the metadata service. The payload is missing.' + ); + + return $payload; + } + + private function validateCertificates(string ...$untrustedCertificates): void + { + if ($this->certificateChainValidator === null || $this->rootCertificateUri === null) { + return; + } + $untrustedCertificates = CertificateToolbox::fixPEMStructures($untrustedCertificates); + $rootCertificate = CertificateToolbox::convertDERToPEM($this->fetch($this->rootCertificateUri, [])); + $this->certificateChainValidator->check($untrustedCertificates, [$rootCertificate]); + } + + /** + * @param array $headerParameters + */ + private function sendPsrRequest(string $uri, array $headerParameters): string + { + $request = $this->requestFactory->createRequest('GET', $uri); + foreach ($headerParameters as $k => $v) { + $request = $request->withHeader($k, $v); + } + $response = $this->httpClient->sendRequest($request); + $response->getStatusCode() === 200 || throw MetadataStatementLoadingException::create(sprintf( + 'Unable to contact the server. Response code is %d', + $response->getStatusCode() + )); + $response->getBody() + ->rewind(); + return $response->getBody() + ->getContents(); + } + + /** + * @param array $headerParameters + */ + private function sendSymfonyRequest(string $uri, array $headerParameters): string + { + $response = $this->httpClient->request('GET', $uri, [ + 'headers' => $headerParameters, + ]); + $response->getStatusCode() === 200 || throw MetadataStatementLoadingException::create(sprintf( + 'Unable to contact the server. Response code is %d', + $response->getStatusCode() + )); + + return $response->getContent(); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FolderResourceMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FolderResourceMetadataService.php new file mode 100644 index 000000000..e554ed9a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/FolderResourceMetadataService.php @@ -0,0 +1,79 @@ +serializer = $serializer ?? (new WebauthnSerializerFactory( + AttestationStatementSupportManager::create() + ))->create(); + $this->rootPath = rtrim($rootPath, DIRECTORY_SEPARATOR); + is_dir($this->rootPath) || throw new InvalidArgumentException('The given parameter is not a valid folder.'); + is_readable($this->rootPath) || throw new InvalidArgumentException( + 'The given parameter is not a valid folder.' + ); + } + + public static function create(string $rootPath, ?SerializerInterface $serializer = null): self + { + return new self($rootPath, $serializer); + } + + public function list(): iterable + { + $files = glob($this->rootPath . DIRECTORY_SEPARATOR . '*'); + is_array($files) || throw MetadataStatementLoadingException::create('Unable to read files.'); + foreach ($files as $file) { + if (is_dir($file) || ! is_readable($file)) { + continue; + } + + yield basename($file); + } + } + + public function has(string $aaguid): bool + { + $filename = $this->rootPath . DIRECTORY_SEPARATOR . $aaguid; + + return is_file($filename) && is_readable($filename); + } + + public function get(string $aaguid): MetadataStatement + { + $this->has($aaguid) || throw new InvalidArgumentException(sprintf( + 'The MDS with the AAGUID "%s" does not exist.', + $aaguid + )); + $filename = $this->rootPath . DIRECTORY_SEPARATOR . $aaguid; + $data = trim(file_get_contents($filename)); + if ($this->serializer !== null) { + $mds = $this->serializer->deserialize($data, MetadataStatement::class, 'json'); + } else { + $mds = MetadataStatement::createFromString($data); + } + + $mds->aaguid !== null || throw MetadataStatementLoadingException::create('Invalid Metadata Statement.'); + + return $mds; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/InMemoryMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/InMemoryMetadataService.php new file mode 100644 index 000000000..6ff6f9943 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/InMemoryMetadataService.php @@ -0,0 +1,73 @@ +addStatements($statement); + } + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + public static function create(MetadataStatement ...$statements): self + { + return new self(...$statements); + } + + public function addStatements(MetadataStatement ...$statements): self + { + foreach ($statements as $statement) { + $aaguid = $statement->aaguid; + if ($aaguid === null) { + continue; + } + $this->statements[$aaguid] = $statement; + } + + return $this; + } + + public function list(): iterable + { + yield from array_keys($this->statements); + } + + public function has(string $aaguid): bool + { + return array_key_exists($aaguid, $this->statements); + } + + public function get(string $aaguid): MetadataStatement + { + array_key_exists($aaguid, $this->statements) || throw MissingMetadataStatementException::create($aaguid); + $mds = $this->statements[$aaguid]; + $this->dispatcher->dispatch(MetadataStatementFound::create($mds)); + + return $mds; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/JsonMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/JsonMetadataService.php new file mode 100644 index 000000000..62bb5df4d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/JsonMetadataService.php @@ -0,0 +1,81 @@ +dispatcher = new NullEventDispatcher(); + $this->serializer = $serializer ?? (new WebauthnSerializerFactory( + AttestationStatementSupportManager::create() + ))->create(); + foreach ($statements as $statement) { + $this->addStatement($statement); + } + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + public function list(): iterable + { + yield from array_keys($this->statements); + } + + public function has(string $aaguid): bool + { + return array_key_exists($aaguid, $this->statements); + } + + public function get(string $aaguid): MetadataStatement + { + array_key_exists($aaguid, $this->statements) || throw MissingMetadataStatementException::create($aaguid); + $mds = $this->statements[$aaguid]; + $this->dispatcher->dispatch(MetadataStatementFound::create($mds)); + + return $mds; + } + + private function addStatement(string $statement): void + { + if ($this->serializer === null) { + $mds = MetadataStatement::createFromString($statement); + } else { + $mds = $this->serializer->deserialize($statement, MetadataStatement::class, 'json'); + } + if ($mds->aaguid === null) { + return; + } + $this->statements[$mds->aaguid] = $mds; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/LocalResourceMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/LocalResourceMetadataService.php new file mode 100644 index 000000000..c510d4fd4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/LocalResourceMetadataService.php @@ -0,0 +1,102 @@ +serializer = $serializer ?? (new WebauthnSerializerFactory( + AttestationStatementSupportManager::create() + ))->create(); + $this->dispatcher = new NullEventDispatcher(); + } + + public static function create( + string $filename, + bool $isBase64Encoded = false, + ?SerializerInterface $serializer = null + ): self { + return new self($filename, $isBase64Encoded, $serializer); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + public function list(): iterable + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + $aaguid = $this->statement->aaguid; + if ($aaguid === null) { + yield from []; + } else { + yield from [$aaguid]; + } + } + + public function has(string $aaguid): bool + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + + return $aaguid === $this->statement->aaguid; + } + + public function get(string $aaguid): MetadataStatement + { + $this->loadData(); + $this->statement !== null || throw MetadataStatementLoadingException::create(); + + if ($aaguid === $this->statement->aaguid) { + $this->dispatcher->dispatch(MetadataStatementFound::create($this->statement)); + + return $this->statement; + } + + throw MissingMetadataStatementException::create($aaguid); + } + + private function loadData(): void + { + if ($this->statement !== null) { + return; + } + + $content = file_get_contents($this->filename); + if ($this->isBase64Encoded) { + $content = Base64::decode($content, true); + } + if ($this->serializer !== null) { + $this->statement = $this->serializer->deserialize($content, MetadataStatement::class, 'json'); + } else { + $this->statement = MetadataStatement::createFromString($content); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayload.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayload.php new file mode 100644 index 000000000..97df91c57 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayload.php @@ -0,0 +1,163 @@ +entries[] = $entry; + + return $this; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getLegalHeader(): ?string + { + return $this->legalHeader; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getNo(): int + { + return $this->no; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getNextUpdate(): string + { + return $this->nextUpdate; + } + + /** + * @return MetadataBLOBPayloadEntry[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getEntries(): array + { + return $this->entries; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + foreach (['no', 'nextUpdate', 'entries'] as $key) { + array_key_exists($key, $data) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid data. The parameter "%s" is missing', + $key + )); + } + is_int($data['no']) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "no" shall be an integer' + ); + is_string($data['nextUpdate']) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "nextUpdate" shall be a string' + ); + is_array($data['entries']) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "entries" shall be a n array of entries' + ); + $object = new self($data['no'], $data['nextUpdate'], $data['legalHeader'] ?? null); + foreach ($data['entries'] as $entry) { + $object->entries[] = MetadataBLOBPayloadEntry::createFromArray($entry); + } + + return $object; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'legalHeader' => $this->legalHeader, + 'nextUpdate' => $this->nextUpdate, + 'no' => $this->no, + 'entries' => $this->entries, + ]; + + return self::filterNullValues($data); + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getRootCertificates(): array + { + return $this->rootCertificates; + } + + /** + * @param string[] $rootCertificates + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function setRootCertificates(array $rootCertificates): self + { + $this->rootCertificates = $rootCertificates; + + return $this; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayloadEntry.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayloadEntry.php new file mode 100644 index 000000000..3e06cfdeb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataBLOBPayloadEntry.php @@ -0,0 +1,231 @@ +aaid; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAaguid(): ?string + { + return $this->aaguid; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttestationCertificateKeyIdentifiers(): array + { + return $this->attestationCertificateKeyIdentifiers; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMetadataStatement(): ?MetadataStatement + { + return $this->metadataStatement; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function addBiometricStatusReports(BiometricStatusReport ...$biometricStatusReports): self + { + foreach ($biometricStatusReports as $biometricStatusReport) { + $this->biometricStatusReports[] = $biometricStatusReport; + } + + return $this; + } + + /** + * @return BiometricStatusReport[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getBiometricStatusReports(): array + { + return $this->biometricStatusReports; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function addStatusReports(StatusReport ...$statusReports): self + { + foreach ($statusReports as $statusReport) { + $this->statusReports[] = $statusReport; + } + + return $this; + } + + /** + * @return StatusReport[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getStatusReports(): array + { + return $this->statusReports; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getTimeOfLastStatusChange(): string + { + return $this->timeOfLastStatusChange; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getRogueListURL(): string|null + { + return $this->rogueListURL; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getRogueListHash(): string|null + { + return $this->rogueListHash; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + array_key_exists('timeOfLastStatusChange', $data) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "timeOfLastStatusChange" is missing' + ); + array_key_exists('statusReports', $data) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "statusReports" is missing' + ); + is_array($data['statusReports']) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "statusReports" shall be an array of StatusReport objects' + ); + + return new self( + $data['timeOfLastStatusChange'], + array_map( + static fn (array $statusReport) => StatusReport::createFromArray($statusReport), + $data['statusReports'] + ), + $data['aaid'] ?? null, + $data['aaguid'] ?? null, + $data['attestationCertificateKeyIdentifiers'] ?? [], + isset($data['metadataStatement']) ? MetadataStatement::createFromArray($data['metadataStatement']) : null, + $data['rogueListURL'] ?? null, + $data['rogueListHash'] ?? null, + array_map( + static fn (array $biometricStatusReport) => BiometricStatusReport::createFromArray( + $biometricStatusReport + ), + $data['biometricStatusReports'] ?? [] + ) + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'aaid' => $this->aaid, + 'aaguid' => $this->aaguid, + 'attestationCertificateKeyIdentifiers' => $this->attestationCertificateKeyIdentifiers, + 'statusReports' => $this->statusReports, + 'timeOfLastStatusChange' => $this->timeOfLastStatusChange, + 'rogueListURL' => $this->rogueListURL, + 'rogueListHash' => $this->rogueListHash, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataService.php similarity index 100% rename from lam/lib/3rdParty/composer/web-auth/metadata-service/src/Service/MetadataService.php rename to lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/MetadataService.php diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/StringMetadataService.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/StringMetadataService.php new file mode 100644 index 000000000..2df755c40 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Service/StringMetadataService.php @@ -0,0 +1,77 @@ +addStatements(MetadataStatement::createFromString($statement)); + } + $this->dispatcher = new NullEventDispatcher(); + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->dispatcher = $eventDispatcher; + } + + public static function create(string ...$statements): self + { + return new self(...$statements); + } + + public function addStatements(MetadataStatement ...$statements): self + { + foreach ($statements as $statement) { + $aaguid = $statement->aaguid; + if ($aaguid === null) { + continue; + } + $this->statements[$aaguid] = $statement; + } + + return $this; + } + + public function list(): iterable + { + yield from array_keys($this->statements); + } + + public function has(string $aaguid): bool + { + return array_key_exists($aaguid, $this->statements); + } + + public function get(string $aaguid): MetadataStatement + { + array_key_exists($aaguid, $this->statements) || throw MissingMetadataStatementException::create($aaguid); + $mds = $this->statements[$aaguid]; + $this->dispatcher->dispatch(MetadataStatementFound::create($mds)); + + return $mds; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AbstractDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AbstractDescriptor.php new file mode 100644 index 000000000..494cc0601 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AbstractDescriptor.php @@ -0,0 +1,41 @@ += 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The value of "maxRetries" must be a positive integer' + ); + $blockSlowdown >= 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The value of "blockSlowdown" must be a positive integer' + ); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMaxRetries(): ?int + { + return $this->maxRetries; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getBlockSlowdown(): ?int + { + return $this->blockSlowdown; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AlternativeDescriptions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AlternativeDescriptions.php new file mode 100644 index 000000000..0baf0f2f4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AlternativeDescriptions.php @@ -0,0 +1,61 @@ + $descriptions + */ + public function __construct( + public array $descriptions = [] + ) { + } + + /** + * @param array $descriptions + */ + public static function create(array $descriptions = []): self + { + return new self($descriptions); + } + + /** + * @return array + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function all(): array + { + return $this->descriptions; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function add(string $locale, string $description): self + { + $this->descriptions[$locale] = $description; + + return $this; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return $this->descriptions; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorGetInfo.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorGetInfo.php new file mode 100644 index 000000000..c1360a61b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorGetInfo.php @@ -0,0 +1,51 @@ + $info + */ + public function __construct( + public array $info = [] + ) { + } + + /** + * @param array $info + */ + public static function create(array $info = []): self + { + return new self($info); + } + + /** + * @deprecated since 4.7.0. Please use the constructor directly. + * @infection-ignore-all + */ + public function add(string|int $key, mixed $value): self + { + $this->info[$key] = $value; + + return $this; + } + + /** + * @return string[] + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return $this->info; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorStatus.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorStatus.php new file mode 100644 index 000000000..03a008bee --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/AuthenticatorStatus.php @@ -0,0 +1,72 @@ +selfAttestedFRR; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + */ + public function getSelfAttestedFAR(): ?float + { + return $this->selfAttestedFAR; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + */ + public function getMaxTemplates(): ?float + { + return $this->maxTemplates; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + */ + public static function createFromArray(array $data): self + { + return self::create( + $data['selfAttestedFRR'] ?? null, + $data['selfAttestedFAR'] ?? null, + $data['maxTemplates'] ?? null, + $data['maxRetries'] ?? null, + $data['blockSlowdown'] ?? null + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'selfAttestedFRR' => $this->selfAttestedFRR, + 'selfAttestedFAR' => $this->selfAttestedFAR, + 'maxTemplates' => $this->maxTemplates, + 'maxRetries' => $this->maxRetries, + 'blockSlowdown' => $this->blockSlowdown, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/BiometricStatusReport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/BiometricStatusReport.php new file mode 100644 index 000000000..ab5472f82 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/BiometricStatusReport.php @@ -0,0 +1,146 @@ +certLevel; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getModality(): int|null + { + return $this->modality; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getEffectiveDate(): ?string + { + return $this->effectiveDate; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationDescriptor(): ?string + { + return $this->certificationDescriptor; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificateNumber(): ?string + { + return $this->certificateNumber; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationPolicyVersion(): ?string + { + return $this->certificationPolicyVersion; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationRequirementsVersion(): ?string + { + return $this->certificationRequirementsVersion; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + return self::create( + $data['certLevel'] ?? null, + $data['modality'] ?? null, + $data['effectiveDate'] ?? null, + $data['certificationDescriptor'] ?? null, + $data['certificateNumber'] ?? null, + $data['certificationPolicyVersion'] ?? null, + $data['certificationRequirementsVersion'] ?? null, + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'certLevel' => $this->certLevel, + 'modality' => $this->modality, + 'effectiveDate' => $this->effectiveDate, + 'certificationDescriptor' => $this->certificationDescriptor, + 'certificateNumber' => $this->certificateNumber, + 'certificationPolicyVersion' => $this->certificationPolicyVersion, + 'certificationRequirementsVersion' => $this->certificationRequirementsVersion, + ]; + + return array_filter($data, static fn ($var): bool => $var !== null); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/CodeAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/CodeAccuracyDescriptor.php new file mode 100644 index 000000000..aa7f8f0f6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/CodeAccuracyDescriptor.php @@ -0,0 +1,95 @@ += 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The value of "base" must be a positive integer' + ); + $minLength >= 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The value of "minLength" must be a positive integer' + ); + parent::__construct($maxRetries, $blockSlowdown); + } + + public static function create(int $base, int $minLength, ?int $maxRetries = null, ?int $blockSlowdown = null): self + { + return new self($base, $minLength, $maxRetries, $blockSlowdown); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getBase(): int + { + return $this->base; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMinLength(): int + { + return $this->minLength; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + array_key_exists('base', $data) || throw MetadataStatementLoadingException::create( + 'The parameter "base" is missing' + ); + array_key_exists('minLength', $data) || throw MetadataStatementLoadingException::create( + 'The parameter "minLength" is missing' + ); + + return self::create( + $data['base'], + $data['minLength'], + $data['maxRetries'] ?? null, + $data['blockSlowdown'] ?? null + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'base' => $this->base, + 'minLength' => $this->minLength, + 'maxRetries' => $this->maxRetries, + 'blockSlowdown' => $this->blockSlowdown, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/DisplayPNGCharacteristicsDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/DisplayPNGCharacteristicsDescriptor.php new file mode 100644 index 000000000..e0c8603b3 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/DisplayPNGCharacteristicsDescriptor.php @@ -0,0 +1,207 @@ += 0 || throw MetadataStatementLoadingException::create('Invalid width'); + $height >= 0 || throw MetadataStatementLoadingException::create('Invalid height'); + ($bitDepth >= 0 && $bitDepth <= 254) || throw MetadataStatementLoadingException::create('Invalid bit depth'); + ($colorType >= 0 && $colorType <= 254) || throw MetadataStatementLoadingException::create( + 'Invalid color type' + ); + ($compression >= 0 && $compression <= 254) || throw MetadataStatementLoadingException::create( + 'Invalid compression' + ); + ($filter >= 0 && $filter <= 254) || throw MetadataStatementLoadingException::create('Invalid filter'); + ($interlace >= 0 && $interlace <= 254) || throw MetadataStatementLoadingException::create( + 'Invalid interlace' + ); + } + + /** + * @param RgbPaletteEntry[] $plte + */ + public static function create( + int $width, + int $height, + int $bitDepth, + int $colorType, + int $compression, + int $filter, + int $interlace, + array $plte = [] + ): self { + return new self($width, $height, $bitDepth, $colorType, $compression, $filter, $interlace, $plte); + } + + /** + * @deprecated since 4.7.0. Please use {self::create} directly. + * @infection-ignore-all + */ + public function addPalettes(RgbPaletteEntry ...$rgbPaletteEntries): self + { + foreach ($rgbPaletteEntries as $rgbPaletteEntry) { + $this->plte[] = $rgbPaletteEntry; + } + + return $this; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getWidth(): int + { + return $this->width; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getHeight(): int + { + return $this->height; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getBitDepth(): int + { + return $this->bitDepth; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getColorType(): int + { + return $this->colorType; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCompression(): int + { + return $this->compression; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getFilter(): int + { + return $this->filter; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getInterlace(): int + { + return $this->interlace; + } + + /** + * @return RgbPaletteEntry[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getPaletteEntries(): array + { + return $this->plte; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + foreach ([ + 'width', + 'compression', + 'height', + 'bitDepth', + 'colorType', + 'compression', + 'filter', + 'interlace', + ] as $key) { + array_key_exists($key, $data) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid data. The key "%s" is missing', + $key + )); + } + return self::create( + $data['width'], + $data['height'], + $data['bitDepth'], + $data['colorType'], + $data['compression'], + $data['filter'], + $data['interlace'], + array_map(static fn (array $item) => RgbPaletteEntry::createFromArray($item), $data['plte'] ?? []) + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'width' => $this->width, + 'height' => $this->height, + 'bitDepth' => $this->bitDepth, + 'colorType' => $this->colorType, + 'compression' => $this->compression, + 'filter' => $this->filter, + 'interlace' => $this->interlace, + 'plte' => $this->plte, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/EcdaaTrustAnchor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/EcdaaTrustAnchor.php new file mode 100644 index 000000000..2d565d314 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/EcdaaTrustAnchor.php @@ -0,0 +1,108 @@ +X; + } + + public function getY(): string + { + return $this->Y; + } + + public function getC(): string + { + return $this->c; + } + + public function getSx(): string + { + return $this->sx; + } + + public function getSy(): string + { + return $this->sy; + } + + public function getG1Curve(): string + { + return $this->G1Curve; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + foreach (['X', 'Y', 'c', 'sx', 'sy', 'G1Curve'] as $key) { + array_key_exists($key, $data) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid data. The key "%s" is missing', + $key + )); + } + + return new self( + Base64UrlSafe::decode($data['X']), + Base64UrlSafe::decode($data['Y']), + Base64UrlSafe::decode($data['c']), + Base64UrlSafe::decode($data['sx']), + Base64UrlSafe::decode($data['sy']), + $data['G1Curve'] + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'X' => Base64UrlSafe::encodeUnpadded($this->X), + 'Y' => Base64UrlSafe::encodeUnpadded($this->Y), + 'c' => Base64UrlSafe::encodeUnpadded($this->c), + 'sx' => Base64UrlSafe::encodeUnpadded($this->sx), + 'sy' => Base64UrlSafe::encodeUnpadded($this->sy), + 'G1Curve' => $this->G1Curve, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/ExtensionDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/ExtensionDescriptor.php new file mode 100644 index 000000000..9c6b0a76d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/ExtensionDescriptor.php @@ -0,0 +1,112 @@ += 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "tag" shall be a positive integer' + ); + } + } + + public static function create( + string $id, + ?int $tag = null, + ?string $data = null, + bool $failIfUnknown = false + ): self { + return new self($id, $tag, $data, $failIfUnknown); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getId(): string + { + return $this->id; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getTag(): ?int + { + return $this->tag; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getData(): ?string + { + return $this->data; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function isFailIfUnknown(): bool + { + return $this->failIfUnknown; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + array_key_exists('id', $data) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "id" is missing' + ); + array_key_exists('fail_if_unknown', $data) || throw MetadataStatementLoadingException::create( + 'Invalid data. The parameter "fail_if_unknown" is missing' + ); + + return new self($data['id'], $data['tag'] ?? null, $data['data'] ?? null, $data['fail_if_unknown']); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $result = [ + 'id' => $this->id, + 'tag' => $this->tag, + 'data' => $this->data, + 'fail_if_unknown' => $this->failIfUnknown, + ]; + + return self::filterNullValues($result); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/MetadataStatement.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/MetadataStatement.php new file mode 100644 index 000000000..5f6afd509 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/MetadataStatement.php @@ -0,0 +1,701 @@ +authenticatorGetInfo = $authenticatorGetInfo ?? AuthenticatorGetInfo::create($attestationTypes); + } + + public static function create( + string $description, + int $authenticatorVersion, + string $protocolFamily, + int $schema, + array $upv, + array $authenticationAlgorithms, + array $publicKeyAlgAndEncodings, + array $attestationTypes, + array $userVerificationDetails, + array $matcherProtection, + array $tcDisplay, + array $attestationRootCertificates, + array $alternativeDescriptions = [], + ?string $legalHeader = null, + ?string $aaid = null, + ?string $aaguid = null, + array $attestationCertificateKeyIdentifiers = [], + array $keyProtection = [], + ?bool $isKeyRestricted = null, + ?bool $isFreshUserVerificationRequired = null, + ?int $cryptoStrength = null, + array $attachmentHint = [], + ?string $tcDisplayContentType = null, + array $tcDisplayPNGCharacteristics = [], + array $ecdaaTrustAnchors = [], + ?string $icon = null, + array $supportedExtensions = [], + ?AuthenticatorGetInfo $authenticatorGetInfo = null, + ): self { + return new self( + $description, + $authenticatorVersion, + $protocolFamily, + $schema, + $upv, + $authenticationAlgorithms, + $publicKeyAlgAndEncodings, + $attestationTypes, + $userVerificationDetails, + $matcherProtection, + $tcDisplay, + $attestationRootCertificates, + AlternativeDescriptions::create($alternativeDescriptions), + $legalHeader, + $aaid, + $aaguid, + $attestationCertificateKeyIdentifiers, + $keyProtection, + $isKeyRestricted, + $isFreshUserVerificationRequired, + $cryptoStrength, + $attachmentHint, + $tcDisplayContentType, + $tcDisplayPNGCharacteristics, + $ecdaaTrustAnchors, + $icon, + $supportedExtensions, + $authenticatorGetInfo, + ); + } + + /** + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromString(string $statement): self + { + $data = json_decode($statement, true, flags: JSON_THROW_ON_ERROR); + + return self::createFromArray($data); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getLegalHeader(): ?string + { + return $this->legalHeader; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAaid(): ?string + { + return $this->aaid; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAaguid(): ?string + { + return $this->aaguid; + } + + public function isKeyRestricted(): ?bool + { + return $this->isKeyRestricted; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function isFreshUserVerificationRequired(): ?bool + { + return $this->isFreshUserVerificationRequired; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAuthenticatorGetInfo(): AuthenticatorGetInfo|null + { + return $this->authenticatorGetInfo; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttestationCertificateKeyIdentifiers(): array + { + return $this->attestationCertificateKeyIdentifiers; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getDescription(): string + { + return $this->description; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAlternativeDescriptions(): null|AlternativeDescriptions + { + return $this->alternativeDescriptions; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAuthenticatorVersion(): int + { + return $this->authenticatorVersion; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getProtocolFamily(): string + { + return $this->protocolFamily; + } + + /** + * @return Version[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getUpv(): array + { + return $this->upv; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getSchema(): ?int + { + return $this->schema; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAuthenticationAlgorithms(): array + { + return $this->authenticationAlgorithms; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getPublicKeyAlgAndEncodings(): array + { + return $this->publicKeyAlgAndEncodings; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttestationTypes(): array + { + return $this->attestationTypes; + } + + /** + * @return VerificationMethodANDCombinations[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getUserVerificationDetails(): array + { + return $this->userVerificationDetails; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getKeyProtection(): array + { + return $this->keyProtection; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMatcherProtection(): array + { + return $this->matcherProtection; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCryptoStrength(): ?int + { + return $this->cryptoStrength; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttachmentHint(): array + { + return $this->attachmentHint; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getTcDisplay(): array + { + return $this->tcDisplay; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getTcDisplayContentType(): ?string + { + return $this->tcDisplayContentType; + } + + /** + * @return DisplayPNGCharacteristicsDescriptor[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getTcDisplayPNGCharacteristics(): array + { + return $this->tcDisplayPNGCharacteristics; + } + + /** + * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttestationRootCertificates(): array + { + return $this->attestationRootCertificates; + } + + /** + * @return EcdaaTrustAnchor[] + * + * @deprecated since 4.2.0 and will be removed in 5.0.0. The ECDAA Trust Anchor does no longer exist in Webauthn specification. + * @infection-ignore-all + */ + public function getEcdaaTrustAnchors(): array + { + return $this->ecdaaTrustAnchors; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getIcon(): ?string + { + return $this->icon; + } + + /** + * @return ExtensionDescriptor[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getSupportedExtensions(): array + { + return $this->supportedExtensions; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $requiredKeys = [ + 'description', + 'authenticatorVersion', + 'protocolFamily', + 'schema', + 'upv', + 'authenticationAlgorithms', + 'publicKeyAlgAndEncodings', + 'attestationTypes', + 'userVerificationDetails', + 'matcherProtection', + 'tcDisplay', + 'attestationRootCertificates', + ]; + foreach ($requiredKeys as $key) { + array_key_exists($key, $data) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid data. The key "%s" is missing', + $key + )); + } + $subObjects = [ + 'authenticationAlgorithms', + 'publicKeyAlgAndEncodings', + 'attestationTypes', + 'matcherProtection', + 'tcDisplay', + 'attestationRootCertificates', + ]; + foreach ($subObjects as $subObject) { + is_array($data[$subObject]) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid Metadata Statement. The parameter "%s" shall be a list of strings.', + $subObject + )); + foreach ($data[$subObject] as $datum) { + is_string($datum) || throw MetadataStatementLoadingException::create(sprintf( + 'Invalid Metadata Statement. The parameter "%s" shall be a list of strings.', + $subObject + )); + } + } + + return self::create( + $data['description'], + $data['authenticatorVersion'], + $data['protocolFamily'], + $data['schema'], + array_map(static function ($upv): Version { + is_array($upv) || throw MetadataStatementLoadingException::create( + 'Invalid Metadata Statement. The parameter "upv" shall be a list of objects.' + ); + + return Version::createFromArray($upv); + }, $data['upv']), + $data['authenticationAlgorithms'], + $data['publicKeyAlgAndEncodings'], + $data['attestationTypes'], + array_map(static function ($userVerificationDetails): VerificationMethodANDCombinations { + is_array($userVerificationDetails) || throw MetadataStatementLoadingException::create( + 'Invalid Metadata Statement. The parameter "userVerificationDetails" shall be a list of objects.' + ); + + return VerificationMethodANDCombinations::createFromArray($userVerificationDetails); + }, $data['userVerificationDetails']), + $data['matcherProtection'], + $data['tcDisplay'], + CertificateToolbox::fixPEMStructures($data['attestationRootCertificates']), + $data['alternativeDescriptions'] ?? [], + $data['legalHeader'] ?? null, + $data['aaid'] ?? null, + $data['aaguid'] ?? null, + $data['attestationCertificateKeyIdentifiers'] ?? [], + $data['keyProtection'] ?? [], + $data['isKeyRestricted'] ?? null, + $data['isFreshUserVerificationRequired'] ?? null, + $data['cryptoStrength'] ?? null, + $data['attachmentHint'] ?? [], + $data['tcDisplayContentType'] ?? null, + array_map( + static fn (array $data): DisplayPNGCharacteristicsDescriptor => DisplayPNGCharacteristicsDescriptor::createFromArray( + $data + ), + $data['tcDisplayPNGCharacteristics'] ?? [] + ), + $data['ecdaaTrustAnchors'] ?? [], + $data['icon'] ?? null, + array_map( + static fn ($supportedExtension): ExtensionDescriptor => ExtensionDescriptor::createFromArray( + $supportedExtension + ), + $data['supportedExtensions'] ?? [] + ), + isset($data['authenticatorGetInfo']) ? AuthenticatorGetInfo::create($data['authenticatorGetInfo']) : null, + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'legalHeader' => $this->legalHeader, + 'aaid' => $this->aaid, + 'aaguid' => $this->aaguid, + 'attestationCertificateKeyIdentifiers' => $this->attestationCertificateKeyIdentifiers, + 'description' => $this->description, + 'alternativeDescriptions' => $this->alternativeDescriptions, + 'authenticatorVersion' => $this->authenticatorVersion, + 'protocolFamily' => $this->protocolFamily, + 'schema' => $this->schema, + 'upv' => $this->upv, + 'authenticationAlgorithms' => $this->authenticationAlgorithms, + 'publicKeyAlgAndEncodings' => $this->publicKeyAlgAndEncodings, + 'attestationTypes' => $this->attestationTypes, + 'userVerificationDetails' => $this->userVerificationDetails, + 'keyProtection' => $this->keyProtection, + 'isKeyRestricted' => $this->isKeyRestricted, + 'isFreshUserVerificationRequired' => $this->isFreshUserVerificationRequired, + 'matcherProtection' => $this->matcherProtection, + 'cryptoStrength' => $this->cryptoStrength, + 'attachmentHint' => $this->attachmentHint, + 'tcDisplay' => $this->tcDisplay, + 'tcDisplayContentType' => $this->tcDisplayContentType, + 'tcDisplayPNGCharacteristics' => $this->tcDisplayPNGCharacteristics, + 'attestationRootCertificates' => CertificateToolbox::fixPEMStructures($this->attestationRootCertificates), + 'ecdaaTrustAnchors' => $this->ecdaaTrustAnchors, + 'icon' => $this->icon, + 'authenticatorGetInfo' => $this->authenticatorGetInfo, + 'supportedExtensions' => $this->supportedExtensions, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/PatternAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/PatternAccuracyDescriptor.php new file mode 100644 index 000000000..8ceed8b8d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/PatternAccuracyDescriptor.php @@ -0,0 +1,83 @@ += 0 || throw MetadataStatementLoadingException::create( + 'Invalid data. The value of "minComplexity" must be a positive integer' + ); + parent::__construct($maxRetries, $blockSlowdown); + } + + public static function create(int $minComplexity, ?int $maxRetries = null, ?int $blockSlowdown = null): self + { + return new self($minComplexity, $maxRetries, $blockSlowdown); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMinComplexity(): int + { + return $this->minComplexity; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + array_key_exists('minComplexity', $data) || throw MetadataStatementLoadingException::create( + 'The key "minComplexity" is missing' + ); + foreach (['minComplexity', 'maxRetries', 'blockSlowdown'] as $key) { + if (array_key_exists($key, $data)) { + is_int($data[$key]) || throw MetadataStatementLoadingException::create( + sprintf('Invalid data. The value of "%s" must be a positive integer', $key) + ); + } + } + + return self::create($data['minComplexity'], $data['maxRetries'] ?? null, $data['blockSlowdown'] ?? null); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'minComplexity' => $this->minComplexity, + 'maxRetries' => $this->maxRetries, + 'blockSlowdown' => $this->blockSlowdown, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RgbPaletteEntry.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RgbPaletteEntry.php new file mode 100644 index 000000000..73061b44a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RgbPaletteEntry.php @@ -0,0 +1,94 @@ += 0 && $r <= 255) || throw MetadataStatementLoadingException::create('The key "r" is invalid'); + ($g >= 0 && $g <= 255) || throw MetadataStatementLoadingException::create('The key "g" is invalid'); + ($b >= 0 && $b <= 255) || throw MetadataStatementLoadingException::create('The key "b" is invalid'); + } + + public static function create(int $r, int $g, int $b): self + { + return new self($r, $g, $b); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getR(): int + { + return $this->r; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getG(): int + { + return $this->g; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getB(): int + { + return $this->b; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + foreach (['r', 'g', 'b'] as $key) { + array_key_exists($key, $data) || throw MetadataStatementLoadingException::create(sprintf( + 'The key "%s" is missing', + $key + )); + is_int($data[$key]) || throw MetadataStatementLoadingException::create( + sprintf('The key "%s" is invalid', $key) + ); + } + + return self::create($data['r'], $data['g'], $data['b']); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return [ + 'r' => $this->r, + 'g' => $this->g, + 'b' => $this->b, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RogueListEntry.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RogueListEntry.php new file mode 100644 index 000000000..4cf5f2928 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/RogueListEntry.php @@ -0,0 +1,76 @@ +sk; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getDate(): ?string + { + return $this->date; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + array_key_exists('sk', $data) || throw MetadataStatementLoadingException::create('The key "sk" is missing'); + is_string($data['sk']) || throw MetadataStatementLoadingException::create('The key "date" is invalid'); + array_key_exists('date', $data) || throw MetadataStatementLoadingException::create( + 'The key "date" is missing' + ); + is_string($data['date']) || throw MetadataStatementLoadingException::create('The key "date" is invalid'); + + return self::create($data['sk'], $data['date']); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return [ + 'sk' => $this->sk, + 'date' => $this->date, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/StatusReport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/StatusReport.php new file mode 100644 index 000000000..0ab13517a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/StatusReport.php @@ -0,0 +1,207 @@ +status, [ + AuthenticatorStatus::ATTESTATION_KEY_COMPROMISE, + AuthenticatorStatus::USER_KEY_PHYSICAL_COMPROMISE, + AuthenticatorStatus::USER_KEY_REMOTE_COMPROMISE, + AuthenticatorStatus::USER_VERIFICATION_BYPASS, + AuthenticatorStatus::REVOKED, + ], true); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getEffectiveDate(): ?string + { + return $this->effectiveDate; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificate(): ?string + { + return $this->certificate; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getUrl(): ?string + { + return $this->url; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationDescriptor(): ?string + { + return $this->certificationDescriptor; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificateNumber(): ?string + { + return $this->certificateNumber; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationPolicyVersion(): ?string + { + return $this->certificationPolicyVersion; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCertificationRequirementsVersion(): ?string + { + return $this->certificationRequirementsVersion; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + array_key_exists('status', $data) || throw MetadataStatementLoadingException::create( + 'The key "status" is missing' + ); + foreach ([ + 'effectiveDate', + 'certificate', + 'url', + 'certificationDescriptor', + 'certificateNumber', + 'certificationPolicyVersion', + 'certificationRequirementsVersion', + ] as $key) { + if (isset($data[$key])) { + $value = $data[$key]; + $value === null || is_string($value) || throw MetadataStatementLoadingException::create(sprintf( + 'The value of the key "%s" is invalid', + $key + )); + } + } + + return self::create( + $data['status'], + $data['effectiveDate'] ?? null, + $data['certificate'] ?? null, + $data['url'] ?? null, + $data['certificationDescriptor'] ?? null, + $data['certificateNumber'] ?? null, + $data['certificationPolicyVersion'] ?? null, + $data['certificationRequirementsVersion'] ?? null + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'status' => $this->status, + 'effectiveDate' => $this->effectiveDate, + 'certificate' => $this->certificate, + 'url' => $this->url, + 'certificationDescriptor' => $this->certificationDescriptor, + 'certificateNumber' => $this->certificateNumber, + 'certificationPolicyVersion' => $this->certificationPolicyVersion, + 'certificationRequirementsVersion' => $this->certificationRequirementsVersion, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodANDCombinations.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodANDCombinations.php new file mode 100644 index 000000000..581d5f596 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodANDCombinations.php @@ -0,0 +1,79 @@ +verificationMethods[] = $verificationMethodDescriptor; + + return $this; + } + + /** + * @return VerificationMethodDescriptor[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getVerificationMethods(): array + { + return $this->verificationMethods; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + return self::create( + array_map( + static fn (array $datum): VerificationMethodDescriptor => VerificationMethodDescriptor::createFromArray( + $datum + ), + $data + ) + ); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + return $this->verificationMethods; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodDescriptor.php new file mode 100644 index 000000000..89184644f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/VerificationMethodDescriptor.php @@ -0,0 +1,274 @@ += 0 || throw MetadataStatementLoadingException::create( + 'The parameter "userVerificationMethod" is invalid' + ); + } + + public static function create( + string $userVerificationMethod, + ?CodeAccuracyDescriptor $caDesc = null, + ?BiometricAccuracyDescriptor $baDesc = null, + ?PatternAccuracyDescriptor $paDesc = null + ): self { + return new self($userVerificationMethod, $caDesc, $baDesc, $paDesc); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getUserVerificationMethod(): string + { + return $this->userVerificationMethod; + } + + public function userPresence(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_PRESENCE_INTERNAL; + } + + public function fingerprint(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_FINGERPRINT_INTERNAL; + } + + public function passcodeInternal(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_PASSCODE_INTERNAL; + } + + public function voicePrint(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_VOICEPRINT_INTERNAL; + } + + public function facePrint(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_FACEPRINT_INTERNAL; + } + + public function location(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_LOCATION_INTERNAL; + } + + public function eyePrint(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_EYEPRINT_INTERNAL; + } + + public function patternInternal(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_PATTERN_INTERNAL; + } + + public function handprint(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_HANDPRINT_INTERNAL; + } + + public function passcodeExternal(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_PASSCODE_EXTERNAL; + } + + public function patternExternal(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_PATTERN_EXTERNAL; + } + + public function none(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_NONE; + } + + public function all(): bool + { + return $this->userVerificationMethod === self::USER_VERIFY_ALL; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getCaDesc(): ?CodeAccuracyDescriptor + { + return $this->caDesc; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getBaDesc(): ?BiometricAccuracyDescriptor + { + return $this->baDesc; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getPaDesc(): ?PatternAccuracyDescriptor + { + return $this->paDesc; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + if (isset($data['userVerification']) && ! isset($data['userVerificationMethod'])) { + $data['userVerificationMethod'] = $data['userVerification']; + unset($data['userVerification']); + } + array_key_exists('userVerificationMethod', $data) || throw MetadataStatementLoadingException::create( + 'The parameters "userVerificationMethod" is missing' + ); + + foreach (['caDesc', 'baDesc', 'paDesc'] as $key) { + if (isset($data[$key])) { + is_array($data[$key]) || throw MetadataStatementLoadingException::create( + sprintf('Invalid parameter "%s"', $key) + ); + } + } + + $caDesc = isset($data['caDesc']) ? CodeAccuracyDescriptor::createFromArray($data['caDesc']) : null; + $baDesc = isset($data['baDesc']) ? BiometricAccuracyDescriptor::createFromArray($data['baDesc']) : null; + $paDesc = isset($data['paDesc']) ? PatternAccuracyDescriptor::createFromArray($data['paDesc']) : null; + + return self::create($data['userVerificationMethod'], $caDesc, $baDesc, $paDesc); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'userVerificationMethod' => $this->userVerificationMethod, + 'caDesc' => $this->caDesc, + 'baDesc' => $this->baDesc, + 'paDesc' => $this->paDesc, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/Version.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/Version.php new file mode 100644 index 000000000..56b7b0faf --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/Statement/Version.php @@ -0,0 +1,89 @@ += 0 || throw MetadataStatementLoadingException::create('Invalid argument "major"'); + $minor >= 0 || throw MetadataStatementLoadingException::create('Invalid argument "minor"'); + } + + public static function create(?int $major, ?int $minor): self + { + return new self($major, $minor); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMajor(): ?int + { + return $this->major; + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getMinor(): ?int + { + return $this->minor; + } + + /** + * @param array $data + * @deprecated since 4.7.0. Please use the symfony/serializer for converting the object. + * @infection-ignore-all + */ + public static function createFromArray(array $data): self + { + $data = self::filterNullValues($data); + foreach (['major', 'minor'] as $key) { + if (array_key_exists($key, $data)) { + is_int($data[$key]) || throw MetadataStatementLoadingException::create( + sprintf('Invalid value for key "%s"', $key) + ); + } + } + + return self::create($data['major'] ?? null, $data['minor'] ?? null); + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $data = [ + 'major' => $this->major, + 'minor' => $this->minor, + ]; + + return self::filterNullValues($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReportRepository.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/StatusReportRepository.php similarity index 100% rename from lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReportRepository.php rename to lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/StatusReportRepository.php diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/ValueFilter.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/ValueFilter.php new file mode 100644 index 000000000..23a9700c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/MetadataService/ValueFilter.php @@ -0,0 +1,21 @@ + $data + * + * @return array + */ + private static function filterNullValues(array $data): array + { + return array_filter($data, static fn ($var): bool => $var !== null); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php index 1a508b4ec..b4930f803 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace Webauthn; -use const JSON_THROW_ON_ERROR; use Stringable; +use function sprintf; +use const E_USER_DEPRECATED; +use const JSON_THROW_ON_ERROR; /** * @see https://www.w3.org/TR/webauthn/#iface-pkcredential @@ -13,24 +15,41 @@ use Stringable; class PublicKeyCredential extends Credential implements Stringable { public function __construct( - string $id, + null|string $id, string $type, - protected string $rawId, - protected AuthenticatorResponse $response + string $rawId, + public readonly AuthenticatorResponse $response ) { - parent::__construct($id, $type); + parent::__construct($id, $type, $rawId); } + /** + * @deprecated since 4.8.0. + * @infection-ignore-all + */ public function __toString(): string { - return json_encode($this, JSON_THROW_ON_ERROR); + return json_encode($this->getPublicKeyCredentialDescriptor(), JSON_THROW_ON_ERROR); } + public static function create(null|string $id, string $type, string $rawId, AuthenticatorResponse $response): self + { + return new self($id, $type, $rawId, $response); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRawId(): string { return $this->rawId; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getResponse(): AuthenticatorResponse { return $this->response; @@ -39,8 +58,24 @@ class PublicKeyCredential extends Credential implements Stringable /** * @param string[] $transport */ - public function getPublicKeyCredentialDescriptor(array $transport = []): PublicKeyCredentialDescriptor + public function getPublicKeyCredentialDescriptor(null|array $transport = null): PublicKeyCredentialDescriptor { - return new PublicKeyCredentialDescriptor($this->getType(), $this->getRawId(), $transport); + if ($transport !== null) { + trigger_deprecation( + 'web-auth/webauthn-lib', + '4.8.0', + 'The parameter "$transport" is deprecated and will be removed in 5.0.0.' + ); + @trigger_error( + sprintf( + 'The $transport argument of %s() is deprecated since 4.8.0 and will be removed in 5.0.0.', + __METHOD__ + ), + E_USER_DEPRECATED + ); + } + $transport ??= $this->response instanceof AuthenticatorAttestationResponse ? $this->response->transports : []; + + return PublicKeyCredentialDescriptor::create($this->type, $this->rawId, $transport); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php index 337f2e74f..3e1377eb5 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php @@ -4,14 +4,22 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use const JSON_THROW_ON_ERROR; +use InvalidArgumentException; use ParagonIE\ConstantTime\Base64UrlSafe; +use Webauthn\AuthenticationExtensions\AuthenticationExtensions; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; +use Webauthn\Exception\InvalidDataException; use Webauthn\Util\Base64; +use function array_key_exists; +use function count; +use function in_array; +use function is_array; +use const JSON_THROW_ON_ERROR; final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOptions { + public const ATTESTATION_CONVEYANCE_PREFERENCE_DEFAULT = null; + public const ATTESTATION_CONVEYANCE_PREFERENCE_NONE = 'none'; public const ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT = 'indirect'; @@ -20,41 +28,82 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption public const ATTESTATION_CONVEYANCE_PREFERENCE_ENTERPRISE = 'enterprise'; - /** - * @var PublicKeyCredentialDescriptor[] - */ - private array $excludeCredentials = []; - - private AuthenticatorSelectionCriteria $authenticatorSelection; - - private string $attestation; + public const ATTESTATION_CONVEYANCE_PREFERENCES = [ + self::ATTESTATION_CONVEYANCE_PREFERENCE_DEFAULT, + self::ATTESTATION_CONVEYANCE_PREFERENCE_NONE, + self::ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT, + self::ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT, + self::ATTESTATION_CONVEYANCE_PREFERENCE_ENTERPRISE, + ]; /** + * @private * @param PublicKeyCredentialParameters[] $pubKeyCredParams + * @param PublicKeyCredentialDescriptor[] $excludeCredentials + * @param null|positive-int $timeout */ public function __construct( - private readonly PublicKeyCredentialRpEntity $rp, - private readonly PublicKeyCredentialUserEntity $user, + public readonly PublicKeyCredentialRpEntity $rp, + public readonly PublicKeyCredentialUserEntity $user, string $challenge, - private array $pubKeyCredParams + public array $pubKeyCredParams = [], + public null|AuthenticatorSelectionCriteria $authenticatorSelection = null, + public null|string $attestation = null, + public array $excludeCredentials = [], + null|int $timeout = null, + null|AuthenticationExtensions $extensions = null, ) { - parent::__construct($challenge); - $this->authenticatorSelection = new AuthenticatorSelectionCriteria(); - $this->attestation = self::ATTESTATION_CONVEYANCE_PREFERENCE_NONE; + foreach ($pubKeyCredParams as $pubKeyCredParam) { + $pubKeyCredParam instanceof PublicKeyCredentialParameters || throw new InvalidArgumentException( + 'Invalid type for $pubKeyCredParams' + ); + } + foreach ($excludeCredentials as $excludeCredential) { + $excludeCredential instanceof PublicKeyCredentialDescriptor || throw new InvalidArgumentException( + 'Invalid type for $excludeCredentials' + ); + } + in_array($attestation, self::ATTESTATION_CONVEYANCE_PREFERENCES, true) || throw InvalidDataException::create( + $attestation, + 'Invalid attestation conveyance mode' + ); + + parent::__construct($challenge, $timeout, $extensions); } /** * @param PublicKeyCredentialParameters[] $pubKeyCredParams + * @param PublicKeyCredentialDescriptor[] $excludeCredentials + * @param null|positive-int $timeout */ public static function create( PublicKeyCredentialRpEntity $rp, PublicKeyCredentialUserEntity $user, string $challenge, - array $pubKeyCredParams + array $pubKeyCredParams = [], + null|AuthenticatorSelectionCriteria $authenticatorSelection = null, + null|string $attestation = null, + array $excludeCredentials = [], + null|int $timeout = null, + null|AuthenticationExtensions $extensions = null, ): self { - return new self($rp, $user, $challenge, $pubKeyCredParams); + return new self( + $rp, + $user, + $challenge, + $pubKeyCredParams, + $authenticatorSelection, + $attestation, + $excludeCredentials, + $timeout, + $extensions + ); } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function addPubKeyCredParam(PublicKeyCredentialParameters $pubKeyCredParam): self { $this->pubKeyCredParams[] = $pubKeyCredParam; @@ -62,15 +111,23 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption return $this; } + /** + * @deprecated since 4.7.0. No replacement. Please use the {self::create} instead. + * @infection-ignore-all + */ public function addPubKeyCredParams(PublicKeyCredentialParameters ...$pubKeyCredParams): self { foreach ($pubKeyCredParams as $pubKeyCredParam) { - $this->addPubKeyCredParam($pubKeyCredParam); + $this->pubKeyCredParams[] = $pubKeyCredParam; } return $this; } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function excludeCredential(PublicKeyCredentialDescriptor $excludeCredential): self { $this->excludeCredentials[] = $excludeCredential; @@ -78,40 +135,58 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption return $this; } + /** + * @deprecated since 4.7.0. No replacement. Please use the {self::create} instead. + * @infection-ignore-all + */ public function excludeCredentials(PublicKeyCredentialDescriptor ...$excludeCredentials): self { foreach ($excludeCredentials as $excludeCredential) { - $this->excludeCredential($excludeCredential); + $this->excludeCredentials[] = $excludeCredential; } return $this; } - public function setAuthenticatorSelection(AuthenticatorSelectionCriteria $authenticatorSelection): self + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ + public function setAuthenticatorSelection(?AuthenticatorSelectionCriteria $authenticatorSelection): self { $this->authenticatorSelection = $authenticatorSelection; return $this; } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function setAttestation(string $attestation): self { - Assertion::inArray($attestation, [ - self::ATTESTATION_CONVEYANCE_PREFERENCE_NONE, - self::ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT, - self::ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT, - self::ATTESTATION_CONVEYANCE_PREFERENCE_ENTERPRISE, - ], 'Invalid attestation conveyance mode'); + in_array($attestation, self::ATTESTATION_CONVEYANCE_PREFERENCES, true) || throw InvalidDataException::create( + $attestation, + 'Invalid attestation conveyance mode' + ); $this->attestation = $attestation; return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRp(): PublicKeyCredentialRpEntity { return $this->rp; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getUser(): PublicKeyCredentialUserEntity { return $this->user; @@ -119,6 +194,8 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption /** * @return PublicKeyCredentialParameters[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getPubKeyCredParams(): array { @@ -127,42 +204,76 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption /** * @return PublicKeyCredentialDescriptor[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getExcludeCredentials(): array { return $this->excludeCredentials; } - public function getAuthenticatorSelection(): AuthenticatorSelectionCriteria + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAuthenticatorSelection(): ?AuthenticatorSelectionCriteria { return $this->authenticatorSelection; } - public function getAttestation(): string + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAttestation(): ?string { return $this->attestation; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromString(string $data): static { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromArray(array $json): static { - Assertion::keyExists($json, 'rp', 'Invalid input. "rp" is missing.'); - Assertion::keyExists($json, 'pubKeyCredParams', 'Invalid input. "pubKeyCredParams" is missing.'); - Assertion::isArray($json['pubKeyCredParams'], 'Invalid input. "pubKeyCredParams" is not an array.'); - Assertion::keyExists($json, 'challenge', 'Invalid input. "challenge" is missing.'); - Assertion::keyExists($json, 'attestation', 'Invalid input. "attestation" is missing.'); - Assertion::keyExists($json, 'user', 'Invalid input. "user" is missing.'); - Assertion::keyExists($json, 'authenticatorSelection', 'Invalid input. "authenticatorSelection" is missing.'); + array_key_exists('rp', $json) || throw InvalidDataException::create($json, 'Invalid input. "rp" is missing.'); + array_key_exists('pubKeyCredParams', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "pubKeyCredParams" is missing.' + ); + is_array($json['pubKeyCredParams']) || throw InvalidDataException::create( + $json, + 'Invalid input. "pubKeyCredParams" is not an array.' + ); + array_key_exists('challenge', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "challenge" is missing.' + ); + array_key_exists('attestation', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "attestation" is missing.' + ); + array_key_exists('user', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "user" is missing.' + ); $pubKeyCredParams = []; foreach ($json['pubKeyCredParams'] as $pubKeyCredParam) { + if (! is_array($pubKeyCredParam)) { + continue; + } $pubKeyCredParams[] = PublicKeyCredentialParameters::createFromArray($pubKeyCredParam); } $excludeCredentials = []; @@ -174,25 +285,27 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption $challenge = Base64::decode($json['challenge']); + $authenticatorSelection = isset($json['authenticatorSelection']) ? AuthenticatorSelectionCriteria::createFromArray( + $json['authenticatorSelection'] + ) : null + ; + $extensions = + isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray( + $json['extensions'] + ) : AuthenticationExtensionsClientInputs::create() + ; return self ::create( PublicKeyCredentialRpEntity::createFromArray($json['rp']), PublicKeyCredentialUserEntity::createFromArray($json['user']), $challenge, - $pubKeyCredParams - ) - ->excludeCredentials(...$excludeCredentials) - ->setAuthenticatorSelection( - AuthenticatorSelectionCriteria::createFromArray($json['authenticatorSelection']) - ) - ->setAttestation($json['attestation']) - ->setTimeout($json['timeout'] ?? null) - ->setExtensions( - isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray( - $json['extensions'] - ) : new AuthenticationExtensionsClientInputs() - ) - ; + $pubKeyCredParams, + $authenticatorSelection, + $json['attestation'] ?? null, + $excludeCredentials, + $json['timeout'] ?? null, + $extensions + ); } /** @@ -200,30 +313,39 @@ final class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOption */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = [ - 'rp' => $this->rp->jsonSerialize(), - 'pubKeyCredParams' => array_map( - static fn (PublicKeyCredentialParameters $object): array => $object->jsonSerialize(), - $this->pubKeyCredParams - ), + 'rp' => $this->rp, + 'user' => $this->user, 'challenge' => Base64UrlSafe::encodeUnpadded($this->challenge), - 'attestation' => $this->attestation, - 'user' => $this->user->jsonSerialize(), - 'authenticatorSelection' => $this->authenticatorSelection->jsonSerialize(), - 'excludeCredentials' => array_map( - static fn (PublicKeyCredentialDescriptor $object): array => $object->jsonSerialize(), - $this->excludeCredentials - ), + 'pubKeyCredParams' => $this->pubKeyCredParams, ]; - if ($this->extensions->count() !== 0) { - $json['extensions'] = $this->extensions; - } - if ($this->timeout !== null) { $json['timeout'] = $this->timeout; } + if (count($this->excludeCredentials) !== 0) { + $json['excludeCredentials'] = $this->excludeCredentials; + } + + if ($this->authenticatorSelection !== null) { + $json['authenticatorSelection'] = $this->authenticatorSelection; + } + + if ($this->attestation !== null) { + $json['attestation'] = $this->attestation; + } + + if ($this->extensions->count() !== 0) { + $json['extensions'] = $this->extensions; + } + return $json; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php index 18bd6a64e..3a351be27 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use function count; -use const JSON_THROW_ON_ERROR; use JsonSerializable; use ParagonIE\ConstantTime\Base64UrlSafe; -use Webauthn\Util\Base64; +use Webauthn\Exception\InvalidDataException; +use function array_key_exists; +use function count; +use const JSON_THROW_ON_ERROR; class PublicKeyCredentialDescriptor implements JsonSerializable { @@ -25,13 +25,21 @@ class PublicKeyCredentialDescriptor implements JsonSerializable final public const AUTHENTICATOR_TRANSPORT_INTERNAL = 'internal'; + final public const AUTHENTICATOR_TRANSPORTS = [ + self::AUTHENTICATOR_TRANSPORT_USB, + self::AUTHENTICATOR_TRANSPORT_NFC, + self::AUTHENTICATOR_TRANSPORT_BLE, + self::AUTHENTICATOR_TRANSPORT_CABLE, + self::AUTHENTICATOR_TRANSPORT_INTERNAL, + ]; + /** * @param string[] $transports */ public function __construct( - protected string $type, - protected string $id, - protected array $transports = [] + public readonly string $type, + public readonly string $id, + public readonly array $transports = [] ) { } @@ -43,11 +51,19 @@ class PublicKeyCredentialDescriptor implements JsonSerializable return new self($type, $id, $transports); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getId(): string { return $this->id; @@ -55,31 +71,39 @@ class PublicKeyCredentialDescriptor implements JsonSerializable /** * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getTransports(): array { return $this->transports; } + /** + * @deprecated since 4.9.0 and will be removed in 5.0.0. Please use the serializer instead. + */ public static function createFromString(string $data): self { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } /** * @param mixed[] $json + * @deprecated since 4.9.0 and will be removed in 5.0.0. Please use the serializer instead. */ public static function createFromArray(array $json): self { - Assertion::keyExists($json, 'type', 'Invalid input. "type" is missing.'); - Assertion::keyExists($json, 'id', 'Invalid input. "id" is missing.'); + array_key_exists('type', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "type" is missing.' + ); + array_key_exists('id', $json) || throw InvalidDataException::create($json, 'Invalid input. "id" is missing.'); - $id = Base64::decodeUrlSafe($json['id']); + $id = Base64UrlSafe::decodeNoPadding($json['id']); - return new self($json['type'], $id, $json['transports'] ?? []); + return self::create($json['type'], $id, $json['transports'] ?? []); } /** @@ -87,6 +111,12 @@ class PublicKeyCredentialDescriptor implements JsonSerializable */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = [ 'type' => $this->type, 'id' => Base64UrlSafe::encodeUnpadded($this->id), diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php index f3352e573..d5f1481c9 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php @@ -4,42 +4,78 @@ declare(strict_types=1); namespace Webauthn; -use function array_key_exists; use ArrayIterator; -use Assert\Assertion; -use function count; -use const COUNT_NORMAL; use Countable; +use InvalidArgumentException; use Iterator; use IteratorAggregate; -use const JSON_THROW_ON_ERROR; use JsonSerializable; +use function array_key_exists; +use function count; +use const COUNT_NORMAL; +use const JSON_THROW_ON_ERROR; /** * @implements IteratorAggregate + * @deprecated since 4.8.0 and will be removed in 5.0.0. + * @infection-ignore-all */ class PublicKeyCredentialDescriptorCollection implements JsonSerializable, Countable, IteratorAggregate { /** - * @var PublicKeyCredentialDescriptor[] + * @var array + * @readonly */ - private array $publicKeyCredentialDescriptors = []; + public array $publicKeyCredentialDescriptors; - public function add(PublicKeyCredentialDescriptor ...$publicKeyCredentialDescriptors): void - { - foreach ($publicKeyCredentialDescriptors as $publicKeyCredentialDescriptor) { - $this->publicKeyCredentialDescriptors[$publicKeyCredentialDescriptor->getId()] = $publicKeyCredentialDescriptor; + /** + * @private + * @param PublicKeyCredentialDescriptor[] $pkCredentialDescriptors + */ + public function __construct( + array $pkCredentialDescriptors = [] + ) { + $this->publicKeyCredentialDescriptors = []; + foreach ($pkCredentialDescriptors as $pkCredentialDescriptor) { + $pkCredentialDescriptor instanceof PublicKeyCredentialDescriptor || throw new InvalidArgumentException( + 'Expected only instances of ' . PublicKeyCredentialDescriptor::class + ); + $this->publicKeyCredentialDescriptors[$pkCredentialDescriptor->id] = $pkCredentialDescriptor; } } + /** + * @param PublicKeyCredentialDescriptor[] $publicKeyCredentialDescriptors + */ + public static function create(array $publicKeyCredentialDescriptors): self + { + return new self($publicKeyCredentialDescriptors); + } + + /** + * @infection-ignore-all + */ + public function add(PublicKeyCredentialDescriptor ...$publicKeyCredentialDescriptors): void + { + foreach ($publicKeyCredentialDescriptors as $publicKeyCredentialDescriptor) { + $this->publicKeyCredentialDescriptors[$publicKeyCredentialDescriptor->id] = $publicKeyCredentialDescriptor; + } + } + + /** + * @infection-ignore-all + */ public function has(string $id): bool { return array_key_exists($id, $this->publicKeyCredentialDescriptors); } + /** + * @infection-ignore-all + */ public function remove(string $id): void { - if (! $this->has($id)) { + if (! array_key_exists($id, $this->publicKeyCredentialDescriptors)) { return; } @@ -64,30 +100,38 @@ class PublicKeyCredentialDescriptorCollection implements JsonSerializable, Count */ public function jsonSerialize(): array { - return array_map( - static fn (PublicKeyCredentialDescriptor $object): array => $object->jsonSerialize(), - $this->publicKeyCredentialDescriptors + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ ); + return $this->publicKeyCredentialDescriptors; } + /** + * @infection-ignore-all + */ public static function createFromString(string $data): self { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } /** * @param mixed[] $json + * @infection-ignore-all */ public static function createFromArray(array $json): self { - $collection = new self(); - foreach ($json as $item) { - $collection->add(PublicKeyCredentialDescriptor::createFromArray($item)); - } - - return $collection; + return self::create( + array_map( + static fn (array $item): PublicKeyCredentialDescriptor => PublicKeyCredentialDescriptor::createFromArray( + $item + ), + $json + ) + ); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php index 22aa22813..844a078b7 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php @@ -9,16 +9,24 @@ use JsonSerializable; abstract class PublicKeyCredentialEntity implements JsonSerializable { public function __construct( - protected string $name, - protected ?string $icon + public readonly string $name, + public readonly ?string $icon ) { } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getName(): string { return $this->name; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getIcon(): ?string { return $this->icon; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php index 49d3dc732..8c28d5389 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php @@ -4,53 +4,54 @@ declare(strict_types=1); namespace Webauthn; -use function array_key_exists; -use Assert\Assertion; -use CBOR\Decoder; -use CBOR\MapObject; use InvalidArgumentException; -use const JSON_THROW_ON_ERROR; -use function ord; +use ParagonIE\ConstantTime\Base64UrlSafe; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use function Safe\unpack; -use Symfony\Component\Uid\Uuid; +use Symfony\Component\Serializer\SerializerInterface; use Throwable; use Webauthn\AttestationStatement\AttestationObjectLoader; -use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputsLoader; +use Webauthn\Exception\InvalidDataException; +use Webauthn\MetadataService\CanLogData; use Webauthn\Util\Base64; +use function array_key_exists; +use function is_array; +use function is_string; +use function sprintf; +use const JSON_THROW_ON_ERROR; -class PublicKeyCredentialLoader +/** + * @deprecated since 4.8.0 and will be removed in 5.0.0. Please use the Symfony serializer instead + */ +class PublicKeyCredentialLoader implements CanLogData { - private const FLAG_AT = 0b01000000; - - private const FLAG_ED = 0b10000000; - - private readonly Decoder $decoder; - private LoggerInterface $logger; public function __construct( - private readonly AttestationObjectLoader $attestationObjectLoader + private readonly null|AttestationObjectLoader $attestationObjectLoader, + private readonly null|SerializerInterface $serializer = null, ) { - $this->decoder = Decoder::create(); + if ($this->attestationObjectLoader === null && $this->serializer === null) { + throw new InvalidArgumentException('You must provide an attestation object loader or a serializer'); + } $this->logger = new NullLogger(); } - public static function create(AttestationObjectLoader $attestationObjectLoader): self - { - return new self($attestationObjectLoader); + public static function create( + null|AttestationObjectLoader $attestationObjectLoader, + null|SerializerInterface $serializer = null + ): self { + return new self($attestationObjectLoader, $serializer); } - public function setLogger(LoggerInterface $logger): self + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; - - return $this; } /** * @param mixed[] $json + * @infection-ignore-all */ public function loadArray(array $json): PublicKeyCredential { @@ -59,19 +60,34 @@ class PublicKeyCredentialLoader ]); try { foreach (['id', 'rawId', 'type'] as $key) { - Assertion::keyExists($json, $key, sprintf('The parameter "%s" is missing', $key)); - Assertion::string($json[$key], sprintf('The parameter "%s" shall be a string', $key)); + array_key_exists($key, $json) || throw InvalidDataException::create($json, sprintf( + 'The parameter "%s" is missing', + $key + )); + is_string($json[$key]) || throw InvalidDataException::create($json, sprintf( + 'The parameter "%s" shall be a string', + $key + )); } - Assertion::keyExists($json, 'response', 'The parameter "response" is missing'); - Assertion::isArray($json['response'], 'The parameter "response" shall be an array'); - Assertion::eq($json['type'], 'public-key', sprintf('Unsupported type "%s"', $json['type'])); + array_key_exists('response', $json) || throw InvalidDataException::create( + $json, + 'The parameter "response" is missing' + ); + is_array($json['response']) || throw InvalidDataException::create( + $json, + 'The parameter "response" shall be an array' + ); + $json['type'] === 'public-key' || throw InvalidDataException::create($json, sprintf( + 'Unsupported type "%s"', + $json['type'] + )); - $id = Base64::decodeUrlSafe($json['id']); + $id = Base64UrlSafe::decodeNoPadding($json['id']); $rawId = Base64::decode($json['rawId']); - Assertion::true(hash_equals($id, $rawId)); + hash_equals($id, $rawId) || throw InvalidDataException::create($json, 'Invalid ID'); - $publicKeyCredential = new PublicKeyCredential( - $json['id'], + $publicKeyCredential = PublicKeyCredential::create( + null, $json['type'], $rawId, $this->createResponse($json['response']) @@ -96,14 +112,17 @@ class PublicKeyCredentialLoader 'data' => $data, ]); try { - $json = json_decode($data, true, 512, JSON_THROW_ON_ERROR); + if ($this->serializer !== null) { + return $this->serializer->deserialize($data, PublicKeyCredential::class, 'json'); + } + $json = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return $this->loadArray($json); } catch (Throwable $throwable) { $this->logger->error('An error occurred', [ 'exception' => $throwable, ]); - throw $throwable; + throw InvalidDataException::create($data, 'Unable to load the data', $throwable); } } @@ -112,78 +131,62 @@ class PublicKeyCredentialLoader */ private function createResponse(array $response): AuthenticatorResponse { - Assertion::keyExists($response, 'clientDataJSON', 'Invalid data. The parameter "clientDataJSON" is missing'); - Assertion::string($response['clientDataJSON'], 'Invalid data. The parameter "clientDataJSON" is invalid'); - Assertion::nullOrString($response['userHandle'] ?? null, 'Invalid data. The parameter "userHandle" is invalid'); + array_key_exists('clientDataJSON', $response) || throw InvalidDataException::create( + $response, + 'Invalid data. The parameter "clientDataJSON" is missing' + ); + is_string($response['clientDataJSON']) || throw InvalidDataException::create( + $response, + 'Invalid data. The parameter "clientDataJSON" is invalid' + ); + $userHandle = $response['userHandle'] ?? null; + $userHandle === null || is_string($userHandle) || throw InvalidDataException::create( + $response, + 'Invalid data. The parameter "userHandle" is invalid' + ); + /** @var string[] $transports */ + $transports = $response['transports'] ?? []; + is_array($transports) || throw InvalidDataException::create( + $response, + 'Invalid data. The parameter "transports" is invalid' + ); + if ($this->serializer !== null) { + return $this->serializer->deserialize($response, AuthenticatorResponse::class, 'json'); + } switch (true) { case array_key_exists('attestationObject', $response): - Assertion::string( - $response['attestationObject'], - 'Invalid data. The parameter "attestationObject " is invalid' - ); $attestationObject = $this->attestationObjectLoader->load($response['attestationObject']); - return new AuthenticatorAttestationResponse(CollectedClientData::createFormJson( + return AuthenticatorAttestationResponse::create(CollectedClientData::createFormJson( $response['clientDataJSON'] - ), $attestationObject); - case array_key_exists('authenticatorData', $response) && array_key_exists('signature', $response): - $authData = Base64::decode($response['authenticatorData']); - - $authDataStream = new StringStream($authData); - $rp_id_hash = $authDataStream->read(32); - $flags = $authDataStream->read(1); - $signCount = $authDataStream->read(4); - $signCount = unpack('N', $signCount); - - $attestedCredentialData = null; - if (0 !== (ord($flags) & self::FLAG_AT)) { - $aaguid = Uuid::fromBinary($authDataStream->read(16)); - $credentialLength = $authDataStream->read(2); - $credentialLength = unpack('n', $credentialLength); - $credentialId = $authDataStream->read($credentialLength[1]); - $credentialPublicKey = $this->decoder->decode($authDataStream); - Assertion::isInstanceOf( - $credentialPublicKey, - MapObject::class, - 'The data does not contain a valid credential public key.' - ); - $attestedCredentialData = new AttestedCredentialData( - $aaguid, - $credentialId, - (string) $credentialPublicKey - ); - } - - $extension = null; - if (0 !== (ord($flags) & self::FLAG_ED)) { - $extension = $this->decoder->decode($authDataStream); - $extension = AuthenticationExtensionsClientOutputsLoader::load($extension); - } - Assertion::true($authDataStream->isEOF(), 'Invalid authentication data. Presence of extra bytes.'); - $authDataStream->close(); - $authenticatorData = new AuthenticatorData( - $authData, - $rp_id_hash, - $flags, - $signCount[1], - $attestedCredentialData, - $extension - ); + ), $attestationObject, $transports); + case array_key_exists('signature', $response): + $authDataLoader = AuthenticatorDataLoader::create(); + $authData = Base64UrlSafe::decodeNoPadding($response['authenticatorData'] ?? ''); + $authenticatorData = $authDataLoader->load($authData); try { $signature = Base64::decode($response['signature']); } catch (Throwable $e) { - throw new InvalidArgumentException('The signature shall be Base64 Url Safe encoded', 0, $e); + throw InvalidDataException::create( + $response['signature'], + 'The signature shall be Base64 Url Safe encoded', + $e + ); + } + $userHandle = $response['userHandle'] ?? null; + if ($userHandle !== '' && $userHandle !== null) { + $userHandle = Base64::decode($userHandle); } - return new AuthenticatorAssertionResponse( + return AuthenticatorAssertionResponse::create( CollectedClientData::createFormJson($response['clientDataJSON']), $authenticatorData, $signature, - $response['userHandle'] ?? null + $userHandle ); default: - throw new InvalidArgumentException('Unable to create the response object'); + throw InvalidDataException::create($response, 'Unable to create the response object'); } } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php index 4be22ae96..8e5ffbe42 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php @@ -4,22 +4,40 @@ declare(strict_types=1); namespace Webauthn; +use InvalidArgumentException; use JsonSerializable; use Webauthn\AuthenticationExtensions\AuthenticationExtension; +use Webauthn\AuthenticationExtensions\AuthenticationExtensions; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; abstract class PublicKeyCredentialOptions implements JsonSerializable { - protected ?int $timeout = null; - - protected AuthenticationExtensionsClientInputs $extensions; + public AuthenticationExtensions $extensions; + /** + * @param positive-int|null $timeout + * @param null|AuthenticationExtensions|array $extensions + * @protected + */ public function __construct( - protected string $challenge + public readonly string $challenge, + public null|int $timeout = null, + null|array|AuthenticationExtensions $extensions = null, ) { - $this->extensions = new AuthenticationExtensionsClientInputs(); + ($this->timeout === null || $this->timeout > 0) || throw new InvalidArgumentException('Invalid timeout'); + if ($extensions === null) { + $this->extensions = AuthenticationExtensionsClientInputs::create(); + } elseif ($extensions instanceof AuthenticationExtensions) { + $this->extensions = $extensions; + } else { + $this->extensions = AuthenticationExtensions::create($extensions); + } } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function setTimeout(?int $timeout): static { $this->timeout = $timeout; @@ -27,51 +45,79 @@ abstract class PublicKeyCredentialOptions implements JsonSerializable return $this; } + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ public function addExtension(AuthenticationExtension $extension): static { - $this->extensions->add($extension); + $this->extensions[$extension->name] = $extension; return $this; } /** * @param AuthenticationExtension[] $extensions + * @deprecated since 4.7.0. No replacement. Please use the {self::create} instead. + * @infection-ignore-all */ public function addExtensions(array $extensions): static { foreach ($extensions as $extension) { - $this->addExtension($extension); + $this->extensions[$extension->name] = $extension; } return $this; } - public function setExtensions(AuthenticationExtensionsClientInputs $extensions): static + /** + * @deprecated since 4.7.0. Please use the {self::create} instead. + * @infection-ignore-all + */ + public function setExtensions(AuthenticationExtensions $extensions): static { $this->extensions = $extensions; return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getChallenge(): string { return $this->challenge; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getTimeout(): ?int { return $this->timeout; } - public function getExtensions(): AuthenticationExtensionsClientInputs + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getExtensions(): AuthenticationExtensions { return $this->extensions; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ abstract public static function createFromString(string $data): static; /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ abstract public static function createFromArray(array $json): static; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php index dcc3a54bd..7ea3cea8f 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php @@ -4,15 +4,19 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use const JSON_THROW_ON_ERROR; use JsonSerializable; +use Webauthn\Exception\InvalidDataException; +use function array_key_exists; +use const JSON_THROW_ON_ERROR; class PublicKeyCredentialParameters implements JsonSerializable { + /** + * @private + */ public function __construct( - private readonly string $type, - private readonly int $alg + public readonly string $type, + public readonly int $alg ) { } @@ -21,35 +25,57 @@ class PublicKeyCredentialParameters implements JsonSerializable return new self($type, $alg); } + public static function createPk(int $alg): self + { + return self::create(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $alg); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAlg(): int { return $this->alg; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromString(string $data): self { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $json): self { - Assertion::keyExists($json, 'type', 'Invalid input. "type" is missing.'); - Assertion::string($json['type'], 'Invalid input. "type" is not a string.'); - Assertion::keyExists($json, 'alg', 'Invalid input. "alg" is missing.'); - Assertion::integer($json['alg'], 'Invalid input. "alg" is not an integer.'); + array_key_exists('type', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "type" is missing.' + ); + array_key_exists('alg', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "alg" is missing.' + ); - return new self($json['type'], $json['alg']); + return self::create($json['type'], $json['alg']); } /** @@ -57,6 +83,12 @@ class PublicKeyCredentialParameters implements JsonSerializable */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); return [ 'type' => $this->type, 'alg' => $this->alg, diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php index 612170779..46b6777d5 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php @@ -4,35 +4,77 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use function count; -use const JSON_THROW_ON_ERROR; use ParagonIE\ConstantTime\Base64UrlSafe; +use Webauthn\AuthenticationExtensions\AuthenticationExtensions; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; +use Webauthn\Exception\InvalidDataException; use Webauthn\Util\Base64; +use function array_key_exists; +use function count; +use function in_array; +use const JSON_THROW_ON_ERROR; final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions { + public const USER_VERIFICATION_REQUIREMENT_DEFAULT = null; + public const USER_VERIFICATION_REQUIREMENT_REQUIRED = 'required'; public const USER_VERIFICATION_REQUIREMENT_PREFERRED = 'preferred'; public const USER_VERIFICATION_REQUIREMENT_DISCOURAGED = 'discouraged'; - private ?string $rpId = null; + public const USER_VERIFICATION_REQUIREMENTS = [ + self::USER_VERIFICATION_REQUIREMENT_DEFAULT, + self::USER_VERIFICATION_REQUIREMENT_REQUIRED, + self::USER_VERIFICATION_REQUIREMENT_PREFERRED, + self::USER_VERIFICATION_REQUIREMENT_DISCOURAGED, + ]; /** - * @var PublicKeyCredentialDescriptor[] + * @private + * @param PublicKeyCredentialDescriptor[] $allowCredentials + * @param null|AuthenticationExtensions|array $extensions */ - private array $allowCredentials = []; - - private ?string $userVerification = null; - - public static function create(string $challenge): self - { - return new self($challenge); + public function __construct( + string $challenge, + public null|string $rpId = null, + public array $allowCredentials = [], + public null|string $userVerification = null, + null|int $timeout = null, + null|array|AuthenticationExtensions $extensions = null, + ) { + in_array($userVerification, self::USER_VERIFICATION_REQUIREMENTS, true) || throw InvalidDataException::create( + $userVerification, + 'Invalid user verification requirement' + ); + parent::__construct( + $challenge, + $timeout, + $extensions + ); } + /** + * @param PublicKeyCredentialDescriptor[] $allowCredentials + * @param positive-int $timeout + * @param null|AuthenticationExtensions|array $extensions + */ + public static function create( + string $challenge, + null|string $rpId = null, + array $allowCredentials = [], + null|string $userVerification = null, + null|int $timeout = null, + null|array|AuthenticationExtensions $extensions = null, + ): self { + return new self($challenge, $rpId, $allowCredentials, $userVerification, $timeout, $extensions); + } + + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function setRpId(?string $rpId): self { $this->rpId = $rpId; @@ -40,6 +82,10 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function allowCredential(PublicKeyCredentialDescriptor $allowCredential): self { $this->allowCredentials[] = $allowCredential; @@ -47,15 +93,23 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions return $this; } + /** + * @deprecated since 4.7.0. No replacement. Please use the property directly. + * @infection-ignore-all + */ public function allowCredentials(PublicKeyCredentialDescriptor ...$allowCredentials): self { foreach ($allowCredentials as $allowCredential) { - $this->allowCredential($allowCredential); + $this->allowCredentials[] = $allowCredential; } return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function setUserVerification(?string $userVerification): self { if ($userVerification === null) { @@ -63,16 +117,20 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions return $this; } - Assertion::inArray($userVerification, [ + in_array($userVerification, [ self::USER_VERIFICATION_REQUIREMENT_REQUIRED, self::USER_VERIFICATION_REQUIREMENT_PREFERRED, self::USER_VERIFICATION_REQUIREMENT_DISCOURAGED, - ], 'Invalid user verification requirement'); + ], true) || throw InvalidDataException::create($userVerification, 'Invalid user verification requirement'); $this->userVerification = $userVerification; return $this; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getRpId(): ?string { return $this->rpId; @@ -80,31 +138,45 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions /** * @return PublicKeyCredentialDescriptor[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getAllowCredentials(): array { return $this->allowCredentials; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getUserVerification(): ?string { return $this->userVerification; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromString(string $data): static { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); return self::createFromArray($data); } /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $json): static { - Assertion::keyExists($json, 'challenge', 'Invalid input. "challenge" is missing.'); + array_key_exists('challenge', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "challenge" is missing.' + ); $allowCredentials = []; $allowCredentialList = $json['allowCredentials'] ?? []; @@ -113,18 +185,18 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions } $challenge = Base64::decode($json['challenge']); + $extensions = isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray( + $json['extensions'] + ) : AuthenticationExtensionsClientInputs::create(); - return self::create($challenge) - ->setRpId($json['rpId'] ?? null) - ->allowCredentials(...$allowCredentials) - ->setUserVerification($json['userVerification'] ?? null) - ->setTimeout($json['timeout'] ?? null) - ->setExtensions( - isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray( - $json['extensions'] - ) : new AuthenticationExtensionsClientInputs() - ) - ; + return self::create( + $challenge, + $json['rpId'] ?? null, + $allowCredentials, + $json['userVerification'] ?? null, + $json['timeout'] ?? null, + $extensions + ); } /** @@ -132,6 +204,12 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = [ 'challenge' => Base64UrlSafe::encodeUnpadded($this->challenge), ]; @@ -145,14 +223,11 @@ final class PublicKeyCredentialRequestOptions extends PublicKeyCredentialOptions } if (count($this->allowCredentials) !== 0) { - $json['allowCredentials'] = array_map( - static fn (PublicKeyCredentialDescriptor $object): array => $object->jsonSerialize(), - $this->allowCredentials - ); + $json['allowCredentials'] = $this->allowCredentials; } if ($this->extensions->count() !== 0) { - $json['extensions'] = $this->extensions->jsonSerialize(); + $json['extensions'] = $this->extensions; } if ($this->timeout !== null) { diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php index 1c8f968e6..670daefae 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; +use Webauthn\Exception\InvalidDataException; +use function array_key_exists; class PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity { public function __construct( string $name, - protected ?string $id = null, + public readonly ?string $id = null, ?string $icon = null ) { parent::__construct($name, $icon); @@ -21,6 +22,10 @@ class PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity return new self($name, $id, $icon); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getId(): ?string { return $this->id; @@ -28,12 +33,17 @@ class PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $json): self { - Assertion::keyExists($json, 'name', 'Invalid input. "name" is missing.'); + array_key_exists('name', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "name" is missing.' + ); - return new self($json['name'], $json['id'] ?? null, $json['icon'] ?? null); + return self::create($json['name'], $json['id'] ?? null, $json['icon'] ?? null); } /** @@ -41,6 +51,12 @@ class PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = parent::jsonSerialize(); if ($this->id !== null) { $json['id'] = $this->id; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php index ba456d4db..fe1ab1808 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php @@ -4,16 +4,16 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use InvalidArgumentException; use JsonSerializable; use ParagonIE\ConstantTime\Base64UrlSafe; -use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Uuid; use Throwable; +use Webauthn\Exception\InvalidDataException; use Webauthn\TrustPath\TrustPath; use Webauthn\TrustPath\TrustPathLoader; -use Webauthn\Util\Base64; +use function array_key_exists; +use function in_array; +use function sprintf; /** * @see https://www.w3.org/TR/webauthn/#iface-pkcredential @@ -21,25 +21,29 @@ use Webauthn\Util\Base64; class PublicKeyCredentialSource implements JsonSerializable { /** - * @param string[] $transports + * @private + * @param string[] $transports * @param array|null $otherUI */ public function __construct( - protected string $publicKeyCredentialId, - protected string $type, - protected array $transports, - protected string $attestationType, - protected TrustPath $trustPath, - protected AbstractUid $aaguid, - protected string $credentialPublicKey, - protected string $userHandle, - protected int $counter, - protected ?array $otherUI = null + public string $publicKeyCredentialId, + public string $type, + public array $transports, + public string $attestationType, + public TrustPath $trustPath, + public Uuid $aaguid, + public string $credentialPublicKey, + public string $userHandle, + public int $counter, + public ?array $otherUI = null, + public ?bool $backupEligible = null, + public ?bool $backupStatus = null, + public ?bool $uvInitialized = null, ) { } /** - * @param string[] $transports + * @param string[] $transports * @param array|null $otherUI */ public static function create( @@ -48,11 +52,14 @@ class PublicKeyCredentialSource implements JsonSerializable array $transports, string $attestationType, TrustPath $trustPath, - AbstractUid $aaguid, + Uuid $aaguid, string $credentialPublicKey, string $userHandle, int $counter, - ?array $otherUI = null + ?array $otherUI = null, + ?bool $backupEligible = null, + ?bool $backupStatus = null, + ?bool $uvInitialized = null, ): self { return new self( $publicKeyCredentialId, @@ -64,10 +71,17 @@ class PublicKeyCredentialSource implements JsonSerializable $credentialPublicKey, $userHandle, $counter, - $otherUI + $otherUI, + $backupEligible, + $backupStatus, + $uvInitialized ); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getPublicKeyCredentialId(): string { return $this->publicKeyCredentialId; @@ -75,14 +89,22 @@ class PublicKeyCredentialSource implements JsonSerializable public function getPublicKeyCredentialDescriptor(): PublicKeyCredentialDescriptor { - return new PublicKeyCredentialDescriptor($this->type, $this->publicKeyCredentialId, $this->transports); + return PublicKeyCredentialDescriptor::create($this->type, $this->publicKeyCredentialId, $this->transports); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getAttestationType(): string { return $this->attestationType; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getTrustPath(): TrustPath { return $this->trustPath; @@ -90,9 +112,13 @@ class PublicKeyCredentialSource implements JsonSerializable public function getAttestedCredentialData(): AttestedCredentialData { - return new AttestedCredentialData($this->aaguid, $this->publicKeyCredentialId, $this->credentialPublicKey); + return AttestedCredentialData::create($this->aaguid, $this->publicKeyCredentialId, $this->credentialPublicKey); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getType(): string { return $this->type; @@ -100,32 +126,54 @@ class PublicKeyCredentialSource implements JsonSerializable /** * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getTransports(): array { return $this->transports; } - public function getAaguid(): AbstractUid + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ + public function getAaguid(): Uuid { return $this->aaguid; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getCredentialPublicKey(): string { return $this->credentialPublicKey; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getUserHandle(): string { return $this->userHandle; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getCounter(): int { return $this->counter; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function setCounter(int $counter): void { $this->counter = $counter; @@ -133,6 +181,8 @@ class PublicKeyCredentialSource implements JsonSerializable /** * @return array|null + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getOtherUI(): ?array { @@ -141,6 +191,8 @@ class PublicKeyCredentialSource implements JsonSerializable /** * @param array|null $otherUI + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function setOtherUI(?array $otherUI): self { @@ -151,34 +203,44 @@ class PublicKeyCredentialSource implements JsonSerializable /** * @param mixed[] $data + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $data): self { $keys = array_keys(get_class_vars(self::class)); foreach ($keys as $key) { - if ($key === 'otherUI') { + if (in_array($key, ['otherUI', 'backupEligible', 'backupStatus', 'uvInitialized'], true)) { continue; } - Assertion::keyExists($data, $key, sprintf('The parameter "%s" is missing', $key)); + array_key_exists($key, $data) || throw InvalidDataException::create($data, sprintf( + 'The parameter "%s" is missing', + $key + )); } - Assertion::length($data['aaguid'], 36, 'Invalid AAGUID', null, '8bit'); + mb_strlen((string) $data['aaguid'], '8bit') === 36 || throw InvalidDataException::create( + $data, + 'Invalid AAGUID' + ); $uuid = Uuid::fromString($data['aaguid']); try { - return new self( - Base64::decodeUrlSafe($data['publicKeyCredentialId']), + return self::create( + Base64UrlSafe::decodeNoPadding($data['publicKeyCredentialId']), $data['type'], $data['transports'], $data['attestationType'], TrustPathLoader::loadTrustPath($data['trustPath']), $uuid, - Base64::decodeUrlSafe($data['credentialPublicKey']), - Base64::decodeUrlSafe($data['userHandle']), + Base64UrlSafe::decodeNoPadding($data['credentialPublicKey']), + Base64UrlSafe::decodeNoPadding($data['userHandle']), $data['counter'], - $data['otherUI'] ?? null + $data['otherUI'] ?? null, + $data['backupEligible'] ?? null, + $data['backupStatus'] ?? null, ); } catch (Throwable $throwable) { - throw new InvalidArgumentException('Unable to load the data', $throwable->getCode(), $throwable); + throw InvalidDataException::create($data, 'Unable to load the data', $throwable); } } @@ -187,17 +249,28 @@ class PublicKeyCredentialSource implements JsonSerializable */ public function jsonSerialize(): array { - return [ + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); + $result = [ 'publicKeyCredentialId' => Base64UrlSafe::encodeUnpadded($this->publicKeyCredentialId), 'type' => $this->type, 'transports' => $this->transports, 'attestationType' => $this->attestationType, - 'trustPath' => $this->trustPath->jsonSerialize(), + 'trustPath' => $this->trustPath, 'aaguid' => $this->aaguid->__toString(), 'credentialPublicKey' => Base64UrlSafe::encodeUnpadded($this->credentialPublicKey), 'userHandle' => Base64UrlSafe::encodeUnpadded($this->userHandle), 'counter' => $this->counter, 'otherUI' => $this->otherUI, + 'backupEligible' => $this->backupEligible, + 'backupStatus' => $this->backupStatus, + 'uvInitialized' => $this->uvInitialized, ]; + + return array_filter($result, static fn ($value): bool => $value !== null); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php index 7ab999238..5174a4181 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php @@ -4,6 +4,10 @@ declare(strict_types=1); namespace Webauthn; +/** + * @deprecated + * @infection-ignore-all + */ interface PublicKeyCredentialSourceRepository { public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialUserEntity.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialUserEntity.php index 1aa9f3329..43cdca2eb 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialUserEntity.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialUserEntity.php @@ -4,23 +4,25 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; -use const JSON_THROW_ON_ERROR; use ParagonIE\ConstantTime\Base64; use ParagonIE\ConstantTime\Base64UrlSafe; +use Webauthn\Exception\InvalidDataException; +use function array_key_exists; +use function is_array; +use const JSON_THROW_ON_ERROR; class PublicKeyCredentialUserEntity extends PublicKeyCredentialEntity { - protected string $id; + public readonly string $id; public function __construct( string $name, string $id, - protected string $displayName, + public readonly string $displayName, ?string $icon = null ) { parent::__construct($name, $icon); - Assertion::maxLength($id, 64, 'User ID max length is 64 bytes', 'id', '8bit'); + mb_strlen($id, '8bit') <= 64 || throw InvalidDataException::create($id, 'User ID max length is 64 bytes'); $this->id = $id; } @@ -29,35 +31,55 @@ class PublicKeyCredentialUserEntity extends PublicKeyCredentialEntity return new self($name, $id, $displayName, $icon); } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getId(): string { return $this->id; } + /** + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all + */ public function getDisplayName(): string { return $this->displayName; } + /** + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all + */ public static function createFromString(string $data): self { - $data = json_decode($data, true, 512, JSON_THROW_ON_ERROR); - Assertion::isArray($data, 'Invalid data'); + $data = json_decode($data, true, flags: JSON_THROW_ON_ERROR); + is_array($data) || throw InvalidDataException::create($data, 'Invalid data'); return self::createFromArray($data); } /** * @param mixed[] $json + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $json): self { - Assertion::keyExists($json, 'name', 'Invalid input. "name" is missing.'); - Assertion::keyExists($json, 'id', 'Invalid input. "id" is missing.'); - Assertion::keyExists($json, 'displayName', 'Invalid input. "displayName" is missing.'); + array_key_exists('name', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "name" is missing.' + ); + array_key_exists('id', $json) || throw InvalidDataException::create($json, 'Invalid input. "id" is missing.'); + array_key_exists('displayName', $json) || throw InvalidDataException::create( + $json, + 'Invalid input. "displayName" is missing.' + ); $id = Base64::decode($json['id'], true); - return new self($json['name'], $id, $json['displayName'], $json['icon'] ?? null); + return self::create($json['name'], $id, $json['displayName'], $json['icon'] ?? null); } /** @@ -65,6 +87,12 @@ class PublicKeyCredentialUserEntity extends PublicKeyCredentialEntity */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); $json = parent::jsonSerialize(); $json['id'] = Base64UrlSafe::encodeUnpadded($this->id); $json['displayName'] = $this->displayName; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/SimpleFakeCredentialGenerator.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/SimpleFakeCredentialGenerator.php new file mode 100644 index 000000000..a0c4fb90d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/SimpleFakeCredentialGenerator.php @@ -0,0 +1,67 @@ +cache === null) { + return $this->generateCredentials($username); + } + + $cacheKey = 'fake_credentials_' . hash('xxh128', $username); + $cacheItem = $this->cache->getItem($cacheKey); + if ($cacheItem->isHit()) { + return $cacheItem->get(); + } + + $credentials = $this->generateCredentials($username); + $cacheItem->set($credentials); + $this->cache->save($cacheItem); + + return $credentials; + } + + /** + * @return PublicKeyCredentialDescriptor[] + */ + private function generateCredentials(string $username): array + { + $transports = [ + PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_USB, + PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_NFC, + PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_BLE, + ]; + $credentials = []; + for ($i = 0; $i < random_int(1, 3); $i++) { + $randomTransportKeys = array_rand($transports, random_int(1, count($transports))); + if (is_int($randomTransportKeys)) { + $randomTransportKeys = [$randomTransportKeys]; + } + $randomTransports = array_values(array_intersect_key($transports, array_flip($randomTransportKeys))); + $credentials[] = PublicKeyCredentialDescriptor::create( + PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, + hash('sha256', random_bytes(16) . $username), + $randomTransports + ); + } + + return $credentials; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php index 3d27b41be..44f718515 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace Webauthn; -use Assert\Assertion; use CBOR\Stream; -use function Safe\fclose; -use function Safe\fopen; -use function Safe\fread; -use function Safe\fwrite; -use function Safe\rewind; +use Webauthn\Exception\InvalidDataException; +use function fclose; +use function fopen; +use function fread; +use function fwrite; +use function rewind; +use function sprintf; final class StringStream implements Stream { @@ -39,13 +40,11 @@ final class StringStream implements Stream } $read = fread($this->data, $length); $bytesRead = mb_strlen($read, '8bit'); - Assertion::length( - $read, + mb_strlen($read, '8bit') === $length || throw InvalidDataException::create(null, sprintf( + 'Out of range. Expected: %d, read: %d.', $length, - sprintf('Out of range. Expected: %d, read: %d.', $length, $bytesRead), - null, - '8bit' - ); + $bytesRead + )); $this->totalRead += $bytesRead; return $read; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php index 1953d4632..037fd8c7a 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php @@ -6,6 +6,10 @@ namespace Webauthn\TokenBinding; use Psr\Http\Message\ServerRequestInterface; +/** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ final class IgnoreTokenBindingHandler implements TokenBindingHandler { public static function create(): self diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/SecTokenBindingHandler.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/SecTokenBindingHandler.php index 22c9dce0c..54b6edc95 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/SecTokenBindingHandler.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/SecTokenBindingHandler.php @@ -4,9 +4,14 @@ declare(strict_types=1); namespace Webauthn\TokenBinding; -use Assert\Assertion; use Psr\Http\Message\ServerRequestInterface; +use Webauthn\Exception\InvalidDataException; +use function count; +/** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ final class SecTokenBindingHandler implements TokenBindingHandler { public static function create(): self @@ -20,13 +25,19 @@ final class SecTokenBindingHandler implements TokenBindingHandler return; } - Assertion::true( - $request->hasHeader('Sec-Token-Binding'), + $request->hasHeader('Sec-Token-Binding') || throw InvalidDataException::create( + $tokenBinding, 'The header parameter "Sec-Token-Binding" is missing.' ); $tokenBindingIds = $request->getHeader('Sec-Token-Binding'); - Assertion::count($tokenBindingIds, 1, 'The header parameter "Sec-Token-Binding" is invalid.'); + count($tokenBindingIds) === 1 || throw InvalidDataException::create( + $tokenBinding, + 'The header parameter "Sec-Token-Binding" is invalid.' + ); $tokenBindingId = reset($tokenBindingIds); - Assertion::eq($tokenBindingId, $tokenBinding->getId(), 'The header parameter "Sec-Token-Binding" is invalid.'); + $tokenBindingId === $tokenBinding->getId() || throw InvalidDataException::create( + $tokenBinding, + 'The header parameter "Sec-Token-Binding" is invalid.' + ); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBinding.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBinding.php index c40296e01..26a2cb7b4 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBinding.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBinding.php @@ -4,10 +4,16 @@ declare(strict_types=1); namespace Webauthn\TokenBinding; +use ParagonIE\ConstantTime\Base64UrlSafe; +use Webauthn\Exception\InvalidDataException; use function array_key_exists; -use Assert\Assertion; -use Webauthn\Util\Base64; +use function in_array; +use function sprintf; +/** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ class TokenBinding { final public const TOKEN_BINDING_STATUS_PRESENT = 'present'; @@ -22,8 +28,8 @@ class TokenBinding public function __construct(string $status, ?string $id) { - Assertion::false( - $status === self::TOKEN_BINDING_STATUS_PRESENT && $id === null, + $status === self::TOKEN_BINDING_STATUS_PRESENT && $id === null && throw InvalidDataException::create( + [$status, $id], 'The member "id" is required when status is "present"' ); $this->status = $status; @@ -35,17 +41,16 @@ class TokenBinding */ public static function createFormArray(array $json): self { - Assertion::keyExists($json, 'status', 'The member "status" is required'); - $status = $json['status']; - Assertion::inArray( - $status, - self::getSupportedStatus(), - sprintf( - 'The member "status" is invalid. Supported values are: %s', - implode(', ', self::getSupportedStatus()) - ) + array_key_exists('status', $json) || throw InvalidDataException::create( + $json, + 'The member "status" is required' ); - $id = array_key_exists('id', $json) ? Base64::decodeUrlSafe($json['id']) : null; + $status = $json['status']; + in_array($status, self::getSupportedStatus(), true) || throw InvalidDataException::create($json, sprintf( + 'The member "status" is invalid. Supported values are: %s', + implode(', ', self::getSupportedStatus()) + )); + $id = array_key_exists('id', $json) ? Base64UrlSafe::decodeNoPadding($json['id']) : null; return new self($status, $id); } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php index 0e91afb21..8c907fdff 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php @@ -6,6 +6,10 @@ namespace Webauthn\TokenBinding; use Psr\Http\Message\ServerRequestInterface; +/** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ interface TokenBindingHandler { public function check(TokenBinding $tokenBinding, ServerRequestInterface $request): void; diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingNotSupportedHandler.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingNotSupportedHandler.php index bcc99d041..b2a2c2c11 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingNotSupportedHandler.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingNotSupportedHandler.php @@ -4,9 +4,13 @@ declare(strict_types=1); namespace Webauthn\TokenBinding; -use Assert\Assertion; use Psr\Http\Message\ServerRequestInterface; +use Webauthn\Exception\InvalidDataException; +/** + * @deprecated Since 4.3.0 and will be removed in 5.0.0 + * @infection-ignore-all + */ final class TokenBindingNotSupportedHandler implements TokenBindingHandler { public static function create(): self @@ -16,8 +20,8 @@ final class TokenBindingNotSupportedHandler implements TokenBindingHandler public function check(TokenBinding $tokenBinding, ServerRequestInterface $request): void { - Assertion::true( - $tokenBinding->getStatus() !== TokenBinding::TOKEN_BINDING_STATUS_PRESENT, + $tokenBinding->getStatus() !== TokenBinding::TOKEN_BINDING_STATUS_PRESENT || throw InvalidDataException::create( + $tokenBinding, 'Token binding not supported.' ); } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php index d380b7d71..31d250c2e 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace Webauthn\TrustPath; -use Assert\Assertion; +use Webauthn\Exception\InvalidTrustPathException; +use function array_key_exists; +use function is_array; final class CertificateTrustPath implements TrustPath { @@ -12,7 +14,7 @@ final class CertificateTrustPath implements TrustPath * @param string[] $certificates */ public function __construct( - private readonly array $certificates + public readonly array $certificates ) { } @@ -26,6 +28,8 @@ final class CertificateTrustPath implements TrustPath /** * @return string[] + * @deprecated since 4.7.0. Please use the property directly. + * @infection-ignore-all */ public function getCertificates(): array { @@ -33,13 +37,18 @@ final class CertificateTrustPath implements TrustPath } /** - * {@inheritdoc} + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $data): static { - Assertion::keyExists($data, 'x5c', 'The trust path type is invalid'); + array_key_exists('x5c', $data) || throw InvalidTrustPathException::create('The trust path type is invalid'); + $x5c = $data['x5c']; + is_array($x5c) || throw InvalidTrustPathException::create( + 'The trust path type is invalid. The parameter "x5c" shall contain strings.' + ); - return new self($data['x5c']); + return self::create($x5c); } /** @@ -47,6 +56,12 @@ final class CertificateTrustPath implements TrustPath */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); return [ 'type' => self::class, 'x5c' => $this->certificates, diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php index 41c5e51a4..d0aa7ffa1 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php @@ -4,8 +4,13 @@ declare(strict_types=1); namespace Webauthn\TrustPath; -use Assert\Assertion; +use Webauthn\Exception\InvalidTrustPathException; +use function array_key_exists; +/** + * @deprecated since 4.2.0 and will be removed in 5.0.0. The ECDAA Trust Anchor does no longer exist in Webauthn specification. + * @infection-ignore-all + */ final class EcdaaKeyIdTrustPath implements TrustPath { public function __construct( @@ -29,12 +34,11 @@ final class EcdaaKeyIdTrustPath implements TrustPath ]; } - /** - * {@inheritdoc} - */ public static function createFromArray(array $data): static { - Assertion::keyExists($data, 'ecdaaKeyId', 'The trust path type is invalid'); + array_key_exists('ecdaaKeyId', $data) || throw InvalidTrustPathException::create( + 'The trust path type is invalid' + ); return new self($data['ecdaaKeyId']); } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php index d48ac7b0e..e1acb0aba 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php @@ -16,16 +16,23 @@ final class EmptyTrustPath implements TrustPath */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. Please use the serializer instead.', + __METHOD__ + ); return [ 'type' => self::class, ]; } /** - * {@inheritdoc} + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $data): static { - return new self(); + return self::create(); } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php index fe2124d97..f28097e0c 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php @@ -10,6 +10,8 @@ interface TrustPath extends JsonSerializable { /** * @param array $data + * @deprecated since 4.8.0. Please use {Webauthn\Denormalizer\WebauthnSerializerFactory} for converting the object. + * @infection-ignore-all */ public static function createFromArray(array $data): static; } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPathLoader.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPathLoader.php index b93ba7fb9..017f55252 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPathLoader.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPathLoader.php @@ -4,28 +4,30 @@ declare(strict_types=1); namespace Webauthn\TrustPath; -use Assert\Assertion; -use function in_array; -use InvalidArgumentException; -use function Safe\class_implements; +use Webauthn\Exception\InvalidTrustPathException; +use function array_key_exists; +use function is_array; +use function is_string; -abstract class TrustPathLoader +/** + * @deprecated since 4.9.0 and will be removed in 5.0.0. Use the serializer instead + */ +final class TrustPathLoader { /** * @param mixed[] $data */ public static function loadTrustPath(array $data): TrustPath { - Assertion::keyExists($data, 'type', 'The trust path type is missing'); - $type = $data['type']; - if (class_exists($type) !== true) { - throw new InvalidArgumentException(sprintf('The trust path type "%s" is not supported', $data['type'])); - } - - $implements = class_implements($type); - if (in_array(TrustPath::class, $implements, true)) { - return $type::createFromArray($data); - } - throw new InvalidArgumentException(sprintf('The trust path type "%s" is not supported', $data['type'])); + return match (true) { + $data === [] || $data === [ + 'type' => EmptyTrustPath::class, + ] => EmptyTrustPath::create(), + array_key_exists('x5c', $data) && is_array($data['x5c']) => CertificateTrustPath::create($data['x5c']), + array_key_exists('ecdaaKeyId', $data) && is_string($data['ecdaaKeyId']) => new EcdaaKeyIdTrustPath( + $data['ecdaaKeyId'] + ), + default => throw InvalidTrustPathException::create('Unsupported trust path'), + }; } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/U2FPublicKey.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/U2FPublicKey.php index 88175331a..bbd85c2b8 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/U2FPublicKey.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/U2FPublicKey.php @@ -12,11 +12,20 @@ use CBOR\UnsignedIntegerObject; use Cose\Algorithms; use Cose\Key\Ec2Key; -class U2FPublicKey +/** + * @internal + */ +final class U2FPublicKey { + private const U2F_KEY_PREFIX = "\x04"; + + private const U2F_KEY_LENGTH = 65; + + private const U2F_KEY_PART_SIZE = 32; + public static function isU2FKey(string $publicKey): bool { - return $publicKey[0] === "\x04" && mb_strlen($publicKey, '8bit') === 65; + return $publicKey[0] === self::U2F_KEY_PREFIX && mb_strlen($publicKey, '8bit') === self::U2F_KEY_LENGTH; } public static function convertToCoseKey(string $publicKey): string @@ -36,11 +45,11 @@ class U2FPublicKey ), MapItem::create( NegativeIntegerObject::create(Ec2Key::DATA_X), - ByteStringObject::create(mb_substr($publicKey, 1, 32, '8bit')) + ByteStringObject::create(mb_substr($publicKey, 1, self::U2F_KEY_PART_SIZE, '8bit')) ), MapItem::create( NegativeIntegerObject::create(Ec2Key::DATA_Y), - ByteStringObject::create(mb_substr($publicKey, 33, null, '8bit')) + ByteStringObject::create(mb_substr($publicKey, 1 + self::U2F_KEY_PART_SIZE, null, '8bit')) ), ])->__toString(); } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/Base64.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/Base64.php index eb1170f9a..71bcaf366 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/Base64.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/Base64.php @@ -4,20 +4,12 @@ declare(strict_types=1); namespace Webauthn\Util; -use Assert\Assertion; -use InvalidArgumentException; use ParagonIE\ConstantTime\Base64UrlSafe; use Throwable; +use Webauthn\Exception\InvalidDataException; abstract class Base64 { - public static function decodeUrlSafe(string $data): string - { - Assertion::regex($data, '/([A-Z][a-z][0-9]\-_)*/', 'Invalid Base 64 Url Safe character'); - - return Base64UrlSafe::decode($data); - } - public static function decode(string $data): string { try { @@ -26,9 +18,9 @@ abstract class Base64 } try { - return \ParagonIE\ConstantTime\Base64::decode($data, true); + return \ParagonIE\ConstantTime\Base64::decode($data); } catch (Throwable $e) { - throw new InvalidArgumentException('Invalid data submitted', 0, $e); + throw InvalidDataException::create($data, 'Invalid data submitted', $e); } } } diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php index 7992a4d36..e7ed1ebbd 100644 --- a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php @@ -21,31 +21,37 @@ use Cose\Algorithm\Signature\Signature; */ abstract class CoseSignatureFixer { + private const ES256_SIGNATURE_LENGTH = 64; + + private const ES384_SIGNATURE_LENGTH = 96; + + private const ES512_SIGNATURE_LENGTH = 132; + public static function fix(string $signature, Signature $algorithm): string { switch ($algorithm::identifier()) { case ES256K::ID: case ES256::ID: - if (mb_strlen($signature, '8bit') === 64) { + if (mb_strlen($signature, '8bit') === self::ES256_SIGNATURE_LENGTH) { return $signature; } return ECSignature::fromAsn1( $signature, - 64 + self::ES256_SIGNATURE_LENGTH ); //TODO: fix this hardcoded value by adding a dedicated method for the algorithms case ES384::ID: - if (mb_strlen($signature, '8bit') === 96) { + if (mb_strlen($signature, '8bit') === self::ES384_SIGNATURE_LENGTH) { return $signature; } - return ECSignature::fromAsn1($signature, 96); + return ECSignature::fromAsn1($signature, self::ES384_SIGNATURE_LENGTH); case ES512::ID: - if (mb_strlen($signature, '8bit') === 132) { + if (mb_strlen($signature, '8bit') === self::ES512_SIGNATURE_LENGTH) { return $signature; } - return ECSignature::fromAsn1($signature, 132); + return ECSignature::fromAsn1($signature, self::ES512_SIGNATURE_LENGTH); } return $signature; diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-checker/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/AlgorithmChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/AlgorithmChecker.php deleted file mode 100644 index cdd4adfc5..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/AlgorithmChecker.php +++ /dev/null @@ -1,68 +0,0 @@ -supportedAlgorithms = $supportedAlgorithms; - $this->protectedHeader = $protectedHeader; - } - - /** - * {@inheritdoc} - */ - public function checkHeader($value): void - { - if (!is_string($value)) { - throw new InvalidHeaderException('"alg" must be a string.', self::HEADER_NAME, $value); - } - if (!in_array($value, $this->supportedAlgorithms, true)) { - throw new InvalidHeaderException('Unsupported algorithm.', self::HEADER_NAME, $value); - } - } - - public function supportedHeader(): string - { - return self::HEADER_NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeader; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/AudienceChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/AudienceChecker.php deleted file mode 100644 index bcdea131e..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/AudienceChecker.php +++ /dev/null @@ -1,93 +0,0 @@ -audience = $audience; - $this->protectedHeader = $protectedHeader; - } - - /** - * {@inheritdoc} - */ - public function checkClaim($value): void - { - $this->checkValue($value, InvalidClaimException::class); - } - - /** - * {@inheritdoc} - */ - public function checkHeader($value): void - { - $this->checkValue($value, InvalidHeaderException::class); - } - - public function supportedClaim(): string - { - return self::CLAIM_NAME; - } - - public function supportedHeader(): string - { - return self::CLAIM_NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeader; - } - - /** - * @param mixed $value - * - * @throws InvalidClaimException if the claim is invalid - * @throws InvalidHeaderException if the header is invalid - */ - private function checkValue($value, string $class): void - { - if (is_string($value) && $value !== $this->audience) { - throw new $class('Bad audience.', self::CLAIM_NAME, $value); - } - if (is_array($value) && !in_array($this->audience, $value, true)) { - throw new $class('Bad audience.', self::CLAIM_NAME, $value); - } - if (!is_array($value) && !is_string($value)) { - throw new $class('Bad audience.', self::CLAIM_NAME, $value); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimChecker.php deleted file mode 100644 index 5de777e07..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimChecker.php +++ /dev/null @@ -1,32 +0,0 @@ -add($checker); - } - } - - /** - * This method returns all checkers handled by this manager. - * - * @return ClaimChecker[] - */ - public function getCheckers(): array - { - return $this->checkers; - } - - /** - * This method checks all the claims passed as argument. - * All claims are checked against the claim checkers. - * If one fails, the InvalidClaimException is thrown. - * - * This method returns an array with all checked claims. - * It is up to the implementor to decide use the claims that have not been checked. - * - * @param string[] $mandatoryClaims - * - * @throws InvalidClaimException - * @throws MissingMandatoryClaimException - */ - public function check(array $claims, array $mandatoryClaims = []): array - { - $this->checkMandatoryClaims($mandatoryClaims, $claims); - $checkedClaims = []; - foreach ($this->checkers as $claim => $checker) { - if (array_key_exists($claim, $claims)) { - $checker->checkClaim($claims[$claim]); - $checkedClaims[$claim] = $claims[$claim]; - } - } - - return $checkedClaims; - } - - private function add(ClaimChecker $checker): void - { - $claim = $checker->supportedClaim(); - $this->checkers[$claim] = $checker; - } - - /** - * @param string[] $mandatoryClaims - * - * @throws MissingMandatoryClaimException - */ - private function checkMandatoryClaims(array $mandatoryClaims, array $claims): void - { - if (0 === count($mandatoryClaims)) { - return; - } - $diff = array_keys(array_diff_key(array_flip($mandatoryClaims), $claims)); - if (0 !== count($diff)) { - throw new MissingMandatoryClaimException(sprintf('The following claims are mandatory: %s.', implode(', ', $diff)), $diff); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimCheckerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimCheckerManagerFactory.php deleted file mode 100644 index 192b34245..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimCheckerManagerFactory.php +++ /dev/null @@ -1,71 +0,0 @@ -checkers[$alias])) { - throw new InvalidArgumentException(sprintf('The claim checker with the alias "%s" is not supported.', $alias)); - } - $checkers[] = $this->checkers[$alias]; - } - - return new ClaimCheckerManager($checkers); - } - - /** - * This method adds a claim checker to this factory. - */ - public function add(string $alias, ClaimChecker $checker): void - { - $this->checkers[$alias] = $checker; - } - - /** - * Returns all claim checker aliases supported by this factory. - * - * @return string[] - */ - public function aliases(): array - { - return array_keys($this->checkers); - } - - /** - * Returns all claim checkers supported by this factory. - * - * @return ClaimChecker[] - */ - public function all(): array - { - return $this->checkers; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimExceptionInterface.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimExceptionInterface.php deleted file mode 100644 index 5ffb5ee48..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/ClaimExceptionInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -allowedTimeDrift = $allowedTimeDrift; - $this->protectedHeaderOnly = $protectedHeaderOnly; - } - - /** - * {@inheritdoc} - * - * @throws InvalidClaimException if the claim "exp" is not valid - */ - public function checkClaim($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidClaimException('"exp" must be an integer.', self::NAME, $value); - } - if (time() > $value + $this->allowedTimeDrift) { - throw new InvalidClaimException('The token expired.', self::NAME, $value); - } - } - - public function supportedClaim(): string - { - return self::NAME; - } - - /** - * @param mixed $value - * - * @throws InvalidHeaderException if the claim "exp" is not valid - */ - public function checkHeader($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidHeaderException('"exp" must be an integer.', self::NAME, $value); - } - if (time() > $value + $this->allowedTimeDrift) { - throw new InvalidHeaderException('The token expired.', self::NAME, $value); - } - } - - public function supportedHeader(): string - { - return self::NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeaderOnly; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderChecker.php deleted file mode 100644 index 03c1c6978..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderChecker.php +++ /dev/null @@ -1,37 +0,0 @@ -add($checker); - } - foreach ($tokenTypes as $tokenType) { - $this->addTokenTypeSupport($tokenType); - } - } - - /** - * This method returns all checkers handled by this manager. - * - * @return HeaderChecker[] - */ - public function getCheckers(): array - { - return $this->checkers; - } - - /** - * This method checks all the header parameters passed as argument. - * All header parameters are checked against the header parameter checkers. - * If one fails, the InvalidHeaderException is thrown. - * - * @param string[] $mandatoryHeaderParameters - * - * @throws InvalidArgumentException if the token format is not valid - */ - public function check(JWT $jwt, int $index, array $mandatoryHeaderParameters = []): void - { - foreach ($this->tokenTypes as $tokenType) { - if ($tokenType->supports($jwt)) { - $protected = []; - $unprotected = []; - $tokenType->retrieveTokenHeaders($jwt, $index, $protected, $unprotected); - $this->checkDuplicatedHeaderParameters($protected, $unprotected); - $this->checkMandatoryHeaderParameters($mandatoryHeaderParameters, $protected, $unprotected); - $this->checkHeaders($protected, $unprotected); - - return; - } - } - - throw new InvalidArgumentException('Unsupported token type.'); - } - - private function addTokenTypeSupport(TokenTypeSupport $tokenType): void - { - $this->tokenTypes[] = $tokenType; - } - - private function add(HeaderChecker $checker): void - { - $header = $checker->supportedHeader(); - $this->checkers[$header] = $checker; - } - - /** - * @throws InvalidArgumentException if the header contains duplicated entries - */ - private function checkDuplicatedHeaderParameters(array $header1, array $header2): void - { - $inter = array_intersect_key($header1, $header2); - if (0 !== count($inter)) { - throw new InvalidArgumentException(sprintf('The header contains duplicated entries: %s.', implode(', ', array_keys($inter)))); - } - } - - /** - * @param string[] $mandatoryHeaderParameters - * - * @throws MissingMandatoryHeaderParameterException if a mandatory header parameter is missing - */ - private function checkMandatoryHeaderParameters(array $mandatoryHeaderParameters, array $protected, array $unprotected): void - { - if (0 === count($mandatoryHeaderParameters)) { - return; - } - $diff = array_keys(array_diff_key(array_flip($mandatoryHeaderParameters), array_merge($protected, $unprotected))); - if (0 !== count($diff)) { - throw new MissingMandatoryHeaderParameterException(sprintf('The following header parameters are mandatory: %s.', implode(', ', $diff)), $diff); - } - } - - /** - * @throws InvalidHeaderException if a protected header parameter is not in the protected header - */ - private function checkHeaders(array $protected, array $header): void - { - $checkedHeaderParameters = []; - foreach ($this->checkers as $headerParameter => $checker) { - if ($checker->protectedHeaderOnly()) { - if (array_key_exists($headerParameter, $protected)) { - $checker->checkHeader($protected[$headerParameter]); - $checkedHeaderParameters[] = $headerParameter; - } elseif (array_key_exists($headerParameter, $header)) { - throw new InvalidHeaderException(sprintf('The header parameter "%s" must be protected.', $headerParameter), $headerParameter, $header[$headerParameter]); - } - } else { - if (array_key_exists($headerParameter, $protected)) { - $checker->checkHeader($protected[$headerParameter]); - $checkedHeaderParameters[] = $headerParameter; - } elseif (array_key_exists($headerParameter, $header)) { - $checker->checkHeader($header[$headerParameter]); - $checkedHeaderParameters[] = $headerParameter; - } - } - } - $this->checkCriticalHeader($protected, $header, $checkedHeaderParameters); - } - - /** - * @throws InvalidHeaderException if the "crit" parameter is not valid or if a critical header parameter cannot be verified - */ - private function checkCriticalHeader(array $protected, array $header, array $checkedHeaderParameters): void - { - if (array_key_exists('crit', $protected)) { - if (!is_array($protected['crit'])) { - throw new InvalidHeaderException('The header "crit" must be a list of header parameters.', 'crit', $protected['crit']); - } - $diff = array_diff($protected['crit'], $checkedHeaderParameters); - if (0 !== count($diff)) { - throw new InvalidHeaderException(sprintf('One or more header parameters are marked as critical, but they are missing or have not been checked: %s.', implode(', ', array_values($diff))), 'crit', $protected['crit']); - } - } elseif (array_key_exists('crit', $header)) { - throw new InvalidHeaderException('The header parameter "crit" must be protected.', 'crit', $header['crit']); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderCheckerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderCheckerManagerFactory.php deleted file mode 100644 index 860580b84..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/HeaderCheckerManagerFactory.php +++ /dev/null @@ -1,88 +0,0 @@ -checkers[$alias])) { - throw new InvalidArgumentException(sprintf('The header checker with the alias "%s" is not supported.', $alias)); - } - $checkers[] = $this->checkers[$alias]; - } - - return new HeaderCheckerManager($checkers, $this->tokenTypes); - } - - /** - * This method adds a header parameter checker to this factory. - * The checker is uniquely identified by an alias. This allows the same header parameter checker to be added twice (or more) - * using several configuration options. - */ - public function add(string $alias, HeaderChecker $checker): void - { - $this->checkers[$alias] = $checker; - } - - /** - * This method adds a token type support to this factory. - */ - public function addTokenTypeSupport(TokenTypeSupport $tokenType): void - { - $this->tokenTypes[] = $tokenType; - } - - /** - * Returns all header parameter checker aliases supported by this factory. - * - * @return string[] - */ - public function aliases(): array - { - return array_keys($this->checkers); - } - - /** - * Returns all header parameter checkers supported by this factory. - * - * @return HeaderChecker[] - */ - public function all(): array - { - return $this->checkers; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidClaimException.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidClaimException.php deleted file mode 100644 index b834843fc..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidClaimException.php +++ /dev/null @@ -1,61 +0,0 @@ -claim = $claim; - $this->value = $value; - } - - /** - * Returns the claim that caused the exception. - */ - public function getClaim(): string - { - return $this->claim; - } - - /** - * Returns the claim value that caused the exception. - * - * @return mixed - */ - public function getValue() - { - return $this->value; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidHeaderException.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidHeaderException.php deleted file mode 100644 index 50d1e9d3f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/InvalidHeaderException.php +++ /dev/null @@ -1,61 +0,0 @@ -header = $header; - $this->value = $value; - } - - /** - * Returns the header parameter that caused the exception. - */ - public function getHeader(): string - { - return $this->header; - } - - /** - * Returns the header parameter value that caused the exception. - * - * @return mixed - */ - public function getValue() - { - return $this->value; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuedAtChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuedAtChecker.php deleted file mode 100644 index d005957b4..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuedAtChecker.php +++ /dev/null @@ -1,86 +0,0 @@ -allowedTimeDrift = $allowedTimeDrift; - $this->protectedHeaderOnly = $protectedHeaderOnly; - } - - /** - * {@inheritdoc} - * - * @throws InvalidClaimException if the claim is invalid - */ - public function checkClaim($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidClaimException('"iat" must be an integer.', self::NAME, $value); - } - if (time() < $value - $this->allowedTimeDrift) { - throw new InvalidClaimException('The JWT is issued in the future.', self::NAME, $value); - } - } - - public function supportedClaim(): string - { - return self::NAME; - } - - /** - * @param mixed $value - * - * @throws InvalidHeaderException if the header parameter is invalid - */ - public function checkHeader($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidHeaderException('The header "iat" must be an integer.', self::NAME, $value); - } - if (time() < $value - $this->allowedTimeDrift) { - throw new InvalidHeaderException('The JWT is issued in the future.', self::NAME, $value); - } - } - - public function supportedHeader(): string - { - return self::NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeaderOnly; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuerChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuerChecker.php deleted file mode 100644 index 614767701..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/IssuerChecker.php +++ /dev/null @@ -1,93 +0,0 @@ -issuers = $issuer; - $this->protectedHeader = $protectedHeader; - } - - /** - * @param mixed $value - * - * @throws InvalidClaimException if the claim is invalid - */ - public function checkClaim($value): void - { - $this->checkValue($value, InvalidClaimException::class); - } - - /** - * @param mixed $value - * - * @throws InvalidHeaderException if the header parameter is invalid - */ - public function checkHeader($value): void - { - $this->checkValue($value, InvalidHeaderException::class); - } - - public function supportedClaim(): string - { - return self::CLAIM_NAME; - } - - public function supportedHeader(): string - { - return self::CLAIM_NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeader; - } - - /** - * @param mixed $value - * - * @throws InvalidClaimException if the claim is invalid - * @throws InvalidHeaderException if the header parameter is invalid - */ - private function checkValue($value, string $class): void - { - if (!is_string($value)) { - throw new $class('Invalid value.', self::CLAIM_NAME, $value); - } - if (!in_array($value, $this->issuers, true)) { - throw new $class('Unknown issuer.', self::CLAIM_NAME, $value); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-checker/LICENSE index 37cf976b1..5ab750604 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/LICENSE +++ b/lam/lib/3rdParty/composer/web-token/jwt-checker/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2019 Spomky-Labs +Copyright (c) 2014-2024 Spomky-Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryClaimException.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryClaimException.php deleted file mode 100644 index 275f92980..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryClaimException.php +++ /dev/null @@ -1,44 +0,0 @@ -claims = $claims; - } - - /** - * @return string[] - */ - public function getClaims(): array - { - return $this->claims; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryHeaderParameterException.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryHeaderParameterException.php deleted file mode 100644 index 97479b26f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/MissingMandatoryHeaderParameterException.php +++ /dev/null @@ -1,44 +0,0 @@ -parameters = $parameters; - } - - /** - * @return string[] - */ - public function getParameters(): array - { - return $this->parameters; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/NotBeforeChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/NotBeforeChecker.php deleted file mode 100644 index 9a9e3b00d..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/NotBeforeChecker.php +++ /dev/null @@ -1,88 +0,0 @@ -allowedTimeDrift = $allowedTimeDrift; - $this->protectedHeaderOnly = $protectedHeaderOnly; - } - - /** - * {@inheritdoc} - * - * @throws InvalidClaimException if the claim "nbf" is not an integer - * @throws InvalidClaimException if the claim "nbf" restrict the use of the token - */ - public function checkClaim($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidClaimException('"nbf" must be an integer.', self::NAME, $value); - } - if (time() < $value - $this->allowedTimeDrift) { - throw new InvalidClaimException('The JWT can not be used yet.', self::NAME, $value); - } - } - - public function supportedClaim(): string - { - return self::NAME; - } - - /** - * @param mixed $value - * - * @throws InvalidHeaderException if the claim "nbf" is not an integer - * @throws InvalidHeaderException if the claim "nbf" restrict the use of the token - */ - public function checkHeader($value): void - { - if (!is_float($value) && !is_int($value)) { - throw new InvalidHeaderException('"nbf" must be an integer.', self::NAME, $value); - } - if (time() < $value - $this->allowedTimeDrift) { - throw new InvalidHeaderException('The JWT can not be used yet.', self::NAME, $value); - } - } - - public function supportedHeader(): string - { - return self::NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeaderOnly; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/README.md b/lam/lib/3rdParty/composer/web-token/jwt-checker/README.md index 7d0a0158d..d5578e4ac 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/README.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-checker/README.md @@ -1,14 +1,15 @@ PHP JWT Checker Component ========================= -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. **Please do not submit any Pull Request here.** You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. # Documentation -The official documentation is available as https://web-token.spomky-labs.com/ +The official documentation is available as https://web-token.spomky-labs.com/ # Licence diff --git a/lam/lib/3rdParty/composer/web-token/jwt-checker/TokenTypeSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-checker/TokenTypeSupport.php deleted file mode 100644 index 14062fd51..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-checker/TokenTypeSupport.php +++ /dev/null @@ -1,32 +0,0 @@ -=8.1", + "psr/clock": "^1.0", + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-core/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Algorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Algorithm.php deleted file mode 100644 index 87e445bb6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Algorithm.php +++ /dev/null @@ -1,29 +0,0 @@ -algorithms[$alias] = $algorithm; - } - - /** - * Returns the list of aliases. - * - * @return string[] - */ - public function aliases(): array - { - return array_keys($this->algorithms); - } - - /** - * Returns all algorithms supported by this factory. - * This is an associative array. Keys are the aliases of the algorithms. - * - * @return Algorithm[] - */ - public function all(): array - { - return $this->algorithms; - } - - /** - * Create an algorithm manager using the given aliases. - * - * @param string[] $aliases - * - * @throws InvalidArgumentException if the alias is invalid or is not supported - */ - public function create(array $aliases): AlgorithmManager - { - $algorithms = []; - foreach ($aliases as $alias) { - if (!is_string($alias)) { - throw new InvalidArgumentException('Invalid alias'); - } - if (!isset($this->algorithms[$alias])) { - throw new InvalidArgumentException(sprintf('The algorithm with the alias "%s" is not supported.', $alias)); - } - $algorithms[] = $this->algorithms[$alias]; - } - - return new AlgorithmManager($algorithms); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/JWK.php b/lam/lib/3rdParty/composer/web-token/jwt-core/JWK.php deleted file mode 100644 index b029cd59a..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/JWK.php +++ /dev/null @@ -1,146 +0,0 @@ -values = $values; - } - - /** - * Creates a JWK object using the given Json string. - * - * @throws InvalidArgumentException if the data is not valid - * - * @return JWK - */ - public static function createFromJson(string $json): self - { - $data = json_decode($json, true); - if (!is_array($data)) { - throw new InvalidArgumentException('Invalid argument.'); - } - - return new self($data); - } - - /** - * Returns the values to be serialized. - */ - public function jsonSerialize(): array - { - return $this->values; - } - - /** - * Get the value with a specific key. - * - * @param string $key The key - * - * @throws InvalidArgumentException if the key does not exist - * - * @return null|mixed - */ - public function get(string $key) - { - if (!$this->has($key)) { - throw new InvalidArgumentException(sprintf('The value identified by "%s" does not exist.', $key)); - } - - return $this->values[$key]; - } - - /** - * Returns true if the JWK has the value identified by. - * - * @param string $key The key - */ - public function has(string $key): bool - { - return array_key_exists($key, $this->values); - } - - /** - * Get all values stored in the JWK object. - * - * @return array Values of the JWK object - */ - public function all(): array - { - return $this->values; - } - - /** - * Returns the thumbprint of the key. - * - * @see https://tools.ietf.org/html/rfc7638 - * - * @throws InvalidArgumentException if the hashing function is not supported - */ - public function thumbprint(string $hash_algorithm): string - { - if (!in_array($hash_algorithm, hash_algos(), true)) { - throw new InvalidArgumentException(sprintf('The hash algorithm "%s" is not supported.', $hash_algorithm)); - } - $values = array_intersect_key($this->values, array_flip(['kty', 'n', 'e', 'crv', 'x', 'y', 'k'])); - ksort($values); - $input = json_encode($values, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - if (false === $input) { - throw new InvalidArgumentException('Unable to compute the key thumbprint'); - } - - return Base64Url::encode(hash($hash_algorithm, $input, true)); - } - - /** - * Returns the associated public key. - * This method has no effect for: - * - public keys - * - shared keys - * - unknown keys. - * - * Known keys are "oct", "RSA", "EC" and "OKP". - * - * @return JWK - */ - public function toPublic(): self - { - $values = array_diff_key($this->values, array_flip(['p', 'd', 'q', 'dp', 'dq', 'qi'])); - - return new self($values); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/JWKSet.php b/lam/lib/3rdParty/composer/web-token/jwt-core/JWKSet.php deleted file mode 100644 index c72cea230..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/JWKSet.php +++ /dev/null @@ -1,340 +0,0 @@ - $key) { - if (!$key instanceof JWK) { - throw new InvalidArgumentException('Invalid list. Should only contains JWK objects'); - } - - if ($key->has('kid')) { - unset($keys[$k]); - $this->keys[$key->get('kid')] = $key; - } else { - $this->keys[] = $key; - } - } - } - - /** - * Creates a JWKSet object using the given values. - * - * @throws InvalidArgumentException if the keyset is not valid - * - * @return JWKSet - */ - public static function createFromKeyData(array $data): self - { - if (!isset($data['keys'])) { - throw new InvalidArgumentException('Invalid data.'); - } - if (!is_array($data['keys'])) { - throw new InvalidArgumentException('Invalid data.'); - } - - $jwkset = new self([]); - foreach ($data['keys'] as $key) { - $jwk = new JWK($key); - if ($jwk->has('kid')) { - $jwkset->keys[$jwk->get('kid')] = $jwk; - } else { - $jwkset->keys[] = $jwk; - } - } - - return $jwkset; - } - - /** - * Creates a JWKSet object using the given Json string. - * - * @throws InvalidArgumentException if the data is not valid - * - * @return JWKSet - */ - public static function createFromJson(string $json): self - { - $data = json_decode($json, true); - if (!is_array($data)) { - throw new InvalidArgumentException('Invalid argument.'); - } - - return self::createFromKeyData($data); - } - - /** - * Returns an array of keys stored in the key set. - * - * @return JWK[] - */ - public function all(): array - { - return $this->keys; - } - - /** - * Add key to store in the key set. - * This method is immutable and will return a new object. - * - * @return JWKSet - */ - public function with(JWK $jwk): self - { - $clone = clone $this; - - if ($jwk->has('kid')) { - $clone->keys[$jwk->get('kid')] = $jwk; - } else { - $clone->keys[] = $jwk; - } - - return $clone; - } - - /** - * Remove key from the key set. - * This method is immutable and will return a new object. - * - * @param int|string $key Key to remove from the key set - * - * @return JWKSet - */ - public function without($key): self - { - if (!$this->has($key)) { - return $this; - } - - $clone = clone $this; - unset($clone->keys[$key]); - - return $clone; - } - - /** - * Returns true if the key set contains a key with the given index. - * - * @param int|string $index - */ - public function has($index): bool - { - return array_key_exists($index, $this->keys); - } - - /** - * Returns the key with the given index. Throws an exception if the index is not present in the key store. - * - * @param int|string $index - * - * @throws InvalidArgumentException if the index is not defined - */ - public function get($index): JWK - { - if (!$this->has($index)) { - throw new InvalidArgumentException('Undefined index.'); - } - - return $this->keys[$index]; - } - - /** - * Returns the values to be serialized. - */ - public function jsonSerialize(): array - { - return ['keys' => array_values($this->keys)]; - } - - /** - * Returns the number of keys in the key set. - * - * @param int $mode - */ - public function count($mode = COUNT_NORMAL): int - { - return count($this->keys, $mode); - } - - /** - * Try to find a key that fits on the selected requirements. - * Returns null if not found. - * - * @param string $type Must be 'sig' (signature) or 'enc' (encryption) - * @param null|Algorithm $algorithm Specifies the algorithm to be used - * @param array $restrictions More restrictions such as 'kid' or 'kty' - * - * @throws InvalidArgumentException if the key type is not valid (must be "sig" or "enc") - */ - public function selectKey(string $type, ?Algorithm $algorithm = null, array $restrictions = []): ?JWK - { - if (!in_array($type, ['enc', 'sig'], true)) { - throw new InvalidArgumentException('Allowed key types are "sig" or "enc".'); - } - - $result = []; - foreach ($this->keys as $key) { - $ind = 0; - - $can_use = $this->canKeyBeUsedFor($type, $key); - if (false === $can_use) { - continue; - } - $ind += $can_use; - - $alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key); - if (false === $alg) { - continue; - } - $ind += $alg; - - if (false === $this->doesKeySatisfyRestrictions($restrictions, $key)) { - continue; - } - - $result[] = ['key' => $key, 'ind' => $ind]; - } - - if (0 === count($result)) { - return null; - } - - usort($result, [$this, 'sortKeys']); - - return $result[0]['key']; - } - - /** - * Internal method only. Should not be used. - * - * @internal - * @internal - */ - public static function sortKeys(array $a, array $b): int - { - if ($a['ind'] === $b['ind']) { - return 0; - } - - return ($a['ind'] > $b['ind']) ? -1 : 1; - } - - /** - * Internal method only. Should not be used. - * - * @internal - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->keys); - } - - /** - * @throws InvalidArgumentException if the key does not fulfill with the "key_ops" constraint - * - * @return bool|int - */ - private function canKeyBeUsedFor(string $type, JWK $key) - { - if ($key->has('use')) { - return $type === $key->get('use') ? 1 : false; - } - if ($key->has('key_ops')) { - $key_ops = $key->get('key_ops'); - if (!is_array($key_ops)) { - throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations'); - } - - return $type === self::convertKeyOpsToKeyUse($key_ops) ? 1 : false; - } - - return 0; - } - - /** - * @return bool|int - */ - private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key) - { - if (null === $algorithm) { - return 0; - } - if (!in_array($key->get('kty'), $algorithm->allowedKeyTypes(), true)) { - return false; - } - if ($key->has('alg')) { - return $algorithm->name() === $key->get('alg') ? 2 : false; - } - - return 1; - } - - private function doesKeySatisfyRestrictions(array $restrictions, JWK $key): bool - { - foreach ($restrictions as $k => $v) { - if (!$key->has($k) || $v !== $key->get($k)) { - return false; - } - } - - return true; - } - - /** - * @throws InvalidArgumentException if the key operation is not supported - */ - private static function convertKeyOpsToKeyUse(array $key_ops): string - { - switch (true) { - case in_array('verify', $key_ops, true): - case in_array('sign', $key_ops, true): - return 'sig'; - - case in_array('encrypt', $key_ops, true): - case in_array('decrypt', $key_ops, true): - case in_array('wrapKey', $key_ops, true): - case in_array('unwrapKey', $key_ops, true): - case in_array('deriveKey', $key_ops, true): - case in_array('deriveBits', $key_ops, true): - return 'enc'; - - default: - throw new InvalidArgumentException(sprintf('Unsupported key operation value "%s"', implode(', ', $key_ops))); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/JWT.php b/lam/lib/3rdParty/composer/web-token/jwt-core/JWT.php deleted file mode 100644 index d3a6065f3..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/JWT.php +++ /dev/null @@ -1,23 +0,0 @@ -value = $value; - } - - /** - * @return BigInteger - */ - public static function createFromBinaryString(string $value): self - { - $res = unpack('H*', $value); - if (false === $res) { - throw new InvalidArgumentException('Unable to convert the value'); - } - $data = current($res); - - return new self(BrickBigInteger::fromBase($data, 16)); - } - - /** - * @return BigInteger - */ - public static function createFromDecimal(int $value): self - { - return new self(BrickBigInteger::of($value)); - } - - /** - * @return BigInteger - */ - public static function createFromBigInteger(BrickBigInteger $value): self - { - return new self($value); - } - - /** - * Converts a BigInteger to a binary string. - */ - public function toBytes(): string - { - if ($this->value->isEqualTo(BrickBigInteger::zero())) { - return ''; - } - - $temp = $this->value->toBase(16); - $temp = 0 !== (mb_strlen($temp, '8bit') & 1) ? '0'.$temp : $temp; - $temp = hex2bin($temp); - if (false === $temp) { - throw new InvalidArgumentException('Unable to convert the value into bytes'); - } - - return ltrim($temp, chr(0)); - } - - /** - * Adds two BigIntegers. - * - * @param BigInteger $y - * - * @return BigInteger - */ - public function add(self $y): self - { - $value = $this->value->plus($y->value); - - return new self($value); - } - - /** - * Subtracts two BigIntegers. - * - * @param BigInteger $y - * - * @return BigInteger - */ - public function subtract(self $y): self - { - $value = $this->value->minus($y->value); - - return new self($value); - } - - /** - * Multiplies two BigIntegers. - * - * @param BigInteger $x - * - * @return BigInteger - */ - public function multiply(self $x): self - { - $value = $this->value->multipliedBy($x->value); - - return new self($value); - } - - /** - * Divides two BigIntegers. - * - * @param BigInteger $x - * - * @return BigInteger - */ - public function divide(self $x): self - { - $value = $this->value->dividedBy($x->value); - - return new self($value); - } - - /** - * Performs modular exponentiation. - * - * @param BigInteger $e - * @param BigInteger $n - * - * @return BigInteger - */ - public function modPow(self $e, self $n): self - { - $value = $this->value->modPow($e->value, $n->value); - - return new self($value); - } - - /** - * Performs modular exponentiation. - * - * @param BigInteger $d - * - * @return BigInteger - */ - public function mod(self $d): self - { - $value = $this->value->mod($d->value); - - return new self($value); - } - - public function modInverse(BigInteger $m): BigInteger - { - return new self($this->value->modInverse($m->value)); - } - - /** - * Compares two numbers. - * - * @param BigInteger $y - */ - public function compare(self $y): int - { - return $this->value->compareTo($y->value); - } - - /** - * @param BigInteger $y - */ - public function equals(self $y): bool - { - return $this->value->isEqualTo($y->value); - } - - /** - * @param BigInteger $y - * - * @return BigInteger - */ - public static function random(self $y): self - { - return new self(BrickBigInteger::randomRange(0, $y->value)); - } - - /** - * @param BigInteger $y - * - * @return BigInteger - */ - public function gcd(self $y): self - { - return new self($this->value->gcd($y->value)); - } - - /** - * @param BigInteger $y - */ - public function lowerThan(self $y): bool - { - return $this->value->isLessThan($y->value); - } - - public function isEven(): bool - { - return $this->value->isEven(); - } - - public function get(): BrickBigInteger - { - return $this->value; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECKey.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECKey.php deleted file mode 100644 index 3e05827ab..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECKey.php +++ /dev/null @@ -1,366 +0,0 @@ -has('d')) { - return self::convertPrivateKeyToPEM($jwk); - } - - return self::convertPublicKeyToPEM($jwk); - } - - /** - * @throws InvalidArgumentException if the curve is not supported - */ - public static function convertPublicKeyToPEM(JWK $jwk): string - { - switch ($jwk->get('crv')) { - case 'P-256': - $der = self::p256PublicKey(); - - break; - - case 'secp256k1': - $der = self::p256KPublicKey(); - - break; - - case 'P-384': - $der = self::p384PublicKey(); - - break; - - case 'P-521': - $der = self::p521PublicKey(); - - break; - - default: - throw new InvalidArgumentException('Unsupported curve.'); - } - $der .= self::getKey($jwk); - $pem = '-----BEGIN PUBLIC KEY-----'.PHP_EOL; - $pem .= chunk_split(base64_encode($der), 64, PHP_EOL); - $pem .= '-----END PUBLIC KEY-----'.PHP_EOL; - - return $pem; - } - - /** - * @throws InvalidArgumentException if the curve is not supported - */ - public static function convertPrivateKeyToPEM(JWK $jwk): string - { - switch ($jwk->get('crv')) { - case 'P-256': - $der = self::p256PrivateKey($jwk); - - break; - - case 'secp256k1': - $der = self::p256KPrivateKey($jwk); - - break; - - case 'P-384': - $der = self::p384PrivateKey($jwk); - - break; - - case 'P-521': - $der = self::p521PrivateKey($jwk); - - break; - - default: - throw new InvalidArgumentException('Unsupported curve.'); - } - $der .= self::getKey($jwk); - $pem = '-----BEGIN EC PRIVATE KEY-----'.PHP_EOL; - $pem .= chunk_split(base64_encode($der), 64, PHP_EOL); - $pem .= '-----END EC PRIVATE KEY-----'.PHP_EOL; - - return $pem; - } - - /** - * Creates a EC key with the given curve and additional values. - * - * @param string $curve The curve - * @param array $values values to configure the key - */ - public static function createECKey(string $curve, array $values = []): JWK - { - $jwk = self::createECKeyUsingOpenSSL($curve); - $values = array_merge($values, $jwk); - - return new JWK($values); - } - - /** - * @throws InvalidArgumentException if the curve is not supported - */ - private static function getNistCurveSize(string $curve): int - { - switch ($curve) { - case 'P-256': - case 'secp256k1': - return 256; - - case 'P-384': - return 384; - - case 'P-521': - return 521; - - default: - throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)); - } - } - - /** - * @throws RuntimeException if the extension OpenSSL is not available - * @throws RuntimeException if the key cannot be created - */ - private static function createECKeyUsingOpenSSL(string $curve): array - { - if (!extension_loaded('openssl')) { - throw new RuntimeException('Please install the OpenSSL extension'); - } - $key = openssl_pkey_new([ - 'curve_name' => self::getOpensslCurveName($curve), - 'private_key_type' => OPENSSL_KEYTYPE_EC, - ]); - if (false === $key) { - throw new RuntimeException('Unable to create the key'); - } - $result = openssl_pkey_export($key, $out); - if (false === $result) { - throw new RuntimeException('Unable to create the key'); - } - $res = openssl_pkey_get_private($out); - if (false === $res) { - throw new RuntimeException('Unable to create the key'); - } - $details = openssl_pkey_get_details($res); - if (false === $details) { - throw new InvalidArgumentException('Unable to get the key details'); - } - $nistCurveSize = self::getNistCurveSize($curve); - - return [ - 'kty' => 'EC', - 'crv' => $curve, - 'd' => Base64Url::encode(str_pad($details['ec']['d'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), - 'x' => Base64Url::encode(str_pad($details['ec']['x'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), - 'y' => Base64Url::encode(str_pad($details['ec']['y'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), - ]; - } - - /** - * @throws InvalidArgumentException if the curve is not supported - */ - private static function getOpensslCurveName(string $curve): string - { - switch ($curve) { - case 'P-256': - return 'prime256v1'; - - case 'secp256k1': - return 'secp256k1'; - - case 'P-384': - return 'secp384r1'; - - case 'P-521': - return 'secp521r1'; - - default: - throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)); - } - } - - private static function p256PublicKey(): string - { - return pack( - 'H*', - '3059' // SEQUENCE, length 89 - .'3013' // SEQUENCE, length 19 - .'0607' // OID, length 7 - .'2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key - .'0608' // OID, length 8 - .'2a8648ce3d030107' // 1.2.840.10045.3.1.7 = P-256 Curve - .'0342' // BIT STRING, length 66 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p256KPublicKey(): string - { - return pack( - 'H*', - '3056' // SEQUENCE, length 86 - .'3010' // SEQUENCE, length 16 - .'0607' // OID, length 7 - .'2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key - .'0605' // OID, length 8 - .'2B8104000A' // 1.3.132.0.10 secp256k1 - .'0342' // BIT STRING, length 66 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p384PublicKey(): string - { - return pack( - 'H*', - '3076' // SEQUENCE, length 118 - .'3010' // SEQUENCE, length 16 - .'0607' // OID, length 7 - .'2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key - .'0605' // OID, length 5 - .'2b81040022' // 1.3.132.0.34 = P-384 Curve - .'0362' // BIT STRING, length 98 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p521PublicKey(): string - { - return pack( - 'H*', - '30819b' // SEQUENCE, length 154 - .'3010' // SEQUENCE, length 16 - .'0607' // OID, length 7 - .'2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key - .'0605' // OID, length 5 - .'2b81040023' // 1.3.132.0.35 = P-521 Curve - .'038186' // BIT STRING, length 134 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p256PrivateKey(JWK $jwk): string - { - $d = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 32, "\0", STR_PAD_LEFT)); - if (!is_array($d) || !isset($d[1])) { - throw new InvalidArgumentException('Unable to get the private key'); - } - - return pack( - 'H*', - '3077' // SEQUENCE, length 87+length($d)=32 - .'020101' // INTEGER, 1 - .'0420' // OCTET STRING, length($d) = 32 - .$d[1] - .'a00a' // TAGGED OBJECT #0, length 10 - .'0608' // OID, length 8 - .'2a8648ce3d030107' // 1.3.132.0.34 = P-256 Curve - .'a144' // TAGGED OBJECT #1, length 68 - .'0342' // BIT STRING, length 66 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p256KPrivateKey(JWK $jwk): string - { - $d = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 32, "\0", STR_PAD_LEFT)); - if (!is_array($d) || !isset($d[1])) { - throw new InvalidArgumentException('Unable to get the private key'); - } - - return pack( - 'H*', - '3074' // SEQUENCE, length 84+length($d)=32 - .'020101' // INTEGER, 1 - .'0420' // OCTET STRING, length($d) = 32 - .$d[1] - .'a007' // TAGGED OBJECT #0, length 7 - .'0605' // OID, length 5 - .'2b8104000a' // 1.3.132.0.10 secp256k1 - .'a144' // TAGGED OBJECT #1, length 68 - .'0342' // BIT STRING, length 66 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p384PrivateKey(JWK $jwk): string - { - $d = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 48, "\0", STR_PAD_LEFT)); - if (!is_array($d) || !isset($d[1])) { - throw new InvalidArgumentException('Unable to get the private key'); - } - - return pack( - 'H*', - '3081a4' // SEQUENCE, length 116 + length($d)=48 - .'020101' // INTEGER, 1 - .'0430' // OCTET STRING, length($d) = 30 - .$d[1] - .'a007' // TAGGED OBJECT #0, length 7 - .'0605' // OID, length 5 - .'2b81040022' // 1.3.132.0.34 = P-384 Curve - .'a164' // TAGGED OBJECT #1, length 100 - .'0362' // BIT STRING, length 98 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function p521PrivateKey(JWK $jwk): string - { - $d = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 66, "\0", STR_PAD_LEFT)); - if (!is_array($d) || !isset($d[1])) { - throw new InvalidArgumentException('Unable to get the private key'); - } - - return pack( - 'H*', - '3081dc' // SEQUENCE, length 154 + length($d)=66 - .'020101' // INTEGER, 1 - .'0442' // OCTET STRING, length(d) = 66 - .$d[1] - .'a007' // TAGGED OBJECT #0, length 7 - .'0605' // OID, length 5 - .'2b81040023' // 1.3.132.0.35 = P-521 Curve - .'a18189' // TAGGED OBJECT #1, length 137 - .'038186' // BIT STRING, length 134 - .'00' // prepend with NUL - pubkey will follow - ); - } - - private static function getKey(JWK $jwk): string - { - $nistCurveSize = self::getNistCurveSize($jwk->get('crv')); - $length = (int) ceil($nistCurveSize / 8); - - return - "\04" - .str_pad(Base64Url::decode($jwk->get('x')), $length, "\0", STR_PAD_LEFT) - .str_pad(Base64Url::decode($jwk->get('y')), $length, "\0", STR_PAD_LEFT); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECSignature.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECSignature.php deleted file mode 100644 index 763d8cd00..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/ECSignature.php +++ /dev/null @@ -1,143 +0,0 @@ - self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : ''; - - $bin = hex2bin( - self::ASN1_SEQUENCE - .$lengthPrefix.dechex($totalLength) - .self::ASN1_INTEGER.dechex($lengthR).$pointR - .self::ASN1_INTEGER.dechex($lengthS).$pointS - ); - if (!is_string($bin)) { - throw new InvalidArgumentException('Unable to parse the data'); - } - - return $bin; - } - - /** - * @throws InvalidArgumentException if the signature is not an ASN.1 sequence - */ - public static function fromAsn1(string $signature, int $length): string - { - $message = bin2hex($signature); - $position = 0; - - if (self::ASN1_SEQUENCE !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) { - throw new InvalidArgumentException('Invalid data. Should start with a sequence.'); - } - - if (self::ASN1_LENGTH_2BYTES === self::readAsn1Content($message, $position, self::BYTE_SIZE)) { - $position += self::BYTE_SIZE; - } - - $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); - $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); - - $bin = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT).str_pad($pointS, $length, '0', STR_PAD_LEFT)); - if (!is_string($bin)) { - throw new InvalidArgumentException('Unable to parse the data'); - } - - return $bin; - } - - private static function octetLength(string $data): int - { - return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE); - } - - private static function preparePositiveInteger(string $data): string - { - if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) { - return self::ASN1_NEGATIVE_INTEGER.$data; - } - - while (0 === mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') - && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) { - $data = mb_substr($data, 2, null, '8bit'); - } - - return $data; - } - - private static function readAsn1Content(string $message, int &$position, int $length): string - { - $content = mb_substr($message, $position, $length, '8bit'); - $position += $length; - - return $content; - } - - /** - * @throws InvalidArgumentException if the data is not an integer - */ - private static function readAsn1Integer(string $message, int &$position): string - { - if (self::ASN1_INTEGER !== self::readAsn1Content($message, $position, self::BYTE_SIZE)) { - throw new InvalidArgumentException('Invalid data. Should contain an integer.'); - } - - $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE)); - - return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE); - } - - private static function retrievePositiveInteger(string $data): string - { - while (0 === mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') - && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) { - $data = mb_substr($data, 2, null, '8bit'); - } - - return $data; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/Hash.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/Hash.php deleted file mode 100644 index ef038c53c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/Hash.php +++ /dev/null @@ -1,103 +0,0 @@ -hash = $hash; - $this->length = $length; - $this->t = $t; - } - - /** - * @return Hash - */ - public static function sha1(): self - { - return new self('sha1', 20, "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14"); - } - - /** - * @return Hash - */ - public static function sha256(): self - { - return new self('sha256', 32, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"); - } - - /** - * @return Hash - */ - public static function sha384(): self - { - return new self('sha384', 48, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30"); - } - - /** - * @return Hash - */ - public static function sha512(): self - { - return new self('sha512', 64, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40"); - } - - public function getLength(): int - { - return $this->length; - } - - /** - * Compute the HMAC. - */ - public function hash(string $text): string - { - return hash($this->hash, $text, true); - } - - public function name(): string - { - return $this->hash; - } - - public function t(): string - { - return $this->t; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/JsonConverter.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/JsonConverter.php deleted file mode 100644 index 259083d73..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/JsonConverter.php +++ /dev/null @@ -1,55 +0,0 @@ -getCode(), $throwable); - } - } - - /** - * @throws RuntimeException if the payload cannot be decoded - * - * @return mixed - */ - public static function decode(string $payload) - { - try { - return json_decode($payload, true, 512, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - } catch (Throwable $throwable) { - throw new RuntimeException('Invalid content.', $throwable->getCode(), $throwable); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/KeyChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/KeyChecker.php deleted file mode 100644 index 30ae84bcb..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/KeyChecker.php +++ /dev/null @@ -1,121 +0,0 @@ -has('use')) { - self::checkUsage($key, $usage); - } - if ($key->has('key_ops')) { - self::checkOperation($key, $usage); - } - } - - /** - * @throws InvalidArgumentException if the key is not suitable for the selected algorithm - */ - public static function checkKeyAlgorithm(JWK $key, string $algorithm): void - { - if (!$key->has('alg')) { - return; - } - if ($key->get('alg') !== $algorithm) { - throw new InvalidArgumentException(sprintf('Key is only allowed for algorithm "%s".', $key->get('alg'))); - } - } - - /** - * @throws InvalidArgumentException if the key is not suitable for the selected operation - */ - private static function checkOperation(JWK $key, string $usage): void - { - $ops = $key->get('key_ops'); - if (!is_array($ops)) { - throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations'); - } - - switch ($usage) { - case 'verification': - if (!in_array('verify', $ops, true)) { - throw new InvalidArgumentException('Key cannot be used to verify a signature'); - } - - break; - - case 'signature': - if (!in_array('sign', $ops, true)) { - throw new InvalidArgumentException('Key cannot be used to sign'); - } - - break; - - case 'encryption': - if (!in_array('encrypt', $ops, true) && !in_array('wrapKey', $ops, true) && !in_array('deriveKey', $ops, true)) { - throw new InvalidArgumentException('Key cannot be used to encrypt'); - } - - break; - - case 'decryption': - if (!in_array('decrypt', $ops, true) && !in_array('unwrapKey', $ops, true) && !in_array('deriveBits', $ops, true)) { - throw new InvalidArgumentException('Key cannot be used to decrypt'); - } - - break; - - default: - throw new InvalidArgumentException('Unsupported key usage.'); - } - } - - /** - * @throws InvalidArgumentException if the key is not suitable for the selected operation - */ - private static function checkUsage(JWK $key, string $usage): void - { - $use = $key->get('use'); - - switch ($usage) { - case 'verification': - case 'signature': - if ('sig' !== $use) { - throw new InvalidArgumentException('Key cannot be used to sign or verify a signature.'); - } - - break; - - case 'encryption': - case 'decryption': - if ('enc' !== $use) { - throw new InvalidArgumentException('Key cannot be used to encrypt or decrypt.'); - } - - break; - - default: - throw new InvalidArgumentException('Unsupported key usage.'); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/RSAKey.php b/lam/lib/3rdParty/composer/web-token/jwt-core/Util/RSAKey.php deleted file mode 100644 index 843ba4c39..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/Util/RSAKey.php +++ /dev/null @@ -1,315 +0,0 @@ -values = $data->all(); - $this->populateBigIntegers(); - $this->private = array_key_exists('d', $this->values); - } - - /** - * @return RSAKey - */ - public static function createFromJWK(JWK $jwk): self - { - return new self($jwk); - } - - public function getModulus(): BigInteger - { - return $this->modulus; - } - - public function getModulusLength(): int - { - return $this->modulus_length; - } - - public function getExponent(): BigInteger - { - $d = $this->getPrivateExponent(); - if (null !== $d) { - return $d; - } - - return $this->getPublicExponent(); - } - - public function getPublicExponent(): BigInteger - { - return $this->public_exponent; - } - - public function getPrivateExponent(): ?BigInteger - { - return $this->private_exponent; - } - - /** - * @return BigInteger[] - */ - public function getPrimes(): array - { - return $this->primes; - } - - /** - * @return BigInteger[] - */ - public function getExponents(): array - { - return $this->exponents; - } - - public function getCoefficient(): ?BigInteger - { - return $this->coefficient; - } - - public function isPublic(): bool - { - return !array_key_exists('d', $this->values); - } - - /** - * @param RSAKey $private - * - * @return RSAKey - */ - public static function toPublic(self $private): self - { - $data = $private->toArray(); - $keys = ['p', 'd', 'q', 'dp', 'dq', 'qi']; - foreach ($keys as $key) { - if (array_key_exists($key, $data)) { - unset($data[$key]); - } - } - - return new self(new JWK($data)); - } - - public function toArray(): array - { - return $this->values; - } - - public function toPEM(): string - { - if (null === $this->sequence) { - $this->sequence = new Sequence(); - if (array_key_exists('d', $this->values)) { - $this->initPrivateKey(); - } else { - $this->initPublicKey(); - } - } - $result = '-----BEGIN '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL; - $result .= chunk_split(base64_encode($this->sequence->getBinary()), 64, PHP_EOL); - $result .= '-----END '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL; - - return $result; - } - - /** - * Exponentiate with or without Chinese Remainder Theorem. - * Operation with primes 'p' and 'q' is appox. 2x faster. - * - * @param RSAKey $key - * - * @throws RuntimeException if the exponentiation cannot be achieved - */ - public static function exponentiate(self $key, BigInteger $c): BigInteger - { - if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) { - throw new RuntimeException(); - } - if ($key->isPublic() || null === $key->getCoefficient() || 0 === count($key->getPrimes()) || 0 === count($key->getExponents())) { - return $c->modPow($key->getExponent(), $key->getModulus()); - } - - $p = $key->getPrimes()[0]; - $q = $key->getPrimes()[1]; - $dP = $key->getExponents()[0]; - $dQ = $key->getExponents()[1]; - $qInv = $key->getCoefficient(); - - $m1 = $c->modPow($dP, $p); - $m2 = $c->modPow($dQ, $q); - $h = $qInv->multiply($m1->subtract($m2)->add($p))->mod($p); - - return $m2->add($h->multiply($q)); - } - - private function populateBigIntegers(): void - { - $this->modulus = $this->convertBase64StringToBigInteger($this->values['n']); - $this->modulus_length = mb_strlen($this->getModulus()->toBytes(), '8bit'); - $this->public_exponent = $this->convertBase64StringToBigInteger($this->values['e']); - - if (!$this->isPublic()) { - $this->private_exponent = $this->convertBase64StringToBigInteger($this->values['d']); - - if (array_key_exists('p', $this->values) && array_key_exists('q', $this->values)) { - $this->primes = [ - $this->convertBase64StringToBigInteger($this->values['p']), - $this->convertBase64StringToBigInteger($this->values['q']), - ]; - if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists('qi', $this->values)) { - $this->exponents = [ - $this->convertBase64StringToBigInteger($this->values['dp']), - $this->convertBase64StringToBigInteger($this->values['dq']), - ]; - $this->coefficient = $this->convertBase64StringToBigInteger($this->values['qi']); - } - } - } - } - - private function convertBase64StringToBigInteger(string $value): BigInteger - { - return BigInteger::createFromBinaryString(Base64Url::decode($value)); - } - - private function initPublicKey(): void - { - $oid_sequence = new Sequence(); - $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1')); - $oid_sequence->addChild(new NullObject()); - $this->sequence->addChild($oid_sequence); - $n = new Integer($this->fromBase64ToInteger($this->values['n'])); - $e = new Integer($this->fromBase64ToInteger($this->values['e'])); - $key_sequence = new Sequence(); - $key_sequence->addChild($n); - $key_sequence->addChild($e); - $key_bit_string = new BitString(bin2hex($key_sequence->getBinary())); - $this->sequence->addChild($key_bit_string); - } - - private function initPrivateKey(): void - { - $this->sequence->addChild(new Integer(0)); - $oid_sequence = new Sequence(); - $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1')); - $oid_sequence->addChild(new NullObject()); - $this->sequence->addChild($oid_sequence); - $v = new Integer(0); - $n = new Integer($this->fromBase64ToInteger($this->values['n'])); - $e = new Integer($this->fromBase64ToInteger($this->values['e'])); - $d = new Integer($this->fromBase64ToInteger($this->values['d'])); - $p = new Integer($this->fromBase64ToInteger($this->values['p'])); - $q = new Integer($this->fromBase64ToInteger($this->values['q'])); - $dp = array_key_exists('dp', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dp'])) : new Integer(0); - $dq = array_key_exists('dq', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dq'])) : new Integer(0); - $qi = array_key_exists('qi', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['qi'])) : new Integer(0); - $key_sequence = new Sequence(); - $key_sequence->addChild($v); - $key_sequence->addChild($n); - $key_sequence->addChild($e); - $key_sequence->addChild($d); - $key_sequence->addChild($p); - $key_sequence->addChild($q); - $key_sequence->addChild($dp); - $key_sequence->addChild($dq); - $key_sequence->addChild($qi); - $key_octet_string = new OctetString(bin2hex($key_sequence->getBinary())); - $this->sequence->addChild($key_octet_string); - } - - /** - * @param string $value - * - * @return string - */ - private function fromBase64ToInteger($value) - { - $unpacked = unpack('H*', Base64Url::decode($value)); - if (!is_array($unpacked) || 0 === count($unpacked)) { - throw new InvalidArgumentException('Unable to get the private key'); - } - - return \Brick\Math\BigInteger::fromBase(current($unpacked), 16)->toBase(10); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-core/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-core/composer.json index 30bf70faa..2e4732e27 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-core/composer.json +++ b/lam/lib/3rdParty/composer/web-token/jwt-core/composer.json @@ -1,33 +1,44 @@ { "name": "web-token/jwt-core", - "description": "Core component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "type": "library", "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], "homepage": "https://github.com/web-token", "authors": [ { "name": "Florent Morselli", "homepage": "https://github.com/Spomky" - },{ + }, + { "name": "All contributors", "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "autoload": { - "psr-4": { - "Jose\\Component\\Core\\": "" - } - }, "require": { - "php": ">=7.2", + "php": ">=8.1", "ext-json": "*", "ext-mbstring": "*", - "brick/math": "^0.8.17|^0.9", - "fgrosse/phpasn1": "^2.0", - "spomky-labs/base64url": "^1.0|^2.0" - }, - "conflict": { - "spomky-labs/jose": "*" + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "spomky-labs/pki-framework": "^1.2.1", + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/CONTRIBUTING.md deleted file mode 100644 index fc360e5d8..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/CONTRIBUTING.md +++ /dev/null @@ -1,4 +0,0 @@ -# Contributing - -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. -Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/FUNDING.yml deleted file mode 100644 index 7e2ca0e7e..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractBuilder.php deleted file mode 100644 index 94d962af9..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractBuilder.php +++ /dev/null @@ -1,160 +0,0 @@ -jwt = new JWT(); - $this->algorithms = (new AlgorithmProvider($this->getAlgorithmMap())) - ->getAvailableAlgorithms() - ; - } - - public function payload(array $payload): self - { - $clone = clone $this; - $clone->jwt->claims->replace($payload); - - return $clone; - } - - public function iss(string $iss, bool $inHeader = false): self - { - return $this->claim('iss', $iss, $inHeader); - } - - public function sub(string $sub, bool $inHeader = false): self - { - return $this->claim('sub', $sub, $inHeader); - } - - public function aud(string $aud, bool $inHeader = false): self - { - $audience = $this->jwt->claims->has('aud') ? $this->jwt->claims->get('aud') : []; - $audience[] = $aud; - - return $this->claim('aud', $audience, $inHeader); - } - - public function jti(string $jti, bool $inHeader = false): self - { - return $this->claim('jti', $jti, $inHeader); - } - - public function exp(int $exp, bool $inHeader = false): self - { - return $this->claim('exp', $exp, $inHeader); - } - - public function iat(?int $iat = null, bool $inHeader = false): self - { - $iat = $iat ?? time(); - - return $this->claim('iat', $iat, $inHeader); - } - - public function nbf(?int $nbf = null, bool $inHeader = false): self - { - $nbf = $nbf ?? time(); - - return $this->claim('nbf', $nbf, $inHeader); - } - - /** - * @param Algorithm\SignatureAlgorithm|string $alg - * - * @throws InvalidArgumentException if the algorithm is not a string or an instance of Jose\Component\Core\Algorithm - */ - public function alg($alg): self - { - $clone = clone $this; - - switch (true) { - case $alg instanceof JoseAlgorithm: - $clone->algorithms[] = $alg; - $clone->jwt->header->set('alg', $alg->name()); - - break; - - case is_string($alg): - $clone->jwt->header->set('alg', $alg); - - break; - - default: - throw new InvalidArgumentException('Invalid parameter "alg". Shall be a string or an algorithm instance.'); - } - - return $clone; - } - - public function cty(string $cty): self - { - return $this->header('cty', $cty); - } - - public function typ(string $typ): self - { - return $this->header('typ', $typ); - } - - public function crit(array $crit): self - { - return $this->header('crit', $crit); - } - - /** - * @param mixed $value - */ - public function claim(string $key, $value, bool $inHeader = false): self - { - $clone = clone $this; - $clone->jwt->claims->set($key, $value); - if ($inHeader) { - $clone->jwt->header->set($key, $value); - } - - return $clone; - } - - /** - * @param mixed $value - */ - public function header(string $key, $value): self - { - $clone = clone $this; - $clone->jwt->header->set($key, $value); - - return $clone; - } - - abstract protected function getAlgorithmMap(): array; -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractLoader.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractLoader.php deleted file mode 100644 index 7e041c05c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/AbstractLoader.php +++ /dev/null @@ -1,296 +0,0 @@ -token = $token; - $this->jwkset = new JWKSet([]); - $this->claimCheckers = []; - - $this->algorithms = (new AlgorithmProvider($this->getAlgorithmMap())) - ->getAvailableAlgorithms() - ; - } - - /** - * @param string[] $mandatoryClaims - */ - public function mandatory(array $mandatoryClaims): self - { - $clone = clone $this; - $clone->mandatoryClaims = $mandatoryClaims; - - return $clone; - } - - public function aud(string $aud, bool $inHeader = false): self - { - return $this->claim('aud', new Checker\AudienceChecker($aud, true), $inHeader); - } - - public function iss(string $iss, bool $inHeader = false): self - { - return $this->claim('iss', new Checker\IssuerChecker([$iss], true), $inHeader); - } - - public function jti(string $jti, bool $inHeader = false): self - { - return $this->claim('jti', $jti, $inHeader); - } - - public function sub(string $sub, bool $inHeader = false): self - { - return $this->claim('sub', $sub, $inHeader); - } - - /** - * @param null|array|callable|Checker\ClaimChecker|mixed $checker - */ - public function claim(string $key, $checker, bool $inHeader = false): self - { - $clone = clone $this; - if (false === $checker) { - unset($clone->claimCheckers[$key]); - - return $clone; - } - - switch (true) { - case $checker instanceof Checker\ClaimChecker: - break; - - case is_callable($checker): - $checker = new CallableChecker($key, $checker); - - break; - - case is_array($checker): - $checker = new CallableChecker($key, static function ($value) use ($checker): bool {return in_array($value, $checker, true); }); - - break; - - default: - $checker = new CallableChecker($key, static function ($value) use ($checker): bool {return $value === $checker; }); - } - - $clone->claimCheckers[$key] = $checker; - if ($inHeader) { - return $clone->header($key, $checker); - } - - return $clone; - } - - /** - * @param false|int $leeway - * - * @throws InvalidArgumentException if the leeway is negative, not an integer or not false - */ - public function exp($leeway = 0, bool $inHeader = false): self - { - if (false === $leeway) { - $clone = clone $this; - unset($clone->claimCheckers['exp']); - - return $clone; - } - if (!is_int($leeway) or $leeway < 0) { - throw new InvalidArgumentException('First parameter for "exp" claim is invalid. Set false to disable or a positive integer.'); - } - - return $this->claim('exp', new Checker\ExpirationTimeChecker($leeway), $inHeader); - } - - /** - * @param false|int $leeway - * - * @throws InvalidArgumentException if the leeway is negative, not an integer or not false - */ - public function nbf($leeway = 0, bool $inHeader = false): self - { - if (false === $leeway) { - $clone = clone $this; - unset($clone->claimCheckers['nbf']); - - return $clone; - } - if (!is_int($leeway) or $leeway < 0) { - throw new InvalidArgumentException('First parameter for "nbf" claim is invalid. Set false to disable or a positive integer.'); - } - - return $this->claim('nbf', new Checker\NotBeforeChecker($leeway, true), $inHeader); - } - - /** - * @param false|int $leeway - * - * @throws InvalidArgumentException if the leeway is negative, not an integer or not false - */ - public function iat($leeway = 0, bool $inHeader = false): self - { - if (false === $leeway) { - $clone = clone $this; - unset($clone->claimCheckers['iat']); - - return $clone; - } - if (!is_int($leeway) or $leeway < 0) { - throw new InvalidArgumentException('First parameter for "iat" claim is invalid. Set false to disable or a positive integer.'); - } - - return $this->claim('iat', new Checker\IssuedAtChecker($leeway, true), $inHeader); - } - - /** - * @param Algorithm|string $alg - * - * @throws InvalidArgumentException if the algorithm is not a string or an instance of Jose\Component\Core\Algorithm - */ - public function alg($alg): self - { - $clone = clone $this; - - switch (true) { - case is_string($alg): - $clone->allowedAlgorithms[] = $alg; - - return $clone; - - case $alg instanceof Algorithm: - $clone->algorithms[$alg->name()] = $alg; - $clone->allowedAlgorithms[] = $alg->name(); - - return $clone; - - default: - throw new InvalidArgumentException('Invalid parameter "alg". Shall be a string or an algorithm instance.'); - } - } - - /** - * @param Algorithm[]|string[] $algs - */ - public function algs($algs): self - { - $clone = clone $this; - foreach ($algs as $alg) { - $clone = $clone->alg($alg); - } - - return $clone; - } - - /** - * @param array|callable|Checker\HeaderChecker|false|mixed $checker - */ - public function header(string $key, $checker): self - { - $clone = clone $this; - if (false === $checker) { - unset($clone->headerCheckers[$key]); - - return $clone; - } - - switch (true) { - case $checker instanceof Checker\HeaderChecker: - break; - - case is_callable($checker): - $checker = new CallableChecker($key, $checker); - - break; - - case is_array($checker): - $checker = new CallableChecker($key, static function ($value) use ($checker): bool {return in_array($value, $checker, true); }); - - break; - - default: - $checker = new CallableChecker($key, static function ($value) use ($checker): bool {return $value === $checker; }); - } - - $clone->headerCheckers[$key] = $checker; - - return $clone; - } - - public function key(JWK $jwk): self - { - $clone = clone $this; - $jwkset = $this->jwkset->with($jwk); - $clone->jwkset = $jwkset; - - return $clone; - } - - public function keyset(JWKSet $jwkset): self - { - $clone = clone $this; - $clone->jwkset = $jwkset; - - return $clone; - } - - abstract protected function getAlgorithmMap(): array; -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/AlgorithmProvider.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/AlgorithmProvider.php deleted file mode 100644 index 3509a7eb0..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/AlgorithmProvider.php +++ /dev/null @@ -1,59 +0,0 @@ -algorithmClasses = $algorithmClasses; - foreach ($algorithmClasses as $algorithmClass) { - $this->addClass($algorithmClass); - } - } - - public function getAlgorithmClasses(): array - { - return $this->algorithmClasses; - } - - public function getAvailableAlgorithms(): array - { - return $this->algorithms; - } - - private function addClass(string $algorithmClass): void - { - if (class_exists($algorithmClass)) { - try { - $this->algorithms[] = new $algorithmClass(); - } catch (Throwable $throwable) { - //does nothing - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/Build.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/Build.php deleted file mode 100644 index c5971d739..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/Build.php +++ /dev/null @@ -1,27 +0,0 @@ -key = $key; - $this->callable = $callable; - } - - /** - * @param mixed $value - * - * @throws InvalidClaimException if the claim is invalid - */ - public function checkClaim($value): void - { - $callable = $this->callable; - $isValid = $callable($value); - if (!$isValid) { - throw new InvalidClaimException(sprintf('Invalid claim "%s"', $this->key), $this->key, $value); - } - } - - public function supportedClaim(): string - { - return $this->key; - } - - /** - * {@inheritdoc} - */ - public function checkHeader($value): void - { - $callable = $this->callable; - $isValid = $callable($value); - if (!$isValid) { - throw new InvalidHeaderException(sprintf('Invalid header "%s"', $this->key), $this->key, $value); - } - } - - public function supportedHeader(): string - { - return $this->key; - } - - public function protectedHeaderOnly(): bool - { - return true; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/ContentEncryptionAlgorithmChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/ContentEncryptionAlgorithmChecker.php deleted file mode 100644 index c7606cf5f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/ContentEncryptionAlgorithmChecker.php +++ /dev/null @@ -1,72 +0,0 @@ -supportedAlgorithms = $supportedAlgorithms; - $this->protectedHeader = $protectedHeader; - } - - /** - * {@inheritdoc} - * - * @throws InvalidHeaderException if the header is invalid - */ - public function checkHeader($value): void - { - if (!is_string($value)) { - throw new InvalidHeaderException('"enc" must be a string.', self::HEADER_NAME, $value); - } - if (!in_array($value, $this->supportedAlgorithms, true)) { - throw new InvalidHeaderException('Unsupported algorithm.', self::HEADER_NAME, $value); - } - } - - public function supportedHeader(): string - { - return self::HEADER_NAME; - } - - public function protectedHeaderOnly(): bool - { - return $this->protectedHeader; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/Decrypt.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/Decrypt.php deleted file mode 100644 index 9c03de93b..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/Decrypt.php +++ /dev/null @@ -1,152 +0,0 @@ -compressionMethods = [ - new Deflate(), - ]; - } - - public static function token(string $token): self - { - return new self($token); - } - - /** - * @param Algorithm|string $enc - * - * @throws InvalidArgumentException if the encryption algorithm is invalid - */ - public function enc($enc): self - { - $clone = clone $this; - - switch (true) { - case is_string($enc): - $clone->allowedContentEncryptionAlgorithms[] = $enc; - - return $clone; - - case $enc instanceof Algorithm: - $clone->algorithms[$enc->name()] = $enc; - $clone->allowedContentEncryptionAlgorithms[] = $enc->name(); - - return $clone; - - default: - throw new InvalidArgumentException('Invalid parameter "enc". Shall be a string or an algorithm instance.'); - } - } - - /** - * @param Algorithm[]|string[] $encs - */ - public function encs($encs): self - { - $clone = clone $this; - foreach ($encs as $enc) { - $clone = $clone->enc($enc); - } - - return $clone; - } - - public function run(): JWT - { - if (0 !== count($this->allowedAlgorithms)) { - $this->headerCheckers[] = new Checker\AlgorithmChecker($this->allowedAlgorithms, true); - } - if (0 !== count($this->allowedContentEncryptionAlgorithms)) { - $this->headerCheckers[] = new ContentEncryptionAlgorithmChecker($this->allowedContentEncryptionAlgorithms, true); - } - $jwe = (new CompactSerializer())->unserialize($this->token); - $headerChecker = new Checker\HeaderCheckerManager($this->headerCheckers, [new JWETokenSupport()]); - $headerChecker->check($jwe, 0); - - $verifier = new JWEDecrypter( - new AlgorithmManager($this->algorithms), - new AlgorithmManager($this->algorithms), - new CompressionMethodManager($this->compressionMethods) - ); - $verifier->decryptUsingKeySet($jwe, $this->jwkset, 0); - - $jwt = new JWT(); - $jwt->header->replace($jwe->getSharedProtectedHeader()); - $jwt->claims->replace(JsonConverter::decode($jwe->getPayload())); - - $claimChecker = new Checker\ClaimCheckerManager($this->claimCheckers); - $claimChecker->check($jwt->claims->all(), $this->mandatoryClaims); - - return $jwt; - } - - protected function getAlgorithmMap(): array - { - return [ - KeyEncryption\A128GCMKW::class, - KeyEncryption\A192GCMKW::class, - KeyEncryption\A256GCMKW::class, - KeyEncryption\A128KW::class, - KeyEncryption\A192KW::class, - KeyEncryption\A256KW::class, - KeyEncryption\Dir::class, - KeyEncryption\ECDHES::class, - KeyEncryption\ECDHESA128KW::class, - KeyEncryption\ECDHESA192KW::class, - KeyEncryption\ECDHESA256KW::class, - KeyEncryption\PBES2HS256A128KW::class, - KeyEncryption\PBES2HS384A192KW::class, - KeyEncryption\PBES2HS512A256KW::class, - KeyEncryption\RSA15::class, - KeyEncryption\RSAOAEP::class, - KeyEncryption\RSAOAEP256::class, - ContentEncryption\A128GCM::class, - ContentEncryption\A192GCM::class, - ContentEncryption\A256GCM::class, - ContentEncryption\A128CBCHS256::class, - ContentEncryption\A192CBCHS384::class, - ContentEncryption\A256CBCHS512::class, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWEBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/JWEBuilder.php deleted file mode 100644 index ca4554c81..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWEBuilder.php +++ /dev/null @@ -1,147 +0,0 @@ -compressionMethods = [ - new Deflate(), - ]; - } - - /** - * @param Algorithm|string $enc - * - * @throws InvalidArgumentException if the header parameter "enc" is invalid - */ - public function enc($enc): self - { - $clone = clone $this; - - switch (true) { - case $enc instanceof Algorithm: - $clone->algorithms[] = $enc; - $clone->jwt->header->set('enc', $enc->name()); - - break; - - case is_string($enc): - $clone->jwt->header->set('enc', $enc); - - break; - - default: - throw new InvalidArgumentException('Invalid algorithm'); - } - - return $clone; - } - - /** - * @param CompressionMethod|string $zip - * - * @throws InvalidArgumentException if the header parameter "zip" is invalid - */ - public function zip($zip): self - { - $clone = clone $this; - - switch (true) { - case $zip instanceof CompressionMethod: - $clone->compressionMethods[] = $zip; - $clone->jwt->header->set('zip', $zip->name()); - - break; - - case is_string($zip): - $clone->jwt->header->set('zip', $zip); - - break; - - default: - throw new InvalidArgumentException('Invalid compression method'); - } - - return $clone; - } - - public function encrypt(JWK $jwk): string - { - $builder = new JoseBuilder( - new AlgorithmManager($this->algorithms), - new AlgorithmManager($this->algorithms), - new CompressionMethodManager($this->compressionMethods) - ); - $jwe = $builder - ->create() - ->withPayload(JsonConverter::encode($this->jwt->claims->all())) - ->withSharedProtectedHeader($this->jwt->header->all()) - ->addRecipient($jwk) - ->build() - ; - - return (new CompactSerializer())->serialize($jwe); - } - - protected function getAlgorithmMap(): array - { - return [ - KeyEncryption\A128GCMKW::class, - KeyEncryption\A192GCMKW::class, - KeyEncryption\A256GCMKW::class, - KeyEncryption\A128KW::class, - KeyEncryption\A192KW::class, - KeyEncryption\A256KW::class, - KeyEncryption\Dir::class, - KeyEncryption\ECDHES::class, - KeyEncryption\ECDHESA128KW::class, - KeyEncryption\ECDHESA192KW::class, - KeyEncryption\ECDHESA256KW::class, - KeyEncryption\PBES2HS256A128KW::class, - KeyEncryption\PBES2HS384A192KW::class, - KeyEncryption\PBES2HS512A256KW::class, - KeyEncryption\RSA15::class, - KeyEncryption\RSAOAEP::class, - KeyEncryption\RSAOAEP256::class, - ContentEncryption\A128GCM::class, - ContentEncryption\A192GCM::class, - ContentEncryption\A256GCM::class, - ContentEncryption\A128CBCHS256::class, - ContentEncryption\A192CBCHS384::class, - ContentEncryption\A256CBCHS512::class, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWSBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/JWSBuilder.php deleted file mode 100644 index 4f5c2f158..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWSBuilder.php +++ /dev/null @@ -1,56 +0,0 @@ -algorithms)); - $jws = $builder - ->create() - ->withPayload(JsonConverter::encode($this->jwt->claims->all())) - ->addSignature($jwk, $this->jwt->header->all()) - ->build() - ; - - return (new CompactSerializer())->serialize($jws); - } - - protected function getAlgorithmMap(): array - { - return [ - Algorithm\HS256::class, - Algorithm\HS384::class, - Algorithm\HS512::class, - Algorithm\RS256::class, - Algorithm\RS384::class, - Algorithm\RS512::class, - Algorithm\PS256::class, - Algorithm\PS384::class, - Algorithm\PS512::class, - Algorithm\ES256::class, - Algorithm\ES384::class, - Algorithm\ES512::class, - Algorithm\EdDSA::class, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWT.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/JWT.php deleted file mode 100644 index c5f923554..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/JWT.php +++ /dev/null @@ -1,33 +0,0 @@ -claims = new ParameterBag(); - $this->header = new ParameterBag(); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-easy/LICENSE deleted file mode 100644 index 37cf976b1..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2019 Spomky-Labs - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/Load.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/Load.php deleted file mode 100644 index 5245ef6bc..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/Load.php +++ /dev/null @@ -1,27 +0,0 @@ -get($name); - } - array_unshift($arguments, $name); - - return call_user_func_array([$this, 'set'], $arguments); - } - - public function all(): array - { - return $this->parameters; - } - - public function keys(): array - { - return array_keys($this->parameters); - } - - public function replace(array $parameters): void - { - $this->parameters = $parameters; - } - - /** - * @throws InvalidArgumentException if the parameters are invalid - */ - public function add(array $parameters): void - { - /** @var null|array $replaced */ - $replaced = array_replace($this->parameters, $parameters); - if (null === $replaced) { - throw new InvalidArgumentException('Invalid parameters'); - } - $this->parameters = $replaced; - } - - /** - * @throws InvalidArgumentException if the selected parameter is missing - * - * @return mixed - */ - public function get(string $key) - { - if (!array_key_exists($key, $this->parameters)) { - throw new InvalidArgumentException(sprintf('Parameter "%s" is missing', $key)); - } - - return $this->parameters[$key]; - } - - /** - * @param mixed $value The value - */ - public function set(string $key, $value): void - { - $this->parameters[$key] = $value; - } - - public function has(string $key): bool - { - return array_key_exists($key, $this->parameters); - } - - public function remove(string $key): void - { - unset($this->parameters[$key]); - } - - public function getIterator(): ArrayIterator - { - return new ArrayIterator($this->parameters); - } - - public function count(): int - { - return count($this->parameters); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/README.md b/lam/lib/3rdParty/composer/web-token/jwt-easy/README.md deleted file mode 100644 index dc2ff743f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/README.md +++ /dev/null @@ -1,15 +0,0 @@ -Easy Toolset For JWT-Framework -=============================== - -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. - -**Please do not submit any Pull Request here.** -You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. - -# Documentation - -The official documentation is available as https://web-token.spomky-labs.com/ - -# Licence - -This software is release under [MIT licence](LICENSE). diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/Validate.php b/lam/lib/3rdParty/composer/web-token/jwt-easy/Validate.php deleted file mode 100644 index 0b3736a82..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/Validate.php +++ /dev/null @@ -1,75 +0,0 @@ -allowedAlgorithms)) { - $this->headerCheckers[] = new Checker\AlgorithmChecker($this->allowedAlgorithms, true); - } - $jws = (new CompactSerializer())->unserialize($this->token); - $headerChecker = new Checker\HeaderCheckerManager($this->headerCheckers, [new JWSTokenSupport()]); - $headerChecker->check($jws, 0); - - $verifier = new JWSVerifier(new AlgorithmManager($this->algorithms)); - if (!$verifier->verifyWithKeySet($jws, $this->jwkset, 0)) { - throw new Exception('Invalid signature'); - } - - $jwt = new JWT(); - $jwt->header->replace($jws->getSignature(0)->getProtectedHeader()); - $jwt->claims->replace(JsonConverter::decode($jws->getPayload())); - - $claimChecker = new Checker\ClaimCheckerManager($this->claimCheckers); - $claimChecker->check($jwt->claims->all(), $this->mandatoryClaims); - - return $jwt; - } - - protected function getAlgorithmMap(): array - { - return [ - Algorithm\HS256::class, - Algorithm\HS384::class, - Algorithm\HS512::class, - Algorithm\RS256::class, - Algorithm\RS384::class, - Algorithm\RS512::class, - Algorithm\PS256::class, - Algorithm\PS384::class, - Algorithm\PS512::class, - Algorithm\ES256::class, - Algorithm\ES384::class, - Algorithm\ES512::class, - Algorithm\EdDSA::class, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-easy/composer.json deleted file mode 100644 index bdc44fb7f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-easy/composer.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "web-token/jwt-easy", - "description": "Easy toolset to use the JWT Framework.", - "type": "library", - "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], - "homepage": "https://github.com/web-token", - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - },{ - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-framework/contributors" - } - ], - "autoload": { - "psr-4": { - "Jose\\Easy\\": "" - } - }, - "require": { - "web-token/jwt-encryption": "^2.1", - "web-token/jwt-signature": "^2.1", - "web-token/jwt-checker": "^2.1" - }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "Adds AES-CBC based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "Adds AES-GCM based encryption algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "Adds AES-GCM Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "Adds AES Key Wrapping based encryption algorithms", - "web-token/jwt-encryption-algorithm-dir": "Adds Direct encryption algorithm", - "web-token/jwt-encryption-algorithm-ecdh-es": "Adds ECDH-ES based encryption algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "Adds PBES2 based encryption algorithms", - "web-token/jwt-encryption-algorithm-rsa": "Adds RSA based encryption algorithms", - "web-token/jwt-signature-algorithm-ecdsa": "Adds ECDSA based signature algorithms", - "web-token/jwt-signature-algorithm-eddsa": "Adds EdDSA based signature algorithms", - "web-token/jwt-signature-algorithm-none": "Adds none signature algorithms", - "web-token/jwt-signature-algorithm-hmac": "Adds HMAC based signature algorithms", - "web-token/jwt-signature-algorithm-rsa": "Adds RSA based signature algorithms" - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Algorithm/ContentEncryptionAlgorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Algorithm/ContentEncryptionAlgorithm.php deleted file mode 100644 index f5047ee30..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Algorithm/ContentEncryptionAlgorithm.php +++ /dev/null @@ -1,54 +0,0 @@ -add($method); - } - } - - /** - * Returns true if the givn compression method is supported. - */ - public function has(string $name): bool - { - return array_key_exists($name, $this->compressionMethods); - } - - /** - * This method returns the compression method with the given name. - * Throws an exception if the method is not supported. - * - * @param string $name The name of the compression method - * - * @throws InvalidArgumentException if the compression method is not supported - */ - public function get(string $name): CompressionMethod - { - if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('The compression method "%s" is not supported.', $name)); - } - - return $this->compressionMethods[$name]; - } - - /** - * Returns the list of compression method names supported by the manager. - * - * @return string[] - */ - public function list(): array - { - return array_keys($this->compressionMethods); - } - - /** - * Add the given compression method to the manager. - */ - protected function add(CompressionMethod $compressionMethod): void - { - $name = $compressionMethod->name(); - $this->compressionMethods[$name] = $compressionMethod; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/CompressionMethodManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/CompressionMethodManagerFactory.php deleted file mode 100644 index 869da3d35..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/CompressionMethodManagerFactory.php +++ /dev/null @@ -1,75 +0,0 @@ -compressionMethods[$alias] = $compressionMethod; - } - - /** - * Returns the list of compression method aliases supported by the factory. - * - * @return string[] - */ - public function aliases(): array - { - return array_keys($this->compressionMethods); - } - - /** - * Returns all compression methods supported by this factory. - * - * @return CompressionMethod[] - */ - public function all(): array - { - return $this->compressionMethods; - } - - /** - * Creates a compression method manager using the compression methods identified by the given aliases. - * If one of the aliases does not exist, an exception is thrown. - * - * @param string[] $aliases - * - * @throws InvalidArgumentException if the compression method alias is not supported - */ - public function create(array $aliases): CompressionMethodManager - { - $compressionMethods = []; - foreach ($aliases as $alias) { - if (!isset($this->compressionMethods[$alias])) { - throw new InvalidArgumentException(sprintf('The compression method with the alias "%s" is not supported.', $alias)); - } - $compressionMethods[] = $this->compressionMethods[$alias]; - } - - return new CompressionMethodManager($compressionMethods); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/Deflate.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/Deflate.php deleted file mode 100644 index db8fbf29b..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Compression/Deflate.php +++ /dev/null @@ -1,83 +0,0 @@ - 9) { - throw new InvalidArgumentException('The compression level can be given as 0 for no compression up to 9 for maximum compression. If -1 given, the default compression level will be the default compression level of the zlib library.'); - } - $this->compressionLevel = $compressionLevel; - } - - public function name(): string - { - return 'DEF'; - } - - /** - * @throws InvalidArgumentException if the compression failed - */ - public function compress(string $data): string - { - try { - $bin = gzdeflate($data, $this->getCompressionLevel()); - if (!is_string($bin)) { - throw new InvalidArgumentException('Unable to encode the data'); - } - - return $bin; - } catch (Throwable $throwable) { - throw new InvalidArgumentException('Unable to compress data.', $throwable->getCode(), $throwable); - } - } - - /** - * @throws InvalidArgumentException if the decompression failed - */ - public function uncompress(string $data): string - { - try { - $bin = gzinflate($data); - if (!is_string($bin)) { - throw new InvalidArgumentException('Unable to encode the data'); - } - - return $bin; - } catch (Throwable $throwable) { - throw new InvalidArgumentException('Unable to uncompress data.', $throwable->getCode(), $throwable); - } - } - - private function getCompressionLevel(): int - { - return $this->compressionLevel; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWE.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWE.php deleted file mode 100644 index ed1bc23e8..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWE.php +++ /dev/null @@ -1,279 +0,0 @@ -ciphertext = $ciphertext; - $this->iv = $iv; - $this->aad = $aad; - $this->tag = $tag; - $this->sharedHeader = $sharedHeader; - $this->sharedProtectedHeader = $sharedProtectedHeader; - $this->encodedSharedProtectedHeader = $encodedSharedProtectedHeader; - $this->recipients = $recipients; - } - - public function getPayload(): ?string - { - return $this->payload; - } - - /** - * Set the payload. - * This method is immutable and a new object will be returned. - * - * @return JWE - */ - public function withPayload(string $payload): self - { - $clone = clone $this; - $clone->payload = $payload; - - return $clone; - } - - /** - * Returns the number of recipients associated with the JWS. - */ - public function countRecipients(): int - { - return count($this->recipients); - } - - /** - * Returns true is the JWE has already been encrypted. - */ - public function isEncrypted(): bool - { - return null !== $this->getCiphertext(); - } - - /** - * Returns the recipients associated with the JWS. - * - * @return Recipient[] - */ - public function getRecipients(): array - { - return $this->recipients; - } - - /** - * Returns the recipient object at the given index. - * - * @throws InvalidArgumentException if the recipient ID does not exist - */ - public function getRecipient(int $id): Recipient - { - if (!isset($this->recipients[$id])) { - throw new InvalidArgumentException('The recipient does not exist.'); - } - - return $this->recipients[$id]; - } - - /** - * Returns the ciphertext. This method will return null is the JWE has not yet been encrypted. - * - * @return null|string The cyphertext - */ - public function getCiphertext(): ?string - { - return $this->ciphertext; - } - - /** - * Returns the Additional Authentication Data if available. - */ - public function getAAD(): ?string - { - return $this->aad; - } - - /** - * Returns the Initialization Vector if available. - */ - public function getIV(): ?string - { - return $this->iv; - } - - /** - * Returns the tag if available. - */ - public function getTag(): ?string - { - return $this->tag; - } - - /** - * Returns the encoded shared protected header. - */ - public function getEncodedSharedProtectedHeader(): string - { - return $this->encodedSharedProtectedHeader ?? ''; - } - - /** - * Returns the shared protected header. - */ - public function getSharedProtectedHeader(): array - { - return $this->sharedProtectedHeader; - } - - /** - * Returns the shared protected header parameter identified by the given key. - * Throws an exception is the the parameter is not available. - * - * @param string $key The key - * - * @throws InvalidArgumentException if the shared protected header parameter does not exist - * - * @return null|mixed - */ - public function getSharedProtectedHeaderParameter(string $key) - { - if (!$this->hasSharedProtectedHeaderParameter($key)) { - throw new InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key)); - } - - return $this->sharedProtectedHeader[$key]; - } - - /** - * Returns true if the shared protected header has the parameter identified by the given key. - * - * @param string $key The key - */ - public function hasSharedProtectedHeaderParameter(string $key): bool - { - return array_key_exists($key, $this->sharedProtectedHeader); - } - - /** - * Returns the shared header. - */ - public function getSharedHeader(): array - { - return $this->sharedHeader; - } - - /** - * Returns the shared header parameter identified by the given key. - * Throws an exception is the the parameter is not available. - * - * @param string $key The key - * - * @throws InvalidArgumentException if the shared header parameter does not exist - * - * @return null|mixed - */ - public function getSharedHeaderParameter(string $key) - { - if (!$this->hasSharedHeaderParameter($key)) { - throw new InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key)); - } - - return $this->sharedHeader[$key]; - } - - /** - * Returns true if the shared header has the parameter identified by the given key. - * - * @param string $key The key - */ - public function hasSharedHeaderParameter(string $key): bool - { - return array_key_exists($key, $this->sharedHeader); - } - - /** - * This method splits the JWE into a list of JWEs. - * It is only useful when the JWE contains more than one recipient (JSON General Serialization). - * - * @return JWE[] - */ - public function split(): array - { - $result = []; - foreach ($this->recipients as $recipient) { - $result[] = new self( - $this->ciphertext, - $this->iv, - $this->tag, - $this->aad, - $this->sharedHeader, - $this->sharedProtectedHeader, - $this->encodedSharedProtectedHeader, - [$recipient] - ); - } - - return $result; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilder.php deleted file mode 100644 index 6353b205b..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilder.php +++ /dev/null @@ -1,537 +0,0 @@ -keyEncryptionAlgorithmManager = $keyEncryptionAlgorithmManager; - $this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager; - $this->compressionManager = $compressionManager; - } - - /** - * Reset the current data. - * - * @return JWEBuilder - */ - public function create(): self - { - $this->payload = null; - $this->aad = null; - $this->recipients = []; - $this->sharedProtectedHeader = []; - $this->sharedHeader = []; - $this->compressionMethod = null; - $this->contentEncryptionAlgorithm = null; - $this->keyManagementMode = null; - - return $this; - } - - /** - * Returns the key encryption algorithm manager. - */ - public function getKeyEncryptionAlgorithmManager(): AlgorithmManager - { - return $this->keyEncryptionAlgorithmManager; - } - - /** - * Returns the content encryption algorithm manager. - */ - public function getContentEncryptionAlgorithmManager(): AlgorithmManager - { - return $this->contentEncryptionAlgorithmManager; - } - - /** - * Returns the compression method manager. - */ - public function getCompressionMethodManager(): CompressionMethodManager - { - return $this->compressionManager; - } - - /** - * Set the payload of the JWE to build. - * - * @throws InvalidArgumentException if the payload is not encoded in UTF-8 - * - * @return JWEBuilder - */ - public function withPayload(string $payload): self - { - if ('UTF-8' !== mb_detect_encoding($payload, 'UTF-8', true)) { - throw new InvalidArgumentException('The payload must be encoded in UTF-8'); - } - $clone = clone $this; - $clone->payload = $payload; - - return $clone; - } - - /** - * Set the Additional Authenticated Data of the JWE to build. - * - * @return JWEBuilder - */ - public function withAAD(?string $aad): self - { - $clone = clone $this; - $clone->aad = $aad; - - return $clone; - } - - /** - * Set the shared protected header of the JWE to build. - * - * @return JWEBuilder - */ - public function withSharedProtectedHeader(array $sharedProtectedHeader): self - { - $this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $this->sharedHeader); - foreach ($this->recipients as $recipient) { - $this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $recipient->getHeader()); - } - $clone = clone $this; - $clone->sharedProtectedHeader = $sharedProtectedHeader; - - return $clone; - } - - /** - * Set the shared header of the JWE to build. - * - * @return JWEBuilder - */ - public function withSharedHeader(array $sharedHeader): self - { - $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $sharedHeader); - foreach ($this->recipients as $recipient) { - $this->checkDuplicatedHeaderParameters($sharedHeader, $recipient->getHeader()); - } - $clone = clone $this; - $clone->sharedHeader = $sharedHeader; - - return $clone; - } - - /** - * Adds a recipient to the JWE to build. - * - * @throws InvalidArgumentException if key management modes are incompatible - * @throws InvalidArgumentException if the compression method is invalid - * - * @return JWEBuilder - */ - public function addRecipient(JWK $recipientKey, array $recipientHeader = []): self - { - $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $recipientHeader); - $this->checkDuplicatedHeaderParameters($this->sharedHeader, $recipientHeader); - $clone = clone $this; - $completeHeader = array_merge($clone->sharedHeader, $recipientHeader, $clone->sharedProtectedHeader); - $clone->checkAndSetContentEncryptionAlgorithm($completeHeader); - $keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeader); - if (null === $clone->keyManagementMode) { - $clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode(); - } else { - if (!$clone->areKeyManagementModesCompatible($clone->keyManagementMode, $keyEncryptionAlgorithm->getKeyManagementMode())) { - throw new InvalidArgumentException('Foreign key management mode forbidden.'); - } - } - - $compressionMethod = $clone->getCompressionMethod($completeHeader); - if (null !== $compressionMethod) { - if (null === $clone->compressionMethod) { - $clone->compressionMethod = $compressionMethod; - } elseif ($clone->compressionMethod->name() !== $compressionMethod->name()) { - throw new InvalidArgumentException('Incompatible compression method.'); - } - } - if (null === $compressionMethod && null !== $clone->compressionMethod) { - throw new InvalidArgumentException('Inconsistent compression method.'); - } - $clone->checkKey($keyEncryptionAlgorithm, $recipientKey); - $clone->recipients[] = [ - 'key' => $recipientKey, - 'header' => $recipientHeader, - 'key_encryption_algorithm' => $keyEncryptionAlgorithm, - ]; - - return $clone; - } - - /** - * Builds the JWE. - * - * @throws LogicException if no payload is set - * @throws LogicException if there are no recipient - */ - public function build(): JWE - { - if (null === $this->payload) { - throw new LogicException('Payload not set.'); - } - if (0 === count($this->recipients)) { - throw new LogicException('No recipient.'); - } - - $additionalHeader = []; - $cek = $this->determineCEK($additionalHeader); - - $recipients = []; - foreach ($this->recipients as $recipient) { - $recipient = $this->processRecipient($recipient, $cek, $additionalHeader); - $recipients[] = $recipient; - } - - if (0 !== count($additionalHeader) && 1 === count($this->recipients)) { - $sharedProtectedHeader = array_merge($additionalHeader, $this->sharedProtectedHeader); - } else { - $sharedProtectedHeader = $this->sharedProtectedHeader; - } - $encodedSharedProtectedHeader = 0 === count($sharedProtectedHeader) ? '' : Base64Url::encode(JsonConverter::encode($sharedProtectedHeader)); - - [$ciphertext, $iv, $tag] = $this->encryptJWE($cek, $encodedSharedProtectedHeader); - - return new JWE($ciphertext, $iv, $tag, $this->aad, $this->sharedHeader, $sharedProtectedHeader, $encodedSharedProtectedHeader, $recipients); - } - - /** - * @throws InvalidArgumentException if the content encryption algorithm is not valid - */ - private function checkAndSetContentEncryptionAlgorithm(array $completeHeader): void - { - $contentEncryptionAlgorithm = $this->getContentEncryptionAlgorithm($completeHeader); - if (null === $this->contentEncryptionAlgorithm) { - $this->contentEncryptionAlgorithm = $contentEncryptionAlgorithm; - } elseif ($contentEncryptionAlgorithm->name() !== $this->contentEncryptionAlgorithm->name()) { - throw new InvalidArgumentException('Inconsistent content encryption algorithm'); - } - } - - /** - * @throws InvalidArgumentException if the key encryption algorithm is not valid - */ - private function processRecipient(array $recipient, string $cek, array &$additionalHeader): Recipient - { - $completeHeader = array_merge($this->sharedHeader, $recipient['header'], $this->sharedProtectedHeader); - $keyEncryptionAlgorithm = $recipient['key_encryption_algorithm']; - if (!$keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) { - throw new InvalidArgumentException('The key encryption algorithm is not valid'); - } - $encryptedContentEncryptionKey = $this->getEncryptedKey($completeHeader, $cek, $keyEncryptionAlgorithm, $additionalHeader, $recipient['key'], $recipient['sender_key'] ?? null); - $recipientHeader = $recipient['header']; - if (0 !== count($additionalHeader) && 1 !== count($this->recipients)) { - $recipientHeader = array_merge($recipientHeader, $additionalHeader); - $additionalHeader = []; - } - - return new Recipient($recipientHeader, $encryptedContentEncryptionKey); - } - - /** - * @throws InvalidArgumentException if the content encryption algorithm is not valid - */ - private function encryptJWE(string $cek, string $encodedSharedProtectedHeader): array - { - if (!$this->contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) { - throw new InvalidArgumentException('The content encryption algorithm is not valid'); - } - $iv_size = $this->contentEncryptionAlgorithm->getIVSize(); - $iv = $this->createIV($iv_size); - $payload = $this->preparePayload(); - $tag = null; - $ciphertext = $this->contentEncryptionAlgorithm->encryptContent($payload, $cek, $iv, $this->aad, $encodedSharedProtectedHeader, $tag); - - return [$ciphertext, $iv, $tag]; - } - - /** - * @return string - */ - private function preparePayload(): ?string - { - $prepared = $this->payload; - if (null === $this->compressionMethod) { - return $prepared; - } - - return $this->compressionMethod->compress($prepared); - } - - /** - * @throws InvalidArgumentException if the key encryption algorithm is not supported - */ - private function getEncryptedKey(array $completeHeader, string $cek, KeyEncryptionAlgorithm $keyEncryptionAlgorithm, array &$additionalHeader, JWK $recipientKey, ?JWK $senderKey): ?string - { - if ($keyEncryptionAlgorithm instanceof KeyEncryption) { - return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($completeHeader, $cek, $keyEncryptionAlgorithm, $recipientKey, $additionalHeader); - } - if ($keyEncryptionAlgorithm instanceof KeyWrapping) { - return $this->getEncryptedKeyFromKeyWrappingAlgorithm($completeHeader, $cek, $keyEncryptionAlgorithm, $recipientKey, $additionalHeader); - } - if ($keyEncryptionAlgorithm instanceof KeyAgreementWithKeyWrapping) { - return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($completeHeader, $cek, $keyEncryptionAlgorithm, $additionalHeader, $recipientKey, $senderKey); - } - if ($keyEncryptionAlgorithm instanceof KeyAgreement) { - return null; - } - if ($keyEncryptionAlgorithm instanceof DirectEncryption) { - return null; - } - - throw new InvalidArgumentException('Unsupported key encryption algorithm.'); - } - - /** - * @throws InvalidArgumentException if the content encryption algorithm is invalid - */ - private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $completeHeader, string $cek, KeyAgreementWithKeyWrapping $keyEncryptionAlgorithm, array &$additionalHeader, JWK $recipientKey, ?JWK $senderKey): string - { - if (null === $this->contentEncryptionAlgorithm) { - throw new InvalidArgumentException('Invalid content encryption algorithm'); - } - - return $keyEncryptionAlgorithm->wrapAgreementKey($recipientKey, $senderKey, $cek, $this->contentEncryptionAlgorithm->getCEKSize(), $completeHeader, $additionalHeader); - } - - private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $completeHeader, string $cek, KeyEncryption $keyEncryptionAlgorithm, JWK $recipientKey, array &$additionalHeader): string - { - return $keyEncryptionAlgorithm->encryptKey($recipientKey, $cek, $completeHeader, $additionalHeader); - } - - private function getEncryptedKeyFromKeyWrappingAlgorithm(array $completeHeader, string $cek, KeyWrapping $keyEncryptionAlgorithm, JWK $recipientKey, array &$additionalHeader): string - { - return $keyEncryptionAlgorithm->wrapKey($recipientKey, $cek, $completeHeader, $additionalHeader); - } - - /** - * @throws InvalidArgumentException if the content encryption algorithm is invalid - * @throws InvalidArgumentException if the key type is not valid - * @throws InvalidArgumentException if the key management mode is not supported - */ - private function checkKey(KeyEncryptionAlgorithm $keyEncryptionAlgorithm, JWK $recipientKey): void - { - if (null === $this->contentEncryptionAlgorithm) { - throw new InvalidArgumentException('Invalid content encryption algorithm'); - } - - KeyChecker::checkKeyUsage($recipientKey, 'encryption'); - if ('dir' !== $keyEncryptionAlgorithm->name()) { - KeyChecker::checkKeyAlgorithm($recipientKey, $keyEncryptionAlgorithm->name()); - } else { - KeyChecker::checkKeyAlgorithm($recipientKey, $this->contentEncryptionAlgorithm->name()); - } - } - - private function determineCEK(array &$additionalHeader): string - { - if (null === $this->contentEncryptionAlgorithm) { - throw new InvalidArgumentException('Invalid content encryption algorithm'); - } - - switch ($this->keyManagementMode) { - case KeyEncryption::MODE_ENCRYPT: - case KeyEncryption::MODE_WRAP: - return $this->createCEK($this->contentEncryptionAlgorithm->getCEKSize()); - - case KeyEncryption::MODE_AGREEMENT: - if (1 !== count($this->recipients)) { - throw new LogicException('Unable to encrypt for multiple recipients using key agreement algorithms.'); - } - $recipientKey = $this->recipients[0]['key']; - $senderKey = $this->recipients[0]['sender_key'] ?? null; - $algorithm = $this->recipients[0]['key_encryption_algorithm']; - if (!$algorithm instanceof KeyAgreement) { - throw new InvalidArgumentException('Invalid content encryption algorithm'); - } - $completeHeader = array_merge($this->sharedHeader, $this->recipients[0]['header'], $this->sharedProtectedHeader); - - return $algorithm->getAgreementKey($this->contentEncryptionAlgorithm->getCEKSize(), $this->contentEncryptionAlgorithm->name(), $recipientKey, $senderKey, $completeHeader, $additionalHeader); - - case KeyEncryption::MODE_DIRECT: - if (1 !== count($this->recipients)) { - throw new LogicException('Unable to encrypt for multiple recipients using key agreement algorithms.'); - } - /** @var JWK $key */ - $key = $this->recipients[0]['key']; - if ('oct' !== $key->get('kty')) { - throw new RuntimeException('Wrong key type.'); - } - - return Base64Url::decode($key->get('k')); - - default: - throw new InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $this->keyManagementMode)); - } - } - - private function getCompressionMethod(array $completeHeader): ?CompressionMethod - { - if (!array_key_exists('zip', $completeHeader)) { - return null; - } - - return $this->compressionManager->get($completeHeader['zip']); - } - - private function areKeyManagementModesCompatible(string $current, string $new): bool - { - $agree = KeyEncryptionAlgorithm::MODE_AGREEMENT; - $dir = KeyEncryptionAlgorithm::MODE_DIRECT; - $enc = KeyEncryptionAlgorithm::MODE_ENCRYPT; - $wrap = KeyEncryptionAlgorithm::MODE_WRAP; - $supportedKeyManagementModeCombinations = [$enc.$enc => true, $enc.$wrap => true, $wrap.$enc => true, $wrap.$wrap => true, $agree.$agree => false, $agree.$dir => false, $agree.$enc => false, $agree.$wrap => false, $dir.$agree => false, $dir.$dir => false, $dir.$enc => false, $dir.$wrap => false, $enc.$agree => false, $enc.$dir => false, $wrap.$agree => false, $wrap.$dir => false]; - - if (array_key_exists($current.$new, $supportedKeyManagementModeCombinations)) { - return $supportedKeyManagementModeCombinations[$current.$new]; - } - - return false; - } - - private function createCEK(int $size): string - { - return random_bytes($size / 8); - } - - private function createIV(int $size): string - { - return random_bytes($size / 8); - } - - /** - * @throws InvalidArgumentException if the header parameter "alg" is missing - * @throws InvalidArgumentException if the header parameter "alg" is not supported or not a key encryption algorithm - */ - private function getKeyEncryptionAlgorithm(array $completeHeader): KeyEncryptionAlgorithm - { - if (!isset($completeHeader['alg'])) { - throw new InvalidArgumentException('Parameter "alg" is missing.'); - } - $keyEncryptionAlgorithm = $this->keyEncryptionAlgorithmManager->get($completeHeader['alg']); - if (!$keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) { - throw new InvalidArgumentException(sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $completeHeader['alg'])); - } - - return $keyEncryptionAlgorithm; - } - - /** - * @throws InvalidArgumentException if the header parameter "enc" is missing - * @throws InvalidArgumentException if the header parameter "enc" is not supported or not a content encryption algorithm - */ - private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm - { - if (!isset($completeHeader['enc'])) { - throw new InvalidArgumentException('Parameter "enc" is missing.'); - } - $contentEncryptionAlgorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']); - if (!$contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) { - throw new InvalidArgumentException(sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $completeHeader['enc'])); - } - - return $contentEncryptionAlgorithm; - } - - /** - * @throws InvalidArgumentException if the header contains duplicated entries - */ - private function checkDuplicatedHeaderParameters(array $header1, array $header2): void - { - $inter = array_intersect_key($header1, $header2); - if (0 !== count($inter)) { - throw new InvalidArgumentException(sprintf('The header contains duplicated entries: %s.', implode(', ', array_keys($inter)))); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilderFactory.php deleted file mode 100644 index 80748090f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEBuilderFactory.php +++ /dev/null @@ -1,55 +0,0 @@ -algorithmManagerFactory = $algorithmManagerFactory; - $this->compressionMethodManagerFactory = $compressionMethodManagerFactory; - } - - /** - * Creates a JWE Builder object using the given key encryption algorithms, content encryption algorithms and compression methods. - * - * @param string[] $keyEncryptionAlgorithms - * @param string[] $contentEncryptionAlgorithm - * @param string[] $compressionMethods - */ - public function create(array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithm, array $compressionMethods): JWEBuilder - { - $keyEncryptionAlgorithmManager = $this->algorithmManagerFactory->create($keyEncryptionAlgorithms); - $contentEncryptionAlgorithmManager = $this->algorithmManagerFactory->create($contentEncryptionAlgorithm); - $compressionMethodManager = $this->compressionMethodManagerFactory->create($compressionMethods); - - return new JWEBuilder($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, $compressionMethodManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypter.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypter.php deleted file mode 100644 index 88c3f9352..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypter.php +++ /dev/null @@ -1,267 +0,0 @@ -keyEncryptionAlgorithmManager = $keyEncryptionAlgorithmManager; - $this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager; - $this->compressionMethodManager = $compressionMethodManager; - } - - /** - * Returns the key encryption algorithm manager. - */ - public function getKeyEncryptionAlgorithmManager(): AlgorithmManager - { - return $this->keyEncryptionAlgorithmManager; - } - - /** - * Returns the content encryption algorithm manager. - */ - public function getContentEncryptionAlgorithmManager(): AlgorithmManager - { - return $this->contentEncryptionAlgorithmManager; - } - - /** - * Returns the compression method manager. - */ - public function getCompressionMethodManager(): CompressionMethodManager - { - return $this->compressionMethodManager; - } - - /** - * This method will try to decrypt the given JWE and recipient using a JWK. - * - * @param JWE $jwe A JWE object to decrypt - * @param JWK $jwk The key used to decrypt the input - * @param int $recipient The recipient used to decrypt the token - */ - public function decryptUsingKey(JWE &$jwe, JWK $jwk, int $recipient, ?JWK $senderKey = null): bool - { - $jwkset = new JWKSet([$jwk]); - - return $this->decryptUsingKeySet($jwe, $jwkset, $recipient, $senderKey); - } - - /** - * This method will try to decrypt the given JWE and recipient using a JWKSet. - * - * @param JWE $jwe A JWE object to decrypt - * @param JWKSet $jwkset The key set used to decrypt the input - * @param JWK $jwk The key used to decrypt the token in case of success - * @param int $recipient The recipient used to decrypt the token in case of success - * - * @throws InvalidArgumentException if no key is set is the keyset - * @throws InvalidArgumentException if the token has no recipients - */ - public function decryptUsingKeySet(JWE &$jwe, JWKSet $jwkset, int $recipient, JWK &$jwk = null, ?JWK $senderKey = null): bool - { - if (0 === $jwkset->count()) { - throw new InvalidArgumentException('No key in the key set.'); - } - if (null !== $jwe->getPayload()) { - return true; - } - if (0 === $jwe->countRecipients()) { - throw new InvalidArgumentException('The JWE does not contain any recipient.'); - } - - $plaintext = $this->decryptRecipientKey($jwe, $jwkset, $recipient, $jwk, $senderKey); - if (null !== $plaintext) { - $jwe = $jwe->withPayload($plaintext); - - return true; - } - - return false; - } - - private function decryptRecipientKey(JWE $jwe, JWKSet $jwkset, int $i, JWK &$successJwk = null, ?JWK $senderKey = null): ?string - { - $recipient = $jwe->getRecipient($i); - $completeHeader = array_merge($jwe->getSharedProtectedHeader(), $jwe->getSharedHeader(), $recipient->getHeader()); - $this->checkCompleteHeader($completeHeader); - - $key_encryption_algorithm = $this->getKeyEncryptionAlgorithm($completeHeader); - $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($completeHeader); - - $this->checkIvSize($jwe->getIV(), $content_encryption_algorithm->getIVSize()); - - foreach ($jwkset as $recipientKey) { - try { - KeyChecker::checkKeyUsage($recipientKey, 'decryption'); - if ('dir' !== $key_encryption_algorithm->name()) { - KeyChecker::checkKeyAlgorithm($recipientKey, $key_encryption_algorithm->name()); - } else { - KeyChecker::checkKeyAlgorithm($recipientKey, $content_encryption_algorithm->name()); - } - $cek = $this->decryptCEK($key_encryption_algorithm, $content_encryption_algorithm, $recipientKey, $senderKey, $recipient, $completeHeader); - $this->checkCekSize($cek, $key_encryption_algorithm, $content_encryption_algorithm); - $payload = $this->decryptPayload($jwe, $cek, $content_encryption_algorithm, $completeHeader); - $successJwk = $recipientKey; - - return $payload; - } catch (Throwable $e) { - //We do nothing, we continue with other keys - continue; - } - } - - return null; - } - - /** - * @throws InvalidArgumentException if the Content Encryption Key size is invalid - */ - private function checkCekSize(string $cek, KeyEncryptionAlgorithm $keyEncryptionAlgorithm, ContentEncryptionAlgorithm $algorithm): void - { - if ($keyEncryptionAlgorithm instanceof DirectEncryption || $keyEncryptionAlgorithm instanceof KeyAgreement) { - return; - } - if (mb_strlen($cek, '8bit') * 8 !== $algorithm->getCEKSize()) { - throw new InvalidArgumentException('Invalid CEK size'); - } - } - - /** - * @throws InvalidArgumentException if the IV size is invalid - */ - private function checkIvSize(?string $iv, int $requiredIvSize): void - { - if (null === $iv && 0 !== $requiredIvSize) { - throw new InvalidArgumentException('Invalid IV size'); - } - if (is_string($iv) && mb_strlen($iv, '8bit') !== $requiredIvSize / 8) { - throw new InvalidArgumentException('Invalid IV size'); - } - } - - /** - * @throws InvalidArgumentException if the CEK creation method is not supported - */ - private function decryptCEK(Algorithm $key_encryption_algorithm, ContentEncryptionAlgorithm $content_encryption_algorithm, JWK $recipientKey, ?JWK $senderKey, Recipient $recipient, array $completeHeader): string - { - if ($key_encryption_algorithm instanceof DirectEncryption) { - return $key_encryption_algorithm->getCEK($recipientKey); - } - if ($key_encryption_algorithm instanceof KeyAgreement) { - return $key_encryption_algorithm->getAgreementKey($content_encryption_algorithm->getCEKSize(), $content_encryption_algorithm->name(), $recipientKey, $senderKey, $completeHeader); - } - if ($key_encryption_algorithm instanceof KeyAgreementWithKeyWrapping) { - return $key_encryption_algorithm->unwrapAgreementKey($recipientKey, $senderKey, $recipient->getEncryptedKey(), $content_encryption_algorithm->getCEKSize(), $completeHeader); - } - if ($key_encryption_algorithm instanceof KeyEncryption) { - return $key_encryption_algorithm->decryptKey($recipientKey, $recipient->getEncryptedKey(), $completeHeader); - } - if ($key_encryption_algorithm instanceof KeyWrapping) { - return $key_encryption_algorithm->unwrapKey($recipientKey, $recipient->getEncryptedKey(), $completeHeader); - } - - throw new InvalidArgumentException('Unsupported CEK generation'); - } - - private function decryptPayload(JWE $jwe, string $cek, ContentEncryptionAlgorithm $content_encryption_algorithm, array $completeHeader): string - { - $payload = $content_encryption_algorithm->decryptContent($jwe->getCiphertext(), $cek, $jwe->getIV(), $jwe->getAAD(), $jwe->getEncodedSharedProtectedHeader(), $jwe->getTag()); - - return $this->decompressIfNeeded($payload, $completeHeader); - } - - private function decompressIfNeeded(string $payload, array $completeHeaders): string - { - if (array_key_exists('zip', $completeHeaders)) { - $compression_method = $this->compressionMethodManager->get($completeHeaders['zip']); - $payload = $compression_method->uncompress($payload); - } - - return $payload; - } - - /** - * @throws InvalidArgumentException if a header parameter is missing - */ - private function checkCompleteHeader(array $completeHeaders): void - { - foreach (['enc', 'alg'] as $key) { - if (!isset($completeHeaders[$key])) { - throw new InvalidArgumentException(sprintf("Parameter '%s' is missing.", $key)); - } - } - } - - /** - * @throws InvalidArgumentException if the key encryption algorithm is not supported or does not implement the KeyEncryptionAlgorithm interface - */ - private function getKeyEncryptionAlgorithm(array $completeHeaders): KeyEncryptionAlgorithm - { - $key_encryption_algorithm = $this->keyEncryptionAlgorithmManager->get($completeHeaders['alg']); - if (!$key_encryption_algorithm instanceof KeyEncryptionAlgorithm) { - throw new InvalidArgumentException(sprintf('The key encryption algorithm "%s" is not supported or does not implement KeyEncryptionAlgorithm interface.', $completeHeaders['alg'])); - } - - return $key_encryption_algorithm; - } - - /** - * @throws InvalidArgumentException if the content encryption algorithm is not supported or does not implement the ContentEncryption interface - */ - private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm - { - $content_encryption_algorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']); - if (!$content_encryption_algorithm instanceof ContentEncryptionAlgorithm) { - throw new InvalidArgumentException(sprintf('The key encryption algorithm "%s" is not supported or does not implement the ContentEncryption interface.', $completeHeader['enc'])); - } - - return $content_encryption_algorithm; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypterFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypterFactory.php deleted file mode 100644 index 71ba0bf24..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWEDecrypterFactory.php +++ /dev/null @@ -1,52 +0,0 @@ -algorithmManagerFactory = $algorithmManagerFactory; - $this->compressionMethodManagerFactory = $compressionMethodManagerFactory; - } - - /** - * Creates a JWE Decrypter object using the given key encryption algorithms, content encryption algorithms and compression methods. - * - * @param string[] $keyEncryptionAlgorithms - * @param string[] $contentEncryptionAlgorithms - * @param string[] $compressionMethods - */ - public function create(array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithms, array $compressionMethods): JWEDecrypter - { - $keyEncryptionAlgorithmManager = $this->algorithmManagerFactory->create($keyEncryptionAlgorithms); - $contentEncryptionAlgorithmManager = $this->algorithmManagerFactory->create($contentEncryptionAlgorithms); - $compressionMethodManager = $this->compressionMethodManagerFactory->create($compressionMethods); - - return new JWEDecrypter($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager, $compressionMethodManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoader.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoader.php deleted file mode 100644 index dcc7557c0..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoader.php +++ /dev/null @@ -1,122 +0,0 @@ -serializerManager = $serializerManager; - $this->jweDecrypter = $jweDecrypter; - $this->headerCheckerManager = $headerCheckerManager; - } - - /** - * Returns the JWE Decrypter object. - */ - public function getJweDecrypter(): JWEDecrypter - { - return $this->jweDecrypter; - } - - /** - * Returns the header checker manager if set. - */ - public function getHeaderCheckerManager(): ?HeaderCheckerManager - { - return $this->headerCheckerManager; - } - - /** - * Returns the serializer manager. - */ - public function getSerializerManager(): JWESerializerManager - { - return $this->serializerManager; - } - - /** - * This method will try to load and decrypt the given token using a JWK. - * If succeeded, the methods will populate the $recipient variable and returns the JWE. - */ - public function loadAndDecryptWithKey(string $token, JWK $key, ?int &$recipient): JWE - { - $keyset = new JWKSet([$key]); - - return $this->loadAndDecryptWithKeySet($token, $keyset, $recipient); - } - - /** - * This method will try to load and decrypt the given token using a JWKSet. - * If succeeded, the methods will populate the $recipient variable and returns the JWE. - * - * @throws RuntimeException if the data cannot be loaded or decrypted - */ - public function loadAndDecryptWithKeySet(string $token, JWKSet $keyset, ?int &$recipient): JWE - { - try { - $jwe = $this->serializerManager->unserialize($token); - $nbRecipients = $jwe->countRecipients(); - for ($i = 0; $i < $nbRecipients; ++$i) { - if ($this->processRecipient($jwe, $keyset, $i)) { - $recipient = $i; - - return $jwe; - } - } - } catch (Throwable $e) { - // Nothing to do. Exception thrown just after - } - - throw new RuntimeException('Unable to load and decrypt the token.'); - } - - private function processRecipient(JWE &$jwe, JWKSet $keyset, int $recipient): bool - { - try { - if (null !== $this->headerCheckerManager) { - $this->headerCheckerManager->check($jwe, $recipient); - } - - return $this->jweDecrypter->decryptUsingKeySet($jwe, $keyset, $recipient); - } catch (Throwable $e) { - return false; - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoaderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoaderFactory.php deleted file mode 100644 index 461cca5ae..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWELoaderFactory.php +++ /dev/null @@ -1,62 +0,0 @@ -jweSerializerManagerFactory = $jweSerializerManagerFactory; - $this->jweDecrypterFactory = $jweDecrypterFactory; - $this->headerCheckerManagerFactory = $headerCheckerManagerFactory; - } - - /** - * Creates a JWELoader using the given serializer aliases, encryption algorithm aliases, compression method aliases - * and header checker aliases. - */ - public function create(array $serializers, array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithms, array $compressionMethods, array $headerCheckers = []): JWELoader - { - $serializerManager = $this->jweSerializerManagerFactory->create($serializers); - $jweDecrypter = $this->jweDecrypterFactory->create($keyEncryptionAlgorithms, $contentEncryptionAlgorithms, $compressionMethods); - if (null !== $this->headerCheckerManagerFactory) { - $headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers); - } else { - $headerCheckerManager = null; - } - - return new JWELoader($serializerManager, $jweDecrypter, $headerCheckerManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWETokenSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWETokenSupport.php deleted file mode 100644 index 0c311ffd7..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/JWETokenSupport.php +++ /dev/null @@ -1,40 +0,0 @@ -getSharedProtectedHeader(); - $unprotectedHeader = $jwt->getSharedHeader(); - $recipient = $jwt->getRecipient($index)->getHeader(); - - $unprotectedHeader = array_merge( - $unprotectedHeader, - $recipient - ); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-encryption/LICENSE index 37cf976b1..5ab750604 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/LICENSE +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2019 Spomky-Labs +Copyright (c) 2014-2024 Spomky-Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/README.md b/lam/lib/3rdParty/composer/web-token/jwt-encryption/README.md index d3dbe017b..f7a144325 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/README.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/README.md @@ -1,14 +1,15 @@ PHP JWT Encryption Component ============================ -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. **Please do not submit any Pull Request here.** You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. # Documentation -The official documentation is available as https://web-token.spomky-labs.com/ +The official documentation is available as https://web-token.spomky-labs.com/ # Licence diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Recipient.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Recipient.php deleted file mode 100644 index 98c4dfb82..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Recipient.php +++ /dev/null @@ -1,83 +0,0 @@ -header = $header; - $this->encryptedKey = $encryptedKey; - } - - /** - * Returns the recipient header. - */ - public function getHeader(): array - { - return $this->header; - } - - /** - * Returns the value of the recipient header parameter with the specified key. - * - * @param string $key The key - * - * @throws InvalidArgumentException if the header parameter does not exist - * - * @return null|mixed - */ - public function getHeaderParameter(string $key) - { - if (!$this->hasHeaderParameter($key)) { - throw new InvalidArgumentException(sprintf('The header "%s" does not exist.', $key)); - } - - return $this->header[$key]; - } - - /** - * Returns true if the recipient header contains the parameter with the specified key. - * - * @param string $key The key - */ - public function hasHeaderParameter(string $key): bool - { - return array_key_exists($key, $this->header); - } - - /** - * Returns the encrypted key. - */ - public function getEncryptedKey(): ?string - { - return $this->encryptedKey; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/CompactSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/CompactSerializer.php deleted file mode 100644 index 6d45bcdd5..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/CompactSerializer.php +++ /dev/null @@ -1,122 +0,0 @@ -getRecipient($recipientIndex); - - $this->checkHasNoAAD($jwe); - $this->checkHasSharedProtectedHeader($jwe); - $this->checkRecipientHasNoHeader($jwe, $recipientIndex); - - return sprintf( - '%s.%s.%s.%s.%s', - $jwe->getEncodedSharedProtectedHeader(), - Base64Url::encode(null === $recipient->getEncryptedKey() ? '' : $recipient->getEncryptedKey()), - Base64Url::encode(null === $jwe->getIV() ? '' : $jwe->getIV()), - Base64Url::encode($jwe->getCiphertext()), - Base64Url::encode(null === $jwe->getTag() ? '' : $jwe->getTag()) - ); - } - - /** - * @throws InvalidArgumentException if the input is not supported - */ - public function unserialize(string $input): JWE - { - $parts = explode('.', $input); - if (5 !== count($parts)) { - throw new InvalidArgumentException('Unsupported input'); - } - - try { - $encodedSharedProtectedHeader = $parts[0]; - $sharedProtectedHeader = JsonConverter::decode(Base64Url::decode($encodedSharedProtectedHeader)); - $encryptedKey = '' === $parts[1] ? null : Base64Url::decode($parts[1]); - $iv = Base64Url::decode($parts[2]); - $ciphertext = Base64Url::decode($parts[3]); - $tag = Base64Url::decode($parts[4]); - - return new JWE( - $ciphertext, - $iv, - $tag, - null, - [], - $sharedProtectedHeader, - $encodedSharedProtectedHeader, - [new Recipient([], $encryptedKey)] - ); - } catch (Throwable $throwable) { - throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable); - } - } - - /** - * @throws LogicException if the AAD is invalid - */ - private function checkHasNoAAD(JWE $jwe): void - { - if (null !== $jwe->getAAD()) { - throw new LogicException('This JWE has AAD and cannot be converted into Compact JSON.'); - } - } - - /** - * @throws LogicException if the JWE has a shared header or recipient header (invalid for compact JSON) - */ - private function checkRecipientHasNoHeader(JWE $jwe, int $id): void - { - if (0 !== count($jwe->getSharedHeader()) || 0 !== count($jwe->getRecipient($id)->getHeader())) { - throw new LogicException('This JWE has shared header parameters or recipient header parameters and cannot be converted into Compact JSON.'); - } - } - - /** - * @throws LogicException if the JWE has no shared protected header (invalid for compact JSON) - */ - private function checkHasSharedProtectedHeader(JWE $jwe): void - { - if (0 === count($jwe->getSharedProtectedHeader())) { - throw new LogicException('This JWE does not have shared protected header parameters and cannot be converted into Compact JSON.'); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONFlattenedSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONFlattenedSerializer.php deleted file mode 100644 index b1164f213..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONFlattenedSerializer.php +++ /dev/null @@ -1,111 +0,0 @@ -getRecipient($recipientIndex); - $data = [ - 'ciphertext' => Base64Url::encode($jwe->getCiphertext()), - 'iv' => Base64Url::encode($jwe->getIV()), - 'tag' => Base64Url::encode($jwe->getTag()), - ]; - if (null !== $jwe->getAAD()) { - $data['aad'] = Base64Url::encode($jwe->getAAD()); - } - if (0 !== count($jwe->getSharedProtectedHeader())) { - $data['protected'] = $jwe->getEncodedSharedProtectedHeader(); - } - if (0 !== count($jwe->getSharedHeader())) { - $data['unprotected'] = $jwe->getSharedHeader(); - } - if (0 !== count($recipient->getHeader())) { - $data['header'] = $recipient->getHeader(); - } - if (null !== $recipient->getEncryptedKey()) { - $data['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey()); - } - - return JsonConverter::encode($data); - } - - public function unserialize(string $input): JWE - { - $data = JsonConverter::decode($input); - $this->checkData($data); - - $ciphertext = Base64Url::decode($data['ciphertext']); - $iv = Base64Url::decode($data['iv']); - $tag = Base64Url::decode($data['tag']); - $aad = array_key_exists('aad', $data) ? Base64Url::decode($data['aad']) : null; - [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data); - $encryptedKey = array_key_exists('encrypted_key', $data) ? Base64Url::decode($data['encrypted_key']) : null; - $header = array_key_exists('header', $data) ? $data['header'] : []; - - return new JWE( - $ciphertext, - $iv, - $tag, - $aad, - $sharedHeader, - $sharedProtectedHeader, - $encodedSharedProtectedHeader, - [new Recipient($header, $encryptedKey)] - ); - } - - /** - * @throws InvalidArgumentException if the payload cannot be encoded - */ - private function checkData(?array $data): void - { - if (null === $data || !isset($data['ciphertext']) || isset($data['recipients'])) { - throw new InvalidArgumentException('Unsupported input.'); - } - } - - private function processHeaders(array $data): array - { - $encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null; - $sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode(Base64Url::decode($encodedSharedProtectedHeader)) : []; - $sharedHeader = $data['unprotected'] ?? []; - - return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONGeneralSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONGeneralSerializer.php deleted file mode 100644 index 65657f91c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JSONGeneralSerializer.php +++ /dev/null @@ -1,131 +0,0 @@ -countRecipients()) { - throw new LogicException('No recipient.'); - } - - $data = [ - 'ciphertext' => Base64Url::encode($jwe->getCiphertext()), - 'iv' => Base64Url::encode($jwe->getIV()), - 'tag' => Base64Url::encode($jwe->getTag()), - ]; - if (null !== $jwe->getAAD()) { - $data['aad'] = Base64Url::encode($jwe->getAAD()); - } - if (0 !== count($jwe->getSharedProtectedHeader())) { - $data['protected'] = $jwe->getEncodedSharedProtectedHeader(); - } - if (0 !== count($jwe->getSharedHeader())) { - $data['unprotected'] = $jwe->getSharedHeader(); - } - $data['recipients'] = []; - foreach ($jwe->getRecipients() as $recipient) { - $temp = []; - if (0 !== count($recipient->getHeader())) { - $temp['header'] = $recipient->getHeader(); - } - if (null !== $recipient->getEncryptedKey()) { - $temp['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey()); - } - $data['recipients'][] = $temp; - } - - return JsonConverter::encode($data); - } - - public function unserialize(string $input): JWE - { - $data = JsonConverter::decode($input); - $this->checkData($data); - - $ciphertext = Base64Url::decode($data['ciphertext']); - $iv = Base64Url::decode($data['iv']); - $tag = Base64Url::decode($data['tag']); - $aad = array_key_exists('aad', $data) ? Base64Url::decode($data['aad']) : null; - [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data); - $recipients = []; - foreach ($data['recipients'] as $recipient) { - [$encryptedKey, $header] = $this->processRecipient($recipient); - $recipients[] = new Recipient($header, $encryptedKey); - } - - return new JWE( - $ciphertext, - $iv, - $tag, - $aad, - $sharedHeader, - $sharedProtectedHeader, - $encodedSharedProtectedHeader, - $recipients - ); - } - - /** - * @throws InvalidArgumentException if the input is not supported - */ - private function checkData(?array $data): void - { - if (null === $data || !isset($data['ciphertext']) || !isset($data['recipients'])) { - throw new InvalidArgumentException('Unsupported input.'); - } - } - - private function processRecipient(array $recipient): array - { - $encryptedKey = array_key_exists('encrypted_key', $recipient) ? Base64Url::decode($recipient['encrypted_key']) : null; - $header = array_key_exists('header', $recipient) ? $recipient['header'] : []; - - return [$encryptedKey, $header]; - } - - private function processHeaders(array $data): array - { - $encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null; - $sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode(Base64Url::decode($encodedSharedProtectedHeader)) : []; - $sharedHeader = array_key_exists('unprotected', $data) ? $data['unprotected'] : []; - - return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializer.php deleted file mode 100644 index aa9c341ac..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializer.php +++ /dev/null @@ -1,44 +0,0 @@ -add($serializer); - } - } - - /** - * Return the serializer names supported by the manager. - * - * @return string[] - */ - public function names(): array - { - return array_keys($this->serializers); - } - - /** - * Converts a JWE into a string. - * Throws an exception if none of the serializer was able to convert the input. - * - * @throws InvalidArgumentException if the serializer is not supported - */ - public function serialize(string $name, JWE $jws, ?int $recipientIndex = null): string - { - if (!isset($this->serializers[$name])) { - throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); - } - - return $this->serializers[$name]->serialize($jws, $recipientIndex); - } - - /** - * Loads data and return a JWE object. - * Throws an exception if none of the serializer was able to convert the input. - * - * @param string $input A string that represents a JWE - * @param null|string $name the name of the serializer if the input is unserialized - * - * @throws InvalidArgumentException if the input cannot be loaded - */ - public function unserialize(string $input, ?string &$name = null): JWE - { - foreach ($this->serializers as $serializer) { - try { - $jws = $serializer->unserialize($input); - $name = $serializer->name(); - - return $jws; - } catch (InvalidArgumentException $e) { - continue; - } - } - - throw new InvalidArgumentException('Unsupported input.'); - } - - /** - * Adds a serializer to the manager. - */ - private function add(JWESerializer $serializer): void - { - $this->serializers[$serializer->name()] = $serializer; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-encryption/composer.json index 91b7ddee0..2130537b5 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/composer.json +++ b/lam/lib/3rdParty/composer/web-token/jwt-encryption/composer.json @@ -1,36 +1,39 @@ { "name": "web-token/jwt-encryption", - "description": "Encryption component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "type": "library", "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], "homepage": "https://github.com/web-token", "authors": [ { "name": "Florent Morselli", "homepage": "https://github.com/Spomky" - },{ + }, + { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-encryption/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "autoload": { - "psr-4": { - "Jose\\Component\\Encryption\\": "" - } - }, "require": { - "web-token/jwt-core": "^2.1" - }, - "suggest": { - "web-token/jwt-encryption-algorithm-aescbc": "AES CBC Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcm": "AES GCM Based Content Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aesgcmkw": "AES GCM Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-aeskw": "AES Key Wrapping Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-dir": "Direct Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-ecdh-es": "ECDH-ES Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-pbes2": "PBES2 Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-rsa": "RSA Based Key Encryption Algorithms", - "web-token/jwt-encryption-algorithm-experimental": "Experimental Key and Signature Algorithms" + "php": ">=8.1", + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/AlgorithmAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/AlgorithmAnalyzer.php deleted file mode 100644 index edb88888c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/AlgorithmAnalyzer.php +++ /dev/null @@ -1,26 +0,0 @@ -has('alg')) { - $bag->add(Message::medium('The parameter "alg" should be added.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES256KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES256KeyAnalyzer.php deleted file mode 100644 index 2b7b71c49..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES256KeyAnalyzer.php +++ /dev/null @@ -1,61 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('crv')) { - $bag->add(Message::high('Invalid key. The components "crv" is missing.')); - - return; - } - if ('P-256' !== $jwk->get('crv')) { - return; - } - $x = Base64Url::decode($jwk->get('x')); - $xLength = 8 * mb_strlen($x, '8bit'); - $y = Base64Url::decode($jwk->get('y')); - $yLength = 8 * mb_strlen($y, '8bit'); - if ($yLength !== $xLength || 256 !== $yLength) { - $bag->add(Message::high('Invalid key. The components "x" and "y" size shall be 256 bits.')); - } - $xBI = BigInteger::fromBase(bin2hex($x), 16); - $yBI = BigInteger::fromBase(bin2hex($y), 16); - $curve = NistCurve::curve256(); - if (!$curve->contains($xBI, $yBI)) { - $bag->add(Message::high('Invalid key. The point is not on the curve.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES384KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES384KeyAnalyzer.php deleted file mode 100644 index 70bd52c57..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES384KeyAnalyzer.php +++ /dev/null @@ -1,61 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('crv')) { - $bag->add(Message::high('Invalid key. The components "crv" is missing.')); - - return; - } - if ('P-384' !== $jwk->get('crv')) { - return; - } - $x = Base64Url::decode($jwk->get('x')); - $xLength = 8 * mb_strlen($x, '8bit'); - $y = Base64Url::decode($jwk->get('y')); - $yLength = 8 * mb_strlen($y, '8bit'); - if ($yLength !== $xLength || 384 !== $yLength) { - $bag->add(Message::high('Invalid key. The components "x" and "y" size shall be 384 bits.')); - } - $xBI = BigInteger::fromBase(bin2hex($x), 16); - $yBI = BigInteger::fromBase(bin2hex($y), 16); - $curve = NistCurve::curve384(); - if (!$curve->contains($xBI, $yBI)) { - $bag->add(Message::high('Invalid key. The point is not on the curve.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES512KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES512KeyAnalyzer.php deleted file mode 100644 index b729dee2f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ES512KeyAnalyzer.php +++ /dev/null @@ -1,61 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('crv')) { - $bag->add(Message::high('Invalid key. The components "crv" is missing.')); - - return; - } - if ('P-521' !== $jwk->get('crv')) { - return; - } - $x = Base64Url::decode($jwk->get('x')); - $xLength = 8 * mb_strlen($x, '8bit'); - $y = Base64Url::decode($jwk->get('y')); - $yLength = 8 * mb_strlen($y, '8bit'); - if ($yLength !== $xLength || 528 !== $yLength) { - $bag->add(Message::high('Invalid key. The components "x" and "y" size shall be 528 bits.')); - } - $xBI = BigInteger::fromBase(bin2hex($x), 16); - $yBI = BigInteger::fromBase(bin2hex($y), 16); - $curve = NistCurve::curve521(); - if (!$curve->contains($xBI, $yBI)) { - $bag->add(Message::high('Invalid key. The point is not on the curve.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS256KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS256KeyAnalyzer.php deleted file mode 100644 index 4e4e4851c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS256KeyAnalyzer.php +++ /dev/null @@ -1,35 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('alg') || 'HS256' !== $jwk->get('alg')) { - return; - } - $k = Base64Url::decode($jwk->get('k')); - $kLength = 8 * mb_strlen($k, '8bit'); - if ($kLength < 256) { - $bag->add(Message::high('HS256 algorithm requires at least 256 bits key length.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS384KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS384KeyAnalyzer.php deleted file mode 100644 index 75174e960..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS384KeyAnalyzer.php +++ /dev/null @@ -1,35 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('alg') || 'HS384' !== $jwk->get('alg')) { - return; - } - $k = Base64Url::decode($jwk->get('k')); - $kLength = 8 * mb_strlen($k, '8bit'); - if ($kLength < 384) { - $bag->add(Message::high('HS384 algorithm requires at least 384 bits key length.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS512KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS512KeyAnalyzer.php deleted file mode 100644 index 1147aecc7..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/HS512KeyAnalyzer.php +++ /dev/null @@ -1,35 +0,0 @@ -get('kty')) { - return; - } - if (!$jwk->has('alg') || 'HS512' !== $jwk->get('alg')) { - return; - } - $k = Base64Url::decode($jwk->get('k')); - $kLength = 8 * mb_strlen($k, '8bit'); - if ($kLength < 512) { - $bag->add(Message::high('HS512 algorithm requires at least 512 bits key length.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyAnalyzer.php deleted file mode 100644 index 978c57d90..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyAnalyzer.php +++ /dev/null @@ -1,24 +0,0 @@ -analyzers[] = $analyzer; - } - - /** - * This method will analyze the JWK object using all analyzers. - * It returns a message bag that may contains messages. - */ - public function analyze(JWK $jwk): MessageBag - { - $bag = new MessageBag(); - foreach ($this->analyzers as $analyzer) { - $analyzer->analyze($jwk, $bag); - } - - return $bag; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyIdentifierAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyIdentifierAnalyzer.php deleted file mode 100644 index a4e7708b6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeyIdentifierAnalyzer.php +++ /dev/null @@ -1,26 +0,0 @@ -has('kid')) { - $bag->add(Message::medium('The parameter "kid" should be added.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeysetAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeysetAnalyzer.php deleted file mode 100644 index 6447e1031..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/KeysetAnalyzer.php +++ /dev/null @@ -1,24 +0,0 @@ -analyzers[] = $analyzer; - } - - /** - * This method will analyze the JWKSet object using all analyzers. - * It returns a message bag that may contains messages. - */ - public function analyze(JWKSet $jwkset): MessageBag - { - $bag = new MessageBag(); - foreach ($this->analyzers as $analyzer) { - $analyzer->analyze($jwkset, $bag); - } - - return $bag; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/Message.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/Message.php deleted file mode 100644 index 19653caea..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/Message.php +++ /dev/null @@ -1,97 +0,0 @@ -message = $message; - $this->severity = $severity; - } - - /** - * Creates a message with severity=low. - * - * @return Message - */ - public static function low(string $message): self - { - return new self($message, self::SEVERITY_LOW); - } - - /** - * Creates a message with severity=medium. - * - * @return Message - */ - public static function medium(string $message): self - { - return new self($message, self::SEVERITY_MEDIUM); - } - - /** - * Creates a message with severity=high. - * - * @return Message - */ - public static function high(string $message): self - { - return new self($message, self::SEVERITY_HIGH); - } - - /** - * Returns the message. - */ - public function getMessage(): string - { - return $this->message; - } - - /** - * Returns the severity of the message. - */ - public function getSeverity(): string - { - return $this->severity; - } - - public function jsonSerialize(): array - { - return [ - 'message' => $this->message, - 'severity' => $this->severity, - ]; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MessageBag.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MessageBag.php deleted file mode 100644 index 515ac7fd7..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MessageBag.php +++ /dev/null @@ -1,71 +0,0 @@ -messages[] = $message; - } - - /** - * Returns all messages. - * - * @return Message[] - */ - public function all(): array - { - return $this->messages; - } - - /** - * {@inheritdoc} - */ - public function jsonSerialize(): array - { - return array_values($this->messages); - } - - /** - * {@inheritdoc} - */ - public function count(): int - { - return count($this->messages); - } - - /** - * {@inheritdoc} - */ - public function getIterator(): Traversable - { - return new ArrayIterator($this->messages); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/NoneAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/NoneAnalyzer.php deleted file mode 100644 index 38b33f28c..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/NoneAnalyzer.php +++ /dev/null @@ -1,28 +0,0 @@ -get('kty')) { - return; - } - - $bag->add(Message::high('This key is a meant to be used with the algorithm "none". This algorithm is not secured and should be used with care.')); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/OctAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/OctAnalyzer.php deleted file mode 100644 index 70a4761a9..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/OctAnalyzer.php +++ /dev/null @@ -1,32 +0,0 @@ -get('kty')) { - return; - } - $k = Base64Url::decode($jwk->get('k')); - $kLength = 8 * mb_strlen($k, '8bit'); - if ($kLength < 128) { - $bag->add(Message::high('The key length is less than 128 bits.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/RsaAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/RsaAnalyzer.php deleted file mode 100644 index 2a5743bfd..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/RsaAnalyzer.php +++ /dev/null @@ -1,54 +0,0 @@ -get('kty')) { - return; - } - - $this->checkExponent($jwk, $bag); - $this->checkModulus($jwk, $bag); - } - - private function checkExponent(JWK $jwk, MessageBag $bag): void - { - $exponent = unpack('l', str_pad(Base64Url::decode($jwk->get('e')), 4, "\0")); - if (!is_array($exponent) || !isset($exponent[1])) { - throw new InvalidArgumentException('Unable to get the private key'); - } - if ($exponent[1] < 65537) { - $bag->add(Message::high('The exponent is too low. It should be at least 65537.')); - } - } - - private function checkModulus(JWK $jwk, MessageBag $bag): void - { - $n = 8 * mb_strlen(Base64Url::decode($jwk->get('n')), '8bit'); - if ($n < 2048) { - $bag->add(Message::high('The key length is less than 2048 bits.')); - } - if ($jwk->has('d') && (!$jwk->has('p') || !$jwk->has('q') || !$jwk->has('dp') || !$jwk->has('dq') || !$jwk->has('p') || !$jwk->has('qi'))) { - $bag->add(Message::medium('The key is a private RSA key, but Chinese Remainder Theorem primes are missing. These primes are not mandatory, but signatures and decryption processes are faster when available.')); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/UsageAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/UsageAnalyzer.php deleted file mode 100644 index 2edb19fe6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/UsageAnalyzer.php +++ /dev/null @@ -1,32 +0,0 @@ -has('use')) { - $bag->add(Message::medium('The parameter "use" should be added.')); - } elseif (!in_array($jwk->get('use'), ['sig', 'enc'], true)) { - $bag->add(Message::high(sprintf('The parameter "use" has an unsupported value "%s". Please use "sig" (signature) or "enc" (encryption).', $jwk->get('use')))); - } - if ($jwk->has('key_ops') && !in_array($jwk->get('key_ops'), ['sign', 'verify', 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], true)) { - $bag->add(Message::high(sprintf('The parameter "key_ops" has an unsupported value "%s". Please use one of the following values: %s.', $jwk->get('use'), implode(', ', ['verify', 'sign', 'encryp', 'decrypt', 'wrapKey', 'unwrapKey'])))); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ZxcvbnKeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ZxcvbnKeyAnalyzer.php deleted file mode 100644 index 66a0457d9..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/ZxcvbnKeyAnalyzer.php +++ /dev/null @@ -1,48 +0,0 @@ -get('kty')) { - return; - } - $k = Base64Url::decode($jwk->get('k')); - if (class_exists(Zxcvbn::class)) { - $zxcvbn = new Zxcvbn(); - $strength = $zxcvbn->passwordStrength($k); - - switch (true) { - case $strength['score'] < 3: - $bag->add(Message::high('The octet string is weak and easily guessable. Please change your key as soon as possible.')); - - break; - - case 3 === $strength['score']: - $bag->add(Message::medium('The octet string is safe, but a longer key is preferable.')); - - break; - - default: - break; - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JKUFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JKUFactory.php deleted file mode 100644 index 6f404c7f2..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JKUFactory.php +++ /dev/null @@ -1,39 +0,0 @@ -getContent($url, $header); - $data = JsonConverter::decode($content); - if (!is_array($data)) { - throw new RuntimeException('Invalid content.'); - } - - return JWKSet::createFromKeyData($data); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JWKFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JWKFactory.php deleted file mode 100644 index 4620089ed..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/JWKFactory.php +++ /dev/null @@ -1,328 +0,0 @@ - $size) { - throw new InvalidArgumentException('Key length is too short. It needs to be at least 512 bits.'); - } - - $key = openssl_pkey_new([ - 'private_key_bits' => $size, - 'private_key_type' => OPENSSL_KEYTYPE_RSA, - ]); - if (false === $key) { - throw new InvalidArgumentException('Unable to create the key'); - } - $details = openssl_pkey_get_details($key); - if (!is_array($details)) { - throw new InvalidArgumentException('Unable to create the key'); - } - $rsa = RSAKey::createFromKeyDetails($details['rsa']); - $values = array_merge( - $values, - $rsa->toArray() - ); - - return new JWK($values); - } - - /** - * Creates a EC key with the given curve and additional values. - * - * @param string $curve The curve - * @param array $values values to configure the key - */ - public static function createECKey(string $curve, array $values = []): JWK - { - return ECKey::createECKey($curve, $values); - } - - /** - * Creates a octet key with the given key size and additional values. - * - * @param int $size The key size in bits - * @param array $values values to configure the key - * - * @throws InvalidArgumentException if the key has an invalid size - */ - public static function createOctKey(int $size, array $values = []): JWK - { - if (0 !== $size % 8) { - throw new InvalidArgumentException('Invalid key size.'); - } - $values = array_merge( - $values, - [ - 'kty' => 'oct', - 'k' => Base64Url::encode(random_bytes($size / 8)), - ] - ); - - return new JWK($values); - } - - /** - * Creates a OKP key with the given curve and additional values. - * - * @param string $curve The curve - * @param array $values values to configure the key - * - * @throws InvalidArgumentException if the extension "sobium" is not available - * @throws InvalidArgumentException if the curve is not supported - */ - public static function createOKPKey(string $curve, array $values = []): JWK - { - if (!extension_loaded('sodium')) { - throw new RuntimeException('The extension "sodium" is not available. Please install it to use this method'); - } - - switch ($curve) { - case 'X25519': - $keyPair = sodium_crypto_box_keypair(); - $secret = sodium_crypto_box_secretkey($keyPair); - $x = sodium_crypto_box_publickey($keyPair); - - break; - - case 'Ed25519': - $keyPair = sodium_crypto_sign_keypair(); - $secret = sodium_crypto_sign_secretkey($keyPair); - $x = sodium_crypto_sign_publickey($keyPair); - - break; - - default: - throw new InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve)); - } - $secretLength = mb_strlen($secret, '8bit'); - $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); - - $values = array_merge( - $values, - [ - 'kty' => 'OKP', - 'crv' => $curve, - 'd' => Base64Url::encode($d), - 'x' => Base64Url::encode($x), - ] - ); - - return new JWK($values); - } - - /** - * Creates a none key with the given additional values. - * Please note that this key type is not pat of any specification. - * It is used to prevent the use of the "none" algorithm with other key types. - * - * @param array $values values to configure the key - */ - public static function createNoneKey(array $values = []): JWK - { - $values = array_merge( - $values, - [ - 'kty' => 'none', - 'alg' => 'none', - 'use' => 'sig', - ] - ); - - return new JWK($values); - } - - /** - * Creates a key from a Json string. - * - * @throws InvalidArgumentException if the key or keyset is not valid - * - * @return JWK|JWKSet - */ - public static function createFromJsonObject(string $value) - { - $json = json_decode($value, true); - if (!is_array($json)) { - throw new InvalidArgumentException('Invalid key or key set.'); - } - - return self::createFromValues($json); - } - - /** - * Creates a key or key set from the given input. - * - * @return JWK|JWKSet - */ - public static function createFromValues(array $values) - { - if (array_key_exists('keys', $values) && is_array($values['keys'])) { - return JWKSet::createFromKeyData($values); - } - - return new JWK($values); - } - - /** - * This method create a JWK object using a shared secret. - */ - public static function createFromSecret(string $secret, array $additional_values = []): JWK - { - $values = array_merge( - $additional_values, - [ - 'kty' => 'oct', - 'k' => Base64Url::encode($secret), - ] - ); - - return new JWK($values); - } - - /** - * This method will try to load a X.509 certificate and convert it into a public key. - */ - public static function createFromCertificateFile(string $file, array $additional_values = []): JWK - { - $values = KeyConverter::loadKeyFromCertificateFile($file); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } - - /** - * Extract a keyfrom a key set identified by the given index . - * - * @param int|string $index - */ - public static function createFromKeySet(JWKSet $jwkset, $index): JWK - { - return $jwkset->get($index); - } - - /** - * This method will try to load a PKCS#12 file and convert it into a public key. - * - * @throws InvalidArgumentException if the certificate cannot be loaded - */ - public static function createFromPKCS12CertificateFile(string $file, ?string $secret = '', array $additional_values = []): JWK - { - try { - $content = file_get_contents($file); - if (!is_string($content)) { - throw new RuntimeException('Unable to read the file.'); - } - openssl_pkcs12_read($content, $certs, $secret); - } catch (Throwable $throwable) { - throw new RuntimeException('Unable to load the certificates.', $throwable->getCode(), $throwable); - } - if (!is_array($certs) || !array_key_exists('pkey', $certs)) { - throw new RuntimeException('Unable to load the certificates.'); - } - - return self::createFromKey($certs['pkey'], null, $additional_values); - } - - /** - * This method will try to convert a X.509 certificate into a public key. - */ - public static function createFromCertificate(string $certificate, array $additional_values = []): JWK - { - $values = KeyConverter::loadKeyFromCertificate($certificate); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } - - /** - * This method will try to convert a X.509 certificate resource into a public key. - * - * @param resource $res - */ - public static function createFromX509Resource($res, array $additional_values = []): JWK - { - $values = KeyConverter::loadKeyFromX509Resource($res); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } - - /** - * This method will try to load and convert a key file into a JWK object. - * If the key is encrypted, the password must be set. - */ - public static function createFromKeyFile(string $file, ?string $password = null, array $additional_values = []): JWK - { - $values = KeyConverter::loadFromKeyFile($file, $password); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } - - /** - * This method will try to load and convert a key into a JWK object. - * If the key is encrypted, the password must be set. - */ - public static function createFromKey(string $key, ?string $password = null, array $additional_values = []): JWK - { - $values = KeyConverter::loadFromKey($key, $password); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } - - /** - * This method will try to load and convert a X.509 certificate chain into a public key. - * - * Be careful! The certificate chain is loaded, but it is NOT VERIFIED by any mean! - * It is mandatory to verify the root CA or intermediate CA are trusted. - * If not done, it may lead to potential security issues. - */ - public static function createFromX5C(array $x5c, array $additional_values = []): JWK - { - $values = KeyConverter::loadFromX5C($x5c); - $values = array_merge($values, $additional_values); - - return new JWK($values); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/ECKey.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/ECKey.php deleted file mode 100644 index a93501b5e..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/ECKey.php +++ /dev/null @@ -1,307 +0,0 @@ -loadJWK($data); - } - - public static function createFromPEM(string $pem): self - { - $data = self::loadPEM($pem); - - return new self($data); - } - - /** - * @param ECKey $private - * - * @return ECKey - */ - public static function toPublic(self $private): self - { - $data = $private->toArray(); - if (array_key_exists('d', $data)) { - unset($data['d']); - } - - return new self($data); - } - - /** - * @return array - */ - public function toArray() - { - return $this->values; - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - * @throws ParserException if the key cannot be loaded - */ - private static function loadPEM(string $data): array - { - $data = base64_decode(preg_replace('#-.*-|\r|\n#', '', $data), true); - $asnObject = ASNObject::fromBinary($data); - if (!$asnObject instanceof Sequence) { - throw new InvalidArgumentException('Unable to load the key.'); - } - $children = $asnObject->getChildren(); - if (self::isPKCS8($children)) { - $children = self::loadPKCS8($children); - } - - if (4 === count($children)) { - return self::loadPrivatePEM($children); - } - if (2 === count($children)) { - return self::loadPublicPEM($children); - } - - throw new InvalidArgumentException('Unable to load the key.'); - } - - /** - * @param ASNObject[] $children - * - * @throws InvalidArgumentException if the key cannot be loaded - * @throws ParserException if the key cannot be loaded - */ - private static function loadPKCS8(array $children): array - { - $binary = hex2bin($children[2]->getContent()); - $asnObject = ASNObject::fromBinary($binary); - if (!$asnObject instanceof Sequence) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - return $asnObject->getChildren(); - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function loadPublicPEM(array $children): array - { - if (!$children[0] instanceof Sequence) { - throw new InvalidArgumentException('Unsupported key type.'); - } - - $sub = $children[0]->getChildren(); - if (!$sub[0] instanceof ObjectIdentifier) { - throw new InvalidArgumentException('Unsupported key type.'); - } - if ('1.2.840.10045.2.1' !== $sub[0]->getContent()) { - throw new InvalidArgumentException('Unsupported key type.'); - } - if (!$sub[1] instanceof ObjectIdentifier) { - throw new InvalidArgumentException('Unsupported key type.'); - } - if (!$children[1] instanceof BitString) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $bits = $children[1]->getContent(); - $bits_length = mb_strlen($bits, '8bit'); - if (0 !== mb_strpos($bits, '04', 0, '8bit')) { - throw new InvalidArgumentException('Unsupported key type'); - } - - $values = ['kty' => 'EC']; - $values['crv'] = self::getCurve($sub[1]->getContent()); - - $xBin = hex2bin(mb_substr($bits, 2, ($bits_length - 2) / 2, '8bit')); - $yBin = hex2bin(mb_substr($bits, (int) (($bits_length - 2) / 2 + 2), ($bits_length - 2) / 2, '8bit')); - if (!is_string($xBin) || !is_string($yBin)) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $values['x'] = Base64Url::encode($xBin); - $values['y'] = Base64Url::encode($yBin); - - return $values; - } - - /** - * @throws InvalidArgumentException if the OID is not supported - */ - private static function getCurve(string $oid): string - { - $curves = self::getSupportedCurves(); - $curve = array_search($oid, $curves, true); - if (!is_string($curve)) { - throw new InvalidArgumentException('Unsupported OID.'); - } - - return $curve; - } - - private static function getSupportedCurves(): array - { - return [ - 'P-256' => '1.2.840.10045.3.1.7', - 'P-384' => '1.3.132.0.34', - 'P-521' => '1.3.132.0.35', - ]; - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function verifyVersion(ASNObject $children): void - { - if (!$children instanceof Integer || '1' !== $children->getContent()) { - throw new InvalidArgumentException('Unable to load the key.'); - } - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function getXAndY(ASNObject $children, string &$x, string &$y): void - { - if (!$children instanceof ExplicitlyTaggedObject || !is_array($children->getContent())) { - throw new InvalidArgumentException('Unable to load the key.'); - } - if (!$children->getContent()[0] instanceof BitString) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $bits = $children->getContent()[0]->getContent(); - $bits_length = mb_strlen($bits, '8bit'); - - if (0 !== mb_strpos($bits, '04', 0, '8bit')) { - throw new InvalidArgumentException('Unsupported key type'); - } - - $x = mb_substr($bits, 2, (int) (($bits_length - 2) / 2), '8bit'); - $y = mb_substr($bits, (int) (($bits_length - 2) / 2 + 2), (int) (($bits_length - 2) / 2), '8bit'); - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function getD(ASNObject $children): string - { - if (!$children instanceof OctetString) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - return $children->getContent(); - } - - /** - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function loadPrivatePEM(array $children): array - { - self::verifyVersion($children[0]); - $x = ''; - $y = ''; - $d = self::getD($children[1]); - self::getXAndY($children[3], $x, $y); - - if (!$children[2] instanceof ExplicitlyTaggedObject || !is_array($children[2]->getContent())) { - throw new InvalidArgumentException('Unable to load the key.'); - } - if (!$children[2]->getContent()[0] instanceof ObjectIdentifier) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $curve = $children[2]->getContent()[0]->getContent(); - $dBin = hex2bin($d); - $xBin = hex2bin($x); - $yBin = hex2bin($y); - if (!is_string($dBin) || !is_string($xBin) || !is_string($yBin)) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $values = ['kty' => 'EC']; - $values['crv'] = self::getCurve($curve); - $values['d'] = Base64Url::encode($dBin); - $values['x'] = Base64Url::encode($xBin); - $values['y'] = Base64Url::encode($yBin); - - return $values; - } - - /** - * @param ASNObject[] $children - */ - private static function isPKCS8(array $children): bool - { - if (3 !== count($children)) { - return false; - } - - $classes = [0 => Integer::class, 1 => Sequence::class, 2 => OctetString::class]; - foreach ($classes as $k => $class) { - if (!$children[$k] instanceof $class) { - return false; - } - } - - return true; - } - - /** - * @throws InvalidArgumentException if the key is invalid - */ - private function loadJWK(array $jwk): void - { - $keys = [ - 'kty' => 'The key parameter "kty" is missing.', - 'crv' => 'Curve parameter is missing', - 'x' => 'Point parameters are missing.', - 'y' => 'Point parameters are missing.', - ]; - foreach ($keys as $k => $v) { - if (!array_key_exists($k, $jwk)) { - throw new InvalidArgumentException($v); - } - } - - if ('EC' !== $jwk['kty']) { - throw new InvalidArgumentException('JWK is not an Elliptic Curve key.'); - } - $this->values = $jwk; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/KeyConverter.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/KeyConverter.php deleted file mode 100644 index 4b986f242..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/KeyConverter.php +++ /dev/null @@ -1,272 +0,0 @@ - $cert) { - $x5c[$id] = '-----BEGIN CERTIFICATE-----'.PHP_EOL.chunk_split($cert, 64, PHP_EOL).'-----END CERTIFICATE-----'; - $x509 = openssl_x509_read($x5c[$id]); - if (false === $x509) { - throw new InvalidArgumentException('Unable to load the certificate chain'); - } - $parsed = openssl_x509_parse($x509); - if (false === $parsed) { - throw new InvalidArgumentException('Unable to load the certificate chain'); - } - } - - return self::loadKeyFromCertificate(reset($x5c)); - } - - private static function loadKeyFromDER(string $der, ?string $password = null): array - { - $pem = self::convertDerToPem($der); - - return self::loadKeyFromPEM($pem, $password); - } - - /** - * @throws InvalidArgumentException if the OpenSSL extension is not available - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function loadKeyFromPEM(string $pem, ?string $password = null): array - { - if (1 === preg_match('#DEK-Info: (.+),(.+)#', $pem, $matches)) { - $pem = self::decodePem($pem, $matches, $password); - } - - if (!extension_loaded('openssl')) { - throw new RuntimeException('Please install the OpenSSL extension'); - } - self::sanitizePEM($pem); - $res = openssl_pkey_get_private($pem); - if (false === $res) { - $res = openssl_pkey_get_public($pem); - } - if (false === $res) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $details = openssl_pkey_get_details($res); - if (!is_array($details) || !array_key_exists('type', $details)) { - throw new InvalidArgumentException('Unable to get details of the key'); - } - - switch ($details['type']) { - case OPENSSL_KEYTYPE_EC: - $ec_key = ECKey::createFromPEM($pem); - - return $ec_key->toArray(); - - case OPENSSL_KEYTYPE_RSA: - $rsa_key = RSAKey::createFromPEM($pem); - - return $rsa_key->toArray(); - - default: - throw new InvalidArgumentException('Unsupported key type'); - } - } - - /** - * This method modifies the PEM to get 64 char lines and fix bug with old OpenSSL versions. - */ - private static function sanitizePEM(string &$pem): void - { - preg_match_all('#(-.*-)#', $pem, $matches, PREG_PATTERN_ORDER); - $ciphertext = preg_replace('#-.*-|\r|\n| #', '', $pem); - - $pem = $matches[0][0].PHP_EOL; - $pem .= chunk_split($ciphertext, 64, PHP_EOL); - $pem .= $matches[0][1].PHP_EOL; - } - - /** - * @param string[] $matches - * - * @throws InvalidArgumentException if the password to decrypt the key is not provided - * @throws InvalidArgumentException if the key cannot be loaded - */ - private static function decodePem(string $pem, array $matches, ?string $password = null): string - { - if (null === $password) { - throw new InvalidArgumentException('Password required for encrypted keys.'); - } - - $iv = pack('H*', trim($matches[2])); - $iv_sub = mb_substr($iv, 0, 8, '8bit'); - $symkey = pack('H*', md5($password.$iv_sub)); - $symkey .= pack('H*', md5($symkey.$password.$iv_sub)); - $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $pem); - $ciphertext = base64_decode(preg_replace('#-.*-|\r|\n#', '', $key), true); - if (!is_string($ciphertext)) { - throw new InvalidArgumentException('Unable to encode the data.'); - } - - $decoded = openssl_decrypt($ciphertext, mb_strtolower($matches[1]), $symkey, OPENSSL_RAW_DATA, $iv); - if (false === $decoded) { - throw new RuntimeException('Unable to decrypt the key'); - } - $number = preg_match_all('#-{5}.*-{5}#', $pem, $result); - if (2 !== $number) { - throw new InvalidArgumentException('Unable to load the key'); - } - - $pem = $result[0][0].PHP_EOL; - $pem .= chunk_split(base64_encode($decoded), 64); - $pem .= $result[0][1].PHP_EOL; - - return $pem; - } - - private static function convertDerToPem(string $der_data): string - { - $pem = chunk_split(base64_encode($der_data), 64, PHP_EOL); - - return '-----BEGIN CERTIFICATE-----'.PHP_EOL.$pem.'-----END CERTIFICATE-----'.PHP_EOL; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/RSAKey.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/RSAKey.php deleted file mode 100644 index a52eb6427..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/KeyConverter/RSAKey.php +++ /dev/null @@ -1,263 +0,0 @@ -loadJWK($data); - } - - /** - * @return RSAKey - */ - public static function createFromKeyDetails(array $details): self - { - $values = ['kty' => 'RSA']; - $keys = [ - 'n' => 'n', - 'e' => 'e', - 'd' => 'd', - 'p' => 'p', - 'q' => 'q', - 'dp' => 'dmp1', - 'dq' => 'dmq1', - 'qi' => 'iqmp', - ]; - foreach ($details as $key => $value) { - if (in_array($key, $keys, true)) { - $value = Base64Url::encode($value); - $values[array_search($key, $keys, true)] = $value; - } - } - - return new self($values); - } - - /** - * @throws RuntimeException if the extension OpenSSL is not available - * @throws InvalidArgumentException if the key cannot be loaded - * - * @return RSAKey - */ - public static function createFromPEM(string $pem): self - { - if (!extension_loaded('openssl')) { - throw new RuntimeException('Please install the OpenSSL extension'); - } - $res = openssl_pkey_get_private($pem); - if (false === $res) { - $res = openssl_pkey_get_public($pem); - } - if (false === $res) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - $details = openssl_pkey_get_details($res); - if (!is_array($details) || !isset($details['rsa'])) { - throw new InvalidArgumentException('Unable to load the key.'); - } - - return self::createFromKeyDetails($details['rsa']); - } - - /** - * @return RSAKey - */ - public static function createFromJWK(JWK $jwk): self - { - return new self($jwk->all()); - } - - public function isPublic(): bool - { - return !array_key_exists('d', $this->values); - } - - /** - * @param RSAKey $private - * - * @return RSAKey - */ - public static function toPublic(self $private): self - { - $data = $private->toArray(); - $keys = ['p', 'd', 'q', 'dp', 'dq', 'qi']; - foreach ($keys as $key) { - if (array_key_exists($key, $data)) { - unset($data[$key]); - } - } - - return new self($data); - } - - public function toArray(): array - { - return $this->values; - } - - public function toJwk(): JWK - { - return new JWK($this->values); - } - - /** - * This method will try to add Chinese Remainder Theorem (CRT) parameters. - * With those primes, the decryption process is really fast. - */ - public function optimize(): void - { - if (array_key_exists('d', $this->values)) { - $this->populateCRT(); - } - } - - /** - * @throws InvalidArgumentException if the key is invalid or not an RSA key - */ - private function loadJWK(array $jwk): void - { - if (!array_key_exists('kty', $jwk)) { - throw new InvalidArgumentException('The key parameter "kty" is missing.'); - } - if ('RSA' !== $jwk['kty']) { - throw new InvalidArgumentException('The JWK is not a RSA key.'); - } - - $this->values = $jwk; - } - - /** - * This method adds Chinese Remainder Theorem (CRT) parameters if primes 'p' and 'q' are available. - * If 'p' and 'q' are missing, they are computed and added to the key data. - */ - private function populateCRT(): void - { - if (!array_key_exists('p', $this->values) && !array_key_exists('q', $this->values)) { - $d = BigInteger::createFromBinaryString(Base64Url::decode($this->values['d'])); - $e = BigInteger::createFromBinaryString(Base64Url::decode($this->values['e'])); - $n = BigInteger::createFromBinaryString(Base64Url::decode($this->values['n'])); - - [$p, $q] = $this->findPrimeFactors($d, $e, $n); - $this->values['p'] = Base64Url::encode($p->toBytes()); - $this->values['q'] = Base64Url::encode($q->toBytes()); - } - - if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists('qi', $this->values)) { - return; - } - - $one = BigInteger::createFromDecimal(1); - $d = BigInteger::createFromBinaryString(Base64Url::decode($this->values['d'])); - $p = BigInteger::createFromBinaryString(Base64Url::decode($this->values['p'])); - $q = BigInteger::createFromBinaryString(Base64Url::decode($this->values['q'])); - - $this->values['dp'] = Base64Url::encode($d->mod($p->subtract($one))->toBytes()); - $this->values['dq'] = Base64Url::encode($d->mod($q->subtract($one))->toBytes()); - $this->values['qi'] = Base64Url::encode($q->modInverse($p)->toBytes()); - } - - /** - * @throws RuntimeException if the prime factors cannot be found - * - * @return BigInteger[] - */ - private function findPrimeFactors(BigInteger $d, BigInteger $e, BigInteger $n): array - { - $zero = BigInteger::createFromDecimal(0); - $one = BigInteger::createFromDecimal(1); - $two = BigInteger::createFromDecimal(2); - - $k = $d->multiply($e)->subtract($one); - - if ($k->isEven()) { - $r = $k; - $t = $zero; - - do { - $r = $r->divide($two); - $t = $t->add($one); - } while ($r->isEven()); - - $found = false; - $y = null; - - for ($i = 1; $i <= 100; ++$i) { - $g = BigInteger::random($n->subtract($one)); - $y = $g->modPow($r, $n); - - if ($y->equals($one) || $y->equals($n->subtract($one))) { - continue; - } - - for ($j = $one; $j->lowerThan($t->subtract($one)); $j = $j->add($one)) { - $x = $y->modPow($two, $n); - - if ($x->equals($one)) { - $found = true; - - break; - } - - if ($x->equals($n->subtract($one))) { - continue; - } - - $y = $x; - } - - $x = $y->modPow($two, $n); - if ($x->equals($one)) { - $found = true; - - break; - } - } - if (null === $y) { - throw new InvalidArgumentException('Unable to find prime factors.'); - } - if (true === $found) { - $p = $y->subtract($one)->gcd($n); - $q = $n->divide($p); - - return [$p, $q]; - } - } - - throw new InvalidArgumentException('Unable to find prime factors.'); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/LICENSE index 37cf976b1..5ab750604 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/LICENSE +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2019 Spomky-Labs +Copyright (c) 2014-2024 Spomky-Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/README.md b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/README.md index 62651e50d..6cd4c485d 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/README.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/README.md @@ -1,14 +1,15 @@ PHP JWT Key Management Component ================================ -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. **Please do not submit any Pull Request here.** You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. # Documentation -The official documentation is available as https://web-token.spomky-labs.com/ +The official documentation is available as https://web-token.spomky-labs.com/ # Licence diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/UrlKeySetFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/UrlKeySetFactory.php deleted file mode 100644 index e880fd6c6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/UrlKeySetFactory.php +++ /dev/null @@ -1,58 +0,0 @@ -client = $client; - $this->requestFactory = $requestFactory; - } - - /** - * @throws RuntimeException if the response content is invalid - */ - protected function getContent(string $url, array $header = []): string - { - $request = $this->requestFactory->createRequest('GET', $url); - foreach ($header as $k => $v) { - $request = $request->withHeader($k, $v); - } - $response = $this->client->sendRequest($request); - - if ($response->getStatusCode() >= 400) { - throw new RuntimeException('Unable to get the key set.', $response->getStatusCode()); - } - - return $response->getBody()->getContents(); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/X5UFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/X5UFactory.php deleted file mode 100644 index 8b81c995f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/X5UFactory.php +++ /dev/null @@ -1,56 +0,0 @@ -getContent($url, $header); - $data = JsonConverter::decode($content); - if (!is_array($data)) { - throw new RuntimeException('Invalid content.'); - } - - $keys = []; - foreach ($data as $kid => $cert) { - if (false === mb_strpos($cert, '-----BEGIN CERTIFICATE-----')) { - $cert = '-----BEGIN CERTIFICATE-----'.PHP_EOL.$cert.PHP_EOL.'-----END CERTIFICATE-----'; - } - $jwk = KeyConverter::loadKeyFromCertificate($cert); - if (is_string($kid)) { - $jwk['kid'] = $kid; - $keys[$kid] = new JWK($jwk); - } else { - $keys[] = new JWK($jwk); - } - } - - return new JWKSet($keys); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/composer.json index 8a3cb3239..6257e2edf 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/composer.json +++ b/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/composer.json @@ -1,34 +1,42 @@ { "name": "web-token/jwt-key-mgmt", - "description": "Key Management component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "type": "library", "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], "homepage": "https://github.com/web-token", "authors": [ { "name": "Florent Morselli", "homepage": "https://github.com/Spomky" - },{ + }, + { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-key-mgmt/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "autoload": { - "psr-4": { - "Jose\\Component\\KeyManagement\\": "" - } - }, "require": { + "php": ">=8.1", "ext-openssl": "*", "psr/http-factory": "^1.0", "psr/http-client": "^1.0", - "web-token/jwt-core": "^2.0" - }, - "suggest": { - "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", - "web-token/jwt-util-ecc": "To use EC key analyzers.", - "php-http/message-factory": "To enable JKU/X5U support.", - "php-http/httplug": "To enable JKU/X5U support." + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/CONTRIBUTING.md new file mode 100644 index 000000000..5e80b426f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contributing + +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. +Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/FUNDING.yml new file mode 100644 index 000000000..726574c1f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: Spomky +patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-easy/.github/PULL_REQUEST_TEMPLATE.md b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from lam/lib/3rdParty/composer/web-token/jwt-easy/.github/PULL_REQUEST_TEMPLATE.md rename to lam/lib/3rdParty/composer/web-token/jwt-library/.github/PULL_REQUEST_TEMPLATE.md diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AlgorithmChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AlgorithmChecker.php new file mode 100644 index 000000000..c2d7d0319 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AlgorithmChecker.php @@ -0,0 +1,46 @@ +supportedAlgorithms, true)) { + throw new InvalidHeaderException('Unsupported algorithm.', self::HEADER_NAME, $value); + } + } + + public function supportedHeader(): string + { + return self::HEADER_NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeader; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AudienceChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AudienceChecker.php new file mode 100644 index 000000000..995a94c9d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/AudienceChecker.php @@ -0,0 +1,62 @@ +checkValue($value, InvalidClaimException::class); + } + + public function checkHeader(mixed $value): void + { + $this->checkValue($value, InvalidHeaderException::class); + } + + public function supportedClaim(): string + { + return self::CLAIM_NAME; + } + + public function supportedHeader(): string + { + return self::CLAIM_NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeader; + } + + private function checkValue(mixed $value, string $class): void + { + if (is_string($value) && $value !== $this->audience) { + throw new $class('Bad audience.', self::CLAIM_NAME, $value); + } + if (is_array($value) && ! in_array($this->audience, $value, true)) { + throw new $class('Bad audience.', self::CLAIM_NAME, $value); + } + if (! is_array($value) && ! is_string($value)) { + throw new $class('Bad audience.', self::CLAIM_NAME, $value); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/CallableChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/CallableChecker.php new file mode 100644 index 000000000..9f51b8c14 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/CallableChecker.php @@ -0,0 +1,58 @@ +callable)) { // @phpstan-ignore-line + throw new InvalidArgumentException('The $callable argument must be a callable.'); + } + } + + public function checkClaim(mixed $value): void + { + if (call_user_func($this->callable, $value) !== true) { + throw new InvalidClaimException(sprintf('The "%s" claim is invalid.', $this->key), $this->key, $value); + } + } + + public function supportedClaim(): string + { + return $this->key; + } + + public function checkHeader(mixed $value): void + { + if (call_user_func($this->callable, $value) !== true) { + throw new InvalidHeaderException(sprintf('The "%s" header is invalid.', $this->key), $this->key, $value); + } + } + + public function supportedHeader(): string + { + return $this->key; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeaderOnly; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimChecker.php new file mode 100644 index 000000000..771f6d3fc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimChecker.php @@ -0,0 +1,19 @@ +add($checker); + } + } + + /** + * This method returns all checkers handled by this manager. + * + * @return ClaimChecker[] + */ + public function getCheckers(): array + { + return $this->checkers; + } + + /** + * This method checks all the claims passed as argument. All claims are checked against the claim checkers. If one + * fails, the InvalidClaimException is thrown. + * + * This method returns an array with all checked claims. It is up to the implementor to decide use the claims that + * have not been checked. + * + * @param string[] $mandatoryClaims + */ + public function check(array $claims, array $mandatoryClaims = []): array + { + $this->checkMandatoryClaims($mandatoryClaims, $claims); + $checkedClaims = []; + foreach ($this->checkers as $claim => $checker) { + if (array_key_exists($claim, $claims)) { + $checker->checkClaim($claims[$claim]); + $checkedClaims[$claim] = $claims[$claim]; + } + } + + return $checkedClaims; + } + + private function add(ClaimChecker $checker): void + { + $claim = $checker->supportedClaim(); + $this->checkers[$claim] = $checker; + } + + /** + * @param string[] $mandatoryClaims + */ + private function checkMandatoryClaims(array $mandatoryClaims, array $claims): void + { + if (count($mandatoryClaims) === 0) { + return; + } + $diff = array_keys(array_diff_key(array_flip($mandatoryClaims), $claims)); + if (count($diff) !== 0) { + throw new MissingMandatoryClaimException(sprintf( + 'The following claims are mandatory: %s.', + implode(', ', $diff) + ), $diff); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimCheckerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimCheckerManagerFactory.php new file mode 100644 index 000000000..f6c45ac9e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimCheckerManagerFactory.php @@ -0,0 +1,68 @@ +checkers[$alias])) { + throw new InvalidArgumentException(sprintf( + 'The claim checker with the alias "%s" is not supported.', + $alias + )); + } + $checkers[] = $this->checkers[$alias]; + } + + return new ClaimCheckerManager($checkers); + } + + /** + * This method adds a claim checker to this factory. + */ + public function add(string $alias, ClaimChecker $checker): void + { + $this->checkers[$alias] = $checker; + } + + /** + * Returns all claim checker aliases supported by this factory. + * + * @return string[] + */ + public function aliases(): array + { + return array_keys($this->checkers); + } + + /** + * Returns all claim checkers supported by this factory. + * + * @return ClaimChecker[] + */ + public function all(): array + { + return $this->checkers; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimExceptionInterface.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimExceptionInterface.php new file mode 100644 index 000000000..47971d03e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/ClaimExceptionInterface.php @@ -0,0 +1,14 @@ +clock = $clock; + } + + public function checkClaim(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidClaimException('"exp" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now > $value + $this->allowedTimeDrift) { + throw new InvalidClaimException('The token expired.', self::NAME, $value); + } + } + + public function supportedClaim(): string + { + return self::NAME; + } + + public function checkHeader(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidHeaderException('"exp" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now > $value + $this->allowedTimeDrift) { + throw new InvalidHeaderException('The token expired.', self::NAME, $value); + } + } + + public function supportedHeader(): string + { + return self::NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeaderOnly; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderChecker.php new file mode 100644 index 000000000..0856235bb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderChecker.php @@ -0,0 +1,24 @@ +add($checker); + } + foreach ($tokenTypes as $tokenType) { + $this->addTokenTypeSupport($tokenType); + } + } + + /** + * This method returns all checkers handled by this manager. + * + * @return HeaderChecker[] + */ + public function getCheckers(): array + { + return $this->checkers; + } + + /** + * This method checks all the header parameters passed as argument. All header parameters are checked against the + * header parameter checkers. If one fails, the InvalidHeaderException is thrown. + * + * @param string[] $mandatoryHeaderParameters + */ + public function check(JWT $jwt, int $index, array $mandatoryHeaderParameters = []): void + { + foreach ($this->tokenTypes as $tokenType) { + if ($tokenType->supports($jwt)) { + $protected = []; + $unprotected = []; + $tokenType->retrieveTokenHeaders($jwt, $index, $protected, $unprotected); + $this->checkDuplicatedHeaderParameters($protected, $unprotected); + $this->checkMandatoryHeaderParameters($mandatoryHeaderParameters, $protected, $unprotected); + $this->checkHeaders($protected, $unprotected); + + return; + } + } + + throw new InvalidArgumentException('Unsupported token type.'); + } + + private function addTokenTypeSupport(TokenTypeSupport $tokenType): void + { + $this->tokenTypes[] = $tokenType; + } + + private function add(HeaderChecker $checker): void + { + $header = $checker->supportedHeader(); + $this->checkers[$header] = $checker; + } + + private function checkDuplicatedHeaderParameters(array $header1, array $header2): void + { + $inter = array_intersect_key($header1, $header2); + if (count($inter) !== 0) { + throw new InvalidArgumentException(sprintf( + 'The header contains duplicated entries: %s.', + implode(', ', array_keys($inter)) + )); + } + } + + /** + * @param string[] $mandatoryHeaderParameters + */ + private function checkMandatoryHeaderParameters( + array $mandatoryHeaderParameters, + array $protected, + array $unprotected + ): void { + if (count($mandatoryHeaderParameters) === 0) { + return; + } + $diff = array_keys( + array_diff_key(array_flip($mandatoryHeaderParameters), array_merge($protected, $unprotected)) + ); + if (count($diff) !== 0) { + throw new MissingMandatoryHeaderParameterException(sprintf( + 'The following header parameters are mandatory: %s.', + implode(', ', $diff) + ), $diff); + } + } + + private function checkHeaders(array $protected, array $header): void + { + $checkedHeaderParameters = []; + foreach ($this->checkers as $headerParameter => $checker) { + if ($checker->protectedHeaderOnly()) { + if (array_key_exists($headerParameter, $protected)) { + $checker->checkHeader($protected[$headerParameter]); + $checkedHeaderParameters[] = $headerParameter; + } elseif (array_key_exists($headerParameter, $header)) { + throw new InvalidHeaderException(sprintf( + 'The header parameter "%s" must be protected.', + $headerParameter + ), $headerParameter, $header[$headerParameter]); + } + } else { + if (array_key_exists($headerParameter, $protected)) { + $checker->checkHeader($protected[$headerParameter]); + $checkedHeaderParameters[] = $headerParameter; + } elseif (array_key_exists($headerParameter, $header)) { + $checker->checkHeader($header[$headerParameter]); + $checkedHeaderParameters[] = $headerParameter; + } + } + } + $this->checkCriticalHeader($protected, $header, $checkedHeaderParameters); + } + + private function checkCriticalHeader(array $protected, array $header, array $checkedHeaderParameters): void + { + if (array_key_exists('crit', $protected)) { + if (! is_array($protected['crit'])) { + throw new InvalidHeaderException( + 'The header "crit" must be a list of header parameters.', + 'crit', + $protected['crit'] + ); + } + $diff = array_diff($protected['crit'], $checkedHeaderParameters); + if (count($diff) !== 0) { + throw new InvalidHeaderException(sprintf( + 'One or more header parameters are marked as critical, but they are missing or have not been checked: %s.', + implode(', ', array_values($diff)) + ), 'crit', $protected['crit']); + } + } elseif (array_key_exists('crit', $header)) { + throw new InvalidHeaderException('The header parameter "crit" must be protected.', 'crit', $header['crit']); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderCheckerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderCheckerManagerFactory.php new file mode 100644 index 000000000..c514050d9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/HeaderCheckerManagerFactory.php @@ -0,0 +1,82 @@ +checkers[$alias])) { + throw new InvalidArgumentException(sprintf( + 'The header checker with the alias "%s" is not supported.', + $alias + )); + } + $checkers[] = $this->checkers[$alias]; + } + + return new HeaderCheckerManager($checkers, $this->tokenTypes); + } + + /** + * This method adds a header parameter checker to this factory. The checker is uniquely identified by an alias. This + * allows the same header parameter checker to be added twice (or more) using several configuration options. + */ + public function add(string $alias, HeaderChecker $checker): void + { + $this->checkers[$alias] = $checker; + } + + /** + * This method adds a token type support to this factory. + */ + public function addTokenTypeSupport(TokenTypeSupport $tokenType): void + { + $this->tokenTypes[] = $tokenType; + } + + /** + * Returns all header parameter checker aliases supported by this factory. + * + * @return string[] + */ + public function aliases(): array + { + return array_keys($this->checkers); + } + + /** + * Returns all header parameter checkers supported by this factory. + * + * @return HeaderChecker[] + */ + public function all(): array + { + return $this->checkers; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InternalClock.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InternalClock.php new file mode 100644 index 000000000..eace993fa --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InternalClock.php @@ -0,0 +1,19 @@ +claim; + } + + /** + * Returns the claim value that caused the exception. + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InvalidHeaderException.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InvalidHeaderException.php new file mode 100644 index 000000000..ae3e1d8b5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/InvalidHeaderException.php @@ -0,0 +1,37 @@ +header; + } + + /** + * Returns the header parameter value that caused the exception. + */ + public function getValue(): mixed + { + return $this->value; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IsEqualChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IsEqualChecker.php new file mode 100644 index 000000000..d826475ca --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IsEqualChecker.php @@ -0,0 +1,53 @@ +value) { + throw new InvalidClaimException(sprintf('The "%s" claim is invalid.', $this->key), $this->key, $value); + } + } + + public function supportedClaim(): string + { + return $this->key; + } + + public function checkHeader(mixed $value): void + { + if ($value !== $this->value) { + throw new InvalidHeaderException(sprintf('The "%s" header is invalid.', $this->key), $this->key, $value); + } + } + + public function supportedHeader(): string + { + return $this->key; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeaderOnly; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuedAtChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuedAtChecker.php new file mode 100644 index 000000000..4ed0fd204 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuedAtChecker.php @@ -0,0 +1,76 @@ +clock = $clock; + } + + public function checkClaim(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidClaimException('"iat" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now < $value - $this->allowedTimeDrift) { + throw new InvalidClaimException('The JWT is issued in the future.', self::NAME, $value); + } + } + + public function supportedClaim(): string + { + return self::NAME; + } + + public function checkHeader(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidHeaderException('The header "iat" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now < $value - $this->allowedTimeDrift) { + throw new InvalidHeaderException('The JWT is issued in the future.', self::NAME, $value); + } + } + + public function supportedHeader(): string + { + return self::NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeaderOnly; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuerChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuerChecker.php new file mode 100644 index 000000000..6c5a9b0f5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/IssuerChecker.php @@ -0,0 +1,58 @@ +checkValue($value, InvalidClaimException::class); + } + + public function checkHeader(mixed $value): void + { + $this->checkValue($value, InvalidHeaderException::class); + } + + public function supportedClaim(): string + { + return self::CLAIM_NAME; + } + + public function supportedHeader(): string + { + return self::CLAIM_NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeader; + } + + private function checkValue(mixed $value, string $class): void + { + if (! is_string($value)) { + throw new $class('Invalid value.', self::CLAIM_NAME, $value); + } + if (! in_array($value, $this->issuers, true)) { + throw new $class('Unknown issuer.', self::CLAIM_NAME, $value); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryClaimException.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryClaimException.php new file mode 100644 index 000000000..f58bb2cb7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryClaimException.php @@ -0,0 +1,30 @@ +claims; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryHeaderParameterException.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryHeaderParameterException.php new file mode 100644 index 000000000..0fe5f7bcc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/MissingMandatoryHeaderParameterException.php @@ -0,0 +1,30 @@ +parameters; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/NotBeforeChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/NotBeforeChecker.php new file mode 100644 index 000000000..c5b6adaf8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/NotBeforeChecker.php @@ -0,0 +1,76 @@ +clock = $clock; + } + + public function checkClaim(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidClaimException('"nbf" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now < $value - $this->allowedTimeDrift) { + throw new InvalidClaimException('The JWT can not be used yet.', self::NAME, $value); + } + } + + public function supportedClaim(): string + { + return self::NAME; + } + + public function checkHeader(mixed $value): void + { + if (! is_float($value) && ! is_int($value)) { + throw new InvalidHeaderException('"nbf" must be an integer.', self::NAME, $value); + } + + $now = $this->clock->now() + ->getTimestamp(); + if ($now < $value - $this->allowedTimeDrift) { + throw new InvalidHeaderException('The JWT can not be used yet.', self::NAME, $value); + } + } + + public function supportedHeader(): string + { + return self::NAME; + } + + public function protectedHeaderOnly(): bool + { + return $this->protectedHeaderOnly; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/TokenTypeSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/TokenTypeSupport.php new file mode 100644 index 000000000..96b179b97 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/TokenTypeSupport.php @@ -0,0 +1,31 @@ + $protectedHeader + * @param array $unprotectedHeader + */ + public function retrieveTokenHeaders( + JWT $jwt, + int $index, + array &$protectedHeader, + array &$unprotectedHeader + ): void; + + /** + * This method returns true if the token in argument is supported, otherwise false. + */ + public function supports(JWT $jwt): bool; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/UnencodedPayloadChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/UnencodedPayloadChecker.php new file mode 100644 index 000000000..91f79a224 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Checker/UnencodedPayloadChecker.php @@ -0,0 +1,34 @@ +setHelp('This command adds a key at the end of a key set.') + ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object') + ->addArgument('jwk', InputArgument::REQUIRED, 'The new JWK object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwkset = $this->getKeyset($input); + $jwk = $this->getKey($input); + $jwkset = $jwkset->with($jwk); + $this->prepareJsonOutput($input, $output, $jwkset); + + return self::SUCCESS; + } + + private function getKeyset(InputInterface $input): JWKSet + { + $jwkset = $input->getArgument('jwkset'); + if (! is_string($jwkset)) { + throw new InvalidArgumentException('The argument must be a valid JWKSet.'); + } + $json = JsonConverter::decode($jwkset); + if (! is_array($json)) { + throw new InvalidArgumentException('The argument must be a valid JWKSet.'); + } + + return JWKSet::createFromKeyData($json); + } + + private function getKey(InputInterface $input): JWK + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('The argument must be a valid JWK.'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('The argument must be a valid JWK.'); + } + + return new JWK($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeyGeneratorCommand.php new file mode 100644 index 000000000..42ff88a74 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeyGeneratorCommand.php @@ -0,0 +1,41 @@ +addArgument('curve', InputArgument::REQUIRED, 'Curve of the key.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $curve = $input->getArgument('curve'); + if (! is_string($curve)) { + throw new InvalidArgumentException('Invalid curve'); + } + $args = $this->getOptions($input); + + $jwk = JWKFactory::createECKey($curve, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeysetGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeysetGeneratorCommand.php new file mode 100644 index 000000000..5dfab7c32 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/EcKeysetGeneratorCommand.php @@ -0,0 +1,50 @@ +addArgument('quantity', InputArgument::REQUIRED, 'Quantity of keys in the key set.') + ->addArgument('curve', InputArgument::REQUIRED, 'Curve of the keys.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $quantity = (int) $input->getArgument('quantity'); + if ($quantity < 1) { + throw new InvalidArgumentException('Invalid quantity'); + } + $curve = $input->getArgument('curve'); + if (! is_string($curve)) { + throw new InvalidArgumentException('Invalid curve'); + } + + $keyset = new JWKSet([]); + for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); + $keyset = $keyset->with(JWKFactory::createECKey($curve, $args)); + } + $this->prepareJsonOutput($input, $output, $keyset); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GeneratorCommand.php new file mode 100644 index 000000000..daf7230b3 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GeneratorCommand.php @@ -0,0 +1,59 @@ +addOption('use', 'u', InputOption::VALUE_OPTIONAL, 'Usage of the key. Must be either "sig" or "enc".') + ->addOption('alg', 'a', InputOption::VALUE_OPTIONAL, 'Algorithm for the key.') + ->addOption( + 'random_id', + null, + InputOption::VALUE_NONE, + 'If this option is set, a random key ID (kid) will be generated.' + ); + } + + protected function getOptions(InputInterface $input): array + { + $args = []; + $useRandomId = $input->getOption('random_id'); + if (! is_bool($useRandomId)) { + throw new InvalidArgumentException('Invalid value for option "random_id"'); + } + if ($useRandomId) { + $args['kid'] = $this->generateKeyID(); + } + foreach (['use', 'alg'] as $key) { + $value = $input->getOption($key); + if ($value !== null) { + $args[$key] = $value; + } + } + + return $args; + } + + private function generateKeyID(): string + { + return Base64UrlSafe::encode(random_bytes(32)); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GetThumbprintCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GetThumbprintCommand.php new file mode 100644 index 000000000..31e0cdf53 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/GetThumbprintCommand.php @@ -0,0 +1,51 @@ +addArgument('jwk', InputArgument::REQUIRED, 'The JWK key.') + ->addOption('hash', null, InputOption::VALUE_OPTIONAL, 'The hashing algorithm.', 'sha256'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $hash = $input->getOption('hash'); + if (! is_string($hash)) { + throw new InvalidArgumentException('Invalid hash algorithm'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid input.'); + } + $key = new JWK($json); + $output->write($key->thumbprint($hash)); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/JKULoaderCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/JKULoaderCommand.php new file mode 100644 index 000000000..94d2f2ef9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/JKULoaderCommand.php @@ -0,0 +1,47 @@ +setHelp('This command will try to get a key set from an URL. The distant key set is a JWKSet.') + ->addArgument('url', InputArgument::REQUIRED, 'The URL'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $url = $input->getArgument('url'); + if (! is_string($url)) { + throw new InvalidArgumentException('Invalid URL'); + } + $result = $this->jkuFactory->loadFromUrl($url); + $this->prepareJsonOutput($input, $output, $result); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyAnalyzerCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyAnalyzerCommand.php new file mode 100644 index 000000000..0c269b7fa --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyAnalyzerCommand.php @@ -0,0 +1,80 @@ +setHelp('This command will analyze a JWK object and find security issues.') + ->addArgument('jwk', InputArgument::REQUIRED, 'The JWK object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->getFormatter() + ->setStyle('success', new OutputFormatterStyle('white', 'green')); + $output->getFormatter() + ->setStyle('high', new OutputFormatterStyle('white', 'red', ['bold'])); + $output->getFormatter() + ->setStyle('medium', new OutputFormatterStyle('yellow')); + $output->getFormatter() + ->setStyle('low', new OutputFormatterStyle('blue')); + $jwk = $this->getKey($input); + + $result = $this->analyzerManager->analyze($jwk); + if ($result->count() === 0) { + $output->writeln('All good! No issue found.'); + } else { + foreach ($result->all() as $message) { + $output->writeln( + '<' . $message->getSeverity() . '>* ' . $message->getMessage() . 'getSeverity() . '>' + ); + } + } + + return self::SUCCESS; + } + + private function getKey(InputInterface $input): JWK + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWK.'); + } + + return new JWK($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyFileLoaderCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyFileLoaderCommand.php new file mode 100644 index 000000000..6ed746762 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeyFileLoaderCommand.php @@ -0,0 +1,47 @@ +addArgument('file', InputArgument::REQUIRED, 'Filename of the key.') + ->addOption('secret', 's', InputOption::VALUE_OPTIONAL, 'Secret if the key is encrypted.', null); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $file = $input->getArgument('file'); + $password = $input->getOption('secret'); + if (! is_string($file)) { + throw new InvalidArgumentException('Invalid file'); + } + if ($password !== null && ! is_string($password)) { + throw new InvalidArgumentException('Invalid secret'); + } + $args = $this->getOptions($input); + + $jwk = JWKFactory::createFromKeyFile($file, $password, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeysetAnalyzerCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeysetAnalyzerCommand.php new file mode 100644 index 000000000..95dfd2f7a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/KeysetAnalyzerCommand.php @@ -0,0 +1,94 @@ +setHelp('This command will analyze a JWKSet object and find security issues.') + ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->getFormatter() + ->setStyle('success', new OutputFormatterStyle('white', 'green')); + $output->getFormatter() + ->setStyle('high', new OutputFormatterStyle('white', 'red', ['bold'])); + $output->getFormatter() + ->setStyle('medium', new OutputFormatterStyle('yellow')); + $output->getFormatter() + ->setStyle('low', new OutputFormatterStyle('blue')); + + $jwkset = $this->getKeyset($input); + + $messages = $this->keysetAnalyzerManager->analyze($jwkset); + $this->showMessages($messages, $output); + foreach ($jwkset as $kid => $jwk) { + $output->writeln(sprintf('Analysing key with index/kid "%s"', $kid)); + $messages = $this->keyAnalyzerManager->analyze($jwk); + $this->showMessages($messages, $output); + } + + return self::SUCCESS; + } + + private function showMessages(MessageBag $messages, OutputInterface $output): void + { + if ($messages->count() === 0) { + $output->writeln(' All good! No issue found.'); + } else { + foreach ($messages->all() as $message) { + $output->writeln( + ' <' . $message->getSeverity() . '>* ' . $message->getMessage() . 'getSeverity() . '>' + ); + } + } + } + + private function getKeyset(InputInterface $input): JWKSet + { + $jwkset = $input->getArgument('jwkset'); + if (! is_string($jwkset)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + $json = JsonConverter::decode($jwkset); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + + return JWKSet::createFromKeyData($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/MergeKeysetCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/MergeKeysetCommand.php new file mode 100644 index 000000000..a558ba694 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/MergeKeysetCommand.php @@ -0,0 +1,51 @@ +setHelp( + 'This command merges several key sets into one. It is very useful when you generate e.g. RSA, EC and OKP keys and you want only one key set to rule them all.' + ) + ->addArgument('jwksets', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'The JWKSet objects'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + /** @var string[] $keySets */ + $keySets = $input->getArgument('jwksets'); + $newJwkset = new JWKSet([]); + foreach ($keySets as $keySet) { + $json = JsonConverter::decode($keySet); + if (! is_array($json)) { + throw new InvalidArgumentException('The argument must be a valid JWKSet.'); + } + $jwkset = JWKSet::createFromKeyData($json); + foreach ($jwkset->all() as $jwk) { + $newJwkset = $newJwkset->with($jwk); + } + } + $this->prepareJsonOutput($input, $output, $newJwkset); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/NoneKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/NoneKeyGeneratorCommand.php new file mode 100644 index 000000000..ec1e1b59d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/NoneKeyGeneratorCommand.php @@ -0,0 +1,36 @@ +getOptions($input); + + $jwk = JWKFactory::createNoneKey($args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/ObjectOutputCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/ObjectOutputCommand.php new file mode 100644 index 000000000..12f0acb37 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/ObjectOutputCommand.php @@ -0,0 +1,20 @@ +write($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeyGeneratorCommand.php new file mode 100644 index 000000000..2601ebf9b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeyGeneratorCommand.php @@ -0,0 +1,40 @@ +addArgument('size', InputArgument::REQUIRED, 'Key size.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $size = (int) $input->getArgument('size'); + if ($size < 1) { + throw new InvalidArgumentException('Invalid size'); + } + $args = $this->getOptions($input); + + $jwk = JWKFactory::createOctKey($size, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeysetGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeysetGeneratorCommand.php new file mode 100644 index 000000000..e7dd92fae --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OctKeysetGeneratorCommand.php @@ -0,0 +1,49 @@ +addArgument('quantity', InputArgument::REQUIRED, 'Quantity of keys in the key set.') + ->addArgument('size', InputArgument::REQUIRED, 'Key size.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $quantity = (int) $input->getArgument('quantity'); + $size = (int) $input->getArgument('size'); + if ($quantity < 1) { + throw new InvalidArgumentException('Invalid quantity'); + } + if ($size < 1) { + throw new InvalidArgumentException('Invalid size'); + } + + $keyset = new JWKSet([]); + for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); + $keyset = $keyset->with(JWKFactory::createOctKey($size, $args)); + } + $this->prepareJsonOutput($input, $output, $keyset); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeyGeneratorCommand.php new file mode 100644 index 000000000..195efb7df --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeyGeneratorCommand.php @@ -0,0 +1,41 @@ +addArgument('curve', InputArgument::REQUIRED, 'Curve of the key.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $curve = $input->getArgument('curve'); + if (! is_string($curve)) { + throw new InvalidArgumentException('Invalid curve'); + } + $args = $this->getOptions($input); + + $jwk = JWKFactory::createOKPKey($curve, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeysetGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeysetGeneratorCommand.php new file mode 100644 index 000000000..a98dfd382 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OkpKeysetGeneratorCommand.php @@ -0,0 +1,53 @@ +addArgument('quantity', InputArgument::REQUIRED, 'Quantity of keys in the key set.') + ->addArgument('curve', InputArgument::REQUIRED, 'Curve of the keys.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $quantity = (int) $input->getArgument('quantity'); + $curve = $input->getArgument('curve'); + if ($quantity < 1) { + throw new InvalidArgumentException('Invalid quantity'); + } + if (! is_string($curve)) { + throw new InvalidArgumentException('Invalid curve'); + } + + $keyset = new JWKSet([]); + for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); + $keyset = $keyset->with(JWKFactory::createOKPKey($curve, $args)); + } + $this->prepareJsonOutput($input, $output, $keyset); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OptimizeRsaKeyCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OptimizeRsaKeyCommand.php new file mode 100644 index 000000000..693bc41d2 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/OptimizeRsaKeyCommand.php @@ -0,0 +1,47 @@ +addArgument('jwk', InputArgument::REQUIRED, 'The RSA key.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $key = RSAKey::createFromJWK(new JWK($json)); + $key->optimize(); + $this->prepareJsonOutput($input, $output, $key->toJwk()); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/P12CertificateLoaderCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/P12CertificateLoaderCommand.php new file mode 100644 index 000000000..92cfccddb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/P12CertificateLoaderCommand.php @@ -0,0 +1,46 @@ +addArgument('file', InputArgument::REQUIRED, 'Filename of the P12 certificate.') + ->addOption('secret', 's', InputOption::VALUE_OPTIONAL, 'Secret if the key is encrypted.', null); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $file = $input->getArgument('file'); + $password = $input->getOption('secret'); + if (! is_string($file)) { + throw new InvalidArgumentException('Invalid file'); + } + if (! is_string($password)) { + throw new InvalidArgumentException('Invalid secret'); + } + $args = $this->getOptions($input); + $jwk = JWKFactory::createFromPKCS12CertificateFile($file, $password, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PemConverterCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PemConverterCommand.php new file mode 100644 index 000000000..1fcb957bd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PemConverterCommand.php @@ -0,0 +1,53 @@ +addArgument('jwk', InputArgument::REQUIRED, 'The key'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWK.'); + } + $key = new JWK($json); + + $pem = match ($key->get('kty')) { + 'RSA' => RSAKey::createFromJWK($key)->toPEM(), + 'EC' => ECKey::convertToPEM($key), + default => throw new InvalidArgumentException('Not a RSA or EC key.'), + }; + $output->write($pem); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeyCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeyCommand.php new file mode 100644 index 000000000..fd721b723 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeyCommand.php @@ -0,0 +1,57 @@ +setHelp('This command converts a private key into a public key.') + ->addArgument('jwk', InputArgument::REQUIRED, 'The JWK object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwk = $this->getKey($input); + $jwk = $jwk->toPublic(); + + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } + + private function getKey(InputInterface $input): JWK + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWK'); + } + + return new JWK($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeysetCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeysetCommand.php new file mode 100644 index 000000000..474ebb0ac --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/PublicKeysetCommand.php @@ -0,0 +1,60 @@ +setHelp('This command converts private keys in a key set into public keys.') + ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwkset = $this->getKeyset($input); + $newJwkset = new JWKSet([]); + + foreach ($jwkset->all() as $jwk) { + $newJwkset = $newJwkset->with($jwk->toPublic()); + } + $this->prepareJsonOutput($input, $output, $newJwkset); + + return self::SUCCESS; + } + + private function getKeyset(InputInterface $input): JWKSet + { + $jwkset = $input->getArgument('jwkset'); + if (! is_string($jwkset)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + $json = JsonConverter::decode($jwkset); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + + return JWKSet::createFromKeyData($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RotateKeysetCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RotateKeysetCommand.php new file mode 100644 index 000000000..d2451f6a8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RotateKeysetCommand.php @@ -0,0 +1,77 @@ +setHelp('This command removes the last key in a key set a place a new one at the beginning.') + ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object') + ->addArgument('jwk', InputArgument::REQUIRED, 'The new JWK object'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jwkset = $this->getKeyset($input) + ->all(); + $jwk = $this->getKey($input); + + if (count($jwkset) !== 0) { + array_pop($jwkset); + } + array_unshift($jwkset, $jwk); + + $this->prepareJsonOutput($input, $output, new JWKSet($jwkset)); + + return self::SUCCESS; + } + + private function getKeyset(InputInterface $input): JWKSet + { + $jwkset = $input->getArgument('jwkset'); + if (! is_string($jwkset)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + $json = JsonConverter::decode($jwkset); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWKSet'); + } + + return JWKSet::createFromKeyData($json); + } + + private function getKey(InputInterface $input): JWK + { + $jwk = $input->getArgument('jwk'); + if (! is_string($jwk)) { + throw new InvalidArgumentException('Invalid JWK'); + } + $json = JsonConverter::decode($jwk); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid JWK'); + } + + return new JWK($json); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeyGeneratorCommand.php new file mode 100644 index 000000000..409158c47 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeyGeneratorCommand.php @@ -0,0 +1,40 @@ +addArgument('size', InputArgument::REQUIRED, 'Key size.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $size = (int) $input->getArgument('size'); + $args = $this->getOptions($input); + if ($size < 1) { + throw new InvalidArgumentException('Invalid size'); + } + + $jwk = JWKFactory::createRSAKey($size, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeysetGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeysetGeneratorCommand.php new file mode 100644 index 000000000..adf309e0e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/RsaKeysetGeneratorCommand.php @@ -0,0 +1,49 @@ +addArgument('quantity', InputArgument::REQUIRED, 'Quantity of keys in the key set.') + ->addArgument('size', InputArgument::REQUIRED, 'Key size.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $quantity = (int) $input->getArgument('quantity'); + $size = (int) $input->getArgument('size'); + if ($quantity < 1) { + throw new InvalidArgumentException('Invalid quantity'); + } + if ($size < 1) { + throw new InvalidArgumentException('Invalid size'); + } + + $keyset = new JWKSet([]); + for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); + $keyset = $keyset->with(JWKFactory::createRSAKey($size, $args)); + } + $this->prepareJsonOutput($input, $output, $keyset); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/SecretKeyGeneratorCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/SecretKeyGeneratorCommand.php new file mode 100644 index 000000000..9db7a74a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/SecretKeyGeneratorCommand.php @@ -0,0 +1,62 @@ +addArgument('secret', InputArgument::REQUIRED, 'The secret') + ->addOption( + 'is_b64', + 'b', + InputOption::VALUE_NONE, + 'Indicates if the secret is Base64 encoded (useful for binary secrets)' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $secret = $input->getArgument('secret'); + if (! is_string($secret)) { + throw new InvalidArgumentException('Invalid secret'); + } + $isBsae64Encoded = $input->getOption('is_b64'); + if (! is_bool($isBsae64Encoded)) { + throw new InvalidArgumentException('Invalid option value for "is_b64"'); + } + if ($isBsae64Encoded) { + $secret = base64_decode($secret, true); + } + if (! is_string($secret)) { + throw new InvalidArgumentException('Invalid secret'); + } + $args = $this->getOptions($input); + + $jwk = JWKFactory::createFromSecret($secret, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X509CertificateLoaderCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X509CertificateLoaderCommand.php new file mode 100644 index 000000000..d26e2d2ff --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X509CertificateLoaderCommand.php @@ -0,0 +1,47 @@ +addArgument('file', InputArgument::REQUIRED, 'Filename of the X.509 certificate.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $file = $input->getArgument('file'); + if (! is_string($file)) { + throw new InvalidArgumentException('Invalid file'); + } + $args = []; + foreach (['use', 'alg'] as $key) { + $value = $input->getOption($key); + if ($value !== null) { + $args[$key] = $value; + } + } + + $jwk = JWKFactory::createFromCertificateFile($file, $args); + $this->prepareJsonOutput($input, $output, $jwk); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X5ULoaderCommand.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X5ULoaderCommand.php new file mode 100644 index 000000000..5c7ae1670 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Console/X5ULoaderCommand.php @@ -0,0 +1,49 @@ +setHelp( + 'This command will try to get a key set from an URL. The distant key set is list of X.509 certificates.' + ) + ->addArgument('url', InputArgument::REQUIRED, 'The URL'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $url = $input->getArgument('url'); + if (! is_string($url)) { + throw new InvalidArgumentException('Invalid URL'); + } + $result = $this->x5uFactory->loadFromUrl($url); + $this->prepareJsonOutput($input, $output, $result); + + return self::SUCCESS; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Algorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Algorithm.php new file mode 100644 index 000000000..6c419cf08 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Algorithm.php @@ -0,0 +1,20 @@ + */ - private $algorithms = []; + private array $algorithms = []; /** * @param Algorithm[] $algorithms */ - public function __construct(array $algorithms) + public function __construct(iterable $algorithms) { foreach ($algorithms as $algorithm) { $this->add($algorithm); @@ -43,6 +34,14 @@ class AlgorithmManager return array_key_exists($algorithm, $this->algorithms); } + /** + * @return array + */ + public function all(): array + { + return $this->algorithms; + } + /** * Returns the list of names of supported algorithms. * @@ -57,12 +56,10 @@ class AlgorithmManager * Returns the algorithm if supported, otherwise throw an exception. * * @param string $algorithm The algorithm - * - * @throws InvalidArgumentException if the algorithm is not supported */ public function get(string $algorithm): Algorithm { - if (!$this->has($algorithm)) { + if (! $this->has($algorithm)) { throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported.', $algorithm)); } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/AlgorithmManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/AlgorithmManagerFactory.php new file mode 100644 index 000000000..4303e512c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/AlgorithmManagerFactory.php @@ -0,0 +1,82 @@ +add($algorithm->name(), $algorithm); + } + } + + /** + * Adds an algorithm. + * + * Each algorithm is identified by an alias hence it is allowed to have the same algorithm twice (or more). This can + * be helpful when an algorithm have several configuration options. + */ + public function add(string $alias, Algorithm $algorithm): void + { + $this->algorithms[$alias] = $algorithm; + } + + /** + * Returns the list of aliases. + * + * @return string[] + */ + public function aliases(): array + { + return array_keys($this->algorithms); + } + + /** + * Returns all algorithms supported by this factory. This is an associative array. Keys are the aliases of the + * algorithms. + * + * @return Algorithm[] + */ + public function all(): array + { + return $this->algorithms; + } + + /** + * Create an algorithm manager using the given aliases. + * + * @param string[] $aliases + */ + public function create(array $aliases): AlgorithmManager + { + $algorithms = []; + foreach ($aliases as $alias) { + if (! is_string($alias)) { + throw new InvalidArgumentException('Invalid alias'); + } + if (! isset($this->algorithms[$alias])) { + throw new InvalidArgumentException(sprintf( + 'The algorithm with the alias "%s" is not supported.', + $alias + )); + } + $algorithms[] = $this->algorithms[$alias]; + } + + return new AlgorithmManager($algorithms); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWK.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWK.php new file mode 100644 index 000000000..27b4bf309 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWK.php @@ -0,0 +1,127 @@ +values = $values; + } + + /** + * Creates a JWK object using the given Json string. + */ + public static function createFromJson(string $json): self + { + $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); + if (! is_array($data)) { + throw new InvalidArgumentException('Invalid argument.'); + } + + return new self($data); + } + + /** + * Returns the values to be serialized. + */ + public function jsonSerialize(): array + { + return $this->values; + } + + /** + * Get the value with a specific key. + * + * @param string $key The key + * + * @return mixed|null + */ + public function get(string $key) + { + if (! $this->has($key)) { + throw new InvalidArgumentException(sprintf('The value identified by "%s" does not exist.', $key)); + } + + return $this->values[$key]; + } + + /** + * Returns true if the JWK has the value identified by. + * + * @param string $key The key + */ + public function has(string $key): bool + { + return array_key_exists($key, $this->values); + } + + /** + * Get all values stored in the JWK object. + * + * @return array Values of the JWK object + */ + public function all(): array + { + return $this->values; + } + + /** + * Returns the thumbprint of the key. + * + * @see https://tools.ietf.org/html/rfc7638 + */ + public function thumbprint(string $hash_algorithm): string + { + if (! in_array($hash_algorithm, hash_algos(), true)) { + throw new InvalidArgumentException(sprintf('The hash algorithm "%s" is not supported.', $hash_algorithm)); + } + $values = array_intersect_key($this->values, array_flip(['kty', 'n', 'e', 'crv', 'x', 'y', 'k'])); + ksort($values); + $input = json_encode($values, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + if ($input === false) { + throw new InvalidArgumentException('Unable to compute the key thumbprint'); + } + + return Base64UrlSafe::encodeUnpadded(hash($hash_algorithm, $input, true)); + } + + /** + * Returns the associated public key. + * This method has no effect for: + * - public keys + * - shared keys + * - unknown keys. + * + * Known keys are "oct", "RSA", "EC" and "OKP". + */ + public function toPublic(): self + { + $values = array_diff_key($this->values, array_flip(['p', 'd', 'q', 'dp', 'dq', 'qi'])); + + return new self($values); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWKSet.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWKSet.php new file mode 100644 index 000000000..87e8ca022 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWKSet.php @@ -0,0 +1,296 @@ + $key) { + if (! $key instanceof JWK) { + throw new InvalidArgumentException('Invalid list. Should only contains JWK objects'); + } + + if ($key->has('kid')) { + unset($keys[$k]); + $this->keys[$key->get('kid')] = $key; + } else { + $this->keys[] = $key; + } + } + } + + /** + * Creates a JWKSet object using the given values. + */ + public static function createFromKeyData(array $data): self + { + if (! isset($data['keys'])) { + throw new InvalidArgumentException('Invalid data.'); + } + if (! is_array($data['keys'])) { + throw new InvalidArgumentException('Invalid data.'); + } + + $jwkset = new self([]); + foreach ($data['keys'] as $key) { + $jwk = new JWK($key); + if ($jwk->has('kid')) { + $jwkset->keys[$jwk->get('kid')] = $jwk; + } else { + $jwkset->keys[] = $jwk; + } + } + + return $jwkset; + } + + /** + * Creates a JWKSet object using the given Json string. + */ + public static function createFromJson(string $json): self + { + $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); + if (! is_array($data)) { + throw new InvalidArgumentException('Invalid argument.'); + } + + return self::createFromKeyData($data); + } + + /** + * Returns an array of keys stored in the key set. + * + * @return JWK[] + */ + public function all(): array + { + return $this->keys; + } + + /** + * Add key to store in the key set. This method is immutable and will return a new object. + */ + public function with(JWK $jwk): self + { + $clone = clone $this; + + if ($jwk->has('kid')) { + $clone->keys[$jwk->get('kid')] = $jwk; + } else { + $clone->keys[] = $jwk; + } + + return $clone; + } + + /** + * Remove key from the key set. This method is immutable and will return a new object. + * + * @param int|string $key Key to remove from the key set + */ + public function without(int|string $key): self + { + if (! $this->has($key)) { + return $this; + } + + $clone = clone $this; + unset($clone->keys[$key]); + + return $clone; + } + + /** + * Returns true if the key set contains a key with the given index. + */ + public function has(int|string $index): bool + { + return array_key_exists($index, $this->keys); + } + + /** + * Returns the key with the given index. Throws an exception if the index is not present in the key store. + */ + public function get(int|string $index): JWK + { + if (! $this->has($index)) { + throw new InvalidArgumentException('Undefined index.'); + } + + return $this->keys[$index]; + } + + /** + * Returns the values to be serialized. + */ + public function jsonSerialize(): array + { + return [ + 'keys' => array_values($this->keys), + ]; + } + + /** + * Returns the number of keys in the key set. + * + * @param int $mode + */ + public function count($mode = COUNT_NORMAL): int + { + return count($this->keys, $mode); + } + + /** + * Try to find a key that fits on the selected requirements. Returns null if not found. + * + * @param string $type Must be 'sig' (signature) or 'enc' (encryption) + * @param Algorithm|null $algorithm Specifies the algorithm to be used + * @param array $restrictions More restrictions such as 'kid' or 'kty' + */ + public function selectKey(string $type, ?Algorithm $algorithm = null, array $restrictions = []): ?JWK + { + if (! in_array($type, ['enc', 'sig'], true)) { + throw new InvalidArgumentException('Allowed key types are "sig" or "enc".'); + } + + $result = []; + foreach ($this->keys as $key) { + $ind = 0; + + $can_use = $this->canKeyBeUsedFor($type, $key); + if ($can_use === false) { + continue; + } + $ind += $can_use; + + $alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key); + if ($alg === false) { + continue; + } + $ind += $alg; + + if ($this->doesKeySatisfyRestrictions($restrictions, $key) === false) { + continue; + } + + $result[] = [ + 'key' => $key, + 'ind' => $ind, + ]; + } + + if (count($result) === 0) { + return null; + } + + usort($result, [$this, 'sortKeys']); + + return $result[0]['key']; + } + + /** + * Internal method only. Should not be used. + * + * @internal + */ + public static function sortKeys(array $a, array $b): int + { + return $b['ind'] <=> $a['ind']; + } + + /** + * Internal method only. Should not be used. + * + * @internal + */ + public function getIterator(): Traversable + { + return new ArrayIterator($this->keys); + } + + private function canKeyBeUsedFor(string $type, JWK $key): bool|int + { + if ($key->has('use')) { + return $type === $key->get('use') ? 1 : false; + } + if ($key->has('key_ops')) { + $key_ops = $key->get('key_ops'); + if (! is_array($key_ops)) { + throw new InvalidArgumentException( + 'Invalid key parameter "key_ops". Should be a list of key operations' + ); + } + + return $type === self::convertKeyOpsToKeyUse($key_ops) ? 1 : false; + } + + return 0; + } + + private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key): bool|int + { + if ($algorithm === null) { + return 0; + } + if (! in_array($key->get('kty'), $algorithm->allowedKeyTypes(), true)) { + return false; + } + if ($key->has('alg')) { + return $algorithm->name() === $key->get('alg') ? 2 : false; + } + + return 1; + } + + private function doesKeySatisfyRestrictions(array $restrictions, JWK $key): bool + { + foreach ($restrictions as $k => $v) { + if (! $key->has($k) || $v !== $key->get($k)) { + return false; + } + } + + return true; + } + + private static function convertKeyOpsToKeyUse(array $key_ops): string + { + return match (true) { + in_array('verify', $key_ops, true), in_array('sign', $key_ops, true) => 'sig', + in_array('encrypt', $key_ops, true), in_array('decrypt', $key_ops, true), in_array( + 'wrapKey', + $key_ops, + true + ), in_array( + 'unwrapKey', + $key_ops, + true + ), in_array('deriveKey', $key_ops, true), in_array('deriveBits', $key_ops, true) => 'enc', + default => throw new InvalidArgumentException(sprintf( + 'Unsupported key operation value "%s"', + implode(', ', $key_ops) + )), + }; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWT.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWT.php new file mode 100644 index 000000000..69e7b6b36 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/JWT.php @@ -0,0 +1,13 @@ + $chunk */ + $chunk = unpack('C*', self::safeSubstr($encodedString, $i, 4)); + $c0 = static::decode6Bits($chunk[1]); + $c1 = static::decode6Bits($chunk[2]); + $c2 = static::decode6Bits($chunk[3]); + $c3 = static::decode6Bits($chunk[4]); + + $dest .= pack( + 'CCC', + ((($c0 << 2) | ($c1 >> 4)) & 0xff), + ((($c1 << 4) | ($c2 >> 2)) & 0xff), + ((($c2 << 6) | $c3) & 0xff) + ); + $err |= ($c0 | $c1 | $c2 | $c3) >> 8; + } + + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', self::safeSubstr($encodedString, $i, $srcLen - $i)); + $c0 = static::decode6Bits($chunk[1]); + + if ($i + 2 < $srcLen) { + $c1 = static::decode6Bits($chunk[2]); + $c2 = static::decode6Bits($chunk[3]); + $dest .= pack('CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff)); + $err |= ($c0 | $c1 | $c2) >> 8; + if ($strictPadding) { + $err |= ($c2 << 6) & 0xff; + } + } elseif ($i + 1 < $srcLen) { + $c1 = static::decode6Bits($chunk[2]); + $dest .= pack('C', ((($c0 << 2) | ($c1 >> 4)) & 0xff)); + $err |= ($c0 | $c1) >> 8; + if ($strictPadding) { + $err |= ($c1 << 4) & 0xff; + } + } elseif ($strictPadding) { + $err |= 1; + } + } + $check = ($err === 0); + if (! $check) { + throw new RangeException('Base64::decode() only expects characters in the correct base64 alphabet'); + } + return $dest; + } + + public static function decodeNoPadding(string $encodedString): string + { + $srcLen = self::safeStrlen($encodedString); + if ($srcLen === 0) { + return ''; + } + if (($srcLen & 3) === 0) { + if ($encodedString[$srcLen - 1] === '=') { + throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding"); + } + if (($srcLen & 3) > 1) { + if ($encodedString[$srcLen - 2] === '=') { + throw new InvalidArgumentException("decodeNoPadding() doesn't tolerate padding"); + } + } + } + return static::decode($encodedString, true); + } + + private static function doEncode(string $src, bool $pad = true): string + { + $dest = ''; + $srcLen = self::safeStrlen($src); + for ($i = 0; $i + 3 <= $srcLen; $i += 3) { + /** @var array $chunk */ + $chunk = unpack('C*', self::safeSubstr($src, $i, 3)); + $b0 = $chunk[1]; + $b1 = $chunk[2]; + $b2 = $chunk[3]; + + $dest .= + static::encode6Bits($b0 >> 2) . + static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . + static::encode6Bits($b2 & 63); + } + + if ($i < $srcLen) { + /** @var array $chunk */ + $chunk = unpack('C*', self::safeSubstr($src, $i, $srcLen - $i)); + $b0 = $chunk[1]; + if ($i + 1 < $srcLen) { + $b1 = $chunk[2]; + $dest .= + static::encode6Bits($b0 >> 2) . + static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . + static::encode6Bits(($b1 << 2) & 63); + if ($pad) { + $dest .= '='; + } + } else { + $dest .= + static::encode6Bits($b0 >> 2) . + static::encode6Bits(($b0 << 4) & 63); + if ($pad) { + $dest .= '=='; + } + } + } + return $dest; + } + + private static function decode6Bits(int $src): int + { + $ret = -1; + $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); + $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); + $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); + $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; + + return $ret + ((((0x5e - $src) & ($src - 0x60)) >> 8) & 64); + } + + private static function encode6Bits(int $src): string + { + $diff = 0x41; + $diff += ((25 - $src) >> 8) & 6; + $diff -= ((51 - $src) >> 8) & 75; + $diff -= ((61 - $src) >> 8) & 13; + $diff += ((62 - $src) >> 8) & 49; + + return pack('C', $src + $diff); + } + + private static function safeStrlen(string $str): int + { + return mb_strlen($str, '8bit'); + } + + private static function safeSubstr(string $str, int $start = 0, $length = null): string + { + if ($length === 0) { + return ''; + } + return mb_substr($str, $start, $length, '8bit'); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/BigInteger.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/BigInteger.php new file mode 100644 index 000000000..5bbea7c2a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/BigInteger.php @@ -0,0 +1,163 @@ +value->isEqualTo(BrickBigInteger::zero())) { + return ''; + } + + $temp = $this->value->toBase(16); + $temp = 0 !== (mb_strlen($temp, '8bit') & 1) ? '0' . $temp : $temp; + $temp = hex2bin($temp); + if ($temp === false) { + throw new InvalidArgumentException('Unable to convert the value into bytes'); + } + + return ltrim($temp, chr(0)); + } + + /** + * Adds two BigIntegers. + */ + public function add(self $y): self + { + $value = $this->value->plus($y->value); + + return new self($value); + } + + /** + * Subtracts two BigIntegers. + */ + public function subtract(self $y): self + { + $value = $this->value->minus($y->value); + + return new self($value); + } + + /** + * Multiplies two BigIntegers. + */ + public function multiply(self $x): self + { + $value = $this->value->multipliedBy($x->value); + + return new self($value); + } + + /** + * Divides two BigIntegers. + */ + public function divide(self $x): self + { + $value = $this->value->dividedBy($x->value); + + return new self($value); + } + + /** + * Performs modular exponentiation. + */ + public function modPow(self $e, self $n): self + { + $value = $this->value->modPow($e->value, $n->value); + + return new self($value); + } + + /** + * Performs modular exponentiation. + */ + public function mod(self $d): self + { + $value = $this->value->mod($d->value); + + return new self($value); + } + + public function modInverse(self $m): self + { + return new self($this->value->modInverse($m->value)); + } + + /** + * Compares two numbers. + */ + public function compare(self $y): int + { + return $this->value->compareTo($y->value); + } + + public function equals(self $y): bool + { + return $this->value->isEqualTo($y->value); + } + + public static function random(self $y): self + { + return new self(BrickBigInteger::randomRange(0, $y->value)); + } + + public function gcd(self $y): self + { + return new self($this->value->gcd($y->value)); + } + + public function lowerThan(self $y): bool + { + return $this->value->isLessThan($y->value); + } + + public function isEven(): bool + { + return $this->value->isEven(); + } + + public function get(): BrickBigInteger + { + return $this->value; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECKey.php new file mode 100644 index 000000000..f84123acc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECKey.php @@ -0,0 +1,326 @@ +has('d')) { + return self::convertPrivateKeyToPEM($jwk); + } + + return self::convertPublicKeyToPEM($jwk); + } + + public static function convertPublicKeyToPEM(JWK $jwk): string + { + $der = match ($jwk->get('crv')) { + 'P-256' => self::p256PublicKey(), + 'secp256k1' => self::p256KPublicKey(), + 'P-384' => self::p384PublicKey(), + 'P-521' => self::p521PublicKey(), + default => throw new InvalidArgumentException('Unsupported curve.'), + }; + $der .= self::getKey($jwk); + $pem = '-----BEGIN PUBLIC KEY-----' . "\n"; + $pem .= chunk_split(base64_encode($der), 64, "\n"); + + return $pem . ('-----END PUBLIC KEY-----' . "\n"); + } + + public static function convertPrivateKeyToPEM(JWK $jwk): string + { + $der = match ($jwk->get('crv')) { + 'P-256' => self::p256PrivateKey($jwk), + 'secp256k1' => self::p256KPrivateKey($jwk), + 'P-384' => self::p384PrivateKey($jwk), + 'P-521' => self::p521PrivateKey($jwk), + default => throw new InvalidArgumentException('Unsupported curve.'), + }; + $der .= self::getKey($jwk); + $pem = '-----BEGIN EC PRIVATE KEY-----' . "\n"; + $pem .= chunk_split(base64_encode($der), 64, "\n"); + + return $pem . ('-----END EC PRIVATE KEY-----' . "\n"); + } + + /** + * Creates a EC key with the given curve and additional values. + * + * @param string $curve The curve + * @param array $values values to configure the key + */ + public static function createECKey(string $curve, array $values = []): JWK + { + $jwk = self::createECKeyUsingOpenSSL($curve); + $values = array_merge($values, $jwk); + + return new JWK($values); + } + + private static function getNistCurveSize(string $curve): int + { + return match ($curve) { + 'P-256', 'secp256k1' => 256, + 'P-384' => 384, + 'P-521' => 521, + default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)), + }; + } + + private static function createECKeyUsingOpenSSL(string $curve): array + { + if (! extension_loaded('openssl')) { + throw new RuntimeException('Please install the OpenSSL extension'); + } + $key = openssl_pkey_new([ + 'curve_name' => self::getOpensslCurveName($curve), + 'private_key_type' => OPENSSL_KEYTYPE_EC, + ]); + if ($key === false) { + throw new RuntimeException('Unable to create the key'); + } + $result = openssl_pkey_export($key, $out); + if ($result === false) { + throw new RuntimeException('Unable to create the key'); + } + $res = openssl_pkey_get_private($out); + if ($res === false) { + throw new RuntimeException('Unable to create the key'); + } + $details = openssl_pkey_get_details($res); + if ($details === false) { + throw new InvalidArgumentException('Unable to get the key details'); + } + $nistCurveSize = self::getNistCurveSize($curve); + + return [ + 'kty' => 'EC', + 'crv' => $curve, + 'd' => Base64UrlSafe::encodeUnpadded( + str_pad((string) $details['ec']['d'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT) + ), + 'x' => Base64UrlSafe::encodeUnpadded( + str_pad((string) $details['ec']['x'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT) + ), + 'y' => Base64UrlSafe::encodeUnpadded( + str_pad((string) $details['ec']['y'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT) + ), + ]; + } + + private static function getOpensslCurveName(string $curve): string + { + return match ($curve) { + 'P-256' => 'prime256v1', + 'secp256k1' => 'secp256k1', + 'P-384' => 'secp384r1', + 'P-521' => 'secp521r1', + default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)), + }; + } + + private static function p256PublicKey(): string + { + return pack( + 'H*', + '3059' // SEQUENCE, length 89 + . '3013' // SEQUENCE, length 19 + . '0607' // OID, length 7 + . '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key + . '0608' // OID, length 8 + . '2a8648ce3d030107' // 1.2.840.10045.3.1.7 = P-256 Curve + . '0342' // BIT STRING, length 66 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p256KPublicKey(): string + { + return pack( + 'H*', + '3056' // SEQUENCE, length 86 + . '3010' // SEQUENCE, length 16 + . '0607' // OID, length 7 + . '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key + . '0605' // OID, length 8 + . '2B8104000A' // 1.3.132.0.10 secp256k1 + . '0342' // BIT STRING, length 66 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p384PublicKey(): string + { + return pack( + 'H*', + '3076' // SEQUENCE, length 118 + . '3010' // SEQUENCE, length 16 + . '0607' // OID, length 7 + . '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key + . '0605' // OID, length 5 + . '2b81040022' // 1.3.132.0.34 = P-384 Curve + . '0362' // BIT STRING, length 98 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p521PublicKey(): string + { + return pack( + 'H*', + '30819b' // SEQUENCE, length 154 + . '3010' // SEQUENCE, length 16 + . '0607' // OID, length 7 + . '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key + . '0605' // OID, length 5 + . '2b81040023' // 1.3.132.0.35 = P-521 Curve + . '038186' // BIT STRING, length 134 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p256PrivateKey(JWK $jwk): string + { + $d = $jwk->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Unable to get the private key'); + } + $d = unpack('H*', str_pad(Base64UrlSafe::decodeNoPadding($d), 32, "\0", STR_PAD_LEFT)); + if (! is_array($d) || ! isset($d[1])) { + throw new InvalidArgumentException('Unable to get the private key'); + } + + return pack( + 'H*', + '3077' // SEQUENCE, length 87+length($d)=32 + . '020101' // INTEGER, 1 + . '0420' // OCTET STRING, length($d) = 32 + . $d[1] + . 'a00a' // TAGGED OBJECT #0, length 10 + . '0608' // OID, length 8 + . '2a8648ce3d030107' // 1.3.132.0.34 = P-256 Curve + . 'a144' // TAGGED OBJECT #1, length 68 + . '0342' // BIT STRING, length 66 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p256KPrivateKey(JWK $jwk): string + { + $d = $jwk->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Unable to get the private key'); + } + $d = unpack('H*', str_pad(Base64UrlSafe::decodeNoPadding($d), 32, "\0", STR_PAD_LEFT)); + if (! is_array($d) || ! isset($d[1])) { + throw new InvalidArgumentException('Unable to get the private key'); + } + + return pack( + 'H*', + '3074' // SEQUENCE, length 84+length($d)=32 + . '020101' // INTEGER, 1 + . '0420' // OCTET STRING, length($d) = 32 + . $d[1] + . 'a007' // TAGGED OBJECT #0, length 7 + . '0605' // OID, length 5 + . '2b8104000a' // 1.3.132.0.10 secp256k1 + . 'a144' // TAGGED OBJECT #1, length 68 + . '0342' // BIT STRING, length 66 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p384PrivateKey(JWK $jwk): string + { + $d = $jwk->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Unable to get the private key'); + } + $d = unpack('H*', str_pad(Base64UrlSafe::decodeNoPadding($d), 48, "\0", STR_PAD_LEFT)); + if (! is_array($d) || ! isset($d[1])) { + throw new InvalidArgumentException('Unable to get the private key'); + } + + return pack( + 'H*', + '3081a4' // SEQUENCE, length 116 + length($d)=48 + . '020101' // INTEGER, 1 + . '0430' // OCTET STRING, length($d) = 30 + . $d[1] + . 'a007' // TAGGED OBJECT #0, length 7 + . '0605' // OID, length 5 + . '2b81040022' // 1.3.132.0.34 = P-384 Curve + . 'a164' // TAGGED OBJECT #1, length 100 + . '0362' // BIT STRING, length 98 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function p521PrivateKey(JWK $jwk): string + { + $d = $jwk->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Unable to get the private key'); + } + $d = unpack('H*', str_pad(Base64UrlSafe::decodeNoPadding($d), 66, "\0", STR_PAD_LEFT)); + if (! is_array($d) || ! isset($d[1])) { + throw new InvalidArgumentException('Unable to get the private key'); + } + + return pack( + 'H*', + '3081dc' // SEQUENCE, length 154 + length($d)=66 + . '020101' // INTEGER, 1 + . '0442' // OCTET STRING, length(d) = 66 + . $d[1] + . 'a007' // TAGGED OBJECT #0, length 7 + . '0605' // OID, length 5 + . '2b81040023' // 1.3.132.0.35 = P-521 Curve + . 'a18189' // TAGGED OBJECT #1, length 137 + . '038186' // BIT STRING, length 134 + . '00' // prepend with NUL - pubkey will follow + ); + } + + private static function getKey(JWK $jwk): string + { + $crv = $jwk->get('crv'); + if (! is_string($crv)) { + throw new InvalidArgumentException('Unable to get the curve'); + } + $nistCurveSize = self::getNistCurveSize($crv); + $length = (int) ceil($nistCurveSize / 8); + $x = $jwk->get('x'); + if (! is_string($x)) { + throw new InvalidArgumentException('Unable to get the public key'); + } + $y = $jwk->get('y'); + if (! is_string($y)) { + throw new InvalidArgumentException('Unable to get the public key'); + } + $binX = ltrim(Base64UrlSafe::decodeNoPadding($x), "\0"); + $binY = ltrim(Base64UrlSafe::decodeNoPadding($y), "\0"); + + return "\04" + . str_pad($binX, $length, "\0", STR_PAD_LEFT) + . str_pad($binY, $length, "\0", STR_PAD_LEFT) + ; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECSignature.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECSignature.php new file mode 100644 index 000000000..4ca1c0c10 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/ECSignature.php @@ -0,0 +1,133 @@ + self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : ''; + + $bin = hex2bin( + self::ASN1_SEQUENCE + . $lengthPrefix . dechex($totalLength) + . self::ASN1_INTEGER . dechex($lengthR) . $pointR + . self::ASN1_INTEGER . dechex($lengthS) . $pointS + ); + if (! is_string($bin)) { + throw new InvalidArgumentException('Unable to parse the data'); + } + + return $bin; + } + + public static function fromAsn1(string $signature, int $length): string + { + $message = bin2hex($signature); + $position = 0; + + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) { + throw new InvalidArgumentException('Invalid data. Should start with a sequence.'); + } + + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) { + $position += self::BYTE_SIZE; + } + + $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); + $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); + + $bin = hex2bin( + str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT) + ); + if (! is_string($bin)) { + throw new InvalidArgumentException('Unable to parse the data'); + } + + return $bin; + } + + private static function octetLength(string $data): int + { + return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE); + } + + private static function preparePositiveInteger(string $data): string + { + if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) { + return self::ASN1_NEGATIVE_INTEGER . $data; + } + + while (mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0 + && mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) { + $data = mb_substr($data, 2, null, '8bit'); + } + + return $data; + } + + private static function readAsn1Content(string $message, int &$position, int $length): string + { + $content = mb_substr($message, $position, $length, '8bit'); + $position += $length; + + return $content; + } + + private static function readAsn1Integer(string $message, int &$position): string + { + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) { + throw new InvalidArgumentException('Invalid data. Should contain an integer.'); + } + + $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE)); + + return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE); + } + + private static function retrievePositiveInteger(string $data): string + { + while (mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0 + && mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) { + $data = mb_substr($data, 2, null, '8bit'); + } + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Curve.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Curve.php new file mode 100644 index 000000000..59be935bf --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Curve.php @@ -0,0 +1,272 @@ +getA()) . ', ' . Math::toString($this->getB()) . ', ' . Math::toString( + $this->getPrime() + ) . ')'; + } + + public function getA(): BigInteger + { + return $this->a; + } + + public function getB(): BigInteger + { + return $this->b; + } + + public function getPrime(): BigInteger + { + return $this->prime; + } + + public function getSize(): int + { + return $this->size; + } + + public function getPoint(BigInteger $x, BigInteger $y, ?BigInteger $order = null): Point + { + if (! $this->contains($x, $y)) { + throw new RuntimeException('Curve ' . $this->__toString() . ' does not contain point (' . Math::toString( + $x + ) . ', ' . Math::toString($y) . ')'); + } + $point = Point::create($x, $y, $order); + if ($order !== null) { + $mul = $this->mul($point, $order); + if (! $mul->isInfinity()) { + throw new RuntimeException('SELF * ORDER MUST EQUAL INFINITY.'); + } + } + + return $point; + } + + public function getPublicKeyFrom(BigInteger $x, BigInteger $y): PublicKey + { + $zero = BigInteger::zero(); + if ($x->compareTo($zero) < 0 || $y->compareTo($zero) < 0 || $this->generator->getOrder()->compareTo( + $x + ) <= 0 || $this->generator->getOrder() + ->compareTo($y) <= 0) { + throw new RuntimeException('Generator point has x and y out of range.'); + } + $point = $this->getPoint($x, $y); + + return new PublicKey($point); + } + + public function contains(BigInteger $x, BigInteger $y): bool + { + return Math::equals( + ModularArithmetic::sub( + $y->power(2), + Math::add(Math::add($x->power(3), $this->getA()->multipliedBy($x)), $this->getB()), + $this->getPrime() + ), + BigInteger::zero() + ); + } + + public function add(Point $one, Point $two): Point + { + if ($two->isInfinity()) { + return clone $one; + } + + if ($one->isInfinity()) { + return clone $two; + } + + if ($two->getX()->isEqualTo($one->getX())) { + if ($two->getY()->isEqualTo($one->getY())) { + return $this->getDouble($one); + } + + return Point::infinity(); + } + + $slope = ModularArithmetic::div( + $two->getY() + ->minus($one->getY()), + $two->getX() + ->minus($one->getX()), + $this->getPrime() + ); + + $xR = ModularArithmetic::sub($slope->power(2)->minus($one->getX()), $two->getX(), $this->getPrime()); + + $yR = ModularArithmetic::sub( + $slope->multipliedBy($one->getX()->minus($xR)), + $one->getY(), + $this->getPrime() + ); + + return $this->getPoint($xR, $yR, $one->getOrder()); + } + + public function mul(Point $one, BigInteger $n): Point + { + if ($one->isInfinity()) { + return Point::infinity(); + } + + /** @var BigInteger $zero */ + $zero = BigInteger::zero(); + if ($one->getOrder()->compareTo($zero) > 0) { + $n = $n->mod($one->getOrder()); + } + + if ($n->isEqualTo($zero)) { + return Point::infinity(); + } + + /** @var Point[] $r */ + $r = [Point::infinity(), clone $one]; + + $k = $this->getSize(); + $n1 = str_pad(Math::baseConvert(Math::toString($n), 10, 2), $k, '0', STR_PAD_LEFT); + + for ($i = 0; $i < $k; ++$i) { + $j = $n1[$i]; + Point::cswap($r[0], $r[1], $j ^ 1); + $r[0] = $this->add($r[0], $r[1]); + $r[1] = $this->getDouble($r[1]); + Point::cswap($r[0], $r[1], $j ^ 1); + } + + $this->validate($r[0]); + + return $r[0]; + } + + public function cmp(self $other): int + { + $equalsA = $this->getA() + ->isEqualTo($other->getA()); + $equalsB = $this->getB() + ->isEqualTo($other->getB()); + $equalsPrime = $this->getPrime() + ->isEqualTo($other->getPrime()); + $equal = $equalsA && $equalsB && $equalsPrime; + + return $equal ? 0 : 1; + } + + public function equals(self $other): bool + { + return $this->cmp($other) === 0; + } + + public function getDouble(Point $point): Point + { + if ($point->isInfinity()) { + return Point::infinity(); + } + + $a = $this->getA(); + $threeX2 = BigInteger::of(3)->multipliedBy($point->getX()->power(2)); + + $tangent = ModularArithmetic::div( + $threeX2->plus($a), + BigInteger::of(2)->multipliedBy($point->getY()), + $this->getPrime() + ); + + $x3 = ModularArithmetic::sub( + $tangent->power(2), + BigInteger::of(2)->multipliedBy($point->getX()), + $this->getPrime() + ); + + $y3 = ModularArithmetic::sub( + $tangent->multipliedBy($point->getX()->minus($x3)), + $point->getY(), + $this->getPrime() + ); + + return $this->getPoint($x3, $y3, $point->getOrder()); + } + + public function createPrivateKey(): PrivateKey + { + return PrivateKey::create($this->generate()); + } + + public function createPublicKey(PrivateKey $privateKey): PublicKey + { + $point = $this->mul($this->generator, $privateKey->getSecret()); + + return new PublicKey($point); + } + + public function getGenerator(): Point + { + return $this->generator; + } + + private function validate(Point $point): void + { + if (! $point->isInfinity() && ! $this->contains($point->getX(), $point->getY())) { + throw new RuntimeException('Invalid point'); + } + } + + private function generate(): BigInteger + { + $max = $this->generator->getOrder(); + $numBits = $this->bnNumBits($max); + $numBytes = (int) ceil($numBits / 8); + // Generate an integer of size >= $numBits + $bytes = BigInteger::randomBits($numBytes); + $mask = BigInteger::of(2)->power($numBits)->minus(1); + + return $bytes->and($mask); + } + + /** + * Returns the number of bits used to store this number. Non-significant upper bits are not counted. + * + * @see https://www.openssl.org/docs/crypto/BN_num_bytes.html + */ + private function bnNumBits(BigInteger $x): int + { + $zero = BigInteger::of(0); + if ($x->isEqualTo($zero)) { + return 0; + } + $log2 = 0; + while (! $x->isEqualTo($zero)) { + $x = $x->shiftedRight(1); + ++$log2; + } + + return $log2; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/EcDH.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/EcDH.php new file mode 100644 index 000000000..c44d803f7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/EcDH.php @@ -0,0 +1,43 @@ +mul($publicKey->getPoint(), $privateKey->getSecret()) + ->getX(); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Math.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Math.php new file mode 100644 index 000000000..645bba54c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/Math.php @@ -0,0 +1,39 @@ +isEqualTo($other); + } + + public static function add(BigInteger $augend, BigInteger $addend): BigInteger + { + return $augend->plus($addend); + } + + public static function toString(BigInteger $value): string + { + return $value->toBase(10); + } + + public static function inverseMod(BigInteger $a, BigInteger $m): BigInteger + { + return CoreBigInteger::createFromBigInteger($a)->modInverse(CoreBigInteger::createFromBigInteger($m))->get(); + } + + public static function baseConvert(string $number, int $from, int $to): string + { + return BigInteger::fromBase($number, $from)->toBase($to); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/ModularArithmetic.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/ModularArithmetic.php new file mode 100644 index 000000000..3d801ff83 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/ModularArithmetic.php @@ -0,0 +1,30 @@ +minus($subtrahend) + ->mod($modulus); + } + + public static function mul(BigInteger $multiplier, BigInteger $muliplicand, BigInteger $modulus): BigInteger + { + return $multiplier->multipliedBy($muliplicand) + ->mod($modulus); + } + + public static function div(BigInteger $dividend, BigInteger $divisor, BigInteger $modulus): BigInteger + { + return self::mul($dividend, Math::inverseMod($divisor, $modulus), $modulus); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/NistCurve.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/NistCurve.php new file mode 100644 index 000000000..190fbcff9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/NistCurve.php @@ -0,0 +1,114 @@ +infinity; + } + + public function getOrder(): BigInteger + { + return $this->order; + } + + public function getX(): BigInteger + { + return $this->x; + } + + public function getY(): BigInteger + { + return $this->y; + } + + public static function cswap(self $a, self $b, int $cond): void + { + self::cswapBigInteger($a->x, $b->x, $cond); + self::cswapBigInteger($a->y, $b->y, $cond); + self::cswapBigInteger($a->order, $b->order, $cond); + self::cswapBoolean($a->infinity, $b->infinity, $cond); + } + + private static function cswapBoolean(bool &$a, bool &$b, int $cond): void + { + $sa = BigInteger::of((int) $a); + $sb = BigInteger::of((int) $b); + + self::cswapBigInteger($sa, $sb, $cond); + + $a = (bool) $sa->toBase(10); + $b = (bool) $sb->toBase(10); + } + + private static function cswapBigInteger(BigInteger &$sa, BigInteger &$sb, int $cond): void + { + $size = max(mb_strlen($sa->toBase(2), '8bit'), mb_strlen($sb->toBase(2), '8bit')); + $mask = (string) (1 - $cond); + $mask = str_pad('', $size, $mask, STR_PAD_LEFT); + $mask = BigInteger::fromBase($mask, 2); + $taA = $sa->and($mask); + $taB = $sb->and($mask); + $sa = $sa->xor($sb) + ->xor($taB); + $sb = $sa->xor($sb) + ->xor($taA); + $sa = $sa->xor($sb) + ->xor($taB); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PrivateKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PrivateKey.php new file mode 100644 index 000000000..1f73ef229 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PrivateKey.php @@ -0,0 +1,45 @@ +secret; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PublicKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PublicKey.php new file mode 100644 index 000000000..1f5507107 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Ecc/PublicKey.php @@ -0,0 +1,38 @@ +point; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Hash.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Hash.php new file mode 100644 index 000000000..cdc00032a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/Hash.php @@ -0,0 +1,61 @@ +length; + } + + /** + * Compute the HMAC. + */ + public function hash(string $text): string + { + return hash($this->hash, $text, true); + } + + public function name(): string + { + return $this->hash; + } + + public function t(): string + { + return $this->t; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/JsonConverter.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/JsonConverter.php new file mode 100644 index 000000000..d51c9777c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/JsonConverter.php @@ -0,0 +1,37 @@ +getCode(), $throwable); + } + } + + public static function decode(string $payload): mixed + { + try { + return json_decode( + $payload, + true, + 512, + JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + ); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unsupported input.', $throwable->getCode(), $throwable); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/KeyChecker.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/KeyChecker.php new file mode 100644 index 000000000..8e902e650 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/KeyChecker.php @@ -0,0 +1,116 @@ +has('use')) { + self::checkUsage($key, $usage); + } + if ($key->has('key_ops')) { + self::checkOperation($key, $usage); + } + } + + public static function checkKeyAlgorithm(JWK $key, string $algorithm): void + { + if (! $key->has('alg')) { + return; + } + $alg = $key->get('alg'); + if (! is_string($alg)) { + throw new InvalidArgumentException('Invalid algorithm.'); + } + if ($alg !== $algorithm) { + throw new InvalidArgumentException(sprintf('Key is only allowed for algorithm "%s".', $alg)); + } + } + + private static function checkOperation(JWK $key, string $usage): void + { + $ops = $key->get('key_ops'); + if (! is_array($ops)) { + throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations'); + } + + switch ($usage) { + case 'verification': + if (! in_array('verify', $ops, true)) { + throw new InvalidArgumentException('Key cannot be used to verify a signature'); + } + + break; + + case 'signature': + if (! in_array('sign', $ops, true)) { + throw new InvalidArgumentException('Key cannot be used to sign'); + } + + break; + + case 'encryption': + if (! in_array('encrypt', $ops, true) && ! in_array('wrapKey', $ops, true) && ! in_array( + 'deriveKey', + $ops, + true + )) { + throw new InvalidArgumentException('Key cannot be used to encrypt'); + } + + break; + + case 'decryption': + if (! in_array('decrypt', $ops, true) && ! in_array('unwrapKey', $ops, true) && ! in_array( + 'deriveBits', + $ops, + true + )) { + throw new InvalidArgumentException('Key cannot be used to decrypt'); + } + + break; + + default: + throw new InvalidArgumentException('Unsupported key usage.'); + } + } + + private static function checkUsage(JWK $key, string $usage): void + { + $use = $key->get('use'); + + switch ($usage) { + case 'verification': + case 'signature': + if ($use !== 'sig') { + throw new InvalidArgumentException('Key cannot be used to sign or verify a signature.'); + } + + break; + + case 'encryption': + case 'decryption': + if ($use !== 'enc') { + throw new InvalidArgumentException('Key cannot be used to encrypt or decrypt.'); + } + + break; + + default: + throw new InvalidArgumentException('Unsupported key usage.'); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/RSAKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/RSAKey.php new file mode 100644 index 000000000..c28fe661e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Core/Util/RSAKey.php @@ -0,0 +1,243 @@ +values = $data->all(); + $this->populateBigIntegers(); + } + + public static function createFromJWK(JWK $jwk): self + { + return new self($jwk); + } + + public function getModulus(): BigInteger + { + return $this->modulus; + } + + public function getModulusLength(): int + { + return $this->modulus_length; + } + + public function getExponent(): BigInteger + { + $d = $this->getPrivateExponent(); + if ($d !== null) { + return $d; + } + + return $this->getPublicExponent(); + } + + public function getPublicExponent(): BigInteger + { + return $this->public_exponent; + } + + public function getPrivateExponent(): ?BigInteger + { + return $this->private_exponent; + } + + /** + * @return BigInteger[] + */ + public function getPrimes(): array + { + return $this->primes; + } + + /** + * @return BigInteger[] + */ + public function getExponents(): array + { + return $this->exponents; + } + + public function getCoefficient(): ?BigInteger + { + return $this->coefficient; + } + + public function isPublic(): bool + { + return ! array_key_exists('d', $this->values); + } + + public static function toPublic(self $private): self + { + $data = $private->toArray(); + $keys = ['p', 'd', 'q', 'dp', 'dq', 'qi']; + foreach ($keys as $key) { + if (array_key_exists($key, $data)) { + unset($data[$key]); + } + } + + return new self(new JWK($data)); + } + + public function toArray(): array + { + return $this->values; + } + + public function toPEM(): string + { + if (array_key_exists('d', $this->values)) { + $this->sequence = Sequence::create( + Integer::create(0), + RSAEncryptionAlgorithmIdentifier::create()->toASN1(), + OctetString::create( + RSAPrivateKey::create( + $this->fromBase64ToInteger($this->values['n']), + $this->fromBase64ToInteger($this->values['e']), + $this->fromBase64ToInteger($this->values['d']), + isset($this->values['p']) ? $this->fromBase64ToInteger($this->values['p']) : '0', + isset($this->values['q']) ? $this->fromBase64ToInteger($this->values['q']) : '0', + isset($this->values['dp']) ? $this->fromBase64ToInteger($this->values['dp']) : '0', + isset($this->values['dq']) ? $this->fromBase64ToInteger($this->values['dq']) : '0', + isset($this->values['qi']) ? $this->fromBase64ToInteger($this->values['qi']) : '0', + )->toDER() + ) + ); + + return PEM::create(PEM::TYPE_PRIVATE_KEY, $this->sequence->toDER()) + ->string(); + } + $this->sequence = Sequence::create( + RSAEncryptionAlgorithmIdentifier::create()->toASN1(), + BitString::create( + RSAPublicKey::create( + $this->fromBase64ToInteger($this->values['n']), + $this->fromBase64ToInteger($this->values['e']) + )->toDER() + ) + ); + + return PEM::create(PEM::TYPE_PUBLIC_KEY, $this->sequence->toDER()) + ->string(); + } + + /** + * Exponentiate with or without Chinese Remainder Theorem. Operation with primes 'p' and 'q' is appox. 2x faster. + */ + public static function exponentiate(self $key, BigInteger $c): BigInteger + { + if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) { + throw new RuntimeException(); + } + if ($key->isPublic() || $key->getCoefficient() === null || count($key->getPrimes()) === 0 || count( + $key->getExponents() + ) === 0) { + return $c->modPow($key->getExponent(), $key->getModulus()); + } + + $p = $key->getPrimes()[0]; + $q = $key->getPrimes()[1]; + $dP = $key->getExponents()[0]; + $dQ = $key->getExponents()[1]; + $qInv = $key->getCoefficient(); + + $m1 = $c->modPow($dP, $p); + $m2 = $c->modPow($dQ, $q); + $h = $qInv->multiply($m1->subtract($m2)->add($p)) + ->mod($p); + + return $m2->add($h->multiply($q)); + } + + private function populateBigIntegers(): void + { + $this->modulus = $this->convertBase64StringToBigInteger($this->values['n']); + $this->modulus_length = mb_strlen($this->getModulus()->toBytes(), '8bit'); + $this->public_exponent = $this->convertBase64StringToBigInteger($this->values['e']); + + if (! $this->isPublic()) { + $this->private_exponent = $this->convertBase64StringToBigInteger($this->values['d']); + + if (array_key_exists('p', $this->values) && array_key_exists('q', $this->values)) { + $this->primes = [ + $this->convertBase64StringToBigInteger($this->values['p']), + $this->convertBase64StringToBigInteger($this->values['q']), + ]; + if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists( + 'qi', + $this->values + )) { + $this->exponents = [ + $this->convertBase64StringToBigInteger($this->values['dp']), + $this->convertBase64StringToBigInteger($this->values['dq']), + ]; + $this->coefficient = $this->convertBase64StringToBigInteger($this->values['qi']); + } + } + } + } + + private function convertBase64StringToBigInteger(string $value): BigInteger + { + return BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($value)); + } + + private function fromBase64ToInteger(string $value): string + { + $unpacked = unpack('H*', Base64UrlSafe::decodeNoPadding($value)); + if (! is_array($unpacked) || count($unpacked) === 0) { + throw new InvalidArgumentException('Unable to get the private key'); + } + + return \Brick\Math\BigInteger::fromBase(current($unpacked), 16)->toBase(10); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128CBCHS256.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128CBCHS256.php new file mode 100644 index 000000000..0554a52b9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/A128CBCHS256.php @@ -0,0 +1,28 @@ +getCEKSize() / 16, null, '8bit'); + $result = openssl_encrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv); + if ($result === false) { + throw new RuntimeException('Unable to encrypt the content'); + } + + $tag = $this->calculateAuthenticationTag($result, $cek, $iv, $aad, $encoded_protected_header); + + return $result; + } + + public function decryptContent( + string $data, + string $cek, + string $iv, + ?string $aad, + string $encoded_protected_header, + string $tag + ): string { + if (! $this->isTagValid($data, $cek, $iv, $aad, $encoded_protected_header, $tag)) { + throw new RuntimeException('Unable to decrypt or to verify the tag.'); + } + $k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit'); + + $result = openssl_decrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv); + if ($result === false) { + throw new RuntimeException('Unable to decrypt or to verify the tag.'); + } + + return $result; + } + + public function getIVSize(): int + { + return 128; + } + + protected function calculateAuthenticationTag( + string $encrypted_data, + string $cek, + string $iv, + ?string $aad, + string $encoded_header + ): string { + $calculated_aad = $encoded_header; + if ($aad !== null) { + $calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad); + } + $mac_key = mb_substr($cek, 0, $this->getCEKSize() / 16, '8bit'); + $auth_data_length = mb_strlen($encoded_header, '8bit'); + + $secured_input = implode('', [ + $calculated_aad, + $iv, + $encrypted_data, + pack('N2', ($auth_data_length / 2_147_483_647) * 8, ($auth_data_length % 2_147_483_647) * 8), + ]); + $hash = hash_hmac($this->getHashAlgorithm(), $secured_input, $mac_key, true); + + return mb_substr($hash, 0, mb_strlen($hash, '8bit') / 2, '8bit'); + } + + protected function isTagValid( + string $encrypted_data, + string $cek, + string $iv, + ?string $aad, + string $encoded_header, + string $authentication_tag + ): bool { + return hash_equals( + $authentication_tag, + $this->calculateAuthenticationTag($encrypted_data, $cek, $iv, $aad, $encoded_header) + ); + } + + abstract protected function getHashAlgorithm(): string; + + abstract protected function getMode(): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESGCM.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESGCM.php new file mode 100644 index 000000000..0b1bf43f8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryption/AESGCM.php @@ -0,0 +1,75 @@ +getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad); + if ($result === false) { + throw new RuntimeException('Unable to encrypt the content'); + } + + return $result; + } + + public function decryptContent( + string $data, + string $cek, + string $iv, + ?string $aad, + string $encoded_protected_header, + string $tag + ): string { + $calculated_aad = $encoded_protected_header; + if ($aad !== null) { + $calculated_aad .= '.' . Base64UrlSafe::encodeUnpadded($aad); + } + + $result = openssl_decrypt($data, $this->getMode(), $cek, OPENSSL_RAW_DATA, $iv, $tag, $calculated_aad); + if ($result === false) { + throw new RuntimeException('Unable to decrypt the content'); + } + + return $result; + } + + public function getIVSize(): int + { + return 96; + } + + abstract protected function getMode(): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryptionAlgorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryptionAlgorithm.php new file mode 100644 index 000000000..0f93f903b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/ContentEncryptionAlgorithm.php @@ -0,0 +1,59 @@ + $completeHeader + * @param array $additionalHeader + */ + public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string + { + $kek = $this->getKey($key); + $iv = random_bytes(96 / 8); + $additionalHeader['iv'] = Base64UrlSafe::encodeUnpadded($iv); + + $mode = sprintf('aes-%d-gcm', $this->getKeySize()); + $tag = ''; + $encrypted_cek = openssl_encrypt($cek, $mode, $kek, OPENSSL_RAW_DATA, $iv, $tag, ''); + if ($encrypted_cek === false) { + throw new RuntimeException('Unable to encrypt the CEK'); + } + $additionalHeader['tag'] = Base64UrlSafe::encodeUnpadded($tag); + + return $encrypted_cek; + } + + /** + * @param array $completeHeader + */ + public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string + { + $kek = $this->getKey($key); + (isset($completeHeader['iv']) && is_string($completeHeader['iv'])) || throw new InvalidArgumentException( + 'Parameter "iv" is missing.' + ); + (isset($completeHeader['tag']) && is_string($completeHeader['tag'])) || throw new InvalidArgumentException( + 'Parameter "tag" is missing.' + ); + + $tag = Base64UrlSafe::decodeNoPadding($completeHeader['tag']); + $iv = Base64UrlSafe::decodeNoPadding($completeHeader['iv']); + + $mode = sprintf('aes-%d-gcm', $this->getKeySize()); + $cek = openssl_decrypt($encrypted_cek, $mode, $kek, OPENSSL_RAW_DATA, $iv, $tag, ''); + if ($cek === false) { + throw new RuntimeException('Unable to decrypt the CEK'); + } + + return $cek; + } + + public function getKeyManagementMode(): string + { + return self::MODE_WRAP; + } + + protected function getKey(JWK $key): string + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + if (! $key->has('k')) { + throw new InvalidArgumentException('The key parameter "k" is missing.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new InvalidArgumentException('The key parameter "k" is invalid.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + } + + abstract protected function getKeySize(): int; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESKW.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESKW.php new file mode 100644 index 000000000..15c408acc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AESKW.php @@ -0,0 +1,74 @@ + $completeHeader + * @param array $additionalHeader + */ + public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string + { + $k = $this->getKey($key); + $wrapper = $this->getWrapper(); + + return $wrapper::wrap($k, $cek); + } + + /** + * @param array $completeHeader + */ + public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string + { + $k = $this->getKey($key); + $wrapper = $this->getWrapper(); + + return $wrapper::unwrap($k, $encrypted_cek); + } + + public function getKeyManagementMode(): string + { + return self::MODE_WRAP; + } + + abstract protected function getWrapper(): WrapperInterface; + + private function getKey(JWK $key): string + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + if (! $key->has('k')) { + throw new InvalidArgumentException('The key parameter "k" is missing.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new InvalidArgumentException('The key parameter "k" is invalid.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php new file mode 100644 index 000000000..1af2818fd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDH.php @@ -0,0 +1,316 @@ + $complete_header + * @param array $additional_header_values + */ + public function getAgreementKey( + int $encryptionKeyLength, + string $algorithm, + JWK $recipientKey, + ?JWK $senderKey, + array $complete_header = [], + array &$additional_header_values = [] + ): string { + if ($recipientKey->has('d')) { + [$public_key, $private_key] = $this->getKeysFromPrivateKeyAndHeader($recipientKey, $complete_header); + } else { + [$public_key, $private_key] = $this->getKeysFromPublicKey( + $recipientKey, + $senderKey, + $additional_header_values + ); + } + + $agreed_key = $this->calculateAgreementKey($private_key, $public_key); + + $apu = array_key_exists('apu', $complete_header) ? $complete_header['apu'] : ''; + is_string($apu) || throw new InvalidArgumentException('Invalid APU.'); + $apv = array_key_exists('apv', $complete_header) ? $complete_header['apv'] : ''; + is_string($apv) || throw new InvalidArgumentException('Invalid APU.'); + + return ConcatKDF::generate($agreed_key, $algorithm, $encryptionKeyLength, $apu, $apv); + } + + public function getKeyManagementMode(): string + { + return self::MODE_AGREEMENT; + } + + protected function calculateAgreementKey(JWK $private_key, JWK $public_key): string + { + $crv = $public_key->get('crv'); + if (! is_string($crv)) { + throw new InvalidArgumentException('Invalid key parameter "crv"'); + } + switch ($crv) { + case 'P-256': + case 'P-384': + case 'P-521': + $curve = $this->getCurve($crv); + if (function_exists('openssl_pkey_derive')) { + try { + $publicPem = ECKey::convertPublicKeyToPEM($public_key); + $privatePem = ECKey::convertPrivateKeyToPEM($private_key); + + $res = openssl_pkey_derive($publicPem, $privatePem, $curve->getSize()); + if ($res === false) { + throw new RuntimeException('Unable to derive the key'); + } + + return $res; + } catch (Throwable) { + //Does nothing. Will fallback to the pure PHP function + } + } + $x = $public_key->get('x'); + if (! is_string($x)) { + throw new InvalidArgumentException('Invalid key parameter "x"'); + } + $y = $public_key->get('y'); + if (! is_string($y)) { + throw new InvalidArgumentException('Invalid key parameter "y"'); + } + $d = $private_key->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Invalid key parameter "d"'); + } + + $rec_x = $this->convertBase64ToBigInteger($x); + $rec_y = $this->convertBase64ToBigInteger($y); + $sen_d = $this->convertBase64ToBigInteger($d); + + $priv_key = PrivateKey::create($sen_d); + $pub_key = $curve->getPublicKeyFrom($rec_x, $rec_y); + + return $this->convertDecToBin(EcDH::computeSharedKey($curve, $pub_key, $priv_key)); + + case 'X25519': + $this->checkSodiumExtensionIsAvailable(); + $x = $public_key->get('x'); + if (! is_string($x)) { + throw new InvalidArgumentException('Invalid key parameter "x"'); + } + $d = $private_key->get('d'); + if (! is_string($d)) { + throw new InvalidArgumentException('Invalid key parameter "d"'); + } + $sKey = Base64UrlSafe::decodeNoPadding($d); + $recipientPublickey = Base64UrlSafe::decodeNoPadding($x); + + return sodium_crypto_scalarmult($sKey, $recipientPublickey); + + default: + throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)); + } + } + + /** + * @param array $additional_header_values + * @return JWK[] + */ + protected function getKeysFromPublicKey( + JWK $recipient_key, + ?JWK $senderKey, + array &$additional_header_values + ): array { + $this->checkKey($recipient_key, false); + $public_key = $recipient_key; + + $crv = $public_key->get('crv'); + if (! is_string($crv)) { + throw new InvalidArgumentException('Invalid key parameter "crv"'); + } + $private_key = match ($crv) { + 'P-256', 'P-384', 'P-521' => $senderKey ?? ECKey::createECKey($crv), + 'X25519' => $senderKey ?? $this->createOKPKey('X25519'), + default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)), + }; + $epk = $private_key->toPublic() + ->all(); + $additional_header_values['epk'] = $epk; + + return [$public_key, $private_key]; + } + + /** + * @param array $complete_header + * @return JWK[] + */ + protected function getKeysFromPrivateKeyAndHeader(JWK $recipient_key, array $complete_header): array + { + $this->checkKey($recipient_key, true); + $private_key = $recipient_key; + $public_key = $this->getPublicKey($complete_header); + if ($private_key->get('crv') !== $public_key->get('crv')) { + throw new InvalidArgumentException('Curves are different'); + } + + return [$public_key, $private_key]; + } + + /** + * @param array $complete_header + */ + private function getPublicKey(array $complete_header): JWK + { + if (! isset($complete_header['epk'])) { + throw new InvalidArgumentException('The header parameter "epk" is missing.'); + } + if (! is_array($complete_header['epk'])) { + throw new InvalidArgumentException('The header parameter "epk" is not an array of parameters'); + } + $public_key = new JWK($complete_header['epk']); + $this->checkKey($public_key, false); + + return $public_key; + } + + private function checkKey(JWK $key, bool $is_private): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + foreach (['x', 'crv'] as $k) { + if (! $key->has($k)) { + throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); + } + } + + $crv = $key->get('crv'); + if (! is_string($crv)) { + throw new InvalidArgumentException('Invalid key parameter "crv"'); + } + switch ($crv) { + case 'P-256': + case 'P-384': + case 'P-521': + if (! $key->has('y')) { + throw new InvalidArgumentException('The key parameter "y" is missing.'); + } + + break; + + case 'X25519': + break; + + default: + throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)); + } + if ($is_private === true && ! $key->has('d')) { + throw new InvalidArgumentException('The key parameter "d" is missing.'); + } + } + + private function getCurve(string $crv): Curve + { + return match ($crv) { + 'P-256' => NistCurve::curve256(), + 'P-384' => NistCurve::curve384(), + 'P-521' => NistCurve::curve521(), + default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported', $crv)), + }; + } + + private function convertBase64ToBigInteger(string $value): BigInteger + { + $data = unpack('H*', Base64UrlSafe::decodeNoPadding($value)); + if (! is_array($data) || ! isset($data[1]) || ! is_string($data[1])) { + throw new InvalidArgumentException('Unable to convert base64 to integer'); + } + + return BigInteger::fromBase($data[1], 16); + } + + private function convertDecToBin(BigInteger $dec): string + { + if ($dec->compareTo(BigInteger::zero()) < 0) { + throw new InvalidArgumentException('Unable to convert negative integer to string'); + } + $hex = $dec->toBase(16); + + if (mb_strlen($hex, '8bit') % 2 !== 0) { + $hex = '0' . $hex; + } + + $bin = hex2bin($hex); + if ($bin === false) { + throw new InvalidArgumentException('Unable to convert integer to string'); + } + + return $bin; + } + + /** + * @param string $curve The curve + */ + private function createOKPKey(string $curve): JWK + { + $this->checkSodiumExtensionIsAvailable(); + + switch ($curve) { + case 'X25519': + $keyPair = sodium_crypto_box_keypair(); + $d = sodium_crypto_box_secretkey($keyPair); + $x = sodium_crypto_box_publickey($keyPair); + + break; + + case 'Ed25519': + $keyPair = sodium_crypto_sign_keypair(); + $secret = sodium_crypto_sign_secretkey($keyPair); + $secretLength = mb_strlen($secret, '8bit'); + $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); + $x = sodium_crypto_sign_publickey($keyPair); + + break; + + default: + throw new InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve)); + } + + return new JWK([ + 'kty' => 'OKP', + 'crv' => $curve, + 'x' => Base64UrlSafe::encodeUnpadded($x), + 'd' => Base64UrlSafe::encodeUnpadded($d), + ]); + } + + private function checkSodiumExtensionIsAvailable(): void + { + if (! extension_loaded('sodium')) { + throw new RuntimeException('The extension "sodium" is not available. Please install it to use this method'); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDHAESKW.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDHAESKW.php new file mode 100644 index 000000000..4aa6f0f7d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/AbstractECDHAESKW.php @@ -0,0 +1,32 @@ +get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + if (! $key->has('k')) { + throw new InvalidArgumentException('The key parameter "k" is missing.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new InvalidArgumentException('The key parameter "k" is invalid.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + } + + public function name(): string + { + return 'dir'; + } + + public function allowedKeyTypes(): array + { + return ['oct']; + } + + public function getKeyManagementMode(): string + { + return self::MODE_DIRECT; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/DirectEncryption.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/DirectEncryption.php new file mode 100644 index 000000000..cec9ad99a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/DirectEncryption.php @@ -0,0 +1,18 @@ + $complete_header + * @param array $additional_header_values + */ + public function wrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $cek, + int $encryption_key_length, + array $complete_header, + array &$additional_header_values + ): string { + $ecdh_es = new ECDHES(); + $agreement_key = $ecdh_es->getAgreementKey( + $this->getKeyLength(), + $this->name(), + $recipientKey->toPublic(), + $senderKey, + $complete_header, + $additional_header_values + ); + $wrapper = $this->getWrapper(); + + return $wrapper::wrap($agreement_key, $cek); + } + + /** + * @param array $complete_header + */ + public function unwrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $encrypted_cek, + int $encryption_key_length, + array $complete_header + ): string { + $ecdh_es = new ECDHES(); + $agreement_key = $ecdh_es->getAgreementKey( + $this->getKeyLength(), + $this->name(), + $recipientKey, + $senderKey, + $complete_header + ); + $wrapper = $this->getWrapper(); + + return $wrapper::unwrap($agreement_key, $encrypted_cek); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSS.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSS.php new file mode 100644 index 000000000..50b832a81 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSS.php @@ -0,0 +1,44 @@ + $complete_header + * @param array $additional_header_values + */ + public function getAgreementKey( + int $encryptionKeyLength, + string $algorithm, + JWK $recipientKey, + ?JWK $senderKey, + array $complete_header = [], + array &$additional_header_values = [] + ): string { + if ($senderKey === null) { + throw new LogicException('The sender key shall be set'); + } + $agreedKey = parent::getAgreementKey( + $encryptionKeyLength, + $algorithm, + $recipientKey, + $senderKey, + $complete_header, + $additional_header_values + ); + unset($additional_header_values['epk']); + + return $agreedKey; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA128KW.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA128KW.php new file mode 100644 index 000000000..1d5f2eb9e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/ECDHSSA128KW.php @@ -0,0 +1,25 @@ + $complete_header + * @param array $additional_header_values + */ + public function wrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $cek, + int $encryption_key_length, + array $complete_header, + array &$additional_header_values + ): string { + $ecdh_ss = new ECDHSS(); + $agreement_key = $ecdh_ss->getAgreementKey( + $this->getKeyLength(), + $this->name(), + $recipientKey->toPublic(), + $senderKey, + $complete_header, + $additional_header_values + ); + $wrapper = $this->getWrapper(); + + return $wrapper::wrap($agreement_key, $cek); + } + + /** + * @param array $complete_header + */ + public function unwrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $encrypted_cek, + int $encryption_key_length, + array $complete_header + ): string { + $ecdh_ss = new ECDHSS(); + $agreement_key = $ecdh_ss->getAgreementKey( + $this->getKeyLength(), + $this->name(), + $recipientKey, + $senderKey, + $complete_header + ); + $wrapper = $this->getWrapper(); + + return $wrapper::unwrap($agreement_key, $encrypted_cek); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreement.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreement.php new file mode 100644 index 000000000..270ffa66f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreement.php @@ -0,0 +1,26 @@ + $completeHeader + * @param array $additionalHeaderValues + */ + public function getAgreementKey( + int $encryptionKeyLength, + string $algorithm, + JWK $recipientKey, + ?JWK $senderKey, + array $completeHeader = [], + array &$additionalHeaderValues = [] + ): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreementWithKeyWrapping.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreementWithKeyWrapping.php new file mode 100644 index 000000000..d6908edc8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyAgreementWithKeyWrapping.php @@ -0,0 +1,47 @@ + $complete_header The complete header of the JWT + * @param array $additional_header_values Set additional header values if needed + */ + public function wrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $cek, + int $encryption_key_length, + array $complete_header, + array &$additional_header_values + ): string; + + /** + * Unwrap and compute the agreement key. + * + * @param JWK $recipientKey The receiver's key + * @param string $encrypted_cek The encrypted CEK + * @param int $encryption_key_length Size of the key expected for the algorithm used for data encryption + * @param array $complete_header The complete header of the JWT + * + * @return string The decrypted CEK + */ + public function unwrapAgreementKey( + JWK $recipientKey, + ?JWK $senderKey, + string $encrypted_cek, + int $encryption_key_length, + array $complete_header + ): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyEncryption.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyEncryption.php new file mode 100644 index 000000000..f27f7fca4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyEncryption.php @@ -0,0 +1,30 @@ + $completeHeader The complete header of the JWT + * @param array $additionalHeader Additional header + */ + public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string; + + /** + * Decrypt de CEK. + * + * @param JWK $key The key used to wrap the CEK + * @param string $encrypted_cek The CEK to decrypt + * @param array $header The complete header of the JWT + */ + public function decryptKey(JWK $key, string $encrypted_cek, array $header): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyWrapping.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyWrapping.php new file mode 100644 index 000000000..e5b37825d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/KeyWrapping.php @@ -0,0 +1,30 @@ + $completeHeader The complete header of the JWT + * @param array $additionalHeader The complete header of the JWT + */ + public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string; + + /** + * Decrypt de CEK. + * + * @param JWK $key The key used to wrap the CEK + * @param string $encrypted_cek The CEK to decrypt + * @param array $completeHeader The complete header of the JWT + */ + public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php new file mode 100644 index 000000000..a93f9ee97 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2AESKW.php @@ -0,0 +1,144 @@ + $completeHeader + * @param array $additionalHeader + */ + public function wrapKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string + { + $password = $this->getKey($key); + $this->checkHeaderAlgorithm($completeHeader); + $wrapper = $this->getWrapper(); + $hash_algorithm = $this->getHashAlgorithm(); + $key_size = $this->getKeySize(); + $salt = random_bytes($this->salt_size); + + // We set header parameters + $additionalHeader['p2s'] = Base64UrlSafe::encodeUnpadded($salt); + $additionalHeader['p2c'] = $this->nb_count; + + $derived_key = hash_pbkdf2( + $hash_algorithm, + $password, + $completeHeader['alg'] . "\x00" . $salt, + $this->nb_count, + $key_size, + true + ); + + return $wrapper::wrap($derived_key, $cek); + } + + /** + * @param array $completeHeader + */ + public function unwrapKey(JWK $key, string $encrypted_cek, array $completeHeader): string + { + $password = $this->getKey($key); + $this->checkHeaderAlgorithm($completeHeader); + $this->checkHeaderAdditionalParameters($completeHeader); + $wrapper = $this->getWrapper(); + $hash_algorithm = $this->getHashAlgorithm(); + $key_size = $this->getKeySize(); + $p2s = $completeHeader['p2s']; + is_string($p2s) || throw new InvalidArgumentException('Invalid salt.'); + $salt = $completeHeader['alg'] . "\x00" . Base64UrlSafe::decodeNoPadding($p2s); + $count = $completeHeader['p2c']; + is_int($count) || throw new InvalidArgumentException('Invalid counter.'); + + $derived_key = hash_pbkdf2($hash_algorithm, $password, $salt, $count, $key_size, true); + + return $wrapper::unwrap($derived_key, $encrypted_cek); + } + + public function getKeyManagementMode(): string + { + return self::MODE_WRAP; + } + + protected function getKey(JWK $key): string + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + if (! $key->has('k')) { + throw new InvalidArgumentException('The key parameter "k" is missing.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new InvalidArgumentException('The key parameter "k" is invalid.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + } + + /** + * @param array $header + */ + protected function checkHeaderAlgorithm(array $header): void + { + if (! isset($header['alg'])) { + throw new InvalidArgumentException('The header parameter "alg" is missing.'); + } + if (! is_string($header['alg'])) { + throw new InvalidArgumentException('The header parameter "alg" is not valid.'); + } + } + + /** + * @param array $header + */ + protected function checkHeaderAdditionalParameters(array $header): void + { + if (! isset($header['p2s'])) { + throw new InvalidArgumentException('The header parameter "p2s" is missing.'); + } + if (! is_string($header['p2s'])) { + throw new InvalidArgumentException('The header parameter "p2s" is not valid.'); + } + if (! isset($header['p2c'])) { + throw new InvalidArgumentException('The header parameter "p2c" is missing.'); + } + if (! is_int($header['p2c']) || $header['p2c'] <= 0) { + throw new InvalidArgumentException('The header parameter "p2c" is not valid.'); + } + } + + abstract protected function getWrapper(): A256KW|A128KW|A192KW; + + abstract protected function getHashAlgorithm(): string; + + abstract protected function getKeySize(): int; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS256A128KW.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS256A128KW.php new file mode 100644 index 000000000..645ac0f23 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/PBES2HS256A128KW.php @@ -0,0 +1,30 @@ + $completeHeader + * @param array $additionalHeader + */ + public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string + { + $this->checkKey($key); + $pub = RSAKey::toPublic(RSAKey::createFromJWK($key)); + + return RSACrypt::encrypt($pub, $cek, $this->getEncryptionMode(), $this->getHashAlgorithm()); + } + + /** + * @param array $header + */ + public function decryptKey(JWK $key, string $encrypted_cek, array $header): string + { + $this->checkKey($key); + if (! $key->has('d')) { + throw new InvalidArgumentException('The key is not a private key'); + } + $priv = RSAKey::createFromJWK($key); + + return RSACrypt::decrypt($priv, $encrypted_cek, $this->getEncryptionMode(), $this->getHashAlgorithm()); + } + + public function getKeyManagementMode(): string + { + return self::MODE_ENCRYPT; + } + + protected function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + } + + abstract protected function getEncryptionMode(): int; + + abstract protected function getHashAlgorithm(): ?string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA15.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA15.php new file mode 100644 index 000000000..0480e2148 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryption/RSA15.php @@ -0,0 +1,25 @@ + $key->getModulusLength() - 11) { + throw new InvalidArgumentException('Message too long'); + } + + $psLen = $key->getModulusLength() - $mLen - 3; + $ps = ''; + while (mb_strlen($ps, '8bit') !== $psLen) { + $temp = random_bytes($psLen - mb_strlen($ps, '8bit')); + $temp = str_replace("\x00", '', $temp); + $ps .= $temp; + } + $type = 2; + $data = chr(0) . chr($type) . $ps . chr(0) . $data; + + $binaryData = BigInteger::createFromBinaryString($data); + $c = self::getRSAEP($key, $binaryData); + + return self::convertIntegerToOctetString($c, $key->getModulusLength()); + } + + public static function decryptWithRSA15(RSAKey $key, string $c): string + { + if (mb_strlen($c, '8bit') !== $key->getModulusLength()) { + throw new InvalidArgumentException('Unable to decrypt'); + } + $c = BigInteger::createFromBinaryString($c); + $m = self::getRSADP($key, $c); + $em = self::convertIntegerToOctetString($m, $key->getModulusLength()); + if (ord($em[0]) !== 0 || ord($em[1]) > 2) { + throw new InvalidArgumentException('Unable to decrypt'); + } + $ps = mb_substr($em, 2, (int) mb_strpos($em, chr(0), 2, '8bit') - 2, '8bit'); + $m = mb_substr($em, mb_strlen($ps, '8bit') + 3, null, '8bit'); + if (mb_strlen($ps, '8bit') < 8) { + throw new InvalidArgumentException('Unable to decrypt'); + } + + return $m; + } + + /** + * Encryption. + */ + public static function encryptWithRSAOAEP(RSAKey $key, string $plaintext, string $hash_algorithm): string + { + /** @var Hash $hash */ + $hash = Hash::$hash_algorithm(); + $length = $key->getModulusLength() - 2 * $hash->getLength() - 2; + if ($length <= 0) { + throw new RuntimeException(); + } + $splitPlaintext = mb_str_split($plaintext, $length, '8bit'); + $ciphertext = ''; + foreach ($splitPlaintext as $m) { + $ciphertext .= self::encryptRSAESOAEP($key, $m, $hash); + } + + return $ciphertext; + } + + /** + * Decryption. + */ + public static function decryptWithRSAOAEP(RSAKey $key, string $ciphertext, string $hash_algorithm): string + { + if ($key->getModulusLength() <= 0) { + throw new RuntimeException('Invalid modulus length'); + } + $hash = Hash::$hash_algorithm(); + $splitCiphertext = mb_str_split($ciphertext, $key->getModulusLength(), '8bit'); + $splitCiphertext[count($splitCiphertext) - 1] = str_pad( + $splitCiphertext[count($splitCiphertext) - 1], + $key->getModulusLength(), + chr(0), + STR_PAD_LEFT + ); + $plaintext = ''; + foreach ($splitCiphertext as $c) { + $temp = self::getRSAESOAEP($key, $c, $hash); + $plaintext .= $temp; + } + + return $plaintext; + } + + private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string + { + $x = $x->toBytes(); + if (mb_strlen($x, '8bit') > $xLen) { + throw new RuntimeException('Invalid length.'); + } + + return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); + } + + /** + * Octet-String-to-Integer primitive. + */ + private static function convertOctetStringToInteger(string $x): BigInteger + { + return BigInteger::createFromBinaryString($x); + } + + /** + * RSA EP. + */ + private static function getRSAEP(RSAKey $key, BigInteger $m): BigInteger + { + if ($m->compare(BigInteger::createFromDecimal(0)) < 0 || $m->compare($key->getModulus()) > 0) { + throw new RuntimeException(); + } + + return RSAKey::exponentiate($key, $m); + } + + /** + * RSA DP. + */ + private static function getRSADP(RSAKey $key, BigInteger $c): BigInteger + { + if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) { + throw new RuntimeException(); + } + + return RSAKey::exponentiate($key, $c); + } + + /** + * MGF1. + */ + private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string + { + $t = ''; + $count = ceil($maskLen / $mgfHash->getLength()); + for ($i = 0; $i < $count; ++$i) { + $c = pack('N', $i); + $t .= $mgfHash->hash($mgfSeed . $c); + } + + return mb_substr($t, 0, $maskLen, '8bit'); + } + + /** + * RSAES-OAEP-ENCRYPT. + */ + private static function encryptRSAESOAEP(RSAKey $key, string $m, Hash $hash): string + { + $mLen = mb_strlen($m, '8bit'); + $lHash = $hash->hash(''); + $ps = str_repeat(chr(0), $key->getModulusLength() - $mLen - 2 * $hash->getLength() - 2); + $db = $lHash . $ps . chr(1) . $m; + $seed = random_bytes($hash->getLength()); + $dbMask = self::getMGF1($seed, $key->getModulusLength() - $hash->getLength() - 1, $hash/*MGF*/); + $maskedDB = $db ^ $dbMask; + $seedMask = self::getMGF1($maskedDB, $hash->getLength(), $hash/*MGF*/); + $maskedSeed = $seed ^ $seedMask; + $em = chr(0) . $maskedSeed . $maskedDB; + + $m = self::convertOctetStringToInteger($em); + $c = self::getRSAEP($key, $m); + + return self::convertIntegerToOctetString($c, $key->getModulusLength()); + } + + /** + * RSAES-OAEP-DECRYPT. + */ + private static function getRSAESOAEP(RSAKey $key, string $c, Hash $hash): string + { + $c = self::convertOctetStringToInteger($c); + $m = self::getRSADP($key, $c); + $em = self::convertIntegerToOctetString($m, $key->getModulusLength()); + $lHash = $hash->hash(''); + $maskedSeed = mb_substr($em, 1, $hash->getLength(), '8bit'); + $maskedDB = mb_substr($em, $hash->getLength() + 1, null, '8bit'); + $seedMask = self::getMGF1($maskedDB, $hash->getLength(), $hash/*MGF*/); + $seed = $maskedSeed ^ $seedMask; + $dbMask = self::getMGF1($seed, $key->getModulusLength() - $hash->getLength() - 1, $hash/*MGF*/); + $db = $maskedDB ^ $dbMask; + $lHash2 = mb_substr($db, 0, $hash->getLength(), '8bit'); + $m = mb_substr($db, $hash->getLength(), null, '8bit'); + if (! hash_equals($lHash, $lHash2)) { + throw new RuntimeException(); + } + $m = ltrim($m, chr(0)); + if (ord($m[0]) !== 1) { + throw new RuntimeException(); + } + + return mb_substr($m, 1, null, '8bit'); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryptionAlgorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryptionAlgorithm.php new file mode 100644 index 000000000..9012a2022 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Algorithm/KeyEncryptionAlgorithm.php @@ -0,0 +1,23 @@ +add($method); + } + } + + /** + * Returns true if the givn compression method is supported. + */ + public function has(string $name): bool + { + return array_key_exists($name, $this->compressionMethods); + } + + /** + * This method returns the compression method with the given name. Throws an exception if the method is not + * supported. + * + * @param string $name The name of the compression method + */ + public function get(string $name): CompressionMethod + { + if (! $this->has($name)) { + throw new InvalidArgumentException(sprintf('The compression method "%s" is not supported.', $name)); + } + + return $this->compressionMethods[$name]; + } + + /** + * Returns the list of compression method names supported by the manager. + * + * @return string[] + */ + public function list(): array + { + return array_keys($this->compressionMethods); + } + + /** + * Add the given compression method to the manager. + */ + protected function add(CompressionMethod $compressionMethod): void + { + $name = $compressionMethod->name(); + $this->compressionMethods[$name] = $compressionMethod; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/CompressionMethodManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/CompressionMethodManagerFactory.php new file mode 100644 index 000000000..592ae7bbb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/CompressionMethodManagerFactory.php @@ -0,0 +1,69 @@ +compressionMethods[$alias] = $compressionMethod; + } + + /** + * Returns the list of compression method aliases supported by the factory. + * + * @return string[] + */ + public function aliases(): array + { + return array_keys($this->compressionMethods); + } + + /** + * Returns all compression methods supported by this factory. + * + * @return CompressionMethod[] + */ + public function all(): array + { + return $this->compressionMethods; + } + + /** + * Creates a compression method manager using the compression methods identified by the given aliases. If one of the + * aliases does not exist, an exception is thrown. + * + * @param string[] $aliases + */ + public function create(array $aliases): CompressionMethodManager + { + $compressionMethods = []; + foreach ($aliases as $alias) { + if (! isset($this->compressionMethods[$alias])) { + throw new InvalidArgumentException(sprintf( + 'The compression method with the alias "%s" is not supported.', + $alias + )); + } + $compressionMethods[] = $this->compressionMethods[$alias]; + } + + return new CompressionMethodManager($compressionMethods); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/Deflate.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/Deflate.php new file mode 100644 index 000000000..5c3deaa4e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Compression/Deflate.php @@ -0,0 +1,65 @@ + 9) { + throw new InvalidArgumentException( + 'The compression level can be given as 0 for no compression up to 9 for maximum compression. If -1 given, the default compression level will be the default compression level of the zlib library.' + ); + } + $this->compressionLevel = $compressionLevel; + } + + public function name(): string + { + return 'DEF'; + } + + public function compress(string $data): string + { + try { + $bin = gzdeflate($data, $this->getCompressionLevel()); + if (! is_string($bin)) { + throw new InvalidArgumentException('Unable to encode the data'); + } + + return $bin; + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unable to compress data.', $throwable->getCode(), $throwable); + } + } + + public function uncompress(string $data): string + { + try { + $bin = gzinflate($data); + if (! is_string($bin)) { + throw new InvalidArgumentException('Unable to encode the data'); + } + + return $bin; + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unable to uncompress data.', $throwable->getCode(), $throwable); + } + } + + private function getCompressionLevel(): int + { + return $this->compressionLevel; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWE.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWE.php new file mode 100644 index 000000000..199085cd9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWE.php @@ -0,0 +1,218 @@ +payload; + } + + /** + * Set the payload. This method is immutable and a new object will be returned. + */ + public function withPayload(string $payload): self + { + $clone = clone $this; + $clone->payload = $payload; + + return $clone; + } + + /** + * Returns the number of recipients associated with the JWS. + */ + public function countRecipients(): int + { + return count($this->recipients); + } + + /** + * Returns true is the JWE has already been encrypted. + */ + public function isEncrypted(): bool + { + return $this->getCiphertext() !== null; + } + + /** + * Returns the recipients associated with the JWS. + * + * @return Recipient[] + */ + public function getRecipients(): array + { + return $this->recipients; + } + + /** + * Returns the recipient object at the given index. + */ + public function getRecipient(int $id): Recipient + { + if (! isset($this->recipients[$id])) { + throw new InvalidArgumentException('The recipient does not exist.'); + } + + return $this->recipients[$id]; + } + + /** + * Returns the ciphertext. This method will return null is the JWE has not yet been encrypted. + * + * @return string|null The ciphertext + */ + public function getCiphertext(): ?string + { + return $this->ciphertext; + } + + /** + * Returns the Additional Authentication Data if available. + */ + public function getAAD(): ?string + { + return $this->aad; + } + + /** + * Returns the Initialization Vector if available. + */ + public function getIV(): ?string + { + return $this->iv; + } + + /** + * Returns the tag if available. + */ + public function getTag(): ?string + { + return $this->tag; + } + + /** + * Returns the encoded shared protected header. + */ + public function getEncodedSharedProtectedHeader(): string + { + return $this->encodedSharedProtectedHeader ?? ''; + } + + /** + * Returns the shared protected header. + */ + public function getSharedProtectedHeader(): array + { + return $this->sharedProtectedHeader; + } + + /** + * Returns the shared protected header parameter identified by the given key. Throws an exception is the the + * parameter is not available. + * + * @param string $key The key + * + * @return mixed|null + */ + public function getSharedProtectedHeaderParameter(string $key) + { + if (! $this->hasSharedProtectedHeaderParameter($key)) { + throw new InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key)); + } + + return $this->sharedProtectedHeader[$key]; + } + + /** + * Returns true if the shared protected header has the parameter identified by the given key. + * + * @param string $key The key + */ + public function hasSharedProtectedHeaderParameter(string $key): bool + { + return array_key_exists($key, $this->sharedProtectedHeader); + } + + /** + * Returns the shared header. + */ + public function getSharedHeader(): array + { + return $this->sharedHeader; + } + + /** + * Returns the shared header parameter identified by the given key. Throws an exception is the the parameter is not + * available. + * + * @param string $key The key + * + * @return mixed|null + */ + public function getSharedHeaderParameter(string $key) + { + if (! $this->hasSharedHeaderParameter($key)) { + throw new InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key)); + } + + return $this->sharedHeader[$key]; + } + + /** + * Returns true if the shared header has the parameter identified by the given key. + * + * @param string $key The key + */ + public function hasSharedHeaderParameter(string $key): bool + { + return array_key_exists($key, $this->sharedHeader); + } + + /** + * This method splits the JWE into a list of JWEs. It is only useful when the JWE contains more than one recipient + * (JSON General Serialization). + * + * @return JWE[] + */ + public function split(): array + { + $result = []; + foreach ($this->recipients as $recipient) { + $result[] = new self( + $this->ciphertext, + $this->iv, + $this->tag, + $this->aad, + $this->sharedHeader, + $this->sharedProtectedHeader, + $this->encodedSharedProtectedHeader, + [$recipient] + ); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilder.php new file mode 100644 index 000000000..505ae6672 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilder.php @@ -0,0 +1,618 @@ +keyEncryptionAlgorithmManager = $algorithmManager; + $this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager; + } else { + $keyEncryptionAlgorithms = []; + $contentEncryptionAlgorithms = []; + foreach ($algorithmManager->all() as $algorithm) { + if ($algorithm instanceof KeyEncryptionAlgorithm) { + $keyEncryptionAlgorithms[] = $algorithm; + } + if ($algorithm instanceof ContentEncryptionAlgorithm) { + $contentEncryptionAlgorithms[] = $algorithm; + } + } + $this->keyEncryptionAlgorithmManager = new AlgorithmManager($keyEncryptionAlgorithms); + $this->contentEncryptionAlgorithmManager = new AlgorithmManager($contentEncryptionAlgorithms); + } + } + + /** + * Reset the current data. + */ + public function create(): self + { + $this->senderKey = null; + $this->payload = null; + $this->aad = null; + $this->recipients = []; + $this->sharedProtectedHeader = []; + $this->sharedHeader = []; + $this->compressionMethod = null; + $this->keyManagementMode = null; + + return $this; + } + + /** + * Returns the key encryption algorithm manager. + */ + public function getKeyEncryptionAlgorithmManager(): AlgorithmManager + { + return $this->keyEncryptionAlgorithmManager; + } + + /** + * Returns the content encryption algorithm manager. + */ + public function getContentEncryptionAlgorithmManager(): AlgorithmManager + { + return $this->contentEncryptionAlgorithmManager; + } + + /** + * Returns the compression method manager. + * @deprecated This method is deprecated and will be removed in v4.0. Compression is not recommended for JWE. + */ + public function getCompressionMethodManager(): null|CompressionMethodManager + { + return $this->compressionManager; + } + + /** + * Set the payload of the JWE to build. + */ + public function withPayload(string $payload): self + { + $clone = clone $this; + $clone->payload = $payload; + + return $clone; + } + + /** + * Set the Additional Authenticated Data of the JWE to build. + */ + public function withAAD(?string $aad): self + { + $clone = clone $this; + $clone->aad = $aad; + + return $clone; + } + + /** + * Set the shared protected header of the JWE to build. + */ + public function withSharedProtectedHeader(array $sharedProtectedHeader): self + { + $this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $this->sharedHeader); + foreach ($this->recipients as $recipient) { + $this->checkDuplicatedHeaderParameters($sharedProtectedHeader, $recipient->getHeader()); + } + $clone = clone $this; + $clone->sharedProtectedHeader = $sharedProtectedHeader; + + return $clone; + } + + /** + * Set the shared header of the JWE to build. + */ + public function withSharedHeader(array $sharedHeader): self + { + $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $sharedHeader); + foreach ($this->recipients as $recipient) { + $this->checkDuplicatedHeaderParameters($sharedHeader, $recipient->getHeader()); + } + $clone = clone $this; + $clone->sharedHeader = $sharedHeader; + + return $clone; + } + + /** + * Adds a recipient to the JWE to build. + */ + public function addRecipient(JWK $recipientKey, array $recipientHeader = []): self + { + $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeader, $recipientHeader); + $this->checkDuplicatedHeaderParameters($this->sharedHeader, $recipientHeader); + $clone = clone $this; + $completeHeader = array_merge($clone->sharedHeader, $recipientHeader, $clone->sharedProtectedHeader); + $clone->checkAndSetContentEncryptionAlgorithm($completeHeader); + $keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeader); + if ($clone->keyManagementMode === null) { + $clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode(); + } else { + if (! $clone->areKeyManagementModesCompatible( + $clone->keyManagementMode, + $keyEncryptionAlgorithm->getKeyManagementMode() + )) { + throw new InvalidArgumentException('Foreign key management mode forbidden.'); + } + } + + $compressionMethod = $clone->getCompressionMethod($completeHeader); + if ($compressionMethod !== null) { + if ($clone->compressionMethod === null) { + $clone->compressionMethod = $compressionMethod; + } elseif ($clone->compressionMethod->name() !== $compressionMethod->name()) { + throw new InvalidArgumentException('Incompatible compression method.'); + } + } + if ($compressionMethod === null && $clone->compressionMethod !== null) { + throw new InvalidArgumentException('Inconsistent compression method.'); + } + $clone->checkKey($keyEncryptionAlgorithm, $recipientKey); + $clone->recipients[] = [ + 'key' => $recipientKey, + 'header' => $recipientHeader, + 'key_encryption_algorithm' => $keyEncryptionAlgorithm, + ]; + + return $clone; + } + + //TODO: Verify if the key is compatible with the key encryption algorithm like is done to the ECDH-ES + /** + * Set the sender JWK to be used instead of the internal generated JWK + */ + public function withSenderKey(JWK $senderKey): self + { + $clone = clone $this; + $completeHeader = array_merge($clone->sharedHeader, $clone->sharedProtectedHeader); + $keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeader); + if ($clone->keyManagementMode === null) { + $clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode(); + } else { + if (! $clone->areKeyManagementModesCompatible( + $clone->keyManagementMode, + $keyEncryptionAlgorithm->getKeyManagementMode() + )) { + throw new InvalidArgumentException('Foreign key management mode forbidden.'); + } + } + $clone->checkKey($keyEncryptionAlgorithm, $senderKey); + $clone->senderKey = $senderKey; + + return $clone; + } + + /** + * Builds the JWE. + */ + public function build(): JWE + { + if ($this->payload === null) { + throw new LogicException('Payload not set.'); + } + if (count($this->recipients) === 0) { + throw new LogicException('No recipient.'); + } + + $additionalHeader = []; + $cek = $this->determineCEK($additionalHeader); + + $recipients = []; + foreach ($this->recipients as $recipient) { + $recipient = $this->processRecipient($recipient, $cek, $additionalHeader); + $recipients[] = $recipient; + } + + if ((is_countable($additionalHeader) ? count($additionalHeader) : 0) !== 0 && count($this->recipients) === 1) { + $sharedProtectedHeader = array_merge($additionalHeader, $this->sharedProtectedHeader); + } else { + $sharedProtectedHeader = $this->sharedProtectedHeader; + } + $encodedSharedProtectedHeader = count($sharedProtectedHeader) === 0 ? '' : Base64UrlSafe::encodeUnpadded( + JsonConverter::encode($sharedProtectedHeader) + ); + + [$ciphertext, $iv, $tag] = $this->encryptJWE($cek, $encodedSharedProtectedHeader); + + return new JWE( + $ciphertext, + $iv, + $tag, + $this->aad, + $this->sharedHeader, + $sharedProtectedHeader, + $encodedSharedProtectedHeader, + $recipients + ); + } + + private function checkAndSetContentEncryptionAlgorithm(array $completeHeader): void + { + $contentEncryptionAlgorithm = $this->getContentEncryptionAlgorithm($completeHeader); + if ($this->contentEncryptionAlgorithm === null) { + $this->contentEncryptionAlgorithm = $contentEncryptionAlgorithm; + } elseif ($contentEncryptionAlgorithm->name() !== $this->contentEncryptionAlgorithm->name()) { + throw new InvalidArgumentException('Inconsistent content encryption algorithm'); + } + } + + private function processRecipient(array $recipient, string $cek, array &$additionalHeader): Recipient + { + $completeHeader = array_merge($this->sharedHeader, $recipient['header'], $this->sharedProtectedHeader); + $keyEncryptionAlgorithm = $recipient['key_encryption_algorithm']; + if (! $keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) { + throw new InvalidArgumentException('The key encryption algorithm is not valid'); + } + $encryptedContentEncryptionKey = $this->getEncryptedKey( + $completeHeader, + $cek, + $keyEncryptionAlgorithm, + $additionalHeader, + $recipient['key'], + $recipient['sender_key'] ?? $this->senderKey ?? null + ); + $recipientHeader = $recipient['header']; + if ((is_countable($additionalHeader) ? count($additionalHeader) : 0) !== 0 && count($this->recipients) !== 1) { + $recipientHeader = array_merge($recipientHeader, $additionalHeader); + $additionalHeader = []; + } + + return new Recipient($recipientHeader, $encryptedContentEncryptionKey); + } + + private function encryptJWE(string $cek, string $encodedSharedProtectedHeader): array + { + if (! $this->contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) { + throw new InvalidArgumentException('The content encryption algorithm is not valid'); + } + $iv_size = $this->contentEncryptionAlgorithm->getIVSize(); + $iv = $this->createIV($iv_size); + $payload = $this->preparePayload(); + $tag = null; + $ciphertext = $this->contentEncryptionAlgorithm->encryptContent( + $payload ?? '', + $cek, + $iv, + $this->aad, + $encodedSharedProtectedHeader, + $tag + ); + + return [$ciphertext, $iv, $tag]; + } + + private function preparePayload(): ?string + { + $prepared = $this->payload; + if ($this->compressionMethod === null) { + return $prepared; + } + + return $this->compressionMethod->compress($prepared ?? ''); + } + + private function getEncryptedKey( + array $completeHeader, + string $cek, + KeyEncryptionAlgorithm $keyEncryptionAlgorithm, + array &$additionalHeader, + JWK $recipientKey, + ?JWK $senderKey + ): ?string { + if ($keyEncryptionAlgorithm instanceof KeyEncryption) { + return $this->getEncryptedKeyFromKeyEncryptionAlgorithm( + $completeHeader, + $cek, + $keyEncryptionAlgorithm, + $recipientKey, + $additionalHeader + ); + } + if ($keyEncryptionAlgorithm instanceof KeyWrapping) { + return $this->getEncryptedKeyFromKeyWrappingAlgorithm( + $completeHeader, + $cek, + $keyEncryptionAlgorithm, + $recipientKey, + $additionalHeader + ); + } + if ($keyEncryptionAlgorithm instanceof KeyAgreementWithKeyWrapping) { + return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm( + $completeHeader, + $cek, + $keyEncryptionAlgorithm, + $additionalHeader, + $recipientKey, + $senderKey + ); + } + if ($keyEncryptionAlgorithm instanceof KeyAgreement) { + return null; + } + if ($keyEncryptionAlgorithm instanceof DirectEncryption) { + return null; + } + + throw new InvalidArgumentException('Unsupported key encryption algorithm.'); + } + + private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm( + array $completeHeader, + string $cek, + KeyAgreementWithKeyWrapping $keyEncryptionAlgorithm, + array &$additionalHeader, + JWK $recipientKey, + ?JWK $senderKey + ): string { + if ($this->contentEncryptionAlgorithm === null) { + throw new InvalidArgumentException('Invalid content encryption algorithm'); + } + + return $keyEncryptionAlgorithm->wrapAgreementKey( + $recipientKey, + $senderKey, + $cek, + $this->contentEncryptionAlgorithm->getCEKSize(), + $completeHeader, + $additionalHeader + ); + } + + private function getEncryptedKeyFromKeyEncryptionAlgorithm( + array $completeHeader, + string $cek, + KeyEncryption $keyEncryptionAlgorithm, + JWK $recipientKey, + array &$additionalHeader + ): string { + return $keyEncryptionAlgorithm->encryptKey($recipientKey, $cek, $completeHeader, $additionalHeader); + } + + private function getEncryptedKeyFromKeyWrappingAlgorithm( + array $completeHeader, + string $cek, + KeyWrapping $keyEncryptionAlgorithm, + JWK $recipientKey, + array &$additionalHeader + ): string { + return $keyEncryptionAlgorithm->wrapKey($recipientKey, $cek, $completeHeader, $additionalHeader); + } + + private function checkKey(KeyEncryptionAlgorithm $keyEncryptionAlgorithm, JWK $recipientKey): void + { + if ($this->contentEncryptionAlgorithm === null) { + throw new InvalidArgumentException('Invalid content encryption algorithm'); + } + + KeyChecker::checkKeyUsage($recipientKey, 'encryption'); + if ($keyEncryptionAlgorithm->name() !== 'dir') { + KeyChecker::checkKeyAlgorithm($recipientKey, $keyEncryptionAlgorithm->name()); + } else { + KeyChecker::checkKeyAlgorithm($recipientKey, $this->contentEncryptionAlgorithm->name()); + } + } + + private function determineCEK(array &$additionalHeader): string + { + if ($this->contentEncryptionAlgorithm === null) { + throw new InvalidArgumentException('Invalid content encryption algorithm'); + } + + switch ($this->keyManagementMode) { + case KeyEncryption::MODE_ENCRYPT: + case KeyEncryption::MODE_WRAP: + return $this->createCEK($this->contentEncryptionAlgorithm->getCEKSize()); + + case KeyEncryption::MODE_AGREEMENT: + if (count($this->recipients) !== 1) { + throw new LogicException( + 'Unable to encrypt for multiple recipients using key agreement algorithms.' + ); + } + $recipientKey = $this->recipients[0]['key']; + $senderKey = $this->recipients[0]['sender_key'] ?? null; + $algorithm = $this->recipients[0]['key_encryption_algorithm']; + if (! $algorithm instanceof KeyAgreement) { + throw new InvalidArgumentException('Invalid content encryption algorithm'); + } + $completeHeader = array_merge( + $this->sharedHeader, + $this->recipients[0]['header'], + $this->sharedProtectedHeader + ); + + return $algorithm->getAgreementKey( + $this->contentEncryptionAlgorithm->getCEKSize(), + $this->contentEncryptionAlgorithm->name(), + $recipientKey, + $senderKey, + $completeHeader, + $additionalHeader + ); + + case KeyEncryption::MODE_DIRECT: + if (count($this->recipients) !== 1) { + throw new LogicException( + 'Unable to encrypt for multiple recipients using key agreement algorithms.' + ); + } + /** @var JWK $key */ + $key = $this->recipients[0]['key']; + if ($key->get('kty') !== 'oct') { + throw new RuntimeException('Wrong key type.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new RuntimeException('Invalid key.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + + default: + throw new InvalidArgumentException(sprintf( + 'Unsupported key management mode "%s".', + $this->keyManagementMode + )); + } + } + + private function getCompressionMethod(array $completeHeader): ?CompressionMethod + { + if ($this->compressionManager === null || ! array_key_exists('zip', $completeHeader)) { + return null; + } + + return $this->compressionManager->get($completeHeader['zip']); + } + + private function areKeyManagementModesCompatible(string $current, string $new): bool + { + $agree = KeyEncryptionAlgorithm::MODE_AGREEMENT; + $dir = KeyEncryptionAlgorithm::MODE_DIRECT; + $enc = KeyEncryptionAlgorithm::MODE_ENCRYPT; + $wrap = KeyEncryptionAlgorithm::MODE_WRAP; + $supportedKeyManagementModeCombinations = [ + $enc . $enc => true, + $enc . $wrap => true, + $wrap . $enc => true, + $wrap . $wrap => true, + $agree . $agree => false, + $agree . $dir => false, + $agree . $enc => false, + $agree . $wrap => false, + $dir . $agree => false, + $dir . $dir => false, + $dir . $enc => false, + $dir . $wrap => false, + $enc . $agree => false, + $enc . $dir => false, + $wrap . $agree => false, + $wrap . $dir => false, + ]; + + if (array_key_exists($current . $new, $supportedKeyManagementModeCombinations)) { + return $supportedKeyManagementModeCombinations[$current . $new]; + } + + return false; + } + + private function createCEK(int $size): string + { + return random_bytes($size / 8); + } + + private function createIV(int $size): string + { + return random_bytes($size / 8); + } + + private function getKeyEncryptionAlgorithm(array $completeHeader): KeyEncryptionAlgorithm + { + if (! isset($completeHeader['alg'])) { + throw new InvalidArgumentException('Parameter "alg" is missing.'); + } + $keyEncryptionAlgorithm = $this->keyEncryptionAlgorithmManager->get($completeHeader['alg']); + if (! $keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithm) { + throw new InvalidArgumentException(sprintf( + 'The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', + $completeHeader['alg'] + )); + } + + return $keyEncryptionAlgorithm; + } + + private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm + { + if (! isset($completeHeader['enc'])) { + throw new InvalidArgumentException('Parameter "enc" is missing.'); + } + $contentEncryptionAlgorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']); + if (! $contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithm) { + throw new InvalidArgumentException(sprintf( + 'The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', + $completeHeader['enc'] + )); + } + + return $contentEncryptionAlgorithm; + } + + private function checkDuplicatedHeaderParameters(array $header1, array $header2): void + { + $inter = array_intersect_key($header1, $header2); + if (count($inter) !== 0) { + throw new InvalidArgumentException(sprintf( + 'The header contains duplicated entries: %s.', + implode(', ', array_keys($inter)) + )); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilderFactory.php new file mode 100644 index 000000000..038050898 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEBuilderFactory.php @@ -0,0 +1,53 @@ + $encryptionAlgorithms + * @param null|array $contentEncryptionAlgorithm + * @param null|string[] $compressionMethods + */ + public function create( + array $encryptionAlgorithms, + null|array $contentEncryptionAlgorithm = null, + null|array $compressionMethods = null + ): JWEBuilder { + if ($contentEncryptionAlgorithm !== null) { + trigger_deprecation( + 'web-token/jwt-library', + '3.3.0', + 'The parameter "$contentEncryptionAlgorithm" is deprecated and will be removed in 4.0.0. Please set "null" instead.' + ); + $encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithm); + } + $encryptionAlgorithmManager = $this->algorithmManagerFactory->create($encryptionAlgorithms); + $compressionMethodManager = $compressionMethods === null ? null : $this->compressionMethodManagerFactory?->create( + $compressionMethods + ); + + return new JWEBuilder($encryptionAlgorithmManager, null, $compressionMethodManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypter.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypter.php new file mode 100644 index 000000000..0b17b4aab --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypter.php @@ -0,0 +1,324 @@ +keyEncryptionAlgorithmManager = $algorithmManager; + $this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager; + } else { + $keyEncryptionAlgorithms = []; + $contentEncryptionAlgorithms = []; + foreach ($algorithmManager->all() as $key => $algorithm) { + if ($algorithm instanceof KeyEncryptionAlgorithm) { + $keyEncryptionAlgorithms[$key] = $algorithm; + } + if ($algorithm instanceof ContentEncryptionAlgorithm) { + $contentEncryptionAlgorithms[$key] = $algorithm; + } + } + $this->keyEncryptionAlgorithmManager = new AlgorithmManager($keyEncryptionAlgorithms); + $this->contentEncryptionAlgorithmManager = new AlgorithmManager($contentEncryptionAlgorithms); + } + } + + /** + * Returns the key encryption algorithm manager. + */ + public function getKeyEncryptionAlgorithmManager(): AlgorithmManager + { + return $this->keyEncryptionAlgorithmManager; + } + + /** + * Returns the content encryption algorithm manager. + */ + public function getContentEncryptionAlgorithmManager(): AlgorithmManager + { + return $this->contentEncryptionAlgorithmManager; + } + + /** + * Returns the compression method manager. + * @deprecated This method is deprecated and will be removed in v4.0. Compression is not recommended for JWE. + */ + public function getCompressionMethodManager(): null|CompressionMethodManager + { + return $this->compressionMethodManager; + } + + /** + * This method will try to decrypt the given JWE and recipient using a JWK. + * + * @param JWE $jwe A JWE object to decrypt + * @param JWK $jwk The key used to decrypt the input + * @param int $recipient The recipient used to decrypt the token + */ + public function decryptUsingKey(JWE &$jwe, JWK $jwk, int $recipient, ?JWK $senderKey = null): bool + { + $jwkset = new JWKSet([$jwk]); + + return $this->decryptUsingKeySet($jwe, $jwkset, $recipient, $senderKey); + } + + /** + * This method will try to decrypt the given JWE and recipient using a JWKSet. + * + * @param JWE $jwe A JWE object to decrypt + * @param JWKSet $jwkset The key set used to decrypt the input + * @param JWK $jwk The key used to decrypt the token in case of success + * @param int $recipient The recipient used to decrypt the token in case of success + */ + public function decryptUsingKeySet( + JWE &$jwe, + JWKSet $jwkset, + int $recipient, + ?JWK &$jwk = null, + ?JWK $senderKey = null + ): bool { + if ($jwkset->count() === 0) { + throw new InvalidArgumentException('No key in the key set.'); + } + if ($jwe->getPayload() !== null) { + return true; + } + if ($jwe->countRecipients() === 0) { + throw new InvalidArgumentException('The JWE does not contain any recipient.'); + } + + $plaintext = $this->decryptRecipientKey($jwe, $jwkset, $recipient, $jwk, $senderKey); + if ($plaintext !== null) { + $jwe = $jwe->withPayload($plaintext); + + return true; + } + + return false; + } + + private function decryptRecipientKey( + JWE $jwe, + JWKSet $jwkset, + int $i, + ?JWK &$successJwk = null, + ?JWK $senderKey = null + ): ?string { + $recipient = $jwe->getRecipient($i); + $completeHeader = array_merge( + $jwe->getSharedProtectedHeader(), + $jwe->getSharedHeader(), + $recipient->getHeader() + ); + $this->checkCompleteHeader($completeHeader); + + $key_encryption_algorithm = $this->getKeyEncryptionAlgorithm($completeHeader); + $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($completeHeader); + + $this->checkIvSize($jwe->getIV(), $content_encryption_algorithm->getIVSize()); + + foreach ($jwkset as $recipientKey) { + try { + KeyChecker::checkKeyUsage($recipientKey, 'decryption'); + if ($key_encryption_algorithm->name() !== 'dir') { + KeyChecker::checkKeyAlgorithm($recipientKey, $key_encryption_algorithm->name()); + } else { + KeyChecker::checkKeyAlgorithm($recipientKey, $content_encryption_algorithm->name()); + } + $cek = $this->decryptCEK( + $key_encryption_algorithm, + $content_encryption_algorithm, + $recipientKey, + $senderKey, + $recipient, + $completeHeader + ); + $this->checkCekSize($cek, $key_encryption_algorithm, $content_encryption_algorithm); + $payload = $this->decryptPayload($jwe, $cek, $content_encryption_algorithm, $completeHeader); + $successJwk = $recipientKey; + + return $payload; + } catch (Throwable) { + //We do nothing, we continue with other keys + continue; + } + } + + return null; + } + + private function checkCekSize( + string $cek, + KeyEncryptionAlgorithm $keyEncryptionAlgorithm, + ContentEncryptionAlgorithm $algorithm + ): void { + if ($keyEncryptionAlgorithm instanceof DirectEncryption || $keyEncryptionAlgorithm instanceof KeyAgreement) { + return; + } + if (mb_strlen($cek, '8bit') * 8 !== $algorithm->getCEKSize()) { + throw new InvalidArgumentException('Invalid CEK size'); + } + } + + private function checkIvSize(?string $iv, int $requiredIvSize): void + { + if ($iv === null && $requiredIvSize !== 0) { + throw new InvalidArgumentException('Invalid IV size'); + } + if (is_string($iv) && mb_strlen($iv, '8bit') !== $requiredIvSize / 8) { + throw new InvalidArgumentException('Invalid IV size'); + } + } + + private function decryptCEK( + Algorithm $key_encryption_algorithm, + ContentEncryptionAlgorithm $content_encryption_algorithm, + JWK $recipientKey, + ?JWK $senderKey, + Recipient $recipient, + array $completeHeader + ): string { + if ($key_encryption_algorithm instanceof DirectEncryption) { + return $key_encryption_algorithm->getCEK($recipientKey); + } + if ($key_encryption_algorithm instanceof KeyAgreement) { + return $key_encryption_algorithm->getAgreementKey( + $content_encryption_algorithm->getCEKSize(), + $content_encryption_algorithm->name(), + $recipientKey, + $senderKey, + $completeHeader + ); + } + if ($key_encryption_algorithm instanceof KeyAgreementWithKeyWrapping) { + return $key_encryption_algorithm->unwrapAgreementKey( + $recipientKey, + $senderKey, + $recipient->getEncryptedKey() ?? '', + $content_encryption_algorithm->getCEKSize(), + $completeHeader + ); + } + if ($key_encryption_algorithm instanceof KeyEncryption) { + return $key_encryption_algorithm->decryptKey( + $recipientKey, + $recipient->getEncryptedKey() ?? '', + $completeHeader + ); + } + if ($key_encryption_algorithm instanceof KeyWrapping) { + return $key_encryption_algorithm->unwrapKey( + $recipientKey, + $recipient->getEncryptedKey() ?? '', + $completeHeader + ); + } + + throw new InvalidArgumentException('Unsupported CEK generation'); + } + + private function decryptPayload( + JWE $jwe, + string $cek, + ContentEncryptionAlgorithm $content_encryption_algorithm, + array $completeHeader + ): string { + $payload = $content_encryption_algorithm->decryptContent( + $jwe->getCiphertext() ?? '', + $cek, + $jwe->getIV() ?? '', + $jwe->getAAD(), + $jwe->getEncodedSharedProtectedHeader(), + $jwe->getTag() ?? '' + ); + + return $this->decompressIfNeeded($payload, $completeHeader); + } + + private function decompressIfNeeded(string $payload, array $completeHeaders): string + { + if ($this->compressionMethodManager === null || ! array_key_exists('zip', $completeHeaders)) { + return $payload; + } + + $compression_method = $this->compressionMethodManager->get($completeHeaders['zip']); + + return $compression_method->uncompress($payload); + } + + private function checkCompleteHeader(array $completeHeaders): void + { + foreach (['enc', 'alg'] as $key) { + if (! isset($completeHeaders[$key])) { + throw new InvalidArgumentException(sprintf("Parameter '%s' is missing.", $key)); + } + } + } + + private function getKeyEncryptionAlgorithm(array $completeHeaders): KeyEncryptionAlgorithm + { + $key_encryption_algorithm = $this->keyEncryptionAlgorithmManager->get($completeHeaders['alg']); + if (! $key_encryption_algorithm instanceof KeyEncryptionAlgorithm) { + throw new InvalidArgumentException(sprintf( + 'The key encryption algorithm "%s" is not supported or does not implement KeyEncryptionAlgorithm interface.', + $completeHeaders['alg'] + )); + } + + return $key_encryption_algorithm; + } + + private function getContentEncryptionAlgorithm(array $completeHeader): ContentEncryptionAlgorithm + { + $content_encryption_algorithm = $this->contentEncryptionAlgorithmManager->get($completeHeader['enc']); + if (! $content_encryption_algorithm instanceof ContentEncryptionAlgorithm) { + throw new InvalidArgumentException(sprintf( + 'The key encryption algorithm "%s" is not supported or does not implement the ContentEncryption interface.', + $completeHeader['enc'] + )); + } + + return $content_encryption_algorithm; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypterFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypterFactory.php new file mode 100644 index 000000000..0df9b7dae --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWEDecrypterFactory.php @@ -0,0 +1,49 @@ +algorithmManagerFactory->create($encryptionAlgorithms); + $compressionMethodManager = $compressionMethods === null ? null : $this->compressionMethodManagerFactory?->create( + $compressionMethods + ); + + return new JWEDecrypter($algorithmManager, null, $compressionMethodManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoader.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoader.php new file mode 100644 index 000000000..c3b261581 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoader.php @@ -0,0 +1,96 @@ +jweDecrypter; + } + + /** + * Returns the header checker manager if set. + */ + public function getHeaderCheckerManager(): ?HeaderCheckerManager + { + return $this->headerCheckerManager; + } + + /** + * Returns the serializer manager. + */ + public function getSerializerManager(): JWESerializerManager + { + return $this->serializerManager; + } + + /** + * This method will try to load and decrypt the given token using a JWK. If succeeded, the methods will populate the + * $recipient variable and returns the JWE. + */ + public function loadAndDecryptWithKey(string $token, JWK $key, ?int &$recipient): JWE + { + $keyset = new JWKSet([$key]); + + return $this->loadAndDecryptWithKeySet($token, $keyset, $recipient); + } + + /** + * This method will try to load and decrypt the given token using a JWKSet. If succeeded, the methods will populate + * the $recipient variable and returns the JWE. + */ + public function loadAndDecryptWithKeySet(string $token, JWKSet $keyset, ?int &$recipient): JWE + { + try { + $jwe = $this->serializerManager->unserialize($token); + $nbRecipients = $jwe->countRecipients(); + for ($i = 0; $i < $nbRecipients; ++$i) { + if ($this->processRecipient($jwe, $keyset, $i)) { + $recipient = $i; + + return $jwe; + } + } + } catch (Throwable) { + // Nothing to do. Exception thrown just after + } + + throw new RuntimeException('Unable to load and decrypt the token.'); + } + + private function processRecipient(JWE &$jwe, JWKSet $keyset, int $recipient): bool + { + try { + if ($this->headerCheckerManager !== null) { + $this->headerCheckerManager->check($jwe, $recipient); + } + + return $this->jweDecrypter->decryptUsingKeySet($jwe, $keyset, $recipient); + } catch (Throwable) { + return false; + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoaderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoaderFactory.php new file mode 100644 index 000000000..98159109a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWELoaderFactory.php @@ -0,0 +1,43 @@ +jweSerializerManagerFactory->create($serializers); + $jweDecrypter = $this->jweDecrypterFactory->create($encryptionAlgorithms, null, $compressionMethods); + if ($this->headerCheckerManagerFactory !== null) { + $headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers); + } else { + $headerCheckerManager = null; + } + + return new JWELoader($serializerManager, $jweDecrypter, $headerCheckerManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWETokenSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWETokenSupport.php new file mode 100644 index 000000000..2b5568aeb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/JWETokenSupport.php @@ -0,0 +1,33 @@ + $protectedHeader + * @param array $unprotectedHeader + */ + public function retrieveTokenHeaders(JWT $jwt, int $index, array &$protectedHeader, array &$unprotectedHeader): void + { + if (! $jwt instanceof JWE) { + return; + } + $protectedHeader = $jwt->getSharedProtectedHeader(); + $unprotectedHeader = $jwt->getSharedHeader(); + $recipient = $jwt->getRecipient($index) + ->getHeader(); + + $unprotectedHeader = array_merge($unprotectedHeader, $recipient); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Recipient.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Recipient.php new file mode 100644 index 000000000..37502e130 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Recipient.php @@ -0,0 +1,62 @@ +header; + } + + /** + * Returns the value of the recipient header parameter with the specified key. + * + * @param string $key The key + * + * @return mixed|null + */ + public function getHeaderParameter(string $key) + { + if (! $this->hasHeaderParameter($key)) { + throw new InvalidArgumentException(sprintf('The header "%s" does not exist.', $key)); + } + + return $this->header[$key]; + } + + /** + * Returns true if the recipient header contains the parameter with the specified key. + * + * @param string $key The key + */ + public function hasHeaderParameter(string $key): bool + { + return array_key_exists($key, $this->header); + } + + /** + * Returns the encrypted key. + */ + public function getEncryptedKey(): ?string + { + return $this->encryptedKey; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/CompactSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/CompactSerializer.php new file mode 100644 index 000000000..4c38ff39b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/CompactSerializer.php @@ -0,0 +1,111 @@ +getRecipient($recipientIndex); + + $this->checkHasNoAAD($jwe); + $this->checkHasSharedProtectedHeader($jwe); + $this->checkRecipientHasNoHeader($jwe, $recipientIndex); + + return sprintf( + '%s.%s.%s.%s.%s', + $jwe->getEncodedSharedProtectedHeader(), + Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey() ?? ''), + Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''), + Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''), + Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? '') + ); + } + + public function unserialize(string $input): JWE + { + $parts = explode('.', $input); + if (count($parts) !== 5) { + throw new InvalidArgumentException('Unsupported input'); + } + + try { + $encodedSharedProtectedHeader = $parts[0]; + $sharedProtectedHeader = JsonConverter::decode( + Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader) + ); + if (! is_array($sharedProtectedHeader)) { + throw new InvalidArgumentException('Unsupported input.'); + } + $encryptedKey = $parts[1] === '' ? null : Base64UrlSafe::decodeNoPadding($parts[1]); + $iv = Base64UrlSafe::decodeNoPadding($parts[2]); + $ciphertext = Base64UrlSafe::decodeNoPadding($parts[3]); + $tag = Base64UrlSafe::decodeNoPadding($parts[4]); + + return new JWE( + $ciphertext, + $iv, + $tag, + null, + [], + $sharedProtectedHeader, + $encodedSharedProtectedHeader, + [new Recipient([], $encryptedKey)] + ); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable); + } + } + + private function checkHasNoAAD(JWE $jwe): void + { + if ($jwe->getAAD() !== null) { + throw new LogicException('This JWE has AAD and cannot be converted into Compact JSON.'); + } + } + + private function checkRecipientHasNoHeader(JWE $jwe, int $id): void + { + if (count($jwe->getSharedHeader()) !== 0 || count($jwe->getRecipient($id)->getHeader()) !== 0) { + throw new LogicException( + 'This JWE has shared header parameters or recipient header parameters and cannot be converted into Compact JSON.' + ); + } + } + + private function checkHasSharedProtectedHeader(JWE $jwe): void + { + if (count($jwe->getSharedProtectedHeader()) === 0) { + throw new LogicException( + 'This JWE does not have shared protected header parameters and cannot be converted into Compact JSON.' + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONFlattenedSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONFlattenedSerializer.php new file mode 100644 index 000000000..02ea352ee --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONFlattenedSerializer.php @@ -0,0 +1,107 @@ +getRecipient($recipientIndex); + $data = [ + 'ciphertext' => Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''), + 'iv' => Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''), + 'tag' => Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? ''), + ]; + if ($jwe->getAAD() !== null) { + $data['aad'] = Base64UrlSafe::encodeUnpadded($jwe->getAAD()); + } + if (count($jwe->getSharedProtectedHeader()) !== 0) { + $data['protected'] = $jwe->getEncodedSharedProtectedHeader(); + } + if (count($jwe->getSharedHeader()) !== 0) { + $data['unprotected'] = $jwe->getSharedHeader(); + } + if (count($recipient->getHeader()) !== 0) { + $data['header'] = $recipient->getHeader(); + } + if ($recipient->getEncryptedKey() !== null) { + $data['encrypted_key'] = Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey()); + } + + return JsonConverter::encode($data); + } + + public function unserialize(string $input): JWE + { + $data = JsonConverter::decode($input); + if (! is_array($data)) { + throw new InvalidArgumentException('Unsupported input.'); + } + $this->checkData($data); + + $ciphertext = Base64UrlSafe::decodeNoPadding($data['ciphertext']); + $iv = Base64UrlSafe::decodeNoPadding($data['iv']); + $tag = Base64UrlSafe::decodeNoPadding($data['tag']); + $aad = array_key_exists('aad', $data) ? Base64UrlSafe::decodeNoPadding($data['aad']) : null; + [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data); + $encryptedKey = array_key_exists('encrypted_key', $data) ? Base64UrlSafe::decodeNoPadding( + $data['encrypted_key'] + ) : null; + $header = array_key_exists('header', $data) ? $data['header'] : []; + + return new JWE( + $ciphertext, + $iv, + $tag, + $aad, + $sharedHeader, + $sharedProtectedHeader, + $encodedSharedProtectedHeader, + [new Recipient($header, $encryptedKey)] + ); + } + + private function checkData(?array $data): void + { + if ($data === null || ! isset($data['ciphertext']) || isset($data['recipients'])) { + throw new InvalidArgumentException('Unsupported input.'); + } + } + + private function processHeaders(array $data): array + { + $encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null; + $sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode( + Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader) + ) : []; + $sharedHeader = $data['unprotected'] ?? []; + + return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader]; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONGeneralSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONGeneralSerializer.php new file mode 100644 index 000000000..15b963a34 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JSONGeneralSerializer.php @@ -0,0 +1,124 @@ +countRecipients() === 0) { + throw new LogicException('No recipient.'); + } + + $data = [ + 'ciphertext' => Base64UrlSafe::encodeUnpadded($jwe->getCiphertext() ?? ''), + 'iv' => Base64UrlSafe::encodeUnpadded($jwe->getIV() ?? ''), + 'tag' => Base64UrlSafe::encodeUnpadded($jwe->getTag() ?? ''), + ]; + if ($jwe->getAAD() !== null) { + $data['aad'] = Base64UrlSafe::encodeUnpadded($jwe->getAAD()); + } + if (count($jwe->getSharedProtectedHeader()) !== 0) { + $data['protected'] = $jwe->getEncodedSharedProtectedHeader(); + } + if (count($jwe->getSharedHeader()) !== 0) { + $data['unprotected'] = $jwe->getSharedHeader(); + } + $data['recipients'] = []; + foreach ($jwe->getRecipients() as $recipient) { + $temp = []; + if (count($recipient->getHeader()) !== 0) { + $temp['header'] = $recipient->getHeader(); + } + if ($recipient->getEncryptedKey() !== null) { + $temp['encrypted_key'] = Base64UrlSafe::encodeUnpadded($recipient->getEncryptedKey()); + } + $data['recipients'][] = $temp; + } + + return JsonConverter::encode($data); + } + + public function unserialize(string $input): JWE + { + $data = JsonConverter::decode($input); + if (! is_array($data)) { + throw new InvalidArgumentException('Unsupported input.'); + } + $this->checkData($data); + + $ciphertext = Base64UrlSafe::decodeNoPadding($data['ciphertext']); + $iv = Base64UrlSafe::decodeNoPadding($data['iv']); + $tag = Base64UrlSafe::decodeNoPadding($data['tag']); + $aad = array_key_exists('aad', $data) ? Base64UrlSafe::decodeNoPadding($data['aad']) : null; + [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader] = $this->processHeaders($data); + $recipients = []; + foreach ($data['recipients'] as $recipient) { + [$encryptedKey, $header] = $this->processRecipient($recipient); + $recipients[] = new Recipient($header, $encryptedKey); + } + + return new JWE( + $ciphertext, + $iv, + $tag, + $aad, + $sharedHeader, + $sharedProtectedHeader, + $encodedSharedProtectedHeader, + $recipients + ); + } + + private function checkData(?array $data): void + { + if ($data === null || ! isset($data['ciphertext']) || ! isset($data['recipients'])) { + throw new InvalidArgumentException('Unsupported input.'); + } + } + + private function processRecipient(array $recipient): array + { + $encryptedKey = array_key_exists('encrypted_key', $recipient) ? Base64UrlSafe::decodeNoPadding( + $recipient['encrypted_key'] + ) : null; + $header = array_key_exists('header', $recipient) ? $recipient['header'] : []; + + return [$encryptedKey, $header]; + } + + private function processHeaders(array $data): array + { + $encodedSharedProtectedHeader = array_key_exists('protected', $data) ? $data['protected'] : null; + $sharedProtectedHeader = $encodedSharedProtectedHeader ? JsonConverter::decode( + Base64UrlSafe::decodeNoPadding($encodedSharedProtectedHeader) + ) : []; + $sharedHeader = array_key_exists('unprotected', $data) ? $data['unprotected'] : []; + + return [$encodedSharedProtectedHeader, $sharedProtectedHeader, $sharedHeader]; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializer.php new file mode 100644 index 000000000..04cd3dd94 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializer.php @@ -0,0 +1,33 @@ +add($serializer); + } + } + + /** + * Return the serializer names supported by the manager. + * + * @return string[] + */ + public function names(): array + { + return array_keys($this->serializers); + } + + /** + * Converts a JWE into a string. Throws an exception if none of the serializer was able to convert the input. + */ + public function serialize(string $name, JWE $jws, ?int $recipientIndex = null): string + { + if (! isset($this->serializers[$name])) { + throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); + } + + return $this->serializers[$name]->serialize($jws, $recipientIndex); + } + + /** + * Loads data and return a JWE object. Throws an exception if none of the serializer was able to convert the input. + * + * @param string $input A string that represents a JWE + * @param string|null $name the name of the serializer if the input is unserialized + */ + public function unserialize(string $input, ?string &$name = null): JWE + { + foreach ($this->serializers as $serializer) { + try { + $jws = $serializer->unserialize($input); + $name = $serializer->name(); + + return $jws; + } catch (InvalidArgumentException) { + continue; + } + } + + throw new InvalidArgumentException('Unsupported input.'); + } + + /** + * Adds a serializer to the manager. + */ + private function add(JWESerializer $serializer): void + { + $this->serializers[$serializer->name()] = $serializer; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializerManagerFactory.php similarity index 77% rename from lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializerManagerFactory.php rename to lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializerManagerFactory.php index 63dd69df3..d62f26d71 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-encryption/Serializer/JWESerializerManagerFactory.php +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Encryption/Serializer/JWESerializerManagerFactory.php @@ -2,15 +2,6 @@ declare(strict_types=1); -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2020 Spomky-Labs - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ - namespace Jose\Component\Encryption\Serializer; use InvalidArgumentException; @@ -20,20 +11,18 @@ class JWESerializerManagerFactory /** * @var JWESerializer[] */ - private $serializers = []; + private array $serializers = []; /** * Creates a serializer manager factory using the given serializers. * * @param string[] $names - * - * @throws InvalidArgumentException if the serializer is not supported */ public function create(array $names): JWESerializerManager { $serializers = []; foreach ($names as $name) { - if (!isset($this->serializers[$name])) { + if (! isset($this->serializers[$name])) { throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); } $serializers[] = $this->serializers[$name]; diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/AlgorithmAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/AlgorithmAnalyzer.php new file mode 100644 index 000000000..a1db8d3ed --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/AlgorithmAnalyzer.php @@ -0,0 +1,17 @@ +has('alg')) { + $bag->add(Message::medium('The parameter "alg" should be added.')); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ES256KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ES256KeyAnalyzer.php new file mode 100644 index 000000000..fbf802068 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ES256KeyAnalyzer.php @@ -0,0 +1,31 @@ +get('kty') !== 'EC') { + return; + } + if (! $jwk->has('crv')) { + $bag->add(Message::high('Invalid key. The components "crv" is missing.')); + + return; + } + if ($jwk->get('crv') !== $this->getCurveName()) { + return; + } + $x = $jwk->get('x'); + if (! is_string($x)) { + $bag->add(Message::high('Invalid key. The components "x" shall be a string.')); + + return; + } + $x = Base64UrlSafe::decodeNoPadding($x); + $xLength = 8 * mb_strlen($x, '8bit'); + $y = $jwk->get('y'); + if (! is_string($y)) { + $bag->add(Message::high('Invalid key. The components "y" shall be a string.')); + + return; + } + $y = Base64UrlSafe::decodeNoPadding($y); + $yLength = 8 * mb_strlen($y, '8bit'); + if ($yLength !== $xLength || $yLength !== $this->getKeySize()) { + $bag->add( + Message::high(sprintf( + 'Invalid key. The components "x" and "y" size shall be %d bits.', + $this->getKeySize() + )) + ); + } + $xBI = BigInteger::fromBase(bin2hex($x), 16); + $yBI = BigInteger::fromBase(bin2hex($y), 16); + if (! $this->getCurve()->contains($xBI, $yBI)) { + $bag->add(Message::high('Invalid key. The point is not on the curve.')); + } + } + + abstract protected function getAlgorithmName(): string; + + abstract protected function getCurveName(): string; + + abstract protected function getCurve(): Curve; + + abstract protected function getKeySize(): int; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/HS256KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/HS256KeyAnalyzer.php new file mode 100644 index 000000000..c83ac6d1f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/HS256KeyAnalyzer.php @@ -0,0 +1,18 @@ +get('kty') !== 'oct') { + return; + } + if (! $jwk->has('alg') || $jwk->get('alg') !== $this->getAlgorithmName()) { + return; + } + $k = $jwk->get('k'); + if (! is_string($k)) { + $bag->add(Message::high('The key is not valid')); + + return; + } + $k = Base64UrlSafe::decodeNoPadding($k); + $kLength = 8 * mb_strlen($k, '8bit'); + if ($kLength < $this->getMinimumKeySize()) { + $bag->add( + Message::high(sprintf( + 'HS512 algorithm requires at least %d bits key length.', + $this->getMinimumKeySize() + )) + ); + } + } + + abstract protected function getAlgorithmName(): string; + + abstract protected function getMinimumKeySize(): int; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyAnalyzer.php new file mode 100644 index 000000000..d48f1f035 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyAnalyzer.php @@ -0,0 +1,15 @@ +analyzers[] = $analyzer; + } + + /** + * This method will analyze the JWK object using all analyzers. It returns a message bag that may contains messages. + */ + public function analyze(JWK $jwk): MessageBag + { + $bag = new MessageBag(); + foreach ($this->analyzers as $analyzer) { + $analyzer->analyze($jwk, $bag); + } + + return $bag; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyIdentifierAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyIdentifierAnalyzer.php new file mode 100644 index 000000000..2f21105f7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeyIdentifierAnalyzer.php @@ -0,0 +1,17 @@ +has('kid')) { + $bag->add(Message::medium('The parameter "kid" should be added.')); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeysetAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeysetAnalyzer.php new file mode 100644 index 000000000..3dc70638b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/KeysetAnalyzer.php @@ -0,0 +1,15 @@ +analyzers[] = $analyzer; + } + + /** + * This method will analyze the JWKSet object using all analyzers. It returns a message bag that may contains + * messages. + */ + public function analyze(JWKSet $jwkset): MessageBag + { + $bag = new MessageBag(); + foreach ($this->analyzers as $analyzer) { + $analyzer->analyze($jwkset, $bag); + } + + return $bag; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/Message.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/Message.php new file mode 100644 index 000000000..b97b19fbc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/Message.php @@ -0,0 +1,70 @@ +message; + } + + /** + * Returns the severity of the message. + */ + public function getSeverity(): string + { + return $this->severity; + } + + public function jsonSerialize(): array + { + return [ + 'message' => $this->message, + 'severity' => $this->severity, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MessageBag.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MessageBag.php new file mode 100644 index 000000000..453fcd285 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MessageBag.php @@ -0,0 +1,53 @@ +messages[] = $message; + } + + /** + * Returns all messages. + * + * @return Message[] + */ + public function all(): array + { + return $this->messages; + } + + public function jsonSerialize(): array + { + return array_values($this->messages); + } + + public function count(): int + { + return count($this->messages); + } + + public function getIterator(): Traversable + { + return new ArrayIterator($this->messages); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedKeyTypes.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedKeyTypes.php similarity index 75% rename from lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedKeyTypes.php rename to lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedKeyTypes.php index af8e1e068..5c473348b 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedKeyTypes.php +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedKeyTypes.php @@ -2,15 +2,6 @@ declare(strict_types=1); -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2020 Spomky-Labs - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ - namespace Jose\Component\KeyManagement\Analyzer; use Jose\Component\Core\JWKSet; @@ -19,7 +10,7 @@ final class MixedKeyTypes implements KeysetAnalyzer { public function analyze(JWKSet $jwkset, MessageBag $bag): void { - if (0 === $jwkset->count()) { + if ($jwkset->count() === 0) { return; } @@ -43,7 +34,7 @@ final class MixedKeyTypes implements KeysetAnalyzer } if ($hasAsymmetricKeys && $hasSymmetricKeys) { - $bag->add(Message::medium('This key set mixes symmetric and assymetric keys.')); + $bag->add(Message::medium('This key set mixes symmetric and asymmetric keys.')); } } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedPublicAndPrivateKeys.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedPublicAndPrivateKeys.php similarity index 79% rename from lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedPublicAndPrivateKeys.php rename to lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedPublicAndPrivateKeys.php index 94ce3519a..aa957a00b 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-key-mgmt/Analyzer/MixedPublicAndPrivateKeys.php +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/MixedPublicAndPrivateKeys.php @@ -2,15 +2,6 @@ declare(strict_types=1); -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2020 Spomky-Labs - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ - namespace Jose\Component\KeyManagement\Analyzer; use Jose\Component\Core\JWKSet; @@ -19,7 +10,7 @@ final class MixedPublicAndPrivateKeys implements KeysetAnalyzer { public function analyze(JWKSet $jwkset, MessageBag $bag): void { - if (0 === $jwkset->count()) { + if ($jwkset->count() === 0) { return; } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/NoneAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/NoneAnalyzer.php new file mode 100644 index 000000000..57488a891 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/NoneAnalyzer.php @@ -0,0 +1,23 @@ +get('kty') !== 'none') { + return; + } + + $bag->add( + Message::high( + 'This key is a meant to be used with the algorithm "none". This algorithm is not secured and should be used with care.' + ) + ); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/OctAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/OctAnalyzer.php new file mode 100644 index 000000000..1d7691065 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/OctAnalyzer.php @@ -0,0 +1,30 @@ +get('kty') !== 'oct') { + return; + } + $k = $jwk->get('k'); + if (! is_string($k)) { + $bag->add(Message::high('The key is not valid')); + + return; + } + $k = Base64UrlSafe::decodeNoPadding($k); + $kLength = 8 * mb_strlen($k, '8bit'); + if ($kLength < 128) { + $bag->add(Message::high('The key length is less than 128 bits.')); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/RsaAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/RsaAnalyzer.php new file mode 100644 index 000000000..9a354c7e0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/RsaAnalyzer.php @@ -0,0 +1,64 @@ +get('kty') !== 'RSA') { + return; + } + + $this->checkExponent($jwk, $bag); + $this->checkModulus($jwk, $bag); + } + + private function checkExponent(JWK $jwk, MessageBag $bag): void + { + $e = $jwk->get('e'); + if (! is_string($e)) { + $bag->add(Message::high('The exponent is not valid.')); + + return; + } + $exponent = unpack('l', str_pad(Base64UrlSafe::decodeNoPadding($e), 4, "\0")); + if (! is_array($exponent) || ! isset($exponent[1])) { + throw new InvalidArgumentException('Unable to get the private key'); + } + if ($exponent[1] < 65537) { + $bag->add(Message::high('The exponent is too low. It should be at least 65537.')); + } + } + + private function checkModulus(JWK $jwk, MessageBag $bag): void + { + $n = $jwk->get('n'); + if (! is_string($n)) { + $bag->add(Message::high('The modulus is not valid.')); + + return; + } + $n = 8 * mb_strlen(Base64UrlSafe::decodeNoPadding($n), '8bit'); + if ($n < 2048) { + $bag->add(Message::high('The key length is less than 2048 bits.')); + } + if ($jwk->has('d') && (! $jwk->has('p') || ! $jwk->has('q') || ! $jwk->has('dp') || ! $jwk->has( + 'dq' + ) || ! $jwk->has('qi'))) { + $bag->add( + Message::medium( + 'The key is a private RSA key, but Chinese Remainder Theorem primes are missing. These primes are not mandatory, but signatures and decryption processes are faster when available.' + ) + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/UsageAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/UsageAnalyzer.php new file mode 100644 index 000000000..e30ae9638 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/UsageAnalyzer.php @@ -0,0 +1,38 @@ +has('use')) { + $bag->add(Message::medium('The parameter "use" should be added.')); + } elseif (! in_array($jwk->get('use'), ['sig', 'enc'], true)) { + $bag->add( + Message::high(sprintf( + 'The parameter "use" has an unsupported value "%s". Please use "sig" (signature) or "enc" (encryption).', + $jwk->get('use') + )) + ); + } + if ($jwk->has('key_ops') && ! in_array( + $jwk->get('key_ops'), + ['sign', 'verify', 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], + true + )) { + $bag->add( + Message::high(sprintf( + 'The parameter "key_ops" has an unsupported value "%s". Please use one of the following values: %s.', + $jwk->get('key_ops'), + implode(', ', ['verify', 'sign', 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey']) + )) + ); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ZxcvbnKeyAnalyzer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ZxcvbnKeyAnalyzer.php new file mode 100644 index 000000000..43a75fa19 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/Analyzer/ZxcvbnKeyAnalyzer.php @@ -0,0 +1,55 @@ +get('kty') !== 'oct') { + return; + } + $k = $jwk->get('k'); + if (! is_string($k)) { + $bag->add(Message::high('The key is not valid')); + + return; + } + $k = Base64UrlSafe::decodeNoPadding($k); + if (! class_exists(Zxcvbn::class)) { + return; + } + $zxcvbn = new Zxcvbn(); + try { + $strength = $zxcvbn->passwordStrength($k); + switch (true) { + case $strength['score'] < 3: + $bag->add( + Message::high( + 'The octet string is weak and easily guessable. Please change your key as soon as possible.' + ) + ); + + break; + + case $strength['score'] === 3: + $bag->add(Message::medium('The octet string is safe, but a longer key is preferable.')); + + break; + + default: + break; + } + } catch (Throwable) { + $bag->add(Message::medium('The test of the weakness cannot be performed.')); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JKUFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JKUFactory.php new file mode 100644 index 000000000..745232045 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JKUFactory.php @@ -0,0 +1,27 @@ +getContent($url, $header); + $data = JsonConverter::decode($content); + if (! is_array($data)) { + throw new RuntimeException('Invalid content.'); + } + + return JWKSet::createFromKeyData($data); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JWKFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JWKFactory.php new file mode 100644 index 000000000..1bf4ac45c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/JWKFactory.php @@ -0,0 +1,295 @@ + $values values to configure the key + */ + public static function createRSAKey(int $size, array $values = []): JWK + { + if (! extension_loaded('openssl')) { + throw new RuntimeException('Please install the OpenSSL extension'); + } + if ($size % 8 !== 0) { + throw new InvalidArgumentException('Invalid key size.'); + } + if ($size < 512) { + throw new InvalidArgumentException('Key length is too short. It needs to be at least 512 bits.'); + } + + $key = openssl_pkey_new([ + 'private_key_bits' => $size, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + ]); + if ($key === false) { + throw new InvalidArgumentException('Unable to create the key'); + } + $details = openssl_pkey_get_details($key); + if (! is_array($details)) { + throw new InvalidArgumentException('Unable to create the key'); + } + $rsa = RSAKey::createFromKeyDetails($details['rsa']); + $values = array_merge($values, $rsa->toArray()); + + return new JWK($values); + } + + /** + * Creates a EC key with the given curve and additional values. + * + * @param string $curve The curve + * @param array $values values to configure the key + */ + public static function createECKey(string $curve, array $values = []): JWK + { + return ECKey::createECKey($curve, $values); + } + + /** + * Creates a octet key with the given key size and additional values. + * + * @param int $size The key size in bits + * @param array $values values to configure the key + */ + public static function createOctKey(int $size, array $values = []): JWK + { + if ($size % 8 !== 0) { + throw new InvalidArgumentException('Invalid key size.'); + } + + return self::createFromSecret(random_bytes($size / 8), $values); + } + + /** + * Creates a OKP key with the given curve and additional values. + * + * @param string $curve The curve + * @param array $values values to configure the key + */ + public static function createOKPKey(string $curve, array $values = []): JWK + { + if (! extension_loaded('sodium')) { + throw new RuntimeException('The extension "sodium" is not available. Please install it to use this method'); + } + + switch ($curve) { + case 'X25519': + $keyPair = sodium_crypto_box_keypair(); + $d = sodium_crypto_box_secretkey($keyPair); + $x = sodium_crypto_box_publickey($keyPair); + + break; + + case 'Ed25519': + $keyPair = sodium_crypto_sign_keypair(); + $secret = sodium_crypto_sign_secretkey($keyPair); + $secretLength = mb_strlen($secret, '8bit'); + $d = mb_substr($secret, 0, -$secretLength / 2, '8bit'); + $x = sodium_crypto_sign_publickey($keyPair); + + break; + + default: + throw new InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve)); + } + + $values = [ + ...$values, + 'kty' => 'OKP', + 'crv' => $curve, + 'd' => Base64UrlSafe::encodeUnpadded($d), + 'x' => Base64UrlSafe::encodeUnpadded($x), + ]; + + return new JWK($values); + } + + /** + * Creates a none key with the given additional values. Please note that this key type is not pat of any + * specification. It is used to prevent the use of the "none" algorithm with other key types. + * + * @param array $values values to configure the key + */ + public static function createNoneKey(array $values = []): JWK + { + $values = [ + ...$values, + 'kty' => 'none', + 'alg' => 'none', + 'use' => 'sig', + ]; + + return new JWK($values); + } + + /** + * Creates a key from a Json string. + */ + public static function createFromJsonObject(string $value): JWK|JWKSet + { + $json = json_decode($value, true, 512, JSON_THROW_ON_ERROR); + if (! is_array($json)) { + throw new InvalidArgumentException('Invalid key or key set.'); + } + + return self::createFromValues($json); + } + + /** + * Creates a key or key set from the given input. + */ + public static function createFromValues(array $values): JWK|JWKSet + { + if (array_key_exists('keys', $values) && is_array($values['keys'])) { + return JWKSet::createFromKeyData($values); + } + + return new JWK($values); + } + + /** + * This method create a JWK object using a shared secret. + */ + public static function createFromSecret(string $secret, array $additional_values = []): JWK + { + $values = array_merge( + $additional_values, + [ + 'kty' => 'oct', + 'k' => Base64UrlSafe::encodeUnpadded($secret), + ] + ); + + return new JWK($values); + } + + /** + * This method will try to load a X.509 certificate and convert it into a public key. + */ + public static function createFromCertificateFile(string $file, array $additional_values = []): JWK + { + $values = KeyConverter::loadKeyFromCertificateFile($file); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } + + /** + * Extract a keyfrom a key set identified by the given index . + */ + public static function createFromKeySet(JWKSet $jwkset, int|string $index): JWK + { + return $jwkset->get($index); + } + + /** + * This method will try to load a PKCS#12 file and convert it into a public key. + */ + public static function createFromPKCS12CertificateFile( + string $file, + string $secret = '', + array $additional_values = [] + ): JWK { + try { + $content = file_get_contents($file); + if (! is_string($content)) { + throw new RuntimeException('Unable to read the file.'); + } + openssl_pkcs12_read($content, $certs, $secret); + if (! is_array($certs) || ! array_key_exists('pkey', $certs)) { + throw new RuntimeException('Unable to load the certificates.'); + } + + return self::createFromKey($certs['pkey'], null, $additional_values); + } catch (Throwable $throwable) { + throw new RuntimeException('Unable to load the certificates.', $throwable->getCode(), $throwable); + } + } + + /** + * This method will try to convert a X.509 certificate into a public key. + */ + public static function createFromCertificate(string $certificate, array $additional_values = []): JWK + { + $values = KeyConverter::loadKeyFromCertificate($certificate); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } + + /** + * This method will try to convert a X.509 certificate resource into a public key. + */ + public static function createFromX509Resource(OpenSSLCertificate $res, array $additional_values = []): JWK + { + $values = KeyConverter::loadKeyFromX509Resource($res); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } + + /** + * This method will try to load and convert a key file into a JWK object. If the key is encrypted, the password must + * be set. + */ + public static function createFromKeyFile(string $file, ?string $password = null, array $additional_values = []): JWK + { + $values = KeyConverter::loadFromKeyFile($file, $password); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } + + /** + * This method will try to load and convert a key into a JWK object. If the key is encrypted, the password must be + * set. + */ + public static function createFromKey(string $key, ?string $password = null, array $additional_values = []): JWK + { + $values = KeyConverter::loadFromKey($key, $password); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } + + /** + * This method will try to load and convert a X.509 certificate chain into a public key. + * + * Be careful! The certificate chain is loaded, but it is NOT VERIFIED by any mean! It is mandatory to verify the + * root CA or intermediate CA are trusted. If not done, it may lead to potential security issues. + */ + public static function createFromX5C(array $x5c, array $additional_values = []): JWK + { + $values = KeyConverter::loadFromX5C($x5c); + $values = array_merge($values, $additional_values); + + return new JWK($values); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/ECKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/ECKey.php new file mode 100644 index 000000000..6c3f61a73 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/ECKey.php @@ -0,0 +1,120 @@ +loadJWK($data); + } + + public static function createFromPEM(string $pem): self + { + $data = self::loadPEM($pem); + + return new self($data); + } + + public static function toPublic(self $private): self + { + $data = $private->toArray(); + if (array_key_exists('d', $data)) { + unset($data['d']); + } + + return new self($data); + } + + /** + * @return array + */ + public function toArray() + { + return $this->values; + } + + private static function loadPEM(string $data): array + { + $pem = PEM::fromString($data); + try { + $key = ECPrivateKey::fromPEM($pem); + + return [ + 'kty' => 'EC', + 'crv' => self::getCurve($key->namedCurve()), + 'd' => Base64UrlSafe::encodeUnpadded($key->privateKeyOctets()), + 'x' => Base64UrlSafe::encodeUnpadded($key->publicKey()->curvePointOctets()[0]), + 'y' => Base64UrlSafe::encodeUnpadded($key->publicKey()->curvePointOctets()[1]), + ]; + } catch (Throwable) { + } + try { + $key = ECPublicKey::fromPEM($pem); + return [ + 'kty' => 'EC', + 'crv' => self::getCurve($key->namedCurve()), + 'x' => Base64UrlSafe::encodeUnpadded($key->curvePointOctets()[0]), + 'y' => Base64UrlSafe::encodeUnpadded($key->curvePointOctets()[1]), + ]; + } catch (Throwable) { + } + throw new InvalidArgumentException('Unable to load the key.'); + } + + private static function getCurve(string $oid): string + { + $curves = self::getSupportedCurves(); + $curve = array_search($oid, $curves, true); + if (! is_string($curve)) { + throw new InvalidArgumentException('Unsupported OID.'); + } + + return $curve; + } + + private static function getSupportedCurves(): array + { + return [ + 'P-256' => '1.2.840.10045.3.1.7', + 'P-384' => '1.3.132.0.34', + 'P-521' => '1.3.132.0.35', + ]; + } + + private function loadJWK(array $jwk): void + { + $keys = [ + 'kty' => 'The key parameter "kty" is missing.', + 'crv' => 'Curve parameter is missing', + 'x' => 'Point parameters are missing.', + 'y' => 'Point parameters are missing.', + ]; + foreach ($keys as $k => $v) { + if (! array_key_exists($k, $jwk)) { + throw new InvalidArgumentException($v); + } + } + + if ($jwk['kty'] !== 'EC') { + throw new InvalidArgumentException('JWK is not an Elliptic Curve key.'); + } + $this->values = $jwk; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/KeyConverter.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/KeyConverter.php new file mode 100644 index 000000000..f72c66b49 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/KeyConverter.php @@ -0,0 +1,419 @@ + $cert) { + $x5c[$id] = '-----BEGIN CERTIFICATE-----' . "\n" . chunk_split( + (string) $cert, + 64, + "\n" + ) . '-----END CERTIFICATE-----'; + $x509 = openssl_x509_read($x5c[$id]); + if ($x509 === false) { + throw new InvalidArgumentException('Unable to load the certificate chain'); + } + $parsed = openssl_x509_parse($x509); + if ($parsed === false) { + throw new InvalidArgumentException('Unable to load the certificate chain'); + } + } + + return self::loadKeyFromCertificate(reset($x5c)); + } + + private static function loadKeyFromDER(string $der, ?string $password = null): array + { + $pem = self::convertDerToPem($der); + + return self::loadKeyFromPEM($pem, $password); + } + + private static function loadKeyFromPEM(string $pem, ?string $password = null): array + { + if (! extension_loaded('openssl')) { + throw new RuntimeException('Please install the OpenSSL extension'); + } + + if (preg_match('#DEK-Info: (.+),(.+)#', $pem, $matches) === 1) { + $pem = self::decodePem($pem, $matches, $password); + } + + if (preg_match('#BEGIN ENCRYPTED PRIVATE KEY(.+)(.+)#', $pem) === 1) { + $decrypted = openssl_pkey_get_private($pem, $password); + if ($decrypted === false) { + throw new InvalidArgumentException('Unable to decrypt the key.'); + } + openssl_pkey_export($decrypted, $pem); + } + + self::sanitizePEM($pem); + $res = openssl_pkey_get_private($pem); + if ($res === false) { + $res = openssl_pkey_get_public($pem); + } + if ($res === false) { + throw new InvalidArgumentException('Unable to load the key.'); + } + + $details = openssl_pkey_get_details($res); + if (! is_array($details) || ! array_key_exists('type', $details)) { + throw new InvalidArgumentException('Unable to get details of the key'); + } + + return match ($details['type']) { + OPENSSL_KEYTYPE_EC => self::tryToLoadECKey($pem), + OPENSSL_KEYTYPE_RSA => RSAKey::createFromPEM($pem)->toArray(), + -1 => self::tryToLoadOtherKeyTypes($pem), + default => throw new InvalidArgumentException('Unsupported key type'), + }; + } + + /** + * This method tries to load Ed448, X488, Ed25519 and X25519 keys. + */ + private static function tryToLoadECKey(string $input): array + { + try { + return ECKey::createFromPEM($input)->toArray(); + } catch (Throwable) { + } + try { + return self::tryToLoadOtherKeyTypes($input); + } catch (Throwable) { + } + throw new InvalidArgumentException('Unable to load the key.'); + } + + /** + * This method tries to load Ed448, X488, Ed25519 and X25519 keys. + */ + private static function tryToLoadOtherKeyTypes(string $input): array + { + $pem = PEM::fromString($input); + return match ($pem->type()) { + PEM::TYPE_PUBLIC_KEY => self::loadPublicKey($pem), + PEM::TYPE_PRIVATE_KEY => self::loadPrivateKey($pem), + default => throw new InvalidArgumentException('Unsupported key type'), + }; + } + + /** + * @return array + */ + private static function loadPrivateKey(PEM $pem): array + { + try { + $key = PrivateKey::fromPEM($pem); + switch ($key->algorithmIdentifier()->oid()) { + case AlgorithmIdentifier::OID_RSASSA_PSS_ENCRYPTION: + assert($key instanceof RSASSAPSSPrivateKey); + return [ + 'kty' => 'RSA', + 'n' => self::convertDecimalToBas64Url($key->modulus()), + 'e' => self::convertDecimalToBas64Url($key->publicExponent()), + 'd' => self::convertDecimalToBas64Url($key->privateExponent()), + 'dp' => self::convertDecimalToBas64Url($key->exponent1()), + 'dq' => self::convertDecimalToBas64Url($key->exponent2()), + 'p' => self::convertDecimalToBas64Url($key->prime1()), + 'q' => self::convertDecimalToBas64Url($key->prime2()), + 'qi' => self::convertDecimalToBas64Url($key->coefficient()), + ]; + case AlgorithmIdentifier::OID_ED25519: + case AlgorithmIdentifier::OID_ED448: + case AlgorithmIdentifier::OID_X25519: + case AlgorithmIdentifier::OID_X448: + $curve = self::getCurve($key->algorithmIdentifier()->oid()); + $values = [ + 'kty' => 'OKP', + 'crv' => $curve, + 'd' => Base64UrlSafe::encodeUnpadded($key->privateKeyData()), + ]; + return self::populatePoints($key, $values); + default: + throw new InvalidArgumentException('Unsupported key type'); + } + } catch (Throwable $e) { + throw new InvalidArgumentException('Unable to load the key.', 0, $e); + } + } + + /** + * @return array + */ + private static function loadPublicKey(PEM $pem): array + { + $key = PublicKey::fromPEM($pem); + switch ($key->algorithmIdentifier()->oid()) { + case AlgorithmIdentifier::OID_ED25519: + case AlgorithmIdentifier::OID_ED448: + case AlgorithmIdentifier::OID_X25519: + case AlgorithmIdentifier::OID_X448: + $curve = self::getCurve($key->algorithmIdentifier()->oid()); + self::checkType($curve); + return [ + 'kty' => 'OKP', + 'crv' => $curve, + 'x' => Base64UrlSafe::encodeUnpadded((string) $key->subjectPublicKey()), + ]; + default: + throw new InvalidArgumentException('Unsupported key type'); + } + } + + private static function convertDecimalToBas64Url(string $decimal): string + { + return Base64UrlSafe::encodeUnpadded(BigInteger::fromBase($decimal, 10)->toBytes()); + } + + /** + * @param array $values + * @return array + */ + private static function populatePoints(PrivateKey $key, array $values): array + { + $crv = $values['crv'] ?? null; + assert(is_string($crv), 'Unsupported key type.'); + $x = self::getPublicKey($key, $crv); + if ($x !== null) { + $values['x'] = Base64UrlSafe::encodeUnpadded($x); + } + + return $values; + } + + private static function getPublicKey(PrivateKey $key, string $crv): ?string + { + switch ($crv) { + case 'Ed25519': + return Ed25519::publickey_from_secretkey($key->privateKeyData()); + case 'X25519': + if (extension_loaded('sodium')) { + return sodium_crypto_scalarmult_base($key->privateKeyData()); + } + // no break + default: + return null; + } + } + + private static function checkType(string $curve): void + { + $curves = ['Ed448ph', 'Ed25519ph', 'Ed448', 'Ed25519', 'X448', 'X25519']; + in_array($curve, $curves, true) || throw new InvalidArgumentException('Unsupported key type.'); + } + + /** + * This method modifies the PEM to get 64 char lines and fix bug with old OpenSSL versions. + */ + private static function getCurve(string $oid): string + { + return match ($oid) { + '1.3.101.115' => 'Ed448ph', + '1.3.101.114' => 'Ed25519ph', + '1.3.101.113' => 'Ed448', + '1.3.101.112' => 'Ed25519', + '1.3.101.111' => 'X448', + '1.3.101.110' => 'X25519', + default => throw new InvalidArgumentException('Unsupported key type.'), + }; + } + + /** + * This method modifies the PEM to get 64 char lines and fix bug with old OpenSSL versions. + */ + private static function sanitizePEM(string &$pem): void + { + $number = preg_match_all('#(-.*-)#', $pem, $matches, PREG_PATTERN_ORDER); + if ($number !== 2) { + throw new InvalidArgumentException('Unable to load the key'); + } + + $ciphertext = preg_replace('#-.*-|\r|\n| #', '', $pem); + + $pem = $matches[0][0] . "\n"; + $pem .= chunk_split($ciphertext ?? '', 64, "\n"); + $pem .= $matches[0][1] . "\n"; + } + + /** + * @param string[] $matches + */ + private static function decodePem(string $pem, array $matches, ?string $password = null): string + { + if ($password === null) { + throw new InvalidArgumentException('Password required for encrypted keys.'); + } + + $iv = pack('H*', trim($matches[2])); + $iv_sub = mb_substr($iv, 0, 8, '8bit'); + $symkey = pack('H*', md5($password . $iv_sub)); + $symkey .= pack('H*', md5($symkey . $password . $iv_sub)); + $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $pem); + $ciphertext = base64_decode(preg_replace('#-.*-|\r|\n#', '', $key ?? '') ?? '', true); + if (! is_string($ciphertext)) { + throw new InvalidArgumentException('Unable to encode the data.'); + } + + $decoded = openssl_decrypt($ciphertext, mb_strtolower($matches[1]), $symkey, OPENSSL_RAW_DATA, $iv); + if ($decoded === false) { + throw new RuntimeException('Unable to decrypt the key'); + } + $number = preg_match_all('#-{5}.*-{5}#', $pem, $result); + if ($number !== 2) { + throw new InvalidArgumentException('Unable to load the key'); + } + + $pem = $result[0][0] . "\n"; + $pem .= chunk_split(base64_encode($decoded), 64); + + return $pem . ($result[0][1] . "\n"); + } + + private static function convertDerToPem(string $der_data): string + { + $pem = chunk_split(base64_encode($der_data), 64, "\n"); + + return '-----BEGIN CERTIFICATE-----' . "\n" . $pem . '-----END CERTIFICATE-----' . "\n"; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/RSAKey.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/RSAKey.php new file mode 100644 index 000000000..fe48e87dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/KeyConverter/RSAKey.php @@ -0,0 +1,233 @@ +loadJWK($data); + } + + public static function createFromKeyDetails(array $details): self + { + $values = [ + 'kty' => 'RSA', + ]; + $keys = [ + 'n' => 'n', + 'e' => 'e', + 'd' => 'd', + 'p' => 'p', + 'q' => 'q', + 'dp' => 'dmp1', + 'dq' => 'dmq1', + 'qi' => 'iqmp', + ]; + foreach ($details as $key => $value) { + if (in_array($key, $keys, true)) { + $value = Base64UrlSafe::encodeUnpadded($value); + $values[array_search($key, $keys, true)] = $value; + } + } + + return new self($values); + } + + public static function createFromPEM(string $pem): self + { + if (! extension_loaded('openssl')) { + throw new RuntimeException('Please install the OpenSSL extension'); + } + $res = openssl_pkey_get_private($pem); + if ($res === false) { + $res = openssl_pkey_get_public($pem); + } + if ($res === false) { + throw new InvalidArgumentException('Unable to load the key.'); + } + + $details = openssl_pkey_get_details($res); + if (! is_array($details) || ! isset($details['rsa'])) { + throw new InvalidArgumentException('Unable to load the key.'); + } + + return self::createFromKeyDetails($details['rsa']); + } + + public static function createFromJWK(JWK $jwk): self + { + return new self($jwk->all()); + } + + public function isPublic(): bool + { + return ! array_key_exists('d', $this->values); + } + + public static function toPublic(self $private): self + { + $data = $private->toArray(); + $keys = ['p', 'd', 'q', 'dp', 'dq', 'qi']; + foreach ($keys as $key) { + if (array_key_exists($key, $data)) { + unset($data[$key]); + } + } + + return new self($data); + } + + public function toArray(): array + { + return $this->values; + } + + public function toJwk(): JWK + { + return new JWK($this->values); + } + + /** + * This method will try to add Chinese Remainder Theorem (CRT) parameters. With those primes, the decryption process + * is really fast. + */ + public function optimize(): void + { + if (array_key_exists('d', $this->values)) { + $this->populateCRT(); + } + } + + private function loadJWK(array $jwk): void + { + if (! array_key_exists('kty', $jwk)) { + throw new InvalidArgumentException('The key parameter "kty" is missing.'); + } + if ($jwk['kty'] !== 'RSA') { + throw new InvalidArgumentException('The JWK is not a RSA key.'); + } + + $this->values = $jwk; + } + + /** + * This method adds Chinese Remainder Theorem (CRT) parameters if primes 'p' and 'q' are available. If 'p' and 'q' + * are missing, they are computed and added to the key data. + */ + private function populateCRT(): void + { + if (! array_key_exists('p', $this->values) && ! array_key_exists('q', $this->values)) { + $d = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['d'])); + $e = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['e'])); + $n = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['n'])); + + [$p, $q] = $this->findPrimeFactors($d, $e, $n); + $this->values['p'] = Base64UrlSafe::encodeUnpadded($p->toBytes()); + $this->values['q'] = Base64UrlSafe::encodeUnpadded($q->toBytes()); + } + + if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists( + 'qi', + $this->values + )) { + return; + } + + $one = BigInteger::createFromDecimal(1); + $d = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['d'])); + $p = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['p'])); + $q = BigInteger::createFromBinaryString(Base64UrlSafe::decodeNoPadding($this->values['q'])); + + $this->values['dp'] = Base64UrlSafe::encodeUnpadded($d->mod($p->subtract($one))->toBytes()); + $this->values['dq'] = Base64UrlSafe::encodeUnpadded($d->mod($q->subtract($one))->toBytes()); + $this->values['qi'] = Base64UrlSafe::encodeUnpadded($q->modInverse($p)->toBytes()); + } + + /** + * @return BigInteger[] + */ + private function findPrimeFactors(BigInteger $d, BigInteger $e, BigInteger $n): array + { + $zero = BigInteger::createFromDecimal(0); + $one = BigInteger::createFromDecimal(1); + $two = BigInteger::createFromDecimal(2); + + $k = $d->multiply($e) + ->subtract($one); + + if ($k->isEven()) { + $r = $k; + $t = $zero; + + do { + $r = $r->divide($two); + $t = $t->add($one); + } while ($r->isEven()); + + $found = false; + $y = null; + + for ($i = 1; $i <= 100; ++$i) { + $g = BigInteger::random($n->subtract($one)); + $y = $g->modPow($r, $n); + + if ($y->equals($one) || $y->equals($n->subtract($one))) { + continue; + } + + for ($j = $one; $j->lowerThan($t->subtract($one)); $j = $j->add($one)) { + $x = $y->modPow($two, $n); + + if ($x->equals($one)) { + $found = true; + + break; + } + + if ($x->equals($n->subtract($one))) { + continue; + } + + $y = $x; + } + + $x = $y->modPow($two, $n); + if ($x->equals($one)) { + $found = true; + + break; + } + } + if ($y === null) { + throw new InvalidArgumentException('Unable to find prime factors.'); + } + if ($found === true) { + $p = $y->subtract($one) + ->gcd($n); + $q = $n->divide($p); + + return [$p, $q]; + } + } + + throw new InvalidArgumentException('Unable to find prime factors.'); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/UrlKeySetFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/UrlKeySetFactory.php new file mode 100644 index 000000000..ede4d62d7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/UrlKeySetFactory.php @@ -0,0 +1,113 @@ +client instanceof ClientInterface) { + trigger_deprecation( + 'web-token/jwt-library', + '3.3', + 'Using "%s" with an instance of "%s" is deprecated, use "%s" instead.', + self::class, + ClientInterface::class, + HttpClientInterface::class + ); + } + if (! $this->client instanceof HttpClientInterface && $this->requestFactory === null) { + throw new RuntimeException(sprintf( + 'The request factory must be provided when using an instance of "%s" as client.', + ClientInterface::class + )); + } + $this->cacheItemPool = new NullAdapter(); + } + + public function enabledCache(CacheItemPoolInterface $cacheItemPool, int $expiresAfter = 3600): void + { + $this->cacheItemPool = $cacheItemPool; + $this->expiresAfter = $expiresAfter; + } + + /** + * @param array $header + */ + protected function getContent(string $url, array $header = []): string + { + $cacheKey = hash('xxh128', $url); + $item = $this->cacheItemPool->getItem($cacheKey); + if ($item->isHit()) { + return $item->get(); + } + + $content = $this->client instanceof HttpClientInterface ? $this->sendSymfonyRequest( + $url, + $header + ) : $this->sendPsrRequest($url, $header); + $item = $this->cacheItemPool->getItem($cacheKey); + $item->expiresAfter($this->expiresAfter); + $item->set($content); + $this->cacheItemPool->save($item); + + return $content; + } + + /** + * @param array $header + */ + private function sendSymfonyRequest(string $url, array $header = []): string + { + assert($this->client instanceof HttpClientInterface); + $response = $this->client->request('GET', $url, [ + 'headers' => $header, + ]); + + if ($response->getStatusCode() >= 400) { + throw new RuntimeException('Unable to get the key set.', $response->getStatusCode()); + } + + return $response->getContent(); + } + + /** + * @param array $header + */ + private function sendPsrRequest(string $url, array $header = []): string + { + assert($this->client instanceof ClientInterface); + assert($this->requestFactory instanceof RequestFactoryInterface); + $request = $this->requestFactory->createRequest('GET', $url); + foreach ($header as $k => $v) { + $request = $request->withHeader($k, $v); + } + $response = $this->client->sendRequest($request); + + if ($response->getStatusCode() >= 400) { + throw new RuntimeException('Unable to get the key set.', $response->getStatusCode()); + } + + return $response->getBody() + ->getContents(); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/X5UFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/X5UFactory.php new file mode 100644 index 000000000..f08c2d8ed --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/KeyManagement/X5UFactory.php @@ -0,0 +1,44 @@ +getContent($url, $header); + $data = JsonConverter::decode($content); + if (! is_array($data)) { + throw new RuntimeException('Invalid content.'); + } + + $keys = []; + foreach ($data as $kid => $cert) { + if (mb_strpos((string) $cert, '-----BEGIN CERTIFICATE-----') === false) { + $cert = '-----BEGIN CERTIFICATE-----' . "\n" . $cert . "\n" . '-----END CERTIFICATE-----'; + } + $jwk = KeyConverter::loadKeyFromCertificate($cert); + if (is_string($kid)) { + $jwk['kid'] = $kid; + $keys[$kid] = new JWK($jwk); + } else { + $keys[] = new JWK($jwk); + } + } + + return new JWKSet($keys); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-library/LICENSE new file mode 100644 index 000000000..5ab750604 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2024 Spomky-Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilder.php new file mode 100644 index 000000000..a187d0407 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilder.php @@ -0,0 +1,83 @@ +, header?: array}} $signatures + * @param array{alg?: string, string?: mixed} $jweSharedProtectedHeader + * @param array{alg?: string, string?: mixed} $jweSharedHeader + * @param array{array{key: JWK, header?: array}} $recipients + */ + public function create( + string $payload, + array $signatures, + string $jws_serialization_mode, + array $jweSharedProtectedHeader, + array $jweSharedHeader, + array $recipients, + string $jwe_serialization_mode, + ?string $aad = null + ): string { + $jws = $this->jwsBuilder->create() + ->withPayload($payload); + foreach ($signatures as $signature) { + if (! is_array($signature) || ! array_key_exists('key', $signature)) { + throw new InvalidArgumentException( + 'The signatures must be an array of arrays containing a key, a protected header and a header' + ); + } + $signature['protected_header'] = array_key_exists( + 'protected_header', + $signature + ) ? $signature['protected_header'] : []; + $signature['header'] = array_key_exists('header', $signature) ? $signature['header'] : []; + $jws = $jws->addSignature($signature['key'], $signature['protected_header'], $signature['header']); + } + $jws = $jws->build(); + $token = $this->jwsSerializerManager->serialize($jws_serialization_mode, $jws); + + $jweSharedProtectedHeader['cty'] = 'JWT'; + + $jwe = $this->jweBuilder + ->create() + ->withPayload($token) + ->withSharedProtectedHeader($jweSharedProtectedHeader) + ->withSharedHeader($jweSharedHeader) + ->withAAD($aad); + foreach ($recipients as $recipient) { + if (! is_array($recipient) || ! array_key_exists('key', $recipient)) { + throw new InvalidArgumentException( + 'The recipients must be an array of arrays containing a key and a header' + ); + } + $recipient['header'] = array_key_exists('header', $recipient) ? $recipient['header'] : []; + $jwe = $jwe->addRecipient($recipient['key'], $recipient['header']); + } + $jwe = $jwe->build(); + + return $this->jweSerializerManager->serialize($jwe_serialization_mode, $jwe); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilderFactory.php new file mode 100644 index 000000000..f3f9259ff --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenBuilderFactory.php @@ -0,0 +1,51 @@ + $jwe_serializers + * @param array $encryptionAlgorithms + * @param null|array $contentEncryptionAlgorithms + * @param null|array $compressionMethods + * @param array $jws_serializers + * @param array $signatureAlgorithms + */ + public function create( + array $jwe_serializers, + array $encryptionAlgorithms, + null|array $contentEncryptionAlgorithms, + null|array $compressionMethods, + array $jws_serializers, + array $signatureAlgorithms + ): NestedTokenBuilder { + if ($contentEncryptionAlgorithms !== null) { + $encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithms); + } + $jweBuilder = $this->jweBuilderFactory->create($encryptionAlgorithms, null, $compressionMethods); + $jweSerializerManager = $this->jweSerializerManagerFactory->create($jwe_serializers); + $jwsBuilder = $this->jwsBuilderFactory->create($signatureAlgorithms); + $jwsSerializerManager = $this->jwsSerializerManagerFactory->create($jws_serializers); + + return new NestedTokenBuilder($jweBuilder, $jweSerializerManager, $jwsBuilder, $jwsSerializerManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoader.php b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoader.php new file mode 100644 index 000000000..fbb2c3d45 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoader.php @@ -0,0 +1,57 @@ +jweLoader->loadAndDecryptWithKeySet($token, $encryptionKeySet, $recipient); + $this->checkContentTypeHeader($jwe, $recipient); + if ($jwe->getPayload() === null) { + throw new InvalidArgumentException('The token has no payload.'); + } + + return $this->jwsLoader->loadAndVerifyWithKeySet($jwe->getPayload(), $signatureKeySet, $signature); + } + + private function checkContentTypeHeader(JWE $jwe, int $recipient): void + { + $cty = match (true) { + $jwe->hasSharedProtectedHeaderParameter('cty') => $jwe->getSharedProtectedHeaderParameter('cty'), + $jwe->hasSharedHeaderParameter('cty') => $jwe->getSharedHeaderParameter('cty'), + $jwe->getRecipient($recipient) + ->hasHeaderParameter('cty') => $jwe->getRecipient($recipient) + ->getHeaderParameter('cty'), + default => throw new InvalidArgumentException('The token is not a nested token.'), + }; + if (! is_string($cty)) { + throw new InvalidArgumentException('Invalid "cty" header parameter.'); + } + + if (strcasecmp($cty, 'jwt') !== 0) { + throw new InvalidArgumentException('The token is not a nested token.'); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoaderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoaderFactory.php new file mode 100644 index 000000000..632ff5e87 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/NestedToken/NestedTokenLoaderFactory.php @@ -0,0 +1,52 @@ + $jweSerializers + * @param array $keyEncryptionAlgorithms + * @param array $contentEncryptionAlgorithms + * @param null|array $compressionMethods + * @param array $jweHeaderCheckers + * @param array $jwsSerializers + * @param array $signatureAlgorithms + * @param array $jwsHeaderCheckers + */ + public function create( + array $jweSerializers, + array $keyEncryptionAlgorithms, + null|array $contentEncryptionAlgorithms, + null|array $compressionMethods, + array $jweHeaderCheckers, + array $jwsSerializers, + array $signatureAlgorithms, + array $jwsHeaderCheckers + ): NestedTokenLoader { + $jweLoader = $this->jweLoaderFactory->create( + $jweSerializers, + $keyEncryptionAlgorithms, + $contentEncryptionAlgorithms, + $compressionMethods, + $jweHeaderCheckers + ); + $jwsLoader = $this->jwsLoaderFactory->create($jwsSerializers, $signatureAlgorithms, $jwsHeaderCheckers); + + return new NestedTokenLoader($jweLoader, $jwsLoader); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/README.md b/lam/lib/3rdParty/composer/web-token/jwt-library/README.md new file mode 100644 index 000000000..4a4ec4369 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/README.md @@ -0,0 +1,16 @@ +PHP JWT Library +=============== + +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. + +**Please do not submit any Pull Request here.** +You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. + +# Documentation + +The official documentation is available as https://web-token.spomky-labs.com/ + +# Licence + +This software is release under [MIT licence](LICENSE). diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ECDSA.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ECDSA.php new file mode 100644 index 000000000..3c1f2a7e2 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ECDSA.php @@ -0,0 +1,76 @@ +checkKey($key); + if (! $key->has('d')) { + throw new InvalidArgumentException('The EC key is not private'); + } + $pem = ECKey::convertPrivateKeyToPEM($key); + openssl_sign($input, $signature, $pem, $this->getHashAlgorithm()); + + return ECSignature::fromAsn1($signature, $this->getSignaturePartLength()); + } + + public function verify(JWK $key, string $input, string $signature): bool + { + $this->checkKey($key); + + try { + $der = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); + $pem = ECKey::convertPublicKeyToPEM($key); + + return openssl_verify($input, $der, $pem, $this->getHashAlgorithm()) === 1; + } catch (Throwable) { + return false; + } + } + + abstract protected function getHashAlgorithm(): string; + + abstract protected function getSignaturePartLength(): int; + + private function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + foreach (['x', 'y', 'crv'] as $k) { + if (! $key->has($k)) { + throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ES256.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ES256.php new file mode 100644 index 000000000..926cde026 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/ES256.php @@ -0,0 +1,23 @@ +checkKey($key); + if (! $key->has('d')) { + throw new InvalidArgumentException('The EC key is not private'); + } + $d = $key->get('d'); + if (! is_string($d) || $d === '') { + throw new InvalidArgumentException('Invalid "d" parameter.'); + } + if (! $key->has('x')) { + $x = self::getPublicKey($key); + } else { + $x = $key->get('x'); + } + if (! is_string($x) || $x === '') { + throw new InvalidArgumentException('Invalid "x" parameter.'); + } + /** @var non-empty-string $x */ + $x = Base64UrlSafe::decodeNoPadding($x); + /** @var non-empty-string $d */ + $d = Base64UrlSafe::decodeNoPadding($d); + $secret = $d . $x; + + return match ($key->get('crv')) { + 'Ed25519' => sodium_crypto_sign_detached($input, $secret), + default => throw new InvalidArgumentException('Unsupported curve'), + }; + } + + /** + * @param non-empty-string $signature + */ + public function verify(JWK $key, string $input, string $signature): bool + { + $this->checkKey($key); + $x = $key->get('x'); + if (! is_string($x)) { + throw new InvalidArgumentException('Invalid "x" parameter.'); + } + + /** @var non-empty-string $public */ + $public = Base64UrlSafe::decodeNoPadding($x); + + return match ($key->get('crv')) { + 'Ed25519' => sodium_crypto_sign_verify_detached($signature, $input, $public), + default => throw new InvalidArgumentException('Unsupported curve'), + }; + } + + public function name(): string + { + return 'EdDSA'; + } + + private static function getPublicKey(JWK $key): string + { + $d = $key->get('d'); + assert(is_string($d), 'Unsupported key type'); + + switch ($key->get('crv')) { + case 'Ed25519': + return Ed25519::publickey_from_secretkey($d); + case 'X25519': + if (extension_loaded('sodium')) { + return sodium_crypto_scalarmult_base($d); + } + // no break + default: + throw new InvalidArgumentException('Unsupported key type'); + } + } + + private function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + foreach (['x', 'crv'] as $k) { + if (! $key->has($k)) { + throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); + } + } + if ($key->get('crv') !== 'Ed25519') { + throw new InvalidArgumentException('Unsupported curve.'); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HMAC.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HMAC.php new file mode 100644 index 000000000..92436b007 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HMAC.php @@ -0,0 +1,49 @@ +hash($key, $input), $signature); + } + + public function hash(JWK $key, string $input): string + { + $k = $this->getKey($key); + + return hash_hmac($this->getHashAlgorithm(), $input, $k, true); + } + + protected function getKey(JWK $key): string + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + if (! $key->has('k')) { + throw new InvalidArgumentException('The key parameter "k" is missing.'); + } + $k = $key->get('k'); + if (! is_string($k)) { + throw new InvalidArgumentException('The key parameter "k" is invalid.'); + } + + return Base64UrlSafe::decodeNoPadding($k); + } + + abstract protected function getHashAlgorithm(): string; +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HS256.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HS256.php new file mode 100644 index 000000000..a27f67eb5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/HS256.php @@ -0,0 +1,31 @@ +checkKey($key); + + return ''; + } + + public function verify(JWK $key, string $input, string $signature): bool + { + return $signature === ''; + } + + public function name(): string + { + return 'none'; + } + + private function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/PS256.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/PS256.php new file mode 100644 index 000000000..8b4ea3167 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/PS256.php @@ -0,0 +1,18 @@ +checkKey($key); + $pub = RSAKey::createFromJWK($key->toPublic()); + + return openssl_verify($input, $signature, $pub->toPEM(), $this->getAlgorithm()) === 1; + } + + public function sign(JWK $key, string $input): string + { + $this->checkKey($key); + if (! $key->has('d')) { + throw new InvalidArgumentException('The key is not a private key.'); + } + + $priv = RSAKey::createFromJWK($key); + + $result = openssl_sign($input, $signature, $priv->toPEM(), $this->getAlgorithm()); + if ($result !== true) { + throw new RuntimeException('Unable to sign'); + } + + return $signature; + } + + abstract protected function getAlgorithm(): string; + + private function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + foreach (['n', 'e'] as $k) { + if (! $key->has($k)) { + throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/RSAPSS.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/RSAPSS.php new file mode 100644 index 000000000..46dafec01 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/RSAPSS.php @@ -0,0 +1,56 @@ +checkKey($key); + $pub = RSAKey::createFromJWK($key->toPublic()); + + return JoseRSA::verify($pub, $input, $signature, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS); + } + + /** + * @return non-empty-string + */ + public function sign(JWK $key, string $input): string + { + $this->checkKey($key); + if (! $key->has('d')) { + throw new InvalidArgumentException('The key is not a private key.'); + } + + $priv = RSAKey::createFromJWK($key); + + return JoseRSA::sign($priv, $input, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS); + } + + abstract protected function getAlgorithm(): string; + + private function checkKey(JWK $key): void + { + if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { + throw new InvalidArgumentException('Wrong key type.'); + } + foreach (['n', 'e'] as $k) { + if (! $key->has($k)) { + throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/SignatureAlgorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/SignatureAlgorithm.php new file mode 100644 index 000000000..a283d1dd7 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Algorithm/SignatureAlgorithm.php @@ -0,0 +1,28 @@ +toPEM(), $hash); + if ($result !== true) { + throw new RuntimeException('Unable to sign the data'); + } + + return $signature; + + default: + throw new InvalidArgumentException('Unsupported mode.'); + } + } + + /** + * Create a signature. + * + * @return non-empty-string + */ + public static function signWithPSS(RSAKey $key, string $message, string $hash): string + { + $em = self::encodeEMSAPSS($message, 8 * $key->getModulusLength() - 1, Hash::$hash()); + $message = BigInteger::createFromBinaryString($em); + $signature = RSAKey::exponentiate($key, $message); + $result = self::convertIntegerToOctetString($signature, $key->getModulusLength()); + if ($result === '') { + throw new InvalidArgumentException('Invalid signature.'); + } + + return $result; + } + + public static function verify(RSAKey $key, string $message, string $signature, string $hash, int $mode): bool + { + switch ($mode) { + case self::SIGNATURE_PSS: + return self::verifyWithPSS($key, $message, $signature, $hash); + case self::SIGNATURE_PKCS1: + if (! extension_loaded('openssl')) { + throw new RuntimeException('Please install the OpenSSL extension'); + } + return openssl_verify($message, $signature, $key->toPEM(), $hash) === 1; + default: + throw new InvalidArgumentException('Unsupported mode.'); + } + } + + /** + * Verifies a signature. + */ + public static function verifyWithPSS(RSAKey $key, string $message, string $signature, string $hash): bool + { + if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) { + throw new RuntimeException(); + } + $s2 = BigInteger::createFromBinaryString($signature); + $m2 = RSAKey::exponentiate($key, $s2); + $em = self::convertIntegerToOctetString($m2, $key->getModulusLength()); + $modBits = 8 * $key->getModulusLength(); + + return self::verifyEMSAPSS($message, $em, $modBits - 1, Hash::$hash()); + } + + private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string + { + $x = $x->toBytes(); + if (mb_strlen($x, '8bit') > $xLen) { + throw new RuntimeException(); + } + + return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); + } + + /** + * MGF1. + */ + private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string + { + $t = ''; + $count = ceil($maskLen / $mgfHash->getLength()); + for ($i = 0; $i < $count; ++$i) { + $c = pack('N', $i); + $t .= $mgfHash->hash($mgfSeed . $c); + } + + return mb_substr($t, 0, $maskLen, '8bit'); + } + + /** + * EMSA-PSS-ENCODE. + */ + private static function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string + { + $emLen = ($modulusLength + 1) >> 3; + $sLen = $hash->getLength(); + $mHash = $hash->hash($message); + if ($emLen <= $hash->getLength() + $sLen + 2) { + throw new RuntimeException(); + } + $salt = random_bytes($sLen); + $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; + $h = $hash->hash($m2); + $ps = str_repeat(chr(0), $emLen - $sLen - $hash->getLength() - 2); + $db = $ps . chr(1) . $salt; + $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash); + $maskedDB = $db ^ $dbMask; + $maskedDB[0] = ~chr(0xFF << ($modulusLength & 7)) & $maskedDB[0]; + + return $maskedDB . $h . chr(0xBC); + } + + /** + * EMSA-PSS-VERIFY. + */ + private static function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool + { + $emLen = ($emBits + 1) >> 3; + $sLen = $hash->getLength(); + $mHash = $hash->hash($m); + if ($emLen < $hash->getLength() + $sLen + 2) { + throw new InvalidArgumentException(); + } + if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) { + throw new InvalidArgumentException(); + } + $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit'); + $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit'); + $temp = chr(0xFF << ($emBits & 7)); + if ((~$maskedDB[0] & $temp) !== $temp) { + throw new InvalidArgumentException(); + } + $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/); + $db = $maskedDB ^ $dbMask; + $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; + $temp = $emLen - $hash->getLength() - $sLen - 2; + if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(chr(0), $temp)) { + throw new InvalidArgumentException(); + } + if (ord($db[$temp]) !== 1) { + throw new InvalidArgumentException(); + } + $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long + $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; + $h2 = $hash->hash($m2); + + return hash_equals($h, $h2); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWS.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWS.php new file mode 100644 index 000000000..715ddcc11 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWS.php @@ -0,0 +1,126 @@ +payload; + } + + /** + * Returns true if the payload is detached. + */ + public function isPayloadDetached(): bool + { + return $this->isPayloadDetached; + } + + /** + * Returns the Base64Url encoded payload. If the payload is detached, this method returns null. + */ + public function getEncodedPayload(): ?string + { + if ($this->isPayloadDetached() === true) { + return null; + } + + return $this->encodedPayload; + } + + /** + * Returns the signatures associated with the JWS. + * + * @return Signature[] + */ + public function getSignatures(): array + { + return $this->signatures; + } + + /** + * Returns the signature at the given index. + */ + public function getSignature(int $id): Signature + { + if (isset($this->signatures[$id])) { + return $this->signatures[$id]; + } + + throw new InvalidArgumentException('The signature does not exist.'); + } + + /** + * This method adds a signature to the JWS object. Its returns a new JWS object. + * + * @internal + * + * @param array{alg?: string, string?: mixed} $protectedHeader + * @param array{alg?: string, string?: mixed} $header + */ + public function addSignature( + string $signature, + array $protectedHeader, + ?string $encodedProtectedHeader, + array $header = [] + ): self { + $jws = clone $this; + $jws->signatures[] = new Signature($signature, $protectedHeader, $encodedProtectedHeader, $header); + + return $jws; + } + + /** + * Returns the number of signature associated with the JWS. + */ + public function countSignatures(): int + { + return count($this->signatures); + } + + /** + * This method splits the JWS into a list of JWSs. It is only useful when the JWS contains more than one signature + * (JSON General Serialization). + * + * @return JWS[] + */ + public function split(): array + { + $result = []; + foreach ($this->signatures as $signature) { + $jws = new self($this->payload, $this->encodedPayload, $this->isPayloadDetached); + $jws = $jws->addSignature( + $signature->getSignature(), + $signature->getProtectedHeader(), + $signature->getEncodedProtectedHeader(), + $signature->getHeader() + ); + + $result[] = $jws; + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilder.php new file mode 100644 index 000000000..3c1a1661d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilder.php @@ -0,0 +1,227 @@ +, + * protected_header: array, + * signature_key: JWK, + * signature_algorithm: Algorithm + * }> + */ + protected array $signatures = []; + + protected ?bool $isPayloadEncoded = null; + + public function __construct( + private readonly AlgorithmManager $signatureAlgorithmManager + ) { + } + + /** + * Returns the algorithm manager associated to the builder. + */ + public function getSignatureAlgorithmManager(): AlgorithmManager + { + return $this->signatureAlgorithmManager; + } + + /** + * Reset the current data. + */ + public function create(): self + { + $this->payload = null; + $this->isPayloadDetached = false; + $this->signatures = []; + $this->isPayloadEncoded = null; + + return $this; + } + + /** + * Set the payload. This method will return a new JWSBuilder object. + */ + public function withPayload(string $payload, bool $isPayloadDetached = false): self + { + $clone = clone $this; + $clone->payload = $payload; + $clone->isPayloadDetached = $isPayloadDetached; + + return $clone; + } + + /** + * Adds the information needed to compute the signature. This method will return a new JWSBuilder object. + * + * @param array $protectedHeader + * @param array $header + */ + public function addSignature(JWK $signatureKey, array $protectedHeader, array $header = []): self + { + $this->checkB64AndCriticalHeader($protectedHeader); + $isPayloadEncoded = $this->checkIfPayloadIsEncoded($protectedHeader); + if ($this->isPayloadEncoded === null) { + $this->isPayloadEncoded = $isPayloadEncoded; + } elseif ($this->isPayloadEncoded !== $isPayloadEncoded) { + throw new InvalidArgumentException('Foreign payload encoding detected.'); + } + $this->checkDuplicatedHeaderParameters($protectedHeader, $header); + KeyChecker::checkKeyUsage($signatureKey, 'signature'); + $algorithm = $this->findSignatureAlgorithm($signatureKey, $protectedHeader, $header); + KeyChecker::checkKeyAlgorithm($signatureKey, $algorithm->name()); + $clone = clone $this; + $clone->signatures[] = [ + 'signature_algorithm' => $algorithm, + 'signature_key' => $signatureKey, + 'protected_header' => $protectedHeader, + 'header' => $header, + ]; + + return $clone; + } + + /** + * Computes all signatures and return the expected JWS object. + */ + public function build(): JWS + { + if ($this->payload === null) { + throw new RuntimeException('The payload is not set.'); + } + if (count($this->signatures) === 0) { + throw new RuntimeException('At least one signature must be set.'); + } + + $encodedPayload = $this->isPayloadEncoded === false ? $this->payload : Base64UrlSafe::encodeUnpadded( + $this->payload + ); + + if ($this->isPayloadEncoded === false && $this->isPayloadDetached === false) { + mb_detect_encoding($this->payload, 'UTF-8', true) !== false || throw new InvalidArgumentException( + 'The payload must be encoded in UTF-8' + ); + } + + $jws = new JWS($this->payload, $encodedPayload, $this->isPayloadDetached); + foreach ($this->signatures as $signature) { + /** @var MacAlgorithm|SignatureAlgorithm $algorithm */ + $algorithm = $signature['signature_algorithm']; + /** @var JWK $signatureKey */ + $signatureKey = $signature['signature_key']; + /** @var array $protectedHeader */ + $protectedHeader = $signature['protected_header']; + /** @var array $header */ + $header = $signature['header']; + $encodedProtectedHeader = count($protectedHeader) === 0 ? null : Base64UrlSafe::encodeUnpadded( + JsonConverter::encode($protectedHeader) + ); + $input = sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload); + if ($algorithm instanceof SignatureAlgorithm) { + $s = $algorithm->sign($signatureKey, $input); + } else { + $s = $algorithm->hash($signatureKey, $input); + } + $jws = $jws->addSignature($s, $protectedHeader, $encodedProtectedHeader, $header); + } + + return $jws; + } + + /** + * @param array $protectedHeader + */ + private function checkIfPayloadIsEncoded(array $protectedHeader): bool + { + return ! array_key_exists('b64', $protectedHeader) || $protectedHeader['b64'] === true; + } + + /** + * @param array $protectedHeader + */ + private function checkB64AndCriticalHeader(array $protectedHeader): void + { + if (! array_key_exists('b64', $protectedHeader)) { + return; + } + if (! array_key_exists('crit', $protectedHeader)) { + throw new LogicException( + 'The protected header parameter "crit" is mandatory when protected header parameter "b64" is set.' + ); + } + if (! is_array($protectedHeader['crit'])) { + throw new LogicException('The protected header parameter "crit" must be an array.'); + } + if (! in_array('b64', $protectedHeader['crit'], true)) { + throw new LogicException( + 'The protected header parameter "crit" must contain "b64" when protected header parameter "b64" is set.' + ); + } + } + + /** + * @param array $protectedHeader + * @param array $header + * @return MacAlgorithm|SignatureAlgorithm + */ + private function findSignatureAlgorithm(JWK $key, array $protectedHeader, array $header): Algorithm + { + $completeHeader = [...$header, ...$protectedHeader]; + $alg = $completeHeader['alg'] ?? null; + if (! is_string($alg)) { + throw new InvalidArgumentException('No "alg" parameter set in the header.'); + } + $keyAlg = $key->has('alg') ? $key->get('alg') : null; + if (is_string($keyAlg) && $keyAlg !== $alg) { + throw new InvalidArgumentException(sprintf('The algorithm "%s" is not allowed with this key.', $alg)); + } + + $algorithm = $this->signatureAlgorithmManager->get($alg); + if (! $algorithm instanceof SignatureAlgorithm && ! $algorithm instanceof MacAlgorithm) { + throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported.', $alg)); + } + + return $algorithm; + } + + /** + * @param array $header1 + * @param array $header2 + */ + private function checkDuplicatedHeaderParameters(array $header1, array $header2): void + { + $inter = array_intersect_key($header1, $header2); + if (count($inter) !== 0) { + throw new InvalidArgumentException(sprintf( + 'The header contains duplicated entries: %s.', + implode(', ', array_keys($inter)) + )); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilderFactory.php new file mode 100644 index 000000000..8d14ed141 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSBuilderFactory.php @@ -0,0 +1,27 @@ +signatureAlgorithmManagerFactory->create($algorithms); + + return new JWSBuilder($algorithmManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoader.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoader.php new file mode 100644 index 000000000..8889d2dad --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoader.php @@ -0,0 +1,100 @@ +jwsVerifier; + } + + /** + * Returns the Header Checker Manager associated to the JWSLoader. + */ + public function getHeaderCheckerManager(): ?HeaderCheckerManager + { + return $this->headerCheckerManager; + } + + /** + * Returns the JWSSerializer associated to the JWSLoader. + */ + public function getSerializerManager(): JWSSerializerManager + { + return $this->serializerManager; + } + + /** + * This method will try to load and verify the token using the given key. It returns a JWS and will populate the + * $signature variable in case of success, otherwise an exception is thrown. + */ + public function loadAndVerifyWithKey(string $token, JWK $key, ?int &$signature, ?string $payload = null): JWS + { + $keyset = new JWKSet([$key]); + + return $this->loadAndVerifyWithKeySet($token, $keyset, $signature, $payload); + } + + /** + * This method will try to load and verify the token using the given key set. It returns a JWS and will populate the + * $signature variable in case of success, otherwise an exception is thrown. + */ + public function loadAndVerifyWithKeySet( + string $token, + JWKSet $keyset, + ?int &$signature, + ?string $payload = null + ): JWS { + try { + $jws = $this->serializerManager->unserialize($token); + $nbSignatures = $jws->countSignatures(); + for ($i = 0; $i < $nbSignatures; ++$i) { + if ($this->processSignature($jws, $keyset, $i, $payload)) { + $signature = $i; + + return $jws; + } + } + } catch (Throwable) { + // Nothing to do. Exception thrown just after + } + + throw new Exception('Unable to load and verify the token.'); + } + + private function processSignature(JWS $jws, JWKSet $keyset, int $signature, ?string $payload): bool + { + try { + if ($this->headerCheckerManager !== null) { + $this->headerCheckerManager->check($jws, $signature); + } + + return $this->jwsVerifier->verifyWithKeySet($jws, $keyset, $signature, $payload); + } catch (Throwable) { + return false; + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoaderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoaderFactory.php new file mode 100644 index 000000000..2601c0582 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSLoaderFactory.php @@ -0,0 +1,40 @@ + $serializers + * @param array $algorithms + * @param array $headerCheckers + */ + public function create(array $serializers, array $algorithms, array $headerCheckers = []): JWSLoader + { + $serializerManager = $this->jwsSerializerManagerFactory->create($serializers); + $jwsVerifier = $this->jwsVerifierFactory->create($algorithms); + if ($this->headerCheckerManagerFactory !== null) { + $headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers); + } else { + $headerCheckerManager = null; + } + + return new JWSLoader($serializerManager, $jwsVerifier, $headerCheckerManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSTokenSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSTokenSupport.php new file mode 100644 index 000000000..607d66245 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSTokenSupport.php @@ -0,0 +1,36 @@ + $protectedHeader + * @param array $unprotectedHeader + */ + public function retrieveTokenHeaders(JWT $jwt, int $index, array &$protectedHeader, array &$unprotectedHeader): void + { + if (! $jwt instanceof JWS) { + return; + } + + if ($index > $jwt->countSignatures()) { + throw new InvalidArgumentException('Unknown signature index.'); + } + $protectedHeader = $jwt->getSignature($index) + ->getProtectedHeader(); + $unprotectedHeader = $jwt->getSignature($index) + ->getHeader(); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifier.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifier.php new file mode 100644 index 000000000..1944c4ddf --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifier.php @@ -0,0 +1,163 @@ +signatureAlgorithmManager; + } + + /** + * This method will try to verify the JWS object using the given key and for the given signature. It returns true if + * the signature is verified, otherwise false. + * + * @return bool true if the verification of the signature succeeded, else false + */ + public function verifyWithKey(JWS $jws, JWK $jwk, int $signature, ?string $detachedPayload = null): bool + { + $jwkset = new JWKSet([$jwk]); + + return $this->verifyWithKeySet($jws, $jwkset, $signature, $detachedPayload); + } + + /** + * This method will try to verify the JWS object using the given key set and for the given signature. It returns + * true if the signature is verified, otherwise false. + * + * @param JWS $jws A JWS object + * @param JWKSet $jwkset The signature will be verified using keys in the key set + * @param JWK $jwk The key used to verify the signature in case of success + * @param string|null $detachedPayload If not null, the value must be the detached payload encoded in Base64 URL safe. If the input contains a payload, throws an exception. + * + * @return bool true if the verification of the signature succeeded, else false + */ + public function verifyWithKeySet( + JWS $jws, + JWKSet $jwkset, + int $signatureIndex, + ?string $detachedPayload = null, + ?JWK &$jwk = null + ): bool { + if ($jwkset->count() === 0) { + throw new InvalidArgumentException('There is no key in the key set.'); + } + if ($jws->countSignatures() === 0) { + throw new InvalidArgumentException('The JWS does not contain any signature.'); + } + $this->checkPayload($jws, $detachedPayload); + $signature = $jws->getSignature($signatureIndex); + + return $this->verifySignature($jws, $jwkset, $signature, $detachedPayload, $jwk); + } + + private function verifySignature( + JWS $jws, + JWKSet $jwkset, + Signature $signature, + ?string $detachedPayload = null, + ?JWK &$successJwk = null + ): bool { + $input = $this->getInputToVerify($jws, $signature, $detachedPayload); + $algorithm = $this->getAlgorithm($signature); + foreach ($jwkset->all() as $jwk) { + try { + KeyChecker::checkKeyUsage($jwk, 'verification'); + KeyChecker::checkKeyAlgorithm($jwk, $algorithm->name()); + if ($algorithm->verify($jwk, $input, $signature->getSignature()) === true) { + $successJwk = $jwk; + + return true; + } + } catch (Throwable) { + //We do nothing, we continue with other keys + continue; + } + } + + return false; + } + + private function getInputToVerify(JWS $jws, Signature $signature, ?string $detachedPayload): string + { + $payload = $jws->getPayload(); + $isPayloadEmpty = $payload === null || $payload === ''; + $encodedProtectedHeader = $signature->getEncodedProtectedHeader() ?? ''; + $isPayloadBase64Encoded = ! $signature->hasProtectedHeaderParameter( + 'b64' + ) || $signature->getProtectedHeaderParameter('b64') === true; + $encodedPayload = $jws->getEncodedPayload(); + + if ($isPayloadBase64Encoded && $encodedPayload !== null) { + return sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload); + } + + $callable = $isPayloadBase64Encoded === true ? static fn (?string $p): string => Base64UrlSafe::encodeUnpadded( + $p ?? '' + ) + : static fn (?string $p): string => $p ?? ''; + + $payloadToUse = $callable($isPayloadEmpty ? $detachedPayload : $payload); + + return sprintf('%s.%s', $encodedProtectedHeader, $payloadToUse); + } + + private function checkPayload(JWS $jws, ?string $detachedPayload = null): void + { + $isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload()); + if ($detachedPayload !== null && ! $isPayloadEmpty) { + throw new InvalidArgumentException('A detached payload is set, but the JWS already has a payload.'); + } + if ($isPayloadEmpty && $detachedPayload === null) { + throw new InvalidArgumentException('The JWS has a detached payload, but no payload is provided.'); + } + } + + /** + * @return MacAlgorithm|SignatureAlgorithm + */ + private function getAlgorithm(Signature $signature): Algorithm + { + $completeHeader = [...$signature->getProtectedHeader(), ...$signature->getHeader()]; + if (! isset($completeHeader['alg'])) { + throw new InvalidArgumentException('No "alg" parameter set in the header.'); + } + + $algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); + if (! $algorithm instanceof SignatureAlgorithm && ! $algorithm instanceof MacAlgorithm) { + throw new InvalidArgumentException(sprintf( + 'The algorithm "%s" is not supported or is not a signature or MAC algorithm.', + $completeHeader['alg'] + )); + } + + return $algorithm; + } + + private function isPayloadEmpty(?string $payload): bool + { + return $payload === null || $payload === ''; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifierFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifierFactory.php new file mode 100644 index 000000000..5ae63a0ae --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/JWSVerifierFactory.php @@ -0,0 +1,27 @@ +algorithmManagerFactory->create($algorithms); + + return new JWSVerifier($algorithmManager); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/CompactSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/CompactSerializer.php new file mode 100644 index 000000000..03a9c0d78 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/CompactSerializer.php @@ -0,0 +1,88 @@ +getSignature($signatureIndex); + if (count($signature->getHeader()) !== 0) { + throw new LogicException( + 'The signature contains unprotected header parameters and cannot be converted into compact JSON.' + ); + } + $isEmptyPayload = $jws->getEncodedPayload() === null || $jws->getEncodedPayload() === ''; + if (! $isEmptyPayload && ! $this->isPayloadEncoded($signature->getProtectedHeader())) { + if (preg_match('/^[\x{20}-\x{2d}|\x{2f}-\x{7e}]*$/u', $jws->getPayload() ?? '') !== 1) { + throw new LogicException('Unable to convert the JWS with non-encoded payload.'); + } + } + + return sprintf( + '%s.%s.%s', + $signature->getEncodedProtectedHeader(), + $jws->getEncodedPayload(), + Base64UrlSafe::encodeUnpadded($signature->getSignature()) + ); + } + + public function unserialize(string $input): JWS + { + $parts = explode('.', $input); + if (count($parts) !== 3) { + throw new InvalidArgumentException('Unsupported input'); + } + + try { + $encodedProtectedHeader = $parts[0]; + $protectedHeader = JsonConverter::decode(Base64UrlSafe::decodeNoPadding($parts[0])); + if (! is_array($protectedHeader)) { + throw new InvalidArgumentException('Bad protected header.'); + } + $hasPayload = $parts[1] !== ''; + if (! $hasPayload) { + $payload = null; + $encodedPayload = null; + } else { + $encodedPayload = $parts[1]; + $payload = $this->isPayloadEncoded($protectedHeader) ? Base64UrlSafe::decodeNoPadding( + $encodedPayload + ) : $encodedPayload; + } + $signature = Base64UrlSafe::decodeNoPadding($parts[2]); + + $jws = new JWS($payload, $encodedPayload, ! $hasPayload); + + return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable); + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONFlattenedSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONFlattenedSerializer.php new file mode 100644 index 000000000..93dae92c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONFlattenedSerializer.php @@ -0,0 +1,97 @@ +getSignature($signatureIndex); + + $data = []; + $encodedPayload = $jws->getEncodedPayload(); + if ($encodedPayload !== null && $encodedPayload !== '') { + $data['payload'] = $encodedPayload; + } + $encodedProtectedHeader = $signature->getEncodedProtectedHeader(); + if ($encodedProtectedHeader !== null && $encodedProtectedHeader !== '') { + $data['protected'] = $encodedProtectedHeader; + } + $header = $signature->getHeader(); + if (count($header) !== 0) { + $data['header'] = $header; + } + $data['signature'] = Base64UrlSafe::encodeUnpadded($signature->getSignature()); + + return JsonConverter::encode($data); + } + + public function unserialize(string $input): JWS + { + $data = JsonConverter::decode($input); + if (! is_array($data)) { + throw new InvalidArgumentException('Unsupported input.'); + } + if (! isset($data['signature'])) { + throw new InvalidArgumentException('Unsupported input.'); + } + $signature = Base64UrlSafe::decodeNoPadding($data['signature']); + + if (isset($data['protected'])) { + $encodedProtectedHeader = $data['protected']; + $protectedHeader = JsonConverter::decode(Base64UrlSafe::decodeNoPadding($data['protected'])); + if (! is_array($protectedHeader)) { + throw new InvalidArgumentException('Bad protected header.'); + } + } else { + $encodedProtectedHeader = null; + $protectedHeader = []; + } + if (isset($data['header'])) { + if (! is_array($data['header'])) { + throw new InvalidArgumentException('Bad header.'); + } + $header = $data['header']; + } else { + $header = []; + } + + if (isset($data['payload'])) { + $encodedPayload = $data['payload']; + $payload = $this->isPayloadEncoded($protectedHeader) ? Base64UrlSafe::decodeNoPadding( + $encodedPayload + ) : $encodedPayload; + } else { + $payload = null; + $encodedPayload = null; + } + + $jws = new JWS($payload, $encodedPayload, $encodedPayload === null); + + return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader, $header); + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONGeneralSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONGeneralSerializer.php new file mode 100644 index 000000000..43acd0e0a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JSONGeneralSerializer.php @@ -0,0 +1,160 @@ +countSignatures() === 0) { + throw new LogicException('No signature.'); + } + + $data = []; + $this->checkPayloadEncoding($jws); + + if ($jws->isPayloadDetached() === false) { + $data['payload'] = $jws->getEncodedPayload(); + } + + $data['signatures'] = []; + foreach ($jws->getSignatures() as $signature) { + $tmp = [ + 'signature' => Base64UrlSafe::encodeUnpadded($signature->getSignature()), + ]; + $values = [ + 'protected' => $signature->getEncodedProtectedHeader(), + 'header' => $signature->getHeader(), + ]; + + foreach ($values as $key => $value) { + if ((is_string($value) && $value !== '') || (is_array($value) && count($value) !== 0)) { + $tmp[$key] = $value; + } + } + $data['signatures'][] = $tmp; + } + + return JsonConverter::encode($data); + } + + public function unserialize(string $input): JWS + { + $data = JsonConverter::decode($input); + if (! is_array($data)) { + throw new InvalidArgumentException('Unsupported input.'); + } + if (! isset($data['signatures'])) { + throw new InvalidArgumentException('Unsupported input.'); + } + + $isPayloadEncoded = null; + $rawPayload = $data['payload'] ?? null; + $signatures = []; + foreach ($data['signatures'] as $signature) { + if (! isset($signature['signature'])) { + throw new InvalidArgumentException('Unsupported input.'); + } + [$encodedProtectedHeader, $protectedHeader, $header] = $this->processHeaders($signature); + $signatures[] = [ + 'signature' => Base64UrlSafe::decodeNoPadding($signature['signature']), + 'protected' => $protectedHeader, + 'encoded_protected' => $encodedProtectedHeader, + 'header' => $header, + ]; + $isPayloadEncoded = $this->processIsPayloadEncoded($isPayloadEncoded, $protectedHeader); + } + + $payload = $this->processPayload($rawPayload, $isPayloadEncoded); + $jws = new JWS($payload, $rawPayload); + foreach ($signatures as $signature) { + $jws = $jws->addSignature( + $signature['signature'], + $signature['protected'], + $signature['encoded_protected'], + $signature['header'] + ); + } + + return $jws; + } + + /** + * @param array $protectedHeader + */ + private function processIsPayloadEncoded(?bool $isPayloadEncoded, array $protectedHeader): bool + { + if ($isPayloadEncoded === null) { + return $this->isPayloadEncoded($protectedHeader); + } + if ($this->isPayloadEncoded($protectedHeader) !== $isPayloadEncoded) { + throw new InvalidArgumentException('Foreign payload encoding detected.'); + } + + return $isPayloadEncoded; + } + + /** + * @param array{protected?: string, header?: array} $signature + * @return array + */ + private function processHeaders(array $signature): array + { + $encodedProtectedHeader = $signature['protected'] ?? null; + $protectedHeader = $encodedProtectedHeader === null ? [] : JsonConverter::decode( + Base64UrlSafe::decodeNoPadding($encodedProtectedHeader) + ); + $header = array_key_exists('header', $signature) ? $signature['header'] : []; + + return [$encodedProtectedHeader, $protectedHeader, $header]; + } + + private function processPayload(?string $rawPayload, ?bool $isPayloadEncoded): ?string + { + if ($rawPayload === null) { + return null; + } + + return $isPayloadEncoded === false ? $rawPayload : Base64UrlSafe::decodeNoPadding($rawPayload); + } + + private function checkPayloadEncoding(JWS $jws): void + { + if ($jws->isPayloadDetached()) { + return; + } + $is_encoded = null; + foreach ($jws->getSignatures() as $signature) { + if ($is_encoded === null) { + $is_encoded = $this->isPayloadEncoded($signature->getProtectedHeader()); + } + if ($is_encoded !== $this->isPayloadEncoded($signature->getProtectedHeader())) { + throw new LogicException('Foreign payload encoding detected.'); + } + } + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializer.php new file mode 100644 index 000000000..d53e84cf6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializer.php @@ -0,0 +1,29 @@ +add($serializer); + } + } + + /** + * @return string[] + */ + public function list(): array + { + return array_keys($this->serializers); + } + + /** + * Converts a JWS into a string. + */ + public function serialize(string $name, JWS $jws, ?int $signatureIndex = null): string + { + if (! isset($this->serializers[$name])) { + throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); + } + + return $this->serializers[$name]->serialize($jws, $signatureIndex); + } + + /** + * Loads data and return a JWS object. + * + * @param string $input A string that represents a JWS + * @param string|null $name the name of the serializer if the input is unserialized + */ + public function unserialize(string $input, ?string &$name = null): JWS + { + foreach ($this->serializers as $serializer) { + try { + $jws = $serializer->unserialize($input); + $name = $serializer->name(); + + return $jws; + } catch (InvalidArgumentException) { + continue; + } + } + + throw new InvalidArgumentException('Unsupported input.'); + } + + private function add(JWSSerializer $serializer): void + { + $this->serializers[$serializer->name()] = $serializer; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializerManagerFactory.php new file mode 100644 index 000000000..361fb9fec --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/JWSSerializerManagerFactory.php @@ -0,0 +1,52 @@ +serializers[$name])) { + throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); + } + $serializers[] = $this->serializers[$name]; + } + + return new JWSSerializerManager($serializers); + } + + /** + * @return string[] + */ + public function names(): array + { + return array_keys($this->serializers); + } + + /** + * @return JWSSerializer[] + */ + public function all(): array + { + return $this->serializers; + } + + public function add(JWSSerializer $serializer): void + { + $this->serializers[$serializer->name()] = $serializer; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/Serializer.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/Serializer.php new file mode 100644 index 000000000..541d3e2ec --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Serializer/Serializer.php @@ -0,0 +1,18 @@ + $protectedHeader + */ + protected function isPayloadEncoded(array $protectedHeader): bool + { + return ! array_key_exists('b64', $protectedHeader) || $protectedHeader['b64'] === true; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Signature.php b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Signature.php new file mode 100644 index 000000000..a9975e33b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/Signature/Signature.php @@ -0,0 +1,120 @@ + + */ + private readonly array $protectedHeader; + + /** + * @param array{alg?: string, string?: mixed} $protectedHeader + * @param array{alg?: string, string?: mixed} $header + */ + public function __construct( + private readonly string $signature, + array $protectedHeader, + ?string $encodedProtectedHeader, + private readonly array $header + ) { + $this->protectedHeader = $encodedProtectedHeader === null ? [] : $protectedHeader; + $this->encodedProtectedHeader = $encodedProtectedHeader; + } + + /** + * The protected header associated with the signature. + * + * @return array + */ + public function getProtectedHeader(): array + { + return $this->protectedHeader; + } + + /** + * The unprotected header associated with the signature. + * + * @return array + */ + public function getHeader(): array + { + return $this->header; + } + + /** + * The protected header associated with the signature. + */ + public function getEncodedProtectedHeader(): ?string + { + return $this->encodedProtectedHeader; + } + + /** + * Returns the value of the protected header of the specified key. + * + * @param string $key The key + * + * @return mixed|null Header value + */ + public function getProtectedHeaderParameter(string $key) + { + if ($this->hasProtectedHeaderParameter($key)) { + return $this->getProtectedHeader()[$key]; + } + + throw new InvalidArgumentException(sprintf('The protected header "%s" does not exist', $key)); + } + + /** + * Returns true if the protected header has the given parameter. + * + * @param string $key The key + */ + public function hasProtectedHeaderParameter(string $key): bool + { + return array_key_exists($key, $this->getProtectedHeader()); + } + + /** + * Returns the value of the unprotected header of the specified key. + * + * @param string $key The key + * + * @return mixed|null Header value + */ + public function getHeaderParameter(string $key) + { + if (array_key_exists($key, $this->header)) { + return $this->header[$key]; + } + + throw new InvalidArgumentException(sprintf('The header "%s" does not exist', $key)); + } + + /** + * Returns true if the unprotected header has the given parameter. + * + * @param string $key The key + */ + public function hasHeaderParameter(string $key): bool + { + return array_key_exists($key, $this->header); + } + + /** + * Returns the value of the signature. + */ + public function getSignature(): string + { + return $this->signature; + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-library/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-library/composer.json new file mode 100644 index 000000000..5774ba238 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-library/composer.json @@ -0,0 +1,68 @@ +{ + "name": "web-token/jwt-library", + "description": "JWT library", + "type": "library", + "license": "MIT", + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], + "homepage": "https://github.com/web-token", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-framework/contributors" + } + ], + "autoload": { + "psr-4": { + "Jose\\Component\\": "" + } + }, + "require": { + "php": ">=8.1", + "ext-json": "*", + "ext-mbstring": "*", + "brick/math": "^0.9|^0.10|^0.11|^0.12", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", + "psr/cache": "^2.0|^3.0", + "psr/clock": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-client": "^1.0", + "spomky-labs/pki-framework": "^1.2.1", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.12" + }, + "conflict": { + "spomky-labs/jose": "*" + }, + "suggest": { + "ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)", + "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance", + "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", + "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "symfony/http-client": "To enable JKU/X5U support.", + "spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW...)" + } +} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/LICENSE index 37cf976b1..5ab750604 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/LICENSE +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2019 Spomky-Labs +Copyright (c) 2014-2024 Spomky-Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/PS256.php b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/PS256.php deleted file mode 100644 index dfaabd58e..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/PS256.php +++ /dev/null @@ -1,27 +0,0 @@ -checkKey($key); - $pub = RSAKey::createFromJWK($key->toPublic()); - - return JoseRSA::verify($pub, $input, $signature, $this->getAlgorithm(), $this->getSignatureMethod()); - } - - /** - * @throws InvalidArgumentException if the key is not private - */ - public function sign(JWK $key, string $input): string - { - $this->checkKey($key); - if (!$key->has('d')) { - throw new InvalidArgumentException('The key is not a private key.'); - } - - $priv = RSAKey::createFromJWK($key); - - return JoseRSA::sign($priv, $input, $this->getAlgorithm(), $this->getSignatureMethod()); - } - - abstract protected function getAlgorithm(): string; - - abstract protected function getSignatureMethod(): int; - - /** - * @throws InvalidArgumentException if the key type is not allowed - * @throws InvalidArgumentException if the key is invalid - */ - private function checkKey(JWK $key): void - { - if (!in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { - throw new InvalidArgumentException('Wrong key type.'); - } - foreach (['n', 'e'] as $k) { - if (!$key->has($k)) { - throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPKCS1.php b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPKCS1.php deleted file mode 100644 index da2fd8076..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPKCS1.php +++ /dev/null @@ -1,75 +0,0 @@ -checkKey($key); - $pub = RSAKey::createFromJWK($key->toPublic()); - - return 1 === openssl_verify($input, $signature, $pub->toPEM(), $this->getAlgorithm()); - } - - /** - * @throws InvalidArgumentException if the key is not private - * @throws InvalidArgumentException if the data cannot be signed - */ - public function sign(JWK $key, string $input): string - { - $this->checkKey($key); - if (!$key->has('d')) { - throw new InvalidArgumentException('The key is not a private key.'); - } - - $priv = RSAKey::createFromJWK($key); - - $result = openssl_sign($input, $signature, $priv->toPEM(), $this->getAlgorithm()); - if (true !== $result) { - throw new RuntimeException('Unable to sign'); - } - - return $signature; - } - - abstract protected function getAlgorithm(): string; - - /** - * @throws InvalidArgumentException if the key type is not allowed - * @throws InvalidArgumentException if the key is not valid - */ - private function checkKey(JWK $key): void - { - if (!in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { - throw new InvalidArgumentException('Wrong key type.'); - } - foreach (['n', 'e'] as $k) { - if (!$key->has($k)) { - throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPSS.php b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPSS.php deleted file mode 100644 index 9112c417b..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/RSAPSS.php +++ /dev/null @@ -1,69 +0,0 @@ -checkKey($key); - $pub = RSAKey::createFromJWK($key->toPublic()); - - return JoseRSA::verify($pub, $input, $signature, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS); - } - - /** - * @throws InvalidArgumentException if the key is not private - */ - public function sign(JWK $key, string $input): string - { - $this->checkKey($key); - if (!$key->has('d')) { - throw new InvalidArgumentException('The key is not a private key.'); - } - - $priv = RSAKey::createFromJWK($key); - - return JoseRSA::sign($priv, $input, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS); - } - - abstract protected function getAlgorithm(): string; - - /** - * @throws InvalidArgumentException if the key type is not allowed - * @throws InvalidArgumentException if the key is not valid - */ - private function checkKey(JWK $key): void - { - if (!in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { - throw new InvalidArgumentException('Wrong key type.'); - } - foreach (['n', 'e'] as $k) { - if (!$key->has($k)) { - throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/Util/RSA.php b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/Util/RSA.php deleted file mode 100644 index b0f7e3136..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/Util/RSA.php +++ /dev/null @@ -1,251 +0,0 @@ -toPEM(), $hash); - if (true !== $result) { - throw new RuntimeException('Unable to sign the data'); - } - - return $signature; - - default: - throw new InvalidArgumentException('Unsupported mode.'); - } - } - - /** - * Create a signature. - */ - public static function signWithPSS(RSAKey $key, string $message, string $hash): string - { - $em = self::encodeEMSAPSS($message, 8 * $key->getModulusLength() - 1, Hash::$hash()); - $message = BigInteger::createFromBinaryString($em); - $signature = RSAKey::exponentiate($key, $message); - - return self::convertIntegerToOctetString($signature, $key->getModulusLength()); - } - - /** - * Create a signature. - * - * @deprecated Please use openssl_sign - */ - public static function signWithPKCS15(RSAKey $key, string $message, string $hash): string - { - $em = self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash()); - $message = BigInteger::createFromBinaryString($em); - $signature = RSAKey::exponentiate($key, $message); - - return self::convertIntegerToOctetString($signature, $key->getModulusLength()); - } - - /** - * @throws InvalidArgumentException if the signature mode is not supported - */ - public static function verify(RSAKey $key, string $message, string $signature, string $hash, int $mode): bool - { - switch ($mode) { - case self::SIGNATURE_PSS: - return self::verifyWithPSS($key, $message, $signature, $hash); - - case self::SIGNATURE_PKCS1: - return 1 === openssl_verify($message, $signature, $key->toPEM(), $hash); - - default: - throw new InvalidArgumentException('Unsupported mode.'); - } - } - - /** - * Verifies a signature. - * - * @throws RuntimeException if the signature cannot be verified - */ - public static function verifyWithPSS(RSAKey $key, string $message, string $signature, string $hash): bool - { - if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) { - throw new RuntimeException(); - } - $s2 = BigInteger::createFromBinaryString($signature); - $m2 = RSAKey::exponentiate($key, $s2); - $em = self::convertIntegerToOctetString($m2, $key->getModulusLength()); - $modBits = 8 * $key->getModulusLength(); - - return self::verifyEMSAPSS($message, $em, $modBits - 1, Hash::$hash()); - } - - /** - * Verifies a signature. - * - * @deprecated Please use openssl_sign - * - * @throws RuntimeException if the signature cannot be verified - */ - public static function verifyWithPKCS15(RSAKey $key, string $message, string $signature, string $hash): bool - { - if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) { - throw new RuntimeException(); - } - $signature = BigInteger::createFromBinaryString($signature); - $m2 = RSAKey::exponentiate($key, $signature); - $em = self::convertIntegerToOctetString($m2, $key->getModulusLength()); - - return hash_equals($em, self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash())); - } - - /** - * @throws RuntimeException if the value cannot be converted - */ - private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string - { - $x = $x->toBytes(); - if (mb_strlen($x, '8bit') > $xLen) { - throw new RuntimeException(); - } - - return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); - } - - /** - * MGF1. - */ - private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string - { - $t = ''; - $count = ceil($maskLen / $mgfHash->getLength()); - for ($i = 0; $i < $count; ++$i) { - $c = pack('N', $i); - $t .= $mgfHash->hash($mgfSeed.$c); - } - - return mb_substr($t, 0, $maskLen, '8bit'); - } - - /** - * EMSA-PSS-ENCODE. - * - * @throws RuntimeException if the message length is invalid - */ - private static function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string - { - $emLen = ($modulusLength + 1) >> 3; - $sLen = $hash->getLength(); - $mHash = $hash->hash($message); - if ($emLen <= $hash->getLength() + $sLen + 2) { - throw new RuntimeException(); - } - $salt = random_bytes($sLen); - $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt; - $h = $hash->hash($m2); - $ps = str_repeat(chr(0), $emLen - $sLen - $hash->getLength() - 2); - $db = $ps.chr(1).$salt; - $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash); - $maskedDB = $db ^ $dbMask; - $maskedDB[0] = ~chr(0xFF << ($modulusLength & 7)) & $maskedDB[0]; - $em = $maskedDB.$h.chr(0xBC); - - return $em; - } - - /** - * EMSA-PSS-VERIFY. - * - * @throws InvalidArgumentException if the signature cannot be verified - */ - private static function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool - { - $emLen = ($emBits + 1) >> 3; - $sLen = $hash->getLength(); - $mHash = $hash->hash($m); - if ($emLen < $hash->getLength() + $sLen + 2) { - throw new InvalidArgumentException(); - } - if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) { - throw new InvalidArgumentException(); - } - $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit'); - $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit'); - $temp = chr(0xFF << ($emBits & 7)); - if ((~$maskedDB[0] & $temp) !== $temp) { - throw new InvalidArgumentException(); - } - $dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/); - $db = $maskedDB ^ $dbMask; - $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; - $temp = $emLen - $hash->getLength() - $sLen - 2; - if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(chr(0), $temp)) { - throw new InvalidArgumentException(); - } - if (1 !== ord($db[$temp])) { - throw new InvalidArgumentException(); - } - $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long - $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt; - $h2 = $hash->hash($m2); - - return hash_equals($h, $h2); - } - - /** - * @throws RuntimeException if the value cannot be encoded - */ - private static function encodeEMSA15(string $m, int $emBits, Hash $hash): string - { - $h = $hash->hash($m); - $t = $hash->t(); - $t .= $h; - $tLen = mb_strlen($t, '8bit'); - if ($emBits < $tLen + 11) { - throw new RuntimeException(); - } - $ps = str_repeat(chr(0xFF), $emBits - $tLen - 3); - - return "\0\1{$ps}\0{$t}"; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/composer.json index eb57efa89..78c770c5f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/composer.json +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature-algorithm-rsa/composer.json @@ -1,31 +1,41 @@ { "name": "web-token/jwt-signature-algorithm-rsa", - "description": "RSA Based Signature Algorithms the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "type": "library", "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], "homepage": "https://github.com/web-token", "authors": [ { "name": "Florent Morselli", "homepage": "https://github.com/Spomky" - },{ + }, + { "name": "All contributors", "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\Algorithm\\": "" - } - }, "require": { - "brick/math": "^0.8.17|^0.9", + "php": ">=8.1", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-openssl": "*", - "web-token/jwt-signature": "^2.1" - }, - "suggest": { - "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance", - "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance" + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/CONTRIBUTING.md b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/CONTRIBUTING.md index fc360e5d8..5e80b426f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/CONTRIBUTING.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. Please do not submit any Pull Requests here. It will be automatically closed. diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/FUNDING.yml b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/FUNDING.yml index 7e2ca0e7e..726574c1f 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/FUNDING.yml +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/FUNDING.yml @@ -1 +1,2 @@ +github: Spomky patreon: FlorentMorselli diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/stale.yml b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/stale.yml new file mode 100644 index 000000000..3c84124dd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/.github/stale.yml @@ -0,0 +1,8 @@ +daysUntilStale: 60 +daysUntilClose: 7 +staleLabel: wontfix +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +closeComment: false diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Algorithm/MacAlgorithm.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Algorithm/MacAlgorithm.php deleted file mode 100644 index 2304b3679..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Algorithm/MacAlgorithm.php +++ /dev/null @@ -1,37 +0,0 @@ -payload = $payload; - $this->encodedPayload = $encodedPayload; - $this->isPayloadDetached = $isPayloadDetached; - } - - public function getPayload(): ?string - { - return $this->payload; - } - - /** - * Returns true if the payload is detached. - */ - public function isPayloadDetached(): bool - { - return $this->isPayloadDetached; - } - - /** - * Returns the Base64Url encoded payload. - * If the payload is detached, this method returns null. - */ - public function getEncodedPayload(): ?string - { - if (true === $this->isPayloadDetached()) { - return null; - } - - return $this->encodedPayload; - } - - /** - * Returns the signatures associated with the JWS. - * - * @return Signature[] - */ - public function getSignatures(): array - { - return $this->signatures; - } - - /** - * Returns the signature at the given index. - * - * @throws InvalidArgumentException if the signature index does not exist - */ - public function getSignature(int $id): Signature - { - if (isset($this->signatures[$id])) { - return $this->signatures[$id]; - } - - throw new InvalidArgumentException('The signature does not exist.'); - } - - /** - * This method adds a signature to the JWS object. - * Its returns a new JWS object. - * - * @internal - * - * @return JWS - */ - public function addSignature(string $signature, array $protectedHeader, ?string $encodedProtectedHeader, array $header = []): self - { - $jws = clone $this; - $jws->signatures[] = new Signature($signature, $protectedHeader, $encodedProtectedHeader, $header); - - return $jws; - } - - /** - * Returns the number of signature associated with the JWS. - */ - public function countSignatures(): int - { - return count($this->signatures); - } - - /** - * This method splits the JWS into a list of JWSs. - * It is only useful when the JWS contains more than one signature (JSON General Serialization). - * - * @return JWS[] - */ - public function split(): array - { - $result = []; - foreach ($this->signatures as $signature) { - $jws = new self( - $this->payload, - $this->encodedPayload, - $this->isPayloadDetached - ); - $jws = $jws->addSignature( - $signature->getSignature(), - $signature->getProtectedHeader(), - $signature->getEncodedProtectedHeader(), - $signature->getHeader() - ); - - $result[] = $jws; - } - - return $result; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilder.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilder.php deleted file mode 100644 index afffd12f5..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilder.php +++ /dev/null @@ -1,235 +0,0 @@ -signatureAlgorithmManager = $signatureAlgorithmManager; - } - - /** - * Returns the algorithm manager associated to the builder. - */ - public function getSignatureAlgorithmManager(): AlgorithmManager - { - return $this->signatureAlgorithmManager; - } - - /** - * Reset the current data. - * - * @return JWSBuilder - */ - public function create(): self - { - $this->payload = null; - $this->isPayloadDetached = false; - $this->signatures = []; - $this->isPayloadEncoded = null; - - return $this; - } - - /** - * Set the payload. - * This method will return a new JWSBuilder object. - * - * @throws InvalidArgumentException if the payload is not UTF-8 encoded - * - * @return JWSBuilder - */ - public function withPayload(string $payload, bool $isPayloadDetached = false): self - { - if (false === mb_detect_encoding($payload, 'UTF-8', true)) { - throw new InvalidArgumentException('The payload must be encoded in UTF-8'); - } - $clone = clone $this; - $clone->payload = $payload; - $clone->isPayloadDetached = $isPayloadDetached; - - return $clone; - } - - /** - * Adds the information needed to compute the signature. - * This method will return a new JWSBuilder object. - * - * @throws InvalidArgumentException if the payload encoding is inconsistent - * - * @return JWSBuilder - */ - public function addSignature(JWK $signatureKey, array $protectedHeader, array $header = []): self - { - $this->checkB64AndCriticalHeader($protectedHeader); - $isPayloadEncoded = $this->checkIfPayloadIsEncoded($protectedHeader); - if (null === $this->isPayloadEncoded) { - $this->isPayloadEncoded = $isPayloadEncoded; - } elseif ($this->isPayloadEncoded !== $isPayloadEncoded) { - throw new InvalidArgumentException('Foreign payload encoding detected.'); - } - $this->checkDuplicatedHeaderParameters($protectedHeader, $header); - KeyChecker::checkKeyUsage($signatureKey, 'signature'); - $algorithm = $this->findSignatureAlgorithm($signatureKey, $protectedHeader, $header); - KeyChecker::checkKeyAlgorithm($signatureKey, $algorithm->name()); - $clone = clone $this; - $clone->signatures[] = [ - 'signature_algorithm' => $algorithm, - 'signature_key' => $signatureKey, - 'protected_header' => $protectedHeader, - 'header' => $header, - ]; - - return $clone; - } - - /** - * Computes all signatures and return the expected JWS object. - * - * @throws RuntimeException if the payload is not set - * @throws RuntimeException if no signature is defined - */ - public function build(): JWS - { - if (null === $this->payload) { - throw new RuntimeException('The payload is not set.'); - } - if (0 === count($this->signatures)) { - throw new RuntimeException('At least one signature must be set.'); - } - - $encodedPayload = false === $this->isPayloadEncoded ? $this->payload : Base64Url::encode($this->payload); - $jws = new JWS($this->payload, $encodedPayload, $this->isPayloadDetached); - foreach ($this->signatures as $signature) { - /** @var MacAlgorithm|SignatureAlgorithm $algorithm */ - $algorithm = $signature['signature_algorithm']; - /** @var JWK $signatureKey */ - $signatureKey = $signature['signature_key']; - /** @var array $protectedHeader */ - $protectedHeader = $signature['protected_header']; - /** @var array $header */ - $header = $signature['header']; - $encodedProtectedHeader = 0 === count($protectedHeader) ? null : Base64Url::encode(JsonConverter::encode($protectedHeader)); - $input = sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload); - if ($algorithm instanceof SignatureAlgorithm) { - $s = $algorithm->sign($signatureKey, $input); - } else { - $s = $algorithm->hash($signatureKey, $input); - } - $jws = $jws->addSignature($s, $protectedHeader, $encodedProtectedHeader, $header); - } - - return $jws; - } - - private function checkIfPayloadIsEncoded(array $protectedHeader): bool - { - return !array_key_exists('b64', $protectedHeader) || true === $protectedHeader['b64']; - } - - /** - * @throws LogicException if the header parameter "crit" is missing, invalid or does not contain "b64" when "b64" is set - */ - private function checkB64AndCriticalHeader(array $protectedHeader): void - { - if (!array_key_exists('b64', $protectedHeader)) { - return; - } - if (!array_key_exists('crit', $protectedHeader)) { - throw new LogicException('The protected header parameter "crit" is mandatory when protected header parameter "b64" is set.'); - } - if (!is_array($protectedHeader['crit'])) { - throw new LogicException('The protected header parameter "crit" must be an array.'); - } - if (!in_array('b64', $protectedHeader['crit'], true)) { - throw new LogicException('The protected header parameter "crit" must contain "b64" when protected header parameter "b64" is set.'); - } - } - - /** - * @throws InvalidArgumentException if the header parameter "alg" is missing or the algorithm is not allowed/not supported - * - * @return MacAlgorithm|SignatureAlgorithm - */ - private function findSignatureAlgorithm(JWK $key, array $protectedHeader, array $header): Algorithm - { - $completeHeader = array_merge($header, $protectedHeader); - if (!array_key_exists('alg', $completeHeader)) { - throw new InvalidArgumentException('No "alg" parameter set in the header.'); - } - if ($key->has('alg') && $key->get('alg') !== $completeHeader['alg']) { - throw new InvalidArgumentException(sprintf('The algorithm "%s" is not allowed with this key.', $completeHeader['alg'])); - } - - $algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); - if (!$algorithm instanceof SignatureAlgorithm && !$algorithm instanceof MacAlgorithm) { - throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported.', $completeHeader['alg'])); - } - - return $algorithm; - } - - /** - * @throws InvalidArgumentException if the header contains duplicated entries - */ - private function checkDuplicatedHeaderParameters(array $header1, array $header2): void - { - $inter = array_intersect_key($header1, $header2); - if (0 !== count($inter)) { - throw new InvalidArgumentException(sprintf('The header contains duplicated entries: %s.', implode(', ', array_keys($inter)))); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilderFactory.php deleted file mode 100644 index dbdf115aa..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSBuilderFactory.php +++ /dev/null @@ -1,41 +0,0 @@ -signatureAlgorithmManagerFactory = $signatureAlgorithmManagerFactory; - } - - /** - * This method creates a JWSBuilder using the given algorithm aliases. - * - * @param string[] $algorithms - */ - public function create(array $algorithms): JWSBuilder - { - $algorithmManager = $this->signatureAlgorithmManagerFactory->create($algorithms); - - return new JWSBuilder($algorithmManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoader.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoader.php deleted file mode 100644 index f19b449e6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoader.php +++ /dev/null @@ -1,124 +0,0 @@ -serializerManager = $serializerManager; - $this->jwsVerifier = $jwsVerifier; - $this->headerCheckerManager = $headerCheckerManager; - } - - /** - * Returns the JWSVerifier associated to the JWSLoader. - */ - public function getJwsVerifier(): JWSVerifier - { - return $this->jwsVerifier; - } - - /** - * Returns the Header Checker Manager associated to the JWSLoader. - */ - public function getHeaderCheckerManager(): ?HeaderCheckerManager - { - return $this->headerCheckerManager; - } - - /** - * Returns the JWSSerializer associated to the JWSLoader. - */ - public function getSerializerManager(): JWSSerializerManager - { - return $this->serializerManager; - } - - /** - * This method will try to load and verify the token using the given key. - * It returns a JWS and will populate the $signature variable in case of success, otherwise an exception is thrown. - * - * @throws Exception if the token cannot be loaded or verified - */ - public function loadAndVerifyWithKey(string $token, JWK $key, ?int &$signature, ?string $payload = null): JWS - { - $keyset = new JWKSet([$key]); - - return $this->loadAndVerifyWithKeySet($token, $keyset, $signature, $payload); - } - - /** - * This method will try to load and verify the token using the given key set. - * It returns a JWS and will populate the $signature variable in case of success, otherwise an exception is thrown. - * - * @throws Exception if the token cannot be loaded or verified - */ - public function loadAndVerifyWithKeySet(string $token, JWKSet $keyset, ?int &$signature, ?string $payload = null): JWS - { - try { - $jws = $this->serializerManager->unserialize($token); - $nbSignatures = $jws->countSignatures(); - for ($i = 0; $i < $nbSignatures; ++$i) { - if ($this->processSignature($jws, $keyset, $i, $payload)) { - $signature = $i; - - return $jws; - } - } - } catch (Throwable $e) { - // Nothing to do. Exception thrown just after - } - - throw new Exception('Unable to load and verify the token.'); - } - - private function processSignature(JWS $jws, JWKSet $keyset, int $signature, ?string $payload): bool - { - try { - if (null !== $this->headerCheckerManager) { - $this->headerCheckerManager->check($jws, $signature); - } - - return $this->jwsVerifier->verifyWithKeySet($jws, $keyset, $signature, $payload); - } catch (Throwable $e) { - return false; - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoaderFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoaderFactory.php deleted file mode 100644 index 8f29650cf..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSLoaderFactory.php +++ /dev/null @@ -1,59 +0,0 @@ -jwsSerializerManagerFactory = $jwsSerializerManagerFactory; - $this->jwsVerifierFactory = $jwsVerifierFactory; - $this->headerCheckerManagerFactory = $headerCheckerManagerFactory; - } - - /** - * Creates a JWSLoader using the given serializer aliases, signature algorithm aliases and (optionally) - * the header checker aliases. - */ - public function create(array $serializers, array $algorithms, array $headerCheckers = []): JWSLoader - { - $serializerManager = $this->jwsSerializerManagerFactory->create($serializers); - $jwsVerifier = $this->jwsVerifierFactory->create($algorithms); - if (null !== $this->headerCheckerManagerFactory) { - $headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers); - } else { - $headerCheckerManager = null; - } - - return new JWSLoader($serializerManager, $jwsVerifier, $headerCheckerManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSTokenSupport.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSTokenSupport.php deleted file mode 100644 index f2f586f39..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSTokenSupport.php +++ /dev/null @@ -1,42 +0,0 @@ - $jwt->countSignatures()) { - throw new InvalidArgumentException('Unknown signature index.'); - } - $protectedHeader = $jwt->getSignature($index)->getProtectedHeader(); - $unprotectedHeader = $jwt->getSignature($index)->getHeader(); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifier.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifier.php deleted file mode 100644 index 42d12a66d..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifier.php +++ /dev/null @@ -1,170 +0,0 @@ -signatureAlgorithmManager = $signatureAlgorithmManager; - } - - /** - * Returns the algorithm manager associated to the JWSVerifier. - */ - public function getSignatureAlgorithmManager(): AlgorithmManager - { - return $this->signatureAlgorithmManager; - } - - /** - * This method will try to verify the JWS object using the given key and for the given signature. - * It returns true if the signature is verified, otherwise false. - * - * @return bool true if the verification of the signature succeeded, else false - */ - public function verifyWithKey(JWS $jws, JWK $jwk, int $signature, ?string $detachedPayload = null): bool - { - $jwkset = new JWKSet([$jwk]); - - return $this->verifyWithKeySet($jws, $jwkset, $signature, $detachedPayload); - } - - /** - * This method will try to verify the JWS object using the given key set and for the given signature. - * It returns true if the signature is verified, otherwise false. - * - * @param JWS $jws A JWS object - * @param JWKSet $jwkset The signature will be verified using keys in the key set - * @param JWK $jwk The key used to verify the signature in case of success - * @param null|string $detachedPayload If not null, the value must be the detached payload encoded in Base64 URL safe. If the input contains a payload, throws an exception. - * - * @throws InvalidArgumentException if there is no key in the keyset - * @throws InvalidArgumentException if the token does not contain any signature - * - * @return bool true if the verification of the signature succeeded, else false - */ - public function verifyWithKeySet(JWS $jws, JWKSet $jwkset, int $signatureIndex, ?string $detachedPayload = null, JWK &$jwk = null): bool - { - if (0 === $jwkset->count()) { - throw new InvalidArgumentException('There is no key in the key set.'); - } - if (0 === $jws->countSignatures()) { - throw new InvalidArgumentException('The JWS does not contain any signature.'); - } - $this->checkPayload($jws, $detachedPayload); - $signature = $jws->getSignature($signatureIndex); - - return $this->verifySignature($jws, $jwkset, $signature, $detachedPayload, $jwk); - } - - private function verifySignature(JWS $jws, JWKSet $jwkset, Signature $signature, ?string $detachedPayload = null, JWK &$successJwk = null): bool - { - $input = $this->getInputToVerify($jws, $signature, $detachedPayload); - $algorithm = $this->getAlgorithm($signature); - foreach ($jwkset->all() as $jwk) { - try { - KeyChecker::checkKeyUsage($jwk, 'verification'); - KeyChecker::checkKeyAlgorithm($jwk, $algorithm->name()); - if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) { - $successJwk = $jwk; - - return true; - } - } catch (Throwable $e) { - //We do nothing, we continue with other keys - continue; - } - } - - return false; - } - - private function getInputToVerify(JWS $jws, Signature $signature, ?string $detachedPayload): string - { - $isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload()); - $encodedProtectedHeader = $signature->getEncodedProtectedHeader(); - if (!$signature->hasProtectedHeaderParameter('b64') || true === $signature->getProtectedHeaderParameter('b64')) { - if (null !== $jws->getEncodedPayload()) { - return sprintf('%s.%s', $encodedProtectedHeader, $jws->getEncodedPayload()); - } - - $payload = $isPayloadEmpty ? $detachedPayload : $jws->getPayload(); - - return sprintf('%s.%s', $encodedProtectedHeader, Base64Url::encode($payload)); - } - - $payload = $isPayloadEmpty ? $detachedPayload : $jws->getPayload(); - - return sprintf('%s.%s', $encodedProtectedHeader, $payload); - } - - /** - * @throws InvalidArgumentException if the payload is set when a detached payload is provided or no payload is defined - */ - private function checkPayload(JWS $jws, ?string $detachedPayload = null): void - { - $isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload()); - if (null !== $detachedPayload && !$isPayloadEmpty) { - throw new InvalidArgumentException('A detached payload is set, but the JWS already has a payload.'); - } - if ($isPayloadEmpty && null === $detachedPayload) { - throw new InvalidArgumentException('The JWS has a detached payload, but no payload is provided.'); - } - } - - /** - * @throws InvalidArgumentException if the header parameter "alg" is missing or invalid - * - * @return MacAlgorithm|SignatureAlgorithm - */ - private function getAlgorithm(Signature $signature): Algorithm - { - $completeHeader = array_merge($signature->getProtectedHeader(), $signature->getHeader()); - if (!isset($completeHeader['alg'])) { - throw new InvalidArgumentException('No "alg" parameter set in the header.'); - } - - $algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); - if (!$algorithm instanceof SignatureAlgorithm && !$algorithm instanceof MacAlgorithm) { - throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported or is not a signature or MAC algorithm.', $completeHeader['alg'])); - } - - return $algorithm; - } - - private function isPayloadEmpty(?string $payload): bool - { - return null === $payload || '' === $payload; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifierFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifierFactory.php deleted file mode 100644 index 67a65e842..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/JWSVerifierFactory.php +++ /dev/null @@ -1,41 +0,0 @@ -algorithmManagerFactory = $algorithmManagerFactory; - } - - /** - * Creates a JWSVerifier using the given signature algorithm aliases. - * - * @param string[] $algorithms - */ - public function create(array $algorithms): JWSVerifier - { - $algorithmManager = $this->algorithmManagerFactory->create($algorithms); - - return new JWSVerifier($algorithmManager); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/LICENSE b/lam/lib/3rdParty/composer/web-token/jwt-signature/LICENSE index 37cf976b1..5ab750604 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/LICENSE +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2019 Spomky-Labs +Copyright (c) 2014-2024 Spomky-Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/README.md b/lam/lib/3rdParty/composer/web-token/jwt-signature/README.md index 26f0befcb..f307bebc4 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/README.md +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/README.md @@ -1,10 +1,11 @@ PHP JWT Signature Component =========================== -This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is READ ONLY. +This repository is a sub repository of [the JWT Framework](https://github.com/web-token/jwt-framework) project and is +READ ONLY. **Please do not submit any Pull Request here.** -You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. +You should go to [the main repository](https://github.com/web-token/jwt-framework) instead. # Documentation diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/CompactSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/CompactSerializer.php deleted file mode 100644 index a4bdab26d..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/CompactSerializer.php +++ /dev/null @@ -1,96 +0,0 @@ -getSignature($signatureIndex); - if (0 !== count($signature->getHeader())) { - throw new LogicException('The signature contains unprotected header parameters and cannot be converted into compact JSON.'); - } - $isEmptyPayload = null === $jws->getEncodedPayload() || '' === $jws->getEncodedPayload(); - if (!$this->isPayloadEncoded($signature->getProtectedHeader()) && !$isEmptyPayload) { - if (1 !== preg_match('/^[\x{20}-\x{2d}|\x{2f}-\x{7e}]*$/u', $jws->getPayload())) { - throw new LogicException('Unable to convert the JWS with non-encoded payload.'); - } - } - - return sprintf( - '%s.%s.%s', - $signature->getEncodedProtectedHeader(), - $jws->getEncodedPayload(), - Base64Url::encode($signature->getSignature()) - ); - } - - /** - * @throws InvalidArgumentException if the input is invalid - */ - public function unserialize(string $input): JWS - { - $parts = explode('.', $input); - if (3 !== count($parts)) { - throw new InvalidArgumentException('Unsupported input'); - } - - try { - $encodedProtectedHeader = $parts[0]; - $protectedHeader = JsonConverter::decode(Base64Url::decode($parts[0])); - $hasPayload = '' !== $parts[1]; - if (!$hasPayload) { - $payload = null; - $encodedPayload = null; - } else { - $encodedPayload = $parts[1]; - $payload = $this->isPayloadEncoded($protectedHeader) ? Base64Url::decode($encodedPayload) : $encodedPayload; - } - $signature = Base64Url::decode($parts[2]); - - $jws = new JWS($payload, $encodedPayload, !$hasPayload); - - return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader); - } catch (Throwable $throwable) { - throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable); - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php deleted file mode 100644 index 0d4f54ec6..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php +++ /dev/null @@ -1,110 +0,0 @@ -getSignature($signatureIndex); - - $data = []; - $values = [ - 'payload' => $jws->getEncodedPayload(), - 'protected' => $signature->getEncodedProtectedHeader(), - 'header' => $signature->getHeader(), - ]; - $encodedPayload = $jws->getEncodedPayload(); - if (null !== $encodedPayload && '' !== $encodedPayload) { - $data['payload'] = $encodedPayload; - } - $encodedProtectedHeader = $signature->getEncodedProtectedHeader(); - if (null !== $encodedProtectedHeader && '' !== $encodedProtectedHeader) { - $data['protected'] = $encodedProtectedHeader; - } - $header = $signature->getHeader(); - if (0 !== count($header)) { - $data['header'] = $header; - } - $data['signature'] = Base64Url::encode($signature->getSignature()); - - return JsonConverter::encode($data); - } - - /** - * @throws InvalidArgumentException if the input is not supported - * @throws InvalidArgumentException if the JWS header is invalid - */ - public function unserialize(string $input): JWS - { - $data = JsonConverter::decode($input); - if (!is_array($data)) { - throw new InvalidArgumentException('Unsupported input.'); - } - if (!isset($data['signature'])) { - throw new InvalidArgumentException('Unsupported input.'); - } - $signature = Base64Url::decode($data['signature']); - - if (isset($data['protected'])) { - $encodedProtectedHeader = $data['protected']; - $protectedHeader = JsonConverter::decode(Base64Url::decode($data['protected'])); - } else { - $encodedProtectedHeader = null; - $protectedHeader = []; - } - if (isset($data['header'])) { - if (!is_array($data['header'])) { - throw new InvalidArgumentException('Bad header.'); - } - $header = $data['header']; - } else { - $header = []; - } - - if (isset($data['payload'])) { - $encodedPayload = $data['payload']; - $payload = $this->isPayloadEncoded($protectedHeader) ? Base64Url::decode($encodedPayload) : $encodedPayload; - } else { - $payload = null; - $encodedPayload = null; - } - - $jws = new JWS($payload, $encodedPayload, null === $encodedPayload); - - return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader, $header); - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php deleted file mode 100644 index 1a88bab1f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php +++ /dev/null @@ -1,167 +0,0 @@ -countSignatures()) { - throw new LogicException('No signature.'); - } - - $data = []; - $this->checkPayloadEncoding($jws); - - if (false === $jws->isPayloadDetached()) { - $data['payload'] = $jws->getEncodedPayload(); - } - - $data['signatures'] = []; - foreach ($jws->getSignatures() as $signature) { - $tmp = ['signature' => Base64Url::encode($signature->getSignature())]; - $values = [ - 'protected' => $signature->getEncodedProtectedHeader(), - 'header' => $signature->getHeader(), - ]; - - foreach ($values as $key => $value) { - if ((is_string($value) && '' !== $value) || (is_array($value) && 0 !== count($value))) { - $tmp[$key] = $value; - } - } - $data['signatures'][] = $tmp; - } - - return JsonConverter::encode($data); - } - - /** - * @throws InvalidArgumentException if the input is not supported - */ - public function unserialize(string $input): JWS - { - $data = JsonConverter::decode($input); - if (!isset($data['signatures'])) { - throw new InvalidArgumentException('Unsupported input.'); - } - - $isPayloadEncoded = null; - $rawPayload = $data['payload'] ?? null; - $signatures = []; - foreach ($data['signatures'] as $signature) { - if (!isset($signature['signature'])) { - throw new InvalidArgumentException('Unsupported input.'); - } - [$encodedProtectedHeader, $protectedHeader, $header] = $this->processHeaders($signature); - $signatures[] = [ - 'signature' => Base64Url::decode($signature['signature']), - 'protected' => $protectedHeader, - 'encoded_protected' => $encodedProtectedHeader, - 'header' => $header, - ]; - $isPayloadEncoded = $this->processIsPayloadEncoded($isPayloadEncoded, $protectedHeader); - } - - $payload = $this->processPayload($rawPayload, $isPayloadEncoded); - $jws = new JWS($payload, $rawPayload); - foreach ($signatures as $signature) { - $jws = $jws->addSignature( - $signature['signature'], - $signature['protected'], - $signature['encoded_protected'], - $signature['header'] - ); - } - - return $jws; - } - - /** - * @throws InvalidArgumentException if the payload encoding is invalid - */ - private function processIsPayloadEncoded(?bool $isPayloadEncoded, array $protectedHeader): bool - { - if (null === $isPayloadEncoded) { - return $this->isPayloadEncoded($protectedHeader); - } - if ($this->isPayloadEncoded($protectedHeader) !== $isPayloadEncoded) { - throw new InvalidArgumentException('Foreign payload encoding detected.'); - } - - return $isPayloadEncoded; - } - - private function processHeaders(array $signature): array - { - $encodedProtectedHeader = $signature['protected'] ?? null; - $protectedHeader = null === $encodedProtectedHeader ? [] : JsonConverter::decode(Base64Url::decode($encodedProtectedHeader)); - $header = array_key_exists('header', $signature) ? $signature['header'] : []; - - return [$encodedProtectedHeader, $protectedHeader, $header]; - } - - private function processPayload(?string $rawPayload, ?bool $isPayloadEncoded): ?string - { - if (null === $rawPayload) { - return null; - } - - return false === $isPayloadEncoded ? $rawPayload : Base64Url::decode($rawPayload); - } - - // @throws LogicException if the payload encoding is invalid - private function checkPayloadEncoding(JWS $jws): void - { - if ($jws->isPayloadDetached()) { - return; - } - $is_encoded = null; - foreach ($jws->getSignatures() as $signature) { - if (null === $is_encoded) { - $is_encoded = $this->isPayloadEncoded($signature->getProtectedHeader()); - } - if (false === $jws->isPayloadDetached()) { - if ($is_encoded !== $this->isPayloadEncoded($signature->getProtectedHeader())) { - throw new LogicException('Foreign payload encoding detected.'); - } - } - } - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializer.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializer.php deleted file mode 100644 index c2edd373f..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializer.php +++ /dev/null @@ -1,38 +0,0 @@ -add($serializer); - } - } - - /** - * @return string[] - */ - public function list(): array - { - return array_keys($this->serializers); - } - - /** - * Converts a JWS into a string. - * - * @throws InvalidArgumentException if the serializer is not supported - */ - public function serialize(string $name, JWS $jws, ?int $signatureIndex = null): string - { - if (!isset($this->serializers[$name])) { - throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); - } - - return $this->serializers[$name]->serialize($jws, $signatureIndex); - } - - /** - * Loads data and return a JWS object. - * - * @param string $input A string that represents a JWS - * @param null|string $name the name of the serializer if the input is unserialized - * - * @throws InvalidArgumentException if the input is not supported - */ - public function unserialize(string $input, ?string &$name = null): JWS - { - foreach ($this->serializers as $serializer) { - try { - $jws = $serializer->unserialize($input); - $name = $serializer->name(); - - return $jws; - } catch (InvalidArgumentException $e) { - continue; - } - } - - throw new InvalidArgumentException('Unsupported input.'); - } - - private function add(JWSSerializer $serializer): void - { - $this->serializers[$serializer->name()] = $serializer; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php deleted file mode 100644 index 7e346eedf..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php +++ /dev/null @@ -1,63 +0,0 @@ -serializers[$name])) { - throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name)); - } - $serializers[] = $this->serializers[$name]; - } - - return new JWSSerializerManager($serializers); - } - - /** - * @return string[] - */ - public function names(): array - { - return array_keys($this->serializers); - } - - /** - * @return JWSSerializer[] - */ - public function all(): array - { - return $this->serializers; - } - - public function add(JWSSerializer $serializer): void - { - $this->serializers[$serializer->name()] = $serializer; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/Serializer.php b/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/Serializer.php deleted file mode 100644 index 48a11477a..000000000 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/Serializer/Serializer.php +++ /dev/null @@ -1,24 +0,0 @@ -protectedHeader = null === $encodedProtectedHeader ? [] : $protectedHeader; - $this->encodedProtectedHeader = $encodedProtectedHeader; - $this->signature = $signature; - $this->header = $header; - } - - /** - * The protected header associated with the signature. - */ - public function getProtectedHeader(): array - { - return $this->protectedHeader; - } - - /** - * The unprotected header associated with the signature. - */ - public function getHeader(): array - { - return $this->header; - } - - /** - * The protected header associated with the signature. - */ - public function getEncodedProtectedHeader(): ?string - { - return $this->encodedProtectedHeader; - } - - /** - * Returns the value of the protected header of the specified key. - * - * @param string $key The key - * - * @throws InvalidArgumentException if the header parameter does not exist - * - * @return null|mixed Header value - */ - public function getProtectedHeaderParameter(string $key) - { - if ($this->hasProtectedHeaderParameter($key)) { - return $this->getProtectedHeader()[$key]; - } - - throw new InvalidArgumentException(sprintf('The protected header "%s" does not exist', $key)); - } - - /** - * Returns true if the protected header has the given parameter. - * - * @param string $key The key - */ - public function hasProtectedHeaderParameter(string $key): bool - { - return array_key_exists($key, $this->getProtectedHeader()); - } - - /** - * Returns the value of the unprotected header of the specified key. - * - * @param string $key The key - * - * @return null|mixed Header value - */ - public function getHeaderParameter(string $key) - { - if ($this->hasHeaderParameter($key)) { - return $this->header[$key]; - } - - throw new InvalidArgumentException(sprintf('The header "%s" does not exist', $key)); - } - - /** - * Returns true if the unprotected header has the given parameter. - * - * @param string $key The key - */ - public function hasHeaderParameter(string $key): bool - { - return array_key_exists($key, $this->header); - } - - /** - * Returns the value of the signature. - */ - public function getSignature(): string - { - return $this->signature; - } -} diff --git a/lam/lib/3rdParty/composer/web-token/jwt-signature/composer.json b/lam/lib/3rdParty/composer/web-token/jwt-signature/composer.json index 92508bf77..7dad9daa1 100644 --- a/lam/lib/3rdParty/composer/web-token/jwt-signature/composer.json +++ b/lam/lib/3rdParty/composer/web-token/jwt-signature/composer.json @@ -1,33 +1,39 @@ { "name": "web-token/jwt-signature", - "description": "Signature component of the JWT Framework.", + "description": "[DEPRECATED] Please use web-token/jwt-library instead.", "type": "library", "license": "MIT", - "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "keywords": [ + "JWS", + "JWT", + "JWE", + "JWA", + "JWK", + "JWKSet", + "Jot", + "Jose", + "RFC7515", + "RFC7516", + "RFC7517", + "RFC7518", + "RFC7519", + "RFC7520", + "Bundle", + "Symfony" + ], "homepage": "https://github.com/web-token", "authors": [ { "name": "Florent Morselli", "homepage": "https://github.com/Spomky" - },{ + }, + { "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-signature/contributors" + "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\": "" - } - }, "require": { - "web-token/jwt-core": "^2.1" - }, - "suggest": { - "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", - "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", - "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms" + "php": ">=8.1", + "web-token/jwt-library": "^3.3" } } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/.github/workflows/tests.yaml b/lam/lib/3rdParty/composer/webklex/php-imap/.github/workflows/tests.yaml index b441efd3d..682cbd514 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/.github/workflows/tests.yaml +++ b/lam/lib/3rdParty/composer/webklex/php-imap/.github/workflows/tests.yaml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['8.0', 8.1, 8.2] + php: ['8.0', 8.1, 8.2, 8.3, 8.4] name: PHP ${{ matrix.php }} diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/CHANGELOG.md b/lam/lib/3rdParty/composer/webklex/php-imap/CHANGELOG.md index 6e7757108..979350230 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/CHANGELOG.md +++ b/lam/lib/3rdParty/composer/webklex/php-imap/CHANGELOG.md @@ -6,25 +6,96 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip ## [UNRELEASED] ### Fixed -- Error token length mismatch in `ImapProtocol::readResponse` #400 -- Attachment name parsing fixed #410 #421 (thanks @nuernbergerA) -- Additional Attachment name fallback added to prevent missing attachments -- Attachment id is now static (based on the raw part content) and now longer random -- Always parse the attachment description if it is available +- NaN ### Added -- Attachment content hash added +- NaN ### Breaking changes - NaN +## [6.2.0] - 2025-04-25 +### Fixed +- When using the chunk function, some messages do not have an element with index 0 #552 #553 (thanks @zeddmaster) +- Get folders list in hierarchical order #560 #561 (thanks @rskrzypczak) +- Fix remaining implicit marking of parameters as nullable (PHP 8.4) #566 (thanks @steffenweber) +- Fix case sensitivity of folder attribute parsing (\NoSelect, \NoInferiors) #469 #571 (thanks @smajti1) +- Fix error on getUid(null) with 0 results (#499) #573 (thanks @pierement) +- Fix Date parsing on non-standard format from Aqua Mail #574 #575 (thanks @lm-cmxkonzepte) + +### Added +- SSL stream context options added #238 #546 (thanks @llemoine) +- Support copy/move Message with utf7 folder path #559 (thanks @loc4l) +- Public `Query::search()` method #565 (Thanks @madbob) + +## [6.1.0] - 2025-01-19 +### Fixed +- Filename sanitization is now optional (enabled via default) +- Address parsing improved and extended to include more cases +- Boundary parsing fixed and improved to support more formats #544 +- Decode partially encoded address names #511 +- Enforce RFC822 parsing if enabled #462 + +### Added +- Security configuration options added +- Spoofing detection added #40 +- RFC4315 MOVE fallback added #123 (thanks @freescout-help-desk) +- Content fetching RFC standard support added #510 (thanks @ybizeul) +- Support unescaped dates inside the search conditions #542 +- `Client::clone()` looses account configuration #521 (thanks @netpok) + +## [6.0.0] - 2025-01-17 +### Fixed +- Fixed date issue if timezone is UT and a 2 digit year #429 (thanks @ferrisbuellers) +- Make the space optional after a comma separator #437 (thanks @marc0adam) +- Fix bug when multipart message getHTMLBody() method returns null #455 (thanks @michalkortas) +- Fix: Improve return type hints and return docblocks for query classes #470 (thanks @olliescase) +- Fix - Query - Chunked - Resolved infinite loop when start chunk > 1 #477 (thanks @NeekTheNook) +- Attachment with symbols in filename #436 (thanks @nuernbergerA) +- Ignore possible untagged lines after IDLE and DONE commands #445 (thanks @gazben) +- Fix Empty Child Folder Error #474 (thanks @bierpub) +- Filename sanitization improved #501 (thanks @neolip) +- `Client::getFolderPath()` return null if folder is not set #506 (thanks @arnolem) +- Fix implicit marking of parameters as nullable, deprecated in PHP 8.4 #518 (thanks @campbell-m) + +### Added +- IMAP STATUS command support added `Folder::status()` #424 (thanks @InterLinked1) +- Add attributes and special flags #428 (thanks @sazanof) +- Better connection check for IMAP #449 (thanks @thin-k-design) +- Config handling moved into a new class `Config::class` to allow class serialization (sponsored by elb-BIT GmbH) +- Support for Carbon 3 added #483 +- Custom decoder support added +- Decoding filename with non-standard encoding #535 (thanks @grnsv) + +### Breaking changes +- The decoder config has been moved from `options.decoder` to `decoding` and contains now the `decoder` class to used as well as their decoding fallbacks +- `Folder::getStatus()` no longer returns the results of `EXAMINE` but `STATUS` instead. If you want to use `EXAMINE` you can use the `Folder::examine()` method instead. +- `ClientManager::class` has now longer access to all configs. Config handling has been moved to its own class `Config::class`. If you want to access the config you can use the retriever method `::getConfig()` instead. Example: `$client->getConfig()` or `$message->getConfig()`, etc. +- `ClientManager::get` isn't available anymore. Use the regular config accessor instead. Example: `$cm->getConfig()->get($key)` +- `M̀essage::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$message->getOptions()` instead. +- `Attachment::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$attachment->getOptions()` instead. +- `Header::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$header->getOptions()` instead. +- `M̀essage::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$message->setOptions` instead. +- `Attachment::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$attachment->setOptions` instead. +- `Header::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$header->setOptions` instead. +- All protocol constructors now require a `Config::class` instance +- The `Client::class` constructor now require a `Config::class` instance +- The `Part::class` constructor now require a `Config::class` instance +- The `Header::class` constructor now require a `Config::class` instance +- The `Message::fromFile` method now requires a `Config::class` instance +- The `Message::fromString` method now requires a `Config::class` instance +- The `Message::boot` method now requires a `Config::class` instance +- The `Message::decode` method has been removed. Use `Message::getDecoder()->decode($str)` instead. +- The `Message::getEncoding` method has been removed. Use `Message::getDecoder()->getEncoding($str)` instead. +- The `Message::convertEncoding` method has been removed. Use `Message::getDecoder()->convertEncoding()` instead. +- The `Header::decode` method has been removed. Use `Header::getDecoder()->decode($str)` instead. ## [5.5.0] - 2023-06-28 ### Fixed - Error token length mismatch in `ImapProtocol::readResponse` #400 - Attachment name parsing fixed #410 #421 (thanks @nuernbergerA) - Additional Attachment name fallback added to prevent missing attachments -- Attachment id is now static (based on the raw part content) and now longer random +- Attachment id is now static (based on the raw part content) instead of random - Always parse the attachment description if it is available ### Added @@ -309,7 +380,7 @@ If you have any questions, please feel welcome to join this issue: https://githu - Extend date parsing error message #173 - Fixed 'Where' method replaces the content with uppercase #148 - Don't surround numeric search values with quotes -- Context added to `InvalidWhereQueryCriteriaException` +- Context added to `InvalidWhereQueryCriteriaException` - Redundant `stream_set_timeout()` removed ### Added @@ -480,7 +551,7 @@ If you have any questions, please feel welcome to join this issue: https://githu - Alias `Message::removeFlag()` for `Message::unsetFlag()` added - Alias `Message::flags()` for `Message::getFlags()` added - New Exception `MessageFlagException::class` added -- New method `Message::setSequenceId($id)` added +- New method `Message::setSequenceId($id)` added - Optional Header attributizion option added ### Affected Classes @@ -492,7 +563,7 @@ If you have any questions, please feel welcome to join this issue: https://githu - [Attribute::class](src/Attribute.php) ### Breaking changes -- Stringified message headers are now separated by ", " instead of " ". +- Stringified message headers are now separated by ", " instead of " ". - All message header values such as subject, message_id, from, to, etc now consists of an `Àttribute::class` instance (should behave the same way as before, but might cause some problem in certain edge cases) - The formal address object "from", "to", etc now consists of an `Address::class` instance (should behave the same way as before, but might cause some problem in certain edge cases) - When fetching or manipulating message flags a `MessageFlagException::class` exception can be thrown if a runtime error occurs @@ -502,12 +573,12 @@ If you have any questions, please feel welcome to join this issue: https://githu ## [2.3.1] - 2020-12-30 ### Fixed -- Missing RFC attributes added +- Missing RFC attributes added - Set the message sequence when idling - Missing UID commands added #64 ### Added -- Get a message by its message number +- Get a message by its message number - Get a message by its uid #72 #66 #63 ### Affected Classes @@ -528,7 +599,7 @@ If you have any questions, please feel welcome to join this issue: https://githu - `Message::getTextBody()` fallback value fixed ### Added -- Proxy support added +- Proxy support added - Flexible disposition support added #58 - New `options.message_key` option `uid` added - Protocol UID support added @@ -862,7 +933,7 @@ If you have any questions, please feel welcome to join this issue: https://githu - Imap client timeout can be modified and read #186 - Decoder config options added #175 - Message search criteria "NOT" added #181 -- Invalid message date exception added +- Invalid message date exception added - Blade examples ### Breaking changes diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/README.md b/lam/lib/3rdParty/composer/webklex/php-imap/README.md index c110d48f3..da47d0489 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/README.md +++ b/lam/lib/3rdParty/composer/webklex/php-imap/README.md @@ -32,6 +32,7 @@ Discord: [discord.gg/rd4cN9h6][link-discord] - [Known issues](#known-issues) - [Support](#support) - [Features & pull requests](#features--pull-requests) +- [Alternatives & Different Flavors](#alternatives--different-flavors) - [Security](#security) - [Credits](#credits) - [License](#license) @@ -45,6 +46,7 @@ Discord: [discord.gg/rd4cN9h6][link-discord] ## Compatibility | Version | PHP 5.6 | PHP 7 | PHP 8 | |:--------|:-------:|:-----:|:-----:| +| v6.x | / | / | X | | v5.x | / | / | X | | v4.x | / | X | X | | v3.x | / | X | / | @@ -98,6 +100,7 @@ foreach($folders as $folder){ ``` ## Sponsors +[![elb-BIT][ico-sponsor-elb-bit]][link-sponsor-elb-bit] [![Feline][ico-sponsor-feline]][link-sponsor-feline] @@ -192,6 +195,14 @@ first, if you're planning to do bigger changes. Of course, you can also create a if you're just wishing a feature ;) +## Alternatives & Different Flavors +This library and especially the code flavor It's written in, is certainly not for everyone. If you are looking for a +different approach, you might want to check out the following libraries: +- [ddeboer/imap](https://github.com/ddeboer/imap) +- [barbushin/php-imap](https://github.com/barbushin/php-imap) +- [stevebauman/php-imap](https://github.com/stevebauman/php-imap) + + ## Change log Please see [CHANGELOG][link-changelog] for more information what has changed recently. @@ -225,8 +236,10 @@ The MIT License (MIT). Please see [License File][link-license] for more informat [link-changelog]: https://github.com/Webklex/php-imap/blob/master/CHANGELOG.md [link-hits]: https://hits.webklex.com [link-snyk]: https://snyk.io/vuln/composer:webklex%2Fphp-imap -[link-discord]: https://discord.gg/rd4cN9h6 +[link-discord]: https://discord.gg/vUHrbfbDr9 [ico-sponsor-feline]: https://cdn.feline.dk/public/feline.png -[link-sponsor-feline]: https://www.feline.dk \ No newline at end of file +[link-sponsor-feline]: https://www.feline.dk +[ico-sponsor-elb-bit]: https://www.elb-bit.de/user/themes/deliver/images/logo_small.png +[link-sponsor-elb-bit]: https://www.elb-bit.de?ref=webklex/php-imap \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/composer.json b/lam/lib/3rdParty/composer/webklex/php-imap/composer.json index 37efc1c5e..334275fa2 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/composer.json +++ b/lam/lib/3rdParty/composer/webklex/php-imap/composer.json @@ -27,7 +27,7 @@ "ext-libxml": "*", "ext-zip": "*", "ext-fileinfo": "*", - "nesbot/carbon": "^2.62.1", + "nesbot/carbon": "^2.62.1|^3.2.4", "symfony/http-foundation": ">=2.8.0", "illuminate/pagination": ">=5.0.0" }, @@ -53,7 +53,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "6.0-dev" } }, "minimum-stability": "dev", diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_attachment_mask.php b/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_attachment_mask.php index 5a6323a35..eb4973e39 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_attachment_mask.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_attachment_mask.php @@ -33,8 +33,9 @@ class CustomAttachmentMask extends \Webklex\PHPIMAP\Support\Masks\AttachmentMask } -/** @var \Webklex\PHPIMAP\Client $client */ $cm = new \Webklex\PHPIMAP\ClientManager('path/to/config/imap.php'); + +/** @var \Webklex\PHPIMAP\Client $client */ $client = $cm->account('default'); $client->connect(); $client->setDefaultAttachmentMask(CustomAttachmentMask::class); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_message_mask.php b/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_message_mask.php index 187eeed4c..0463c65b2 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_message_mask.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/examples/custom_message_mask.php @@ -30,8 +30,9 @@ class CustomMessageMask extends \Webklex\PHPIMAP\Support\Masks\MessageMask { } -/** @var \Webklex\PHPIMAP\Client $client */ $cm = new \Webklex\PHPIMAP\ClientManager('path/to/config/imap.php'); + +/** @var \Webklex\PHPIMAP\Client $client */ $client = $cm->account('default'); $client->connect(); @@ -44,7 +45,7 @@ $message = $folder->query()->limit(1)->get()->first(); /** @var CustomMessageMask $masked_message */ $masked_message = $message->mask(CustomMessageMask::class); -echo 'Token for uid ['.$masked_message->uid.']: '.$masked_message->token().' @atms:'.$masked_message->getAttachmentCount(); +echo 'Token for uid [' . $masked_message->uid . ']: ' . $masked_message->token() . ' @atms:' . $masked_message->getAttachmentCount(); $masked_message->setFlag('seen'); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Address.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Address.php index b45c72dec..87c6479e9 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Address.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Address.php @@ -43,6 +43,24 @@ class Address { if (property_exists($object, "host")){ $this->host = $object->host ?? ''; } if (property_exists($object, "mail")){ $this->mail = $object->mail ?? ''; } if (property_exists($object, "full")){ $this->full = $object->full ?? ''; } + $this->boot(); + } + + /** + * Boot the address + */ + private function boot(): void { + if($this->mail === "" && $this->mailbox !== "" && $this->host !== ""){ + $this->mail = $this->mailbox . "@" . $this->host; + }elseif($this->mail === "" && $this->mailbox !== ""){ + $this->mail = $this->mailbox; + } + + if($this->full === "" && $this->mail !== "" && $this->personal !== ""){ + $this->full = $this->personal . " <" . $this->mail . ">"; + }elseif($this->full === "" && $this->mail !== ""){ + $this->full = $this->mail; + } } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Attachment.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Attachment.php index 15b83f636..e2ce81285 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Attachment.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Attachment.php @@ -13,6 +13,8 @@ namespace Webklex\PHPIMAP; use Illuminate\Support\Str; +use Webklex\PHPIMAP\Decoder\DecoderInterface; +use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException; use Webklex\PHPIMAP\Exceptions\MaskNotFoundException; use Webklex\PHPIMAP\Exceptions\MethodNotFoundException; use Webklex\PHPIMAP\Support\Masks\AttachmentMask; @@ -22,18 +24,18 @@ use Webklex\PHPIMAP\Support\Masks\AttachmentMask; * * @package Webklex\PHPIMAP * - * @property integer part_number - * @property integer size - * @property string content - * @property string type - * @property string content_type - * @property string id - * @property string hash - * @property string name - * @property string description - * @property string filename - * @property ?string disposition - * @property string img_src + * @property integer $part_number + * @property integer $size + * @property string $content + * @property string $type + * @property string $content_type + * @property string $id + * @property string $hash + * @property string $name + * @property string $description + * @property string $filename + * @property ?string $disposition + * @property string $img_src * * @method integer getPartNumber() * @method integer setPartNumber(integer $part_number) @@ -57,20 +59,34 @@ use Webklex\PHPIMAP\Support\Masks\AttachmentMask; class Attachment { /** - * @var Message $oMessage + * @var Message $message */ - protected Message $oMessage; + protected Message $message; /** * Used config * - * @var array $config + * @var Config $config */ - protected array $config = []; + protected Config $config; + + /** + * Attachment options + * + * @var array $options + */ + protected array $options = []; /** @var Part $part */ protected Part $part; + /** + * Decoder instance + * + * @var DecoderInterface $decoder + */ + protected DecoderInterface $decoder; + /** * Attribute holder * @@ -100,23 +116,26 @@ class Attachment { /** * Attachment constructor. - * @param Message $oMessage + * @param Message $message * @param Part $part + * @throws DecoderNotFoundException */ - public function __construct(Message $oMessage, Part $part) { - $this->config = ClientManager::get('options'); + public function __construct(Message $message, Part $part) { + $this->message = $message; + $this->config = $this->message->getConfig(); + $this->options = $this->config->get('options'); + $this->decoder = $this->config->getDecoder("attachment"); - $this->oMessage = $oMessage; $this->part = $part; $this->part_number = $part->part_number; - if ($this->oMessage->getClient()) { - $default_mask = $this->oMessage->getClient()?->getDefaultAttachmentMask(); + if ($this->message->getClient()) { + $default_mask = $this->message->getClient()?->getDefaultAttachmentMask(); if ($default_mask != null) { $this->mask = $default_mask; } } else { - $default_mask = ClientManager::getMask("attachment"); + $default_mask = $this->config->getMask("attachment"); if ($default_mask != "") { $this->mask = $default_mask; } @@ -205,7 +224,7 @@ class Attachment { $content = $this->part->content; $this->content_type = $this->part->content_type; - $this->content = $this->oMessage->decodeString($content, $this->part->encoding); + $this->content = $this->decoder->decode($content, $this->part->encoding); // Create a hash of the raw part - this can be used to identify the attachment in the message context. However, // it is not guaranteed to be unique and collisions are possible. @@ -237,7 +256,7 @@ class Attachment { } if (($description = $this->part->description) !== null) { - $this->description = $this->part->getHeader()->decode($description); + $this->description = $this->part->getHeader()->getDecoder()->decode($description); } if (($name = $this->part->name) !== null) { @@ -288,13 +307,14 @@ class Attachment { if (str_contains($name, "''")) { $parts = explode("''", $name); if (EncodingAliases::has($parts[0])) { + $encoding = $parts[0]; $name = implode("''", array_slice($parts, 1)); } } - $decoder = $this->config['decoder']['message']; + $decoder = $this->decoder->getOptions()['message']; if (preg_match('/=\?([^?]+)\?(Q|B)\?(.+)\?=/i', $name, $matches)) { - $name = $this->part->getHeader()->decode($name); + $name = $this->part->getHeader()->getDecoder()->decode($name); } elseif ($decoder === 'utf-8' && extension_loaded('imap')) { $name = \imap_utf8($name); } @@ -304,9 +324,15 @@ class Attachment { $name = urldecode($name); } - // sanitize $name - // order of '..' is important - return str_replace(['\\', '/', chr(0), ':', '..'], '', $name); + if (isset($encoding)) { + $name = EncodingAliases::convert($name, $encoding); + } + + if($this->config->get('security.sanitize_filenames', true)) { + $name = $this->sanitizeName($name); + } + + return $name; } return ""; } @@ -364,7 +390,7 @@ class Attachment { * @return Message */ public function getMessage(): Message { - return $this->oMessage; + return $this->message; } /** @@ -390,6 +416,45 @@ class Attachment { return $this->mask; } + /** + * Get the attachment options + * @return array + */ + public function getOptions(): array { + return $this->options; + } + + /** + * Set the attachment options + * @param array $options + * + * @return $this + */ + public function setOptions(array $options): Attachment { + $this->options = $options; + return $this; + } + + /** + * Get the used config + * + * @return Config + */ + public function getConfig(): Config { + return $this->config; + } + + /** + * Set the used config + * @param Config $config + * + * @return $this + */ + public function setConfig(Config $config): Attachment { + $this->config = $config; + return $this; + } + /** * Get a masked instance by providing a mask name * @param string|null $mask @@ -397,7 +462,7 @@ class Attachment { * @return mixed * @throws MaskNotFoundException */ - public function mask(string $mask = null): mixed { + public function mask(?string $mask = null): mixed { $mask = $mask !== null ? $mask : $this->mask; if (class_exists($mask)) { return new $mask($this); @@ -405,4 +470,46 @@ class Attachment { throw new MaskNotFoundException("Unknown mask provided: " . $mask); } + + /** + * Get the decoder instance + * + * @return DecoderInterface + */ + public function getDecoder(): DecoderInterface { + return $this->decoder; + } + + /** + * Set the decoder instance + * @param DecoderInterface $decoder + * + * @return $this + */ + public function setDecoder(DecoderInterface $decoder): static { + $this->decoder = $decoder; + return $this; + } + + /** + * Sanitize a given name to prevent common attacks + * !!IMPORTANT!! Do not rely on this method alone - this is just the bare minimum. Additional measures should be taken + * to ensure that the file is safe to use. + * @param string $name + * + * @return string + */ + private function sanitizeName(string $name): string { + $replaces = [ + '/\\\\/' => '', + '/[\/\0:]+/' => '', + '/\.+/' => '.', + ]; + $name_starts_with_dots = str_starts_with($name, '..'); + $name = preg_replace(array_keys($replaces), array_values($replaces), $name); + if($name_starts_with_dots) { + return substr($name, 1); + } + return $name; + } } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Client.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Client.php index 8027dc53f..5eb26ff2f 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Client.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Client.php @@ -46,6 +46,13 @@ class Client { */ public ?ProtocolInterface $connection = null; + /** + * Client configuration + * + * @var Config + */ + protected Config $config; + /** * Server hostname. * @@ -93,6 +100,16 @@ class Client { 'password' => null, ]; + + /** + * SSL stream context options + * + * @see https://www.php.net/manual/en/context.ssl.php for possible options + * + * @var array + */ + protected array $ssl_options = []; + /** * Connection timeout * @var int $timeout @@ -120,6 +137,13 @@ class Client { */ public array $extensions; + /** + * Account rfc. + * + * @var string + */ + public string $rfc; + /** * Account authentication method. * @@ -161,6 +185,7 @@ class Client { 'validate_cert' => true, 'username' => '', 'password' => '', + 'rfc' => 'RFC822', 'authentication' => null, "extensions" => [], 'proxy' => [ @@ -169,19 +194,20 @@ class Client { 'username' => null, 'password' => null, ], - "timeout" => 30 + 'ssl_options' => [], + "timeout" => 30, ]; /** * Client constructor. - * @param array $config + * @param Config $config * * @throws MaskNotFoundException */ - public function __construct(array $config = []) { + public function __construct(Config $config) { $this->setConfig($config); - $this->setMaskFromConfig($config); - $this->setEventsFromConfig($config); + $this->setMaskFromConfig(); + $this->setEventsFromConfig(); } /** @@ -199,16 +225,17 @@ class Client { * Clone the current Client instance * * @return Client + * @throws MaskNotFoundException */ public function clone(): Client { - $client = new self(); + $client = new self($this->config); $client->events = $this->events; $client->timeout = $this->timeout; $client->active_folder = $this->active_folder; $client->default_account_config = $this->default_account_config; $config = $this->getAccountConfig(); foreach($config as $key => $value) { - $client->setAccountConfig($key, $config, $this->default_account_config); + $client->setAccountConfig($key, $config); } $client->default_message_mask = $this->default_message_mask; $client->default_attachment_mask = $this->default_message_mask; @@ -217,16 +244,17 @@ class Client { /** * Set the Client configuration - * @param array $config + * @param Config $config * * @return self */ - public function setConfig(array $config): Client { - $default_account = ClientManager::get('default'); - $default_config = ClientManager::get("accounts.$default_account"); + public function setConfig(Config $config): Client { + $this->config = $config; + $default_account = $this->config->get('default'); + $default_config = $this->config->get("accounts.$default_account"); foreach ($this->default_account_config as $key => $value) { - $this->setAccountConfig($key, $config, $default_config); + $this->setAccountConfig($key, $default_config); } return $this; @@ -235,27 +263,20 @@ class Client { /** * Get the current config * - * @return array + * @return Config */ - public function getConfig(): array { - $config = []; - foreach($this->default_account_config as $key => $value) { - $config[$key] = $this->$key; - } - return $config; + public function getConfig(): Config { + return $this->config; } /** * Set a specific account config * @param string $key - * @param array $config * @param array $default_config */ - private function setAccountConfig(string $key, array $config, array $default_config): void { + private function setAccountConfig(string $key, array $default_config): void { $value = $this->default_account_config[$key]; - if(isset($config[$key])) { - $value = $config[$key]; - }elseif(isset($default_config[$key])) { + if(isset($default_config[$key])) { $value = $default_config[$key]; } $this->$key = $value; @@ -278,10 +299,9 @@ class Client { /** * Look for a possible events in any available config - * @param $config */ - protected function setEventsFromConfig($config): void { - $this->events = ClientManager::get("events"); + protected function setEventsFromConfig(): void { + $this->events = $this->config->get("events"); if(isset($config['events'])){ foreach($config['events'] as $section => $events) { $this->events[$section] = array_merge($this->events[$section], $events); @@ -291,35 +311,35 @@ class Client { /** * Look for a possible mask in any available config - * @param $config * * @throws MaskNotFoundException */ - protected function setMaskFromConfig($config): void { + protected function setMaskFromConfig(): void { + $masks = $this->config->get("masks"); - if(isset($config['masks'])){ - if(isset($config['masks']['message'])) { - if(class_exists($config['masks']['message'])) { - $this->default_message_mask = $config['masks']['message']; + if(isset($masks)){ + if(isset($masks['message'])) { + if(class_exists($masks['message'])) { + $this->default_message_mask = $masks['message']; }else{ - throw new MaskNotFoundException("Unknown mask provided: ".$config['masks']['message']); + throw new MaskNotFoundException("Unknown mask provided: ".$masks['message']); } }else{ - $default_mask = ClientManager::getMask("message"); + $default_mask = $this->config->getMask("message"); if($default_mask != ""){ $this->default_message_mask = $default_mask; }else{ throw new MaskNotFoundException("Unknown message mask provided"); } } - if(isset($config['masks']['attachment'])) { - if(class_exists($config['masks']['attachment'])) { - $this->default_attachment_mask = $config['masks']['attachment']; + if(isset($masks['attachment'])) { + if(class_exists($masks['attachment'])) { + $this->default_attachment_mask = $masks['attachment']; }else{ - throw new MaskNotFoundException("Unknown mask provided: ". $config['masks']['attachment']); + throw new MaskNotFoundException("Unknown mask provided: ". $masks['attachment']); } }else{ - $default_mask = ClientManager::getMask("attachment"); + $default_mask = $this->config->getMask("attachment"); if($default_mask != ""){ $this->default_attachment_mask = $default_mask; }else{ @@ -327,14 +347,14 @@ class Client { } } }else{ - $default_mask = ClientManager::getMask("message"); + $default_mask = $this->config->getMask("message"); if($default_mask != ""){ $this->default_message_mask = $default_mask; }else{ throw new MaskNotFoundException("Unknown message mask provided"); } - $default_mask = ClientManager::getMask("attachment"); + $default_mask = $this->config->getMask("attachment"); if($default_mask != ""){ $this->default_attachment_mask = $default_mask; }else{ @@ -424,25 +444,26 @@ class Client { $protocol = strtolower($this->protocol); if (in_array($protocol, ['imap', 'imap4', 'imap4rev1'])) { - $this->connection = new ImapProtocol($this->validate_cert, $this->encryption); + $this->connection = new ImapProtocol($this->config, $this->validate_cert, $this->encryption); $this->connection->setConnectionTimeout($this->timeout); $this->connection->setProxy($this->proxy); + $this->connection->setSslOptions($this->ssl_options); }else{ if (extension_loaded('imap') === false) { throw new ConnectionFailedException("connection setup failed", 0, new ProtocolNotSupportedException($protocol." is an unsupported protocol")); } - $this->connection = new LegacyProtocol($this->validate_cert, $this->encryption); + $this->connection = new LegacyProtocol($this->config, $this->validate_cert, $this->encryption); if (str_starts_with($protocol, "legacy-")) { $protocol = substr($protocol, 7); } $this->connection->setProtocol($protocol); } - if (ClientManager::get('options.debug')) { + if ($this->config->get('options.debug')) { $this->connection->enableDebug(); } - if (!ClientManager::get('options.uid_cache')) { + if (!$this->config->get('options.uid_cache')) { $this->connection->disableUidCache(); } @@ -507,7 +528,7 @@ class Client { */ public function getFolder(string $folder_name, ?string $delimiter = null, bool $utf7 = false): ?Folder { // Set delimiter to false to force selection via getFolderByName (maybe useful for uncommon folder names) - $delimiter = is_null($delimiter) ? ClientManager::get('options.delimiter', "/") : $delimiter; + $delimiter = is_null($delimiter) ? $this->config->get('options.delimiter', "/") : $delimiter; if (str_contains($folder_name, (string)$delimiter)) { return $this->getFolderByPath($folder_name, $utf7); @@ -571,7 +592,7 @@ class Client { * @throws ResponseException * @throws RuntimeException */ - public function getFolders(bool $hierarchical = true, string $parent_folder = null, bool $soft_fail = false): FolderCollection { + public function getFolders(bool $hierarchical = true, ?string $parent_folder = null, bool $soft_fail = false): FolderCollection { $this->checkConnection(); $folders = FolderCollection::make([]); @@ -583,9 +604,9 @@ class Client { $folder = new Folder($this, $folder_name, $item["delimiter"], $item["flags"]); if ($hierarchical && $folder->hasChildren()) { - $pattern = $folder->full_name.$folder->delimiter.'%'; + $pattern = $folder->path.$folder->delimiter.'%'; - $children = $this->getFolders(true, $pattern, $soft_fail); + $children = $this->getFolders(true, $pattern, true); $folder->setChildren($children); } @@ -617,7 +638,7 @@ class Client { * @throws RuntimeException * @throws ResponseException */ - public function getFoldersWithStatus(bool $hierarchical = true, string $parent_folder = null, bool $soft_fail = false): FolderCollection { + public function getFoldersWithStatus(bool $hierarchical = true, ?string $parent_folder = null, bool $soft_fail = false): FolderCollection { $this->checkConnection(); $folders = FolderCollection::make([]); @@ -629,9 +650,9 @@ class Client { $folder = new Folder($this, $folder_name, $item["delimiter"], $item["flags"]); if ($hierarchical && $folder->hasChildren()) { - $pattern = $folder->full_name.$folder->delimiter.'%'; + $pattern = $folder->path.$folder->delimiter.'%'; - $children = $this->getFoldersWithStatus(true, $pattern, $soft_fail); + $children = $this->getFoldersWithStatus(true, $pattern, true); $folder->setChildren($children); } @@ -714,8 +735,7 @@ class Client { $folder = $this->getFolderByPath($folder_path, true); if($status && $folder) { - $event = $this->getEvent("folder", "new"); - $event::dispatch($folder); + $this->dispatch("folder", "new", $folder); } return $folder; @@ -746,8 +766,7 @@ class Client { $status = $this->getConnection()->deleteFolder($folder->path)->validatedData(); if ($expunge) $this->expunge(); - $event = $this->getEvent("folder", "deleted"); - $event::dispatch($folder); + $this->dispatch("folder", "deleted", $folder); return $status; } @@ -772,9 +791,9 @@ class Client { /** * Get the current active folder * - * @return string + * @return null|string */ - public function getFolderPath(): string { + public function getFolderPath(): ?string { return $this->active_folder; } @@ -792,7 +811,7 @@ class Client { * @throws RuntimeException * @throws ResponseException */ - public function Id(array $ids = null): array { + public function Id(?array $ids = null): array { $this->checkConnection(); return $this->connection->ID($ids)->validatedData(); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/ClientManager.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/ClientManager.php index 7f724ffe0..6f66886bf 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/ClientManager.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/ClientManager.php @@ -16,17 +16,15 @@ namespace Webklex\PHPIMAP; * Class ClientManager * * @package Webklex\IMAP - * - * @mixin Client */ class ClientManager { /** * All library config * - * @var array $config + * @var Config $config */ - public static array $config = []; + public Config $config; /** * @var array $accounts @@ -35,9 +33,9 @@ class ClientManager { /** * ClientManager constructor. - * @param array|string $config + * @param array|string|Config $config */ - public function __construct(array|string $config = []) { + public function __construct(array|string|Config $config = []) { $this->setConfig($config); } @@ -63,52 +61,10 @@ class ClientManager { * @throws Exceptions\MaskNotFoundException */ public function make(array $config): Client { - return new Client($config); - } - - /** - * Get a dotted config parameter - * @param string $key - * @param null $default - * - * @return mixed|null - */ - public static function get(string $key, $default = null): mixed { - $parts = explode('.', $key); - $value = null; - foreach ($parts as $part) { - if ($value === null) { - if (isset(self::$config[$part])) { - $value = self::$config[$part]; - } else { - break; - } - } else { - if (isset($value[$part])) { - $value = $value[$part]; - } else { - break; - } - } - } - - return $value === null ? $default : $value; - } - - /** - * Get the mask for a given section - * @param string $section section name such as "message" or "attachment" - * - * @return string|null - */ - public static function getMask(string $section): ?string { - $default_masks = ClientManager::get("masks"); - if (isset($default_masks[$section])) { - if (class_exists($default_masks[$section])) { - return $default_masks[$section]; - } - } - return null; + $name = $this->config->getDefaultAccount(); + $clientConfig = $this->config->all(); + $clientConfig["accounts"] = [$name => $config]; + return new Client(Config::make($clientConfig)); } /** @@ -118,8 +74,8 @@ class ClientManager { * @return Client * @throws Exceptions\MaskNotFoundException */ - public function account(string $name = null): Client { - $name = $name ?: $this->getDefaultAccount(); + public function account(?string $name = null): Client { + $name = $name ?: $this->config->getDefaultAccount(); // If the connection has not been resolved we will resolve it now as all // the connections are resolved when they are actually needed, so we do @@ -139,45 +95,11 @@ class ClientManager { * @throws Exceptions\MaskNotFoundException */ protected function resolve(string $name): Client { - $config = $this->getClientConfig($name); + $config = $this->config->getClientConfig($name); return new Client($config); } - /** - * Get the account configuration. - * @param string|null $name - * - * @return array - */ - protected function getClientConfig(?string $name): array { - if ($name === null || $name === 'null' || $name === "") { - return ['driver' => 'null']; - } - $account = self::$config["accounts"][$name] ?? []; - - return is_array($account) ? $account : []; - } - - /** - * Get the name of the default account. - * - * @return string - */ - public function getDefaultAccount(): string { - return self::$config['default']; - } - - /** - * Set the name of the default account. - * @param string $name - * - * @return void - */ - public function setDefaultAccount(string $name): void { - self::$config['default'] = $name; - } - /** * Merge the vendor settings with the local config @@ -186,108 +108,24 @@ class ClientManager { * If however the default account is missing a parameter the package default account parameter will be used. * This can be disabled by setting imap.default in your config file to 'false' * - * @param array|string $config + * @param array|string|Config $config * * @return $this */ - public function setConfig(array|string $config): ClientManager { - - if (is_array($config) === false) { - $config = require $config; + public function setConfig(array|string|Config $config): ClientManager { + if (!$config instanceof Config) { + $config = Config::make($config); } - - $config_key = 'imap'; - $path = __DIR__ . '/config/' . $config_key . '.php'; - - $vendor_config = require $path; - $config = $this->array_merge_recursive_distinct($vendor_config, $config); - - if (is_array($config)) { - if (isset($config['default'])) { - if (isset($config['accounts']) && $config['default']) { - - $default_config = $vendor_config['accounts']['default']; - if (isset($config['accounts'][$config['default']])) { - $default_config = array_merge($default_config, $config['accounts'][$config['default']]); - } - - if (is_array($config['accounts'])) { - foreach ($config['accounts'] as $account_key => $account) { - $config['accounts'][$account_key] = array_merge($default_config, $account); - } - } - } - } - } - - self::$config = $config; + $this->config = $config; return $this; } /** - * Marge arrays recursively and distinct - * - * Merges any number of arrays / parameters recursively, replacing - * entries with string keys with values from latter arrays. - * If the entry or the next value to be assigned is an array, then it - * automatically treats both arguments as an array. - * Numeric entries are appended, not replaced, but only if they are - * unique - * - * @return array|mixed - * - * @link http://www.php.net/manual/en/function.array-merge-recursive.php#96201 - * @author Mark Roduner + * Get the config instance + * @return Config */ - private function array_merge_recursive_distinct(): mixed { - - $arrays = func_get_args(); - $base = array_shift($arrays); - - // From https://stackoverflow.com/a/173479 - $isAssoc = function(array $arr) { - if (array() === $arr) return false; - return array_keys($arr) !== range(0, count($arr) - 1); - }; - - if (!is_array($base)) $base = empty($base) ? array() : array($base); - - foreach ($arrays as $append) { - - if (!is_array($append)) $append = array($append); - - foreach ($append as $key => $value) { - - if (!array_key_exists($key, $base) and !is_numeric($key)) { - $base[$key] = $value; - continue; - } - - if ( - ( - is_array($value) - && $isAssoc($value) - ) - || ( - is_array($base[$key]) - && $isAssoc($base[$key]) - ) - ) { - // If the arrays are not associates we don't want to array_merge_recursive_distinct - // else merging $baseConfig['dispositions'] = ['attachment', 'inline'] with $customConfig['dispositions'] = ['attachment'] - // results in $resultConfig['dispositions'] = ['attachment', 'inline'] - $base[$key] = $this->array_merge_recursive_distinct($base[$key], $value); - } else if (is_numeric($key)) { - if (!in_array($value, $base)) $base[] = $value; - } else { - $base[$key] = $value; - } - - } - - } - - return $base; + public function getConfig(): Config { + return $this->config; } } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Config.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Config.php new file mode 100644 index 000000000..f2f1a1748 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Config.php @@ -0,0 +1,295 @@ +config = $config; + } + + /** + * Get a dotted config parameter + * @param string $key + * @param null $default + * + * @return mixed|null + */ + public function get(string $key, $default = null): mixed { + $parts = explode('.', $key); + $value = null; + foreach ($parts as $part) { + if ($value === null) { + if (isset($this->config[$part])) { + $value = $this->config[$part]; + } else { + break; + } + } else { + if (isset($value[$part])) { + $value = $value[$part]; + } else { + break; + } + } + } + + return $value === null ? $default : $value; + } + + /** + * Set a dotted config parameter + * @param string $key + * @param string|array|mixed$value + * + * @return void + */ + public function set(string $key, mixed $value): void { + $parts = explode('.', $key); + $config = &$this->config; + + foreach ($parts as $part) { + if (!isset($config[$part])) { + $config[$part] = []; + } + $config = &$config[$part]; + } + + if(is_array($config) && is_array($value)){ + $config = array_merge($config, $value); + }else{ + $config = $value; + } + } + + /** + * Get the decoder for a given name + * @param $name string Decoder name + * + * @return DecoderInterface + * @throws DecoderNotFoundException + */ + public function getDecoder(string $name): DecoderInterface { + $default_decoders = $this->get('decoding.decoder', [ + 'header' => \Webklex\PHPIMAP\Decoder\HeaderDecoder::class, + 'message' => \Webklex\PHPIMAP\Decoder\MessageDecoder::class, + 'attachment' => \Webklex\PHPIMAP\Decoder\AttachmentDecoder::class + ]); + $options = $this->get('decoding.options', [ + 'header' => 'utf-8', + 'message' => 'utf-8', + 'attachment' => 'utf-8', + ]); + if (isset($default_decoders[$name])) { + if (class_exists($default_decoders[$name])) { + return new $default_decoders[$name]($options); + } + } + throw new DecoderNotFoundException(); + } + + /** + * Get the mask for a given section + * @param string $section section name such as "message" or "attachment" + * + * @return string|null + */ + public function getMask(string $section): ?string { + $default_masks = $this->get('masks', []); + if (isset($default_masks[$section])) { + if (class_exists($default_masks[$section])) { + return $default_masks[$section]; + } + } + return null; + } + + /** + * Get the account configuration. + * @param string|null $name + * + * @return self + */ + public function getClientConfig(?string $name): self { + $config = $this->all(); + $defaultName = $this->getDefaultAccount(); + $defaultAccount = $this->get('accounts.'.$defaultName, []); + + if ($name === null || $name === 'null' || $name === "") { + $account = $defaultAccount; + $name = $defaultName; + }else{ + $account = $this->get('accounts.'.$name, $defaultAccount); + } + + $config["default"] = $name; + $config["accounts"] = [ + $name => $account + ]; + + return new self($config); + } + + /** + * Get the name of the default account. + * + * @return string + */ + public function getDefaultAccount(): string { + return $this->get('default', 'default'); + } + + /** + * Set the name of the default account. + * @param string $name + * + * @return void + */ + public function setDefaultAccount(string $name): void { + $this->set('default', $name); + } + + /** + * Create a new instance of the Config class + * @param array|string $config + * @return Config + */ + public static function make(array|string $config = []): Config { + if (is_array($config) === false) { + $config = require $config; + } + + $config_key = 'imap'; + $path = __DIR__ . '/config/' . $config_key . '.php'; + + $vendor_config = require $path; + $config = self::array_merge_recursive_distinct($vendor_config, $config); + + if (isset($config['default'])) { + if (isset($config['accounts']) && $config['default']) { + + $default_config = $vendor_config['accounts']['default']; + if (isset($config['accounts'][$config['default']])) { + $default_config = array_merge($default_config, $config['accounts'][$config['default']]); + } + + if (is_array($config['accounts'])) { + foreach ($config['accounts'] as $account_key => $account) { + $config['accounts'][$account_key] = array_merge($default_config, $account); + } + } + } + } + + return new self($config); + } + + /** + * Marge arrays recursively and distinct + * + * Merges any number of arrays / parameters recursively, replacing + * entries with string keys with values from latter arrays. + * If the entry or the next value to be assigned is an array, then it + * automatically treats both arguments as an array. + * Numeric entries are appended, not replaced, but only if they are + * unique + * + * @return array + * + * @link http://www.php.net/manual/en/function.array-merge-recursive.php#96201 + * @author Mark Roduner + */ + private static function array_merge_recursive_distinct(): array { + $arrays = func_get_args(); + $base = array_shift($arrays); + + // From https://stackoverflow.com/a/173479 + $isAssoc = function(array $arr) { + if (array() === $arr) return false; + return array_keys($arr) !== range(0, count($arr) - 1); + }; + + if (!is_array($base)) $base = empty($base) ? array() : array($base); + + foreach ($arrays as $append) { + if (!is_array($append)) $append = array($append); + + foreach ($append as $key => $value) { + + if (!array_key_exists($key, $base) and !is_numeric($key)) { + $base[$key] = $value; + continue; + } + + if ((is_array($value) && $isAssoc($value)) || (is_array($base[$key]) && $isAssoc($base[$key]))) { + // If the arrays are not associates we don't want to array_merge_recursive_distinct + // else merging $baseConfig['dispositions'] = ['attachment', 'inline'] with $customConfig['dispositions'] = ['attachment'] + // results in $resultConfig['dispositions'] = ['attachment', 'inline'] + $base[$key] = self::array_merge_recursive_distinct($base[$key], $value); + } else if (is_numeric($key)) { + if (!in_array($value, $base)) $base[] = $value; + } else { + $base[$key] = $value; + } + + } + + } + + return $base; + } + + /** + * Get all configuration values + * @return array + */ + public function all(): array { + return $this->config; + } + + /** + * Check if a configuration value exists + * @param string $key + * @return bool + */ + public function has(string $key): bool { + return $this->get($key) !== null; + } + + /** + * Remove all configuration values + * @return $this + */ + public function clear(): static { + $this->config = []; + return $this; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php index 4d54579f8..ed1dac6ec 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php @@ -13,6 +13,8 @@ namespace Webklex\PHPIMAP\Connection\Protocols; use Exception; +use Throwable; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\AuthFailedException; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; use Webklex\PHPIMAP\Exceptions\ImapBadRequestException; @@ -41,10 +43,12 @@ class ImapProtocol extends Protocol { /** * Imap constructor. + * @param Config $config * @param bool $cert_validation set to false to skip SSL certificate validation * @param mixed $encryption Connection encryption method */ - public function __construct(bool $cert_validation = true, mixed $encryption = false) { + public function __construct(Config $config, bool $cert_validation = true, mixed $encryption = false) { + $this->config = $config; $this->setCertValidation($cert_validation); $this->encryption = $encryption; } @@ -63,7 +67,7 @@ class ImapProtocol extends Protocol { * * @throws ConnectionFailedException */ - public function connect(string $host, int $port = null): bool { + public function connect(string $host, ?int $port = null): bool { $transport = 'tcp'; $encryption = ''; @@ -90,6 +94,24 @@ class ImapProtocol extends Protocol { return true; } + /** + * Check if the current session is connected + * + * @return bool + * @throws ImapBadRequestException + */ + public function connected(): bool { + if ((bool)$this->stream) { + try { + $this->requestAndResponse('NOOP'); + return true; + } catch (ImapServerErrorException|RuntimeException) { + return false; + } + } + return false; + } + /** * Enable tls on the current connection * @@ -98,7 +120,7 @@ class ImapProtocol extends Protocol { * @throws ImapServerErrorException * @throws RuntimeException */ - protected function enableStartTls() { + protected function enableStartTls(): void { $response = $this->requestAndResponse('STARTTLS'); $result = $response->successful() && stream_socket_enable_crypto($this->stream, true, $this->getCryptoMethod()); if (!$result) { @@ -114,7 +136,7 @@ class ImapProtocol extends Protocol { */ public function nextLine(Response $response): string { $line = ""; - while (($next_char = fread($this->stream, 1)) !== false && !in_array($next_char, ["","\n"])) { + while (($next_char = fread($this->stream, 1)) !== false && !in_array($next_char, ["", "\n"])) { $line .= $next_char; } if ($line === "" && ($next_char === false || $next_char === "")) { @@ -138,6 +160,25 @@ class ImapProtocol extends Protocol { return str_starts_with($this->nextLine($response), $start); } + /** + * Get the next line and check if it starts with a given string + * The server can send untagged status updates starting with '*' if we are not looking for a status update, + * the untagged lines will be ignored. + * + * @param Response $response + * @param string $start + * + * @return bool + * @throws RuntimeException + */ + protected function assumedNextLineIgnoreUntagged(Response $response, string $start): bool { + do { + $line = $this->nextLine($response); + } while (!(str_starts_with($start, '*')) && $this->isUntaggedLine($line)); + + return str_starts_with($line, $start); + } + /** * Get the next line and split the tag * @param string|null $tag reference tag @@ -154,6 +195,25 @@ class ImapProtocol extends Protocol { return $line ?? ''; } + /** + * Get the next line and split the tag + * The server can send untagged status updates starting with '*', the untagged lines will be ignored. + * + * @param string|null $tag reference tag + * + * @return string next line + * @throws RuntimeException + */ + protected function nextTaggedLineIgnoreUntagged(Response $response, &$tag): string { + do { + $line = $this->nextLine($response); + } while ($this->isUntaggedLine($line)); + + list($tag, $line) = explode(' ', $line, 2); + + return $line; + } + /** * Get the next line and check if it contains a given string and split the tag * @param Response $response @@ -167,6 +227,32 @@ class ImapProtocol extends Protocol { return str_contains($this->nextTaggedLine($response, $tag), $start); } + /** + * Get the next line and check if it contains a given string and split the tag + * @param string $start + * @param $tag + * + * @return bool + * @throws RuntimeException + */ + protected function assumedNextTaggedLineIgnoreUntagged(Response $response, string $start, &$tag): bool { + $line = $this->nextTaggedLineIgnoreUntagged($response, $tag); + return strpos($line, $start) !== false; + } + + /** + * RFC3501 - 2.2.2 + * Data transmitted by the server to the client and status responses + * that do not indicate command completion are prefixed with the token + * "*", and are called untagged responses. + * + * @param string $line + * @return bool + */ + protected function isUntaggedLine(string $line) : bool { + return str_starts_with($line, '* '); + } + /** * Split a given line in values. A value is literal of any form or a list * @param Response $response @@ -300,16 +386,35 @@ class ImapProtocol extends Protocol { $tokens = [trim(substr($tokens, 0, 3))]; } - $original = is_array($original)?$original : [$original]; + $original = is_array($original) ? $original : [$original]; + // last line has response code if ($tokens[0] == 'OK') { return $lines ?: [true]; } elseif ($tokens[0] == 'NO' || $tokens[0] == 'BAD' || $tokens[0] == 'BYE') { - throw new ImapServerErrorException(implode("\n", $original)); + throw new ImapServerErrorException($this->stringifyArray($original)); } - throw new ImapBadRequestException(implode("\n", $original)); + throw new ImapBadRequestException($this->stringifyArray($original)); + } + + /** + * Convert an array to a string + * @param array $arr array to stringify + * + * @return string stringified array + */ + private function stringifyArray(array $arr): string { + $string = ""; + foreach ($arr as $value) { + if (is_array($value)) { + $string .= "(" . $this->stringifyArray($value) . ")"; + } else { + $string .= $value . " "; + } + } + return $string; } /** @@ -321,7 +426,7 @@ class ImapProtocol extends Protocol { * @return Response * @throws RuntimeException */ - public function sendRequest(string $command, array $tokens = [], string &$tag = null): Response { + public function sendRequest(string $command, array $tokens = [], ?string &$tag = null): Response { if (!$tag) { $this->noun++; $tag = 'TAG' . $this->noun; @@ -492,7 +597,7 @@ class ImapProtocol extends Protocol { if (!$this->stream) { $this->reset(); return new Response(0, $this->debug); - }elseif ($this->meta()["timed_out"]) { + } elseif ($this->meta()["timed_out"]) { $this->reset(); return new Response(0, $this->debug); } @@ -501,7 +606,8 @@ class ImapProtocol extends Protocol { try { $result = $this->requestAndResponse('LOGOUT', [], true); fclose($this->stream); - } catch (\Throwable) {} + } catch (Throwable) { + } $this->reset(); @@ -549,7 +655,7 @@ class ImapProtocol extends Protocol { $result = []; $tokens = []; // define $tokens variable before first use - while (!$this->readLine($response, $tokens, $tag, false)) { + while (!$this->readLine($response, $tokens, $tag)) { if ($tokens[0] == 'FLAGS') { array_shift($tokens); $result['flags'] = $tokens; @@ -609,6 +715,42 @@ class ImapProtocol extends Protocol { return $this->examineOrSelect('EXAMINE', $folder); } + /** + * Get the status of a given folder + * + * @param string $folder + * @param string[] $arguments + * @return Response list of STATUS items + * + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws ResponseException + * @throws RuntimeException + */ + public function folderStatus(string $folder = 'INBOX', $arguments = ['MESSAGES', 'UNSEEN', 'RECENT', 'UIDNEXT', 'UIDVALIDITY']): Response { + $response = $this->requestAndResponse('STATUS', [$this->escapeString($folder), $this->escapeList($arguments)]); + $data = $response->validatedData(); + + if (!isset($data[0]) || !isset($data[0][2])) { + throw new RuntimeException("folder status could not be fetched"); + } + + $result = []; + $key = null; + foreach ($data[0][2] as $value) { + if ($key === null) { + $key = $value; + } else { + $result[strtolower($key)] = (int)$value; + $key = null; + } + } + + $response->setResult($result); + + return $response; + } + /** * Fetch one or more items of one or more messages * @param array|string $items items to fetch [RFC822.HEADER, FLAGS, RFC822.TEXT, etc] @@ -625,10 +767,13 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function fetch(array|string $items, array|int $from, mixed $to = null, int|string $uid = IMAP::ST_UID): Response { - if (is_array($from)) { + if (is_array($from) && count($from) > 1) { $set = implode(',', $from); + } elseif (is_array($from) && count($from) === 1) { + $from = array_values($from); + $set = $from[0] . ':' . $from[0]; } elseif ($to === null) { - $set = $from; + $set = $from . ':' . $from; } elseif ($to == INF) { $set = $from . ':*'; } else { @@ -723,7 +868,7 @@ class ImapProtocol extends Protocol { } /** - * Fetch message headers + * Fetch message body (without headers) * @param int|array $uids * @param string $rfc * @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use @@ -733,7 +878,9 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function content(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response { - return $this->fetch(["$rfc.TEXT"], is_array($uids)?$uids:[$uids], null, $uid); + $rfc = $rfc ?? "RFC822"; + $item = $rfc === "BODY" ? "BODY[TEXT]" : "$rfc.TEXT"; + return $this->fetch([$item], is_array($uids) ? $uids : [$uids], null, $uid); } /** @@ -747,7 +894,7 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function headers(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response { - return $this->fetch(["$rfc.HEADER"], is_array($uids)?$uids:[$uids], null, $uid); + return $this->fetch(["$rfc.HEADER"], is_array($uids) ? $uids : [$uids], null, $uid); } /** @@ -760,7 +907,7 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response { - return $this->fetch(["FLAGS"], is_array($uids)?$uids:[$uids], null, $uid); + return $this->fetch(["FLAGS"], is_array($uids) ? $uids : [$uids], null, $uid); } /** @@ -773,7 +920,7 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response { - return $this->fetch(["RFC822.SIZE"], is_array($uids)?$uids:[$uids], null, $uid); + return $this->fetch(["RFC822.SIZE"], is_array($uids) ? $uids : [$uids], null, $uid); } /** @@ -793,7 +940,7 @@ class ImapProtocol extends Protocol { $uids = $this->uid_cache; if ($id == null) { - return Response::empty($this->debug)->setResult($uids); + return Response::empty($this->debug)->setResult($uids)->setCanBeEmpty(true); } foreach ($uids as $k => $v) { @@ -877,7 +1024,7 @@ class ImapProtocol extends Protocol { * @throws RuntimeException */ public function store( - array|string $flags, int $from, int $to = null, string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, string $item = null + array|string $flags, int $from, ?int $to = null, ?string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, ?string $item = null ): Response { $flags = $this->escapeList(is_array($flags) ? $flags : [$flags]); $set = $this->buildSet($from, $to); @@ -917,7 +1064,7 @@ class ImapProtocol extends Protocol { * @throws ImapServerErrorException * @throws RuntimeException */ - public function appendMessage(string $folder, string $message, array $flags = null, string $date = null): Response { + public function appendMessage(string $folder, string $message, ?array $flags = null, ?string $date = null): Response { $tokens = []; $tokens[] = $this->escapeString($folder); if ($flags !== null) { @@ -947,7 +1094,7 @@ class ImapProtocol extends Protocol { * @throws ImapServerErrorException * @throws RuntimeException */ - public function copyMessage(string $folder, $from, int $to = null, int|string $uid = IMAP::ST_UID): Response { + public function copyMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response { $set = $this->buildSet($from, $to); $command = $this->buildUIDCommand("COPY", $uid); @@ -993,11 +1140,29 @@ class ImapProtocol extends Protocol { * @throws ImapServerErrorException * @throws RuntimeException */ - public function moveMessage(string $folder, $from, int $to = null, int|string $uid = IMAP::ST_UID): Response { + public function moveMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response { $set = $this->buildSet($from, $to); $command = $this->buildUIDCommand("MOVE", $uid); - return $this->requestAndResponse($command, [$set, $this->escapeString($folder)], true); + $result = $this->requestAndResponse($command, [$set, $this->escapeString($folder)], true); + // RFC4315 fallback to COPY, STORE and EXPUNGE. + // Required for cases where MOVE isn't supported by the server. So we copy the message to the target folder, + // mark the original message as deleted and expunge the mailbox. + // See the following links for more information: + // - https://github.com/freescout-help-desk/freescout/issues/4313 + // - https://github.com/Webklex/php-imap/issues/123 + if (!$result->boolean()) { + $result = $this->copyMessage($folder, $from, $to, $uid); + if (!$result->boolean()) { + return $result; + } + $result = $this->store(['\Deleted'], $from, $to, null, true, $uid); + if (!$result->boolean()) { + return $result; + } + return $this->expunge(); + } + return $result; } /** @@ -1019,7 +1184,27 @@ class ImapProtocol extends Protocol { $set = implode(',', $messages); $tokens = [$set, $this->escapeString($folder)]; - return $this->requestAndResponse($command, $tokens, true); + $result = $this->requestAndResponse($command, $tokens, true); + // RFC4315 fallback to COPY, STORE and EXPUNGE. + // Required for cases where MOVE isn't supported by the server. So we copy the message to the target folder, + // mark the original message as deleted and expunge the mailbox. + // See the following links for more information: + // - https://github.com/freescout-help-desk/freescout/issues/4313 + // - https://github.com/Webklex/php-imap/issues/123 + if (!$result->boolean()) { + $result = $this->copyManyMessages($messages, $folder, $uid); + if (!$result->boolean()) { + return $result; + } + foreach ($messages as $message) { + $result = $this->store(['\Deleted'], $message, $message, null, true, $uid); + if (!$result->boolean()) { + return $result; + } + } + return $this->expunge(); + } + return $result; } /** @@ -1186,9 +1371,9 @@ class ImapProtocol extends Protocol { * * @throws RuntimeException */ - public function idle() { + public function idle(): void { $response = $this->sendRequest("IDLE"); - if (!$this->assumedNextLine($response, '+ ')) { + if (!$this->assumedNextLineIgnoreUntagged($response, '+ ')) { throw new RuntimeException('idle failed'); } } @@ -1200,7 +1385,7 @@ class ImapProtocol extends Protocol { public function done(): bool { $response = new Response($this->noun, $this->debug); $this->write($response, "DONE"); - if (!$this->assumedNextTaggedLine($response, 'OK', $tags)) { + if (!$this->assumedNextTaggedLineIgnoreUntagged($response, 'OK', $tags)) { throw new RuntimeException('done failed'); } return true; @@ -1259,7 +1444,7 @@ class ImapProtocol extends Protocol { $headers = $this->headers($ids, "RFC822", $uid); $response->stack($headers); foreach ($headers->data() as $id => $raw_header) { - $result[$id] = (new Header($raw_header, false))->getAttributes(); + $result[$id] = (new Header($raw_header, $this->config))->getAttributes(); } } return $response->setResult($result)->setCanBeEmpty(true); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php index 10bc9d9f5..81b52f772 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php @@ -13,6 +13,7 @@ namespace Webklex\PHPIMAP\Connection\Protocols; use Webklex\PHPIMAP\ClientManager; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\AuthFailedException; use Webklex\PHPIMAP\Exceptions\ImapBadRequestException; use Webklex\PHPIMAP\Exceptions\MethodNotSupportedException; @@ -32,10 +33,12 @@ class LegacyProtocol extends Protocol { /** * Imap constructor. + * @param Config $config * @param bool $cert_validation set to false to skip SSL certificate validation * @param mixed $encryption Connection encryption method */ - public function __construct(bool $cert_validation = true, mixed $encryption = false) { + public function __construct(Config $config, bool $cert_validation = true, mixed $encryption = false) { + $this->config = $config; $this->setCertValidation($cert_validation); $this->encryption = $encryption; } @@ -52,7 +55,7 @@ class LegacyProtocol extends Protocol { * @param string $host * @param int|null $port */ - public function connect(string $host, int $port = null) { + public function connect(string $host, ?int $port = null): void { if ($this->encryption) { $encryption = strtolower($this->encryption); if ($encryption == "ssl") { @@ -81,7 +84,7 @@ class LegacyProtocol extends Protocol { $password, 0, $attempts = 3, - ClientManager::get('options.open') + $this->config->get('options.open') ); $response->addCommand("imap_open"); } catch (\ErrorException $e) { @@ -122,8 +125,6 @@ class LegacyProtocol extends Protocol { * @param string $token access token * * @return Response - * @throws AuthFailedException - * @throws RuntimeException */ public function authenticate(string $user, string $token): Response { return $this->login($user, $token); @@ -236,6 +237,16 @@ class LegacyProtocol extends Protocol { }); } + /** + * Get the status of a given folder + * + * @return Response list of STATUS items + * @throws MethodNotSupportedException + */ + public function folderStatus(string $folder = 'INBOX', $arguments = ['MESSAGES', 'UNSEEN', 'RECENT', 'UIDNEXT', 'UIDVALIDITY']): Response { + throw new MethodNotSupportedException(); + } + /** * Fetch message content * @param int|array $uids @@ -349,7 +360,7 @@ class LegacyProtocol extends Protocol { * * @return Response message number for given message or all messages as array */ - public function getUid(int $id = null): Response { + public function getUid(?int $id = null): Response { return $this->response()->wrap(function($response) use ($id) { /** @var Response $response */ if ($id === null) { @@ -379,7 +390,7 @@ class LegacyProtocol extends Protocol { } /** - * Get a message number for a uid + * Get the message number of a given uid * @param string $id uid * * @return Response message number @@ -444,7 +455,7 @@ class LegacyProtocol extends Protocol { * * @return Response new flags if $silent is false, else true or false depending on success */ - public function store(array|string $flags, int $from, int $to = null, string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, string $item = null): Response { + public function store(array|string $flags, int $from, ?int $to = null, ?string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, ?string $item = null): Response { $flag = trim(is_array($flags) ? implode(" ", $flags) : $flags); return $this->response()->wrap(function($response) use ($mode, $from, $flag, $uid, $silent) { @@ -480,7 +491,7 @@ class LegacyProtocol extends Protocol { * * @return Response */ - public function appendMessage(string $folder, string $message, array $flags = null, mixed $date = null): Response { + public function appendMessage(string $folder, string $message, ?array $flags = null, mixed $date = null): Response { return $this->response("imap_append")->wrap(function($response) use ($folder, $message, $flags, $date) { /** @var Response $response */ if ($date != null) { @@ -511,7 +522,7 @@ class LegacyProtocol extends Protocol { * * @return Response */ - public function copyMessage(string $folder, $from, int $to = null, int|string $uid = IMAP::ST_UID): Response { + public function copyMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response { return $this->response("imap_mail_copy")->wrap(function($response) use ($from, $folder, $uid) { /** @var Response $response */ @@ -561,7 +572,7 @@ class LegacyProtocol extends Protocol { * * @return Response success */ - public function moveMessage(string $folder, $from, int $to = null, int|string $uid = IMAP::ST_UID): Response { + public function moveMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response { return $this->response("imap_mail_move")->wrap(function($response) use ($from, $folder, $uid) { if (\imap_mail_move($this->stream, $from, $this->getAddress() . $folder, $uid ? IMAP::ST_UID : IMAP::NIL)) { return [ diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/Protocol.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/Protocol.php index 6fe88ee99..a1404b4b0 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/Protocol.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/Protocol.php @@ -12,6 +12,7 @@ namespace Webklex\PHPIMAP\Connection\Protocols; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; use Webklex\PHPIMAP\IMAP; @@ -38,10 +39,15 @@ abstract class Protocol implements ProtocolInterface { protected bool $enable_uid_cache = true; /** - * @var resource + * @var resource|mixed|boolean|null $stream */ public $stream = false; + /** + * @var Config $config + */ + protected Config $config; + /** * Connection encryption method * @var string $encryption @@ -65,6 +71,15 @@ abstract class Protocol implements ProtocolInterface { 'password' => null, ]; + /** + * SSL stream context options + * + * @see https://www.php.net/manual/en/context.ssl.php for possible options + * + * @var array + */ + protected array $ssl_options = []; + /** * Cache for uid of active folder. * @@ -156,6 +171,28 @@ abstract class Protocol implements ProtocolInterface { return $this->proxy; } + /** + * Set SSL context options settings + * @var array $options + * + * @return Protocol + */ + public function setSslOptions(array $options): Protocol + { + $this->ssl_options = $options; + + return $this; + } + + /** + * Get the current SSL context options settings + * + * @return array + */ + public function getSslOptions(): array { + return $this->ssl_options; + } + /** * Prepare socket options * @return array @@ -169,6 +206,11 @@ abstract class Protocol implements ProtocolInterface { 'verify_peer_name' => $this->getCertValidation(), 'verify_peer' => $this->getCertValidation(), ]; + + if (count($this->ssl_options)) { + /* Get the ssl context options from the config, but prioritize the 'validate_cert' config over the ssl context options */ + $options["ssl"] = array_replace($this->ssl_options, $options["ssl"]); + } } if ($this->proxy["socket"] != null) { @@ -268,7 +310,7 @@ abstract class Protocol implements ProtocolInterface { * * @param array|null $uids */ - public function setUidCache(?array $uids) { + public function setUidCache(?array $uids): void { if (is_null($uids)) { $this->uid_cache = []; return; @@ -330,7 +372,7 @@ abstract class Protocol implements ProtocolInterface { } /** - * Retrieves header/meta data from the resource stream + * Retrieves header/metadata from the resource stream * * @return array */ @@ -363,4 +405,13 @@ abstract class Protocol implements ProtocolInterface { public function getStream(): mixed { return $this->stream; } + + /** + * Set the Config instance + * + * @return Config + */ + public function getConfig(): Config { + return $this->config; + } } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php index c02d78003..eb6d7c9d0 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php @@ -118,7 +118,18 @@ interface ProtocolInterface { public function examineFolder(string $folder = 'INBOX'): Response; /** - * Fetch message headers + * Get the status of a given folder + * + * @return Response list of STATUS items + * + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws RuntimeException + */ + public function folderStatus(string $folder = 'INBOX', $arguments = ['MESSAGES', 'UNSEEN', 'RECENT', 'UIDNEXT', 'UIDVALIDITY']): Response; + + /** + * Fetch message contents * @param int|array $uids * @param string $rfc * @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/AttachmentDecoder.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/AttachmentDecoder.php new file mode 100644 index 000000000..227803530 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/AttachmentDecoder.php @@ -0,0 +1,25 @@ +options = array_merge([ + 'header' => 'utf-8', + 'message' => 'utf-8', + 'attachment' => 'utf-8', + ], $this->options); + } + + /** + * Decode a given value + * @param array|string|null $value + * @param string|null $encoding + * @return mixed + */ + public function decode(array|string|null $value, ?string $encoding = null): mixed { + return $value; + } + + /** + * Convert the encoding + * @param string $str The string to convert + * @param string $from The source encoding + * @param string $to The target encoding + * + * @return mixed|string + */ + public function convertEncoding(string $str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed { + $from = EncodingAliases::get($from, $this->fallback_encoding); + $to = EncodingAliases::get($to, $this->fallback_encoding); + + if ($from === $to) { + return $str; + } + + return EncodingAliases::convert($str, $from, $to); + } + + /** + * Decode MIME header elements + * @link https://php.net/manual/en/function.imap-mime-header-decode.php + * @param string $text The MIME text + * + * @return array Returns an array of objects. Each *object has two properties, charset and text. + */ + public function mimeHeaderDecode(string $text): array { + if (extension_loaded('imap')) { + $result = \imap_mime_header_decode($text); + return is_array($result) ? $result : []; + } + $charset = $this->getEncoding($text); + return [(object)[ + "charset" => $charset, + "text" => $this->convertEncoding($text, $charset) + ]]; + } + + /** + * Test if a given value is utf-8 encoded + * @param $value + * + * @return bool + */ + public static function isUTF8($value): bool { + return str_starts_with(strtolower($value), '=?utf-8?'); + } + + /** + * Check if a given pair of strings has been decoded + * @param $encoded + * @param $decoded + * + * @return bool + */ + public static function notDecoded($encoded, $decoded): bool { + return str_starts_with($decoded, '=?') + && strlen($decoded) - 2 === strpos($decoded, '?=') + && str_contains($encoded, $decoded); + } + + /** + * Set the configuration used for decoding + * @param array $config + * + * @return Decoder + */ + public function setOptions(array $config): static { + $this->options = $config; + return $this; + } + + /** + * Get the configuration used for decoding + * + * @return array + */ + public function getOptions(): array { + return $this->options; + } + + /** + * Get the fallback encoding + * + * @return string + */ + public function getFallbackEncoding(): string { + return $this->fallback_encoding; + } + + /** + * Set the fallback encoding + * + * @param string $fallback_encoding + * @return Decoder + */ + public function setFallbackEncoding(string $fallback_encoding): static { + $this->fallback_encoding = $fallback_encoding; + return $this; + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/DecoderInterface.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/DecoderInterface.php new file mode 100644 index 000000000..e48746024 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/DecoderInterface.php @@ -0,0 +1,52 @@ +decodeHeaderArray($value); + } + $original_value = $value; + $decoder = $this->options['header']; + + if ($value !== null) { + if ($decoder === 'utf-8') { + $decoded_values = $this->mimeHeaderDecode($value); + $tempValue = ""; + foreach ($decoded_values as $decoded_value) { + $tempValue .= $this->convertEncoding($decoded_value->text, $decoded_value->charset); + } + if ($tempValue) { + $value = $tempValue; + } else if (extension_loaded('imap')) { + $value = \imap_utf8($value); + } else if (function_exists('iconv_mime_decode')) { + $value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8"); + } else { + $value = mb_decode_mimeheader($value); + } + } elseif ($decoder === 'iconv') { + $value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8"); + } else if (self::isUTF8($value)) { + $value = mb_decode_mimeheader($value); + } + + if (self::notDecoded($original_value, $value)) { + $value = $this->convertEncoding($original_value, $this->getEncoding($original_value)); + } + } + + return $value; + } + + /** + * Get the encoding of a given abject + * @param object|string $structure + * + * @return string + */ + public function getEncoding(object|string $structure): string { + if (property_exists($structure, 'parameters')) { + foreach ($structure->parameters as $parameter) { + if (strtolower($parameter->attribute) == "charset") { + return EncodingAliases::get($parameter->value == "default" ? EncodingAliases::detectEncoding($parameter->value) : $parameter->value, $this->fallback_encoding); + } + } + } elseif (property_exists($structure, 'charset')) { + return EncodingAliases::get($structure->charset == "default" ? EncodingAliases::detectEncoding($structure->charset) : $structure->charset, $this->fallback_encoding); + } elseif (is_string($structure) === true) { + $result = mb_detect_encoding($structure); + return $result === false ? $this->fallback_encoding : $result; + } + + return $this->fallback_encoding; + } + + + /** + * Decode a given array + * @param array $values + * + * @return array + */ + private function decodeHeaderArray(array $values): array { + foreach ($values as $key => $value) { + $values[$key] = $this->decode($value); + } + return $values; + } + +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/MessageDecoder.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/MessageDecoder.php new file mode 100644 index 000000000..4a2cff2f3 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Decoder/MessageDecoder.php @@ -0,0 +1,119 @@ +decode($item); + }, $value); + } + + switch ($encoding) { + case IMAP::MESSAGE_ENC_BINARY: + if (extension_loaded('imap')) { + return base64_decode(\imap_binary($value)); + } + return base64_decode($value); + case IMAP::MESSAGE_ENC_BASE64: + return base64_decode($value); + case IMAP::MESSAGE_ENC_QUOTED_PRINTABLE: + return quoted_printable_decode($value); + case IMAP::MESSAGE_ENC_8BIT: + case IMAP::MESSAGE_ENC_7BIT: + case IMAP::MESSAGE_ENC_OTHER: + default: + return $value; + } + } + + /** + * Get the encoding of a given abject + * @param object|string $structure + * + * @return string + */ + public function getEncoding(object|string $structure): string { + if (property_exists($structure, 'parameters')) { + foreach ($structure->parameters as $parameter) { + if (strtolower($parameter->attribute) == "charset") { + return EncodingAliases::get($parameter->value, "ISO-8859-2"); + } + } + } elseif (property_exists($structure, 'charset')) { + return EncodingAliases::get($structure->charset, "ISO-8859-2"); + } elseif (is_string($structure) === true) { + return EncodingAliases::detectEncoding($structure); + } + + return $this->fallback_encoding; + } + + + /** + * Convert the encoding + * @param $str + * @param string $from + * @param string $to + * + * @return mixed|string + */ + public function convertEncoding($str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed { + $from = EncodingAliases::get($from); + $to = EncodingAliases::get($to); + + if ($from === $to) { + return $str; + } + + // We don't need to do convertEncoding() if charset is ASCII (us-ascii): + // ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded + // https://stackoverflow.com/a/11303410 + // + // us-ascii is the same as ASCII: + // ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA) + // prefers the updated name US-ASCII, which clarifies that this system was developed in the US and + // based on the typographical symbols predominantly in use there. + // https://en.wikipedia.org/wiki/ASCII + // + // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken. + if (strtolower($from ?? '') == 'us-ascii' && $to == 'UTF-8') { + return $str; + } + + if (function_exists('iconv') && !EncodingAliases::isUtf7($from) && !EncodingAliases::isUtf7($to)) { + try { + return iconv($from, $to.'//IGNORE', $str); + } catch (Exception) { + return @iconv($from, $to, $str); + } + } else { + if (!$from) { + return mb_convert_encoding($str, $to); + } + return mb_convert_encoding($str, $to, $from); + } + } + +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/EncodingAliases.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/EncodingAliases.php index 888fc7fab..8a3dc0fba 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/EncodingAliases.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/EncodingAliases.php @@ -474,7 +474,7 @@ class EncodingAliases { * * @return string */ - public static function get(?string $encoding, string $fallback = null): string { + public static function get(?string $encoding, ?string $fallback = null): string { if (isset(self::$aliases[strtolower($encoding ?? '')])) { return self::$aliases[strtolower($encoding ?? '')]; } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Exceptions/DecoderNotFoundException.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Exceptions/DecoderNotFoundException.php new file mode 100644 index 000000000..0acdb9c86 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Exceptions/DecoderNotFoundException.php @@ -0,0 +1,24 @@ +delimiter, $name) as $item) { - $parts[] = EncodingAliases::convert($item, "UTF7-IMAP", "UTF-8"); + $parts[] = EncodingAliases::convert($item, "UTF7-IMAP"); } return implode($this->delimiter, $parts); @@ -259,8 +259,8 @@ class Folder { * @param $attributes */ protected function parseAttributes($attributes): void { - $this->no_inferiors = in_array('\NoInferiors', $attributes); - $this->no_select = in_array('\NoSelect', $attributes); + $this->no_inferiors = in_array('\NoInferiors', $attributes, true) || \in_array('\Noinferiors', $attributes, true); + $this->no_select = in_array('\NoSelect', $attributes, true) || \in_array('\Noselect', $attributes, true); $this->marked = in_array('\Marked', $attributes); $this->referral = in_array('\Referral', $attributes); $this->has_children = in_array('\HasChildren', $attributes); @@ -287,8 +287,7 @@ class Folder { if ($expunge) $this->client->expunge(); $folder = $this->client->getFolder($new_name); - $event = $this->getEvent("folder", "moved"); - $event::dispatch($this, $folder); + $this->dispatch("folder", "moved", $this, $folder); return $status; } @@ -307,10 +306,10 @@ class Folder { * @throws MessageNotFoundException * @throws ResponseException */ - public function overview(string $sequence = null): array { + public function overview(?string $sequence = null): array { $this->client->openFolder($this->path); $sequence = $sequence === null ? "1:*" : $sequence; - $uid = ClientManager::get('options.sequence', IMAP::ST_MSGN); + $uid = $this->client->getConfig()->get('options.sequence', IMAP::ST_MSGN); $response = $this->client->getConnection()->overview($sequence, $uid); return $response->validatedData(); } @@ -329,7 +328,7 @@ class Folder { * @throws AuthFailedException * @throws ResponseException */ - public function appendMessage(string $message, array $options = null, Carbon|string $internal_date = null): array { + public function appendMessage(string $message, ?array $options = null, Carbon|string|null $internal_date = null): array { /** * Check if $internal_date is parsed. If it is null it should not be set. Otherwise, the message can't be stored. * If this parameter is set, it will set the INTERNALDATE on the appended message. The parameter should be a @@ -378,13 +377,12 @@ class Folder { public function delete(bool $expunge = true): array { $status = $this->client->getConnection()->deleteFolder($this->path)->validatedData(); if ($this->client->getActiveFolder() == $this->path){ - $this->client->setActiveFolder(null); + $this->client->setActiveFolder(); } if ($expunge) $this->client->expunge(); - $event = $this->getEvent("folder", "deleted"); - $event::dispatch($this); + $this->dispatch("folder", "deleted", $this); return $status; } @@ -448,11 +446,20 @@ class Folder { $last_action = Carbon::now()->addSeconds($timeout); - $sequence = ClientManager::get('options.sequence', IMAP::ST_MSGN); + $sequence = $this->client->getConfig()->get('options.sequence', IMAP::ST_MSGN); while (true) { - // This polymorphic call is fine - Protocol::idle() will throw an exception beforehand - $line = $idle_client->getConnection()->nextLine(Response::empty()); + try { + // This polymorphic call is fine - Protocol::idle() will throw an exception beforehand + $line = $idle_client->getConnection()->nextLine(Response::empty()); + } catch (Exceptions\RuntimeException $e) { + if(strpos($e->getMessage(), "empty response") >= 0 && $idle_client->getConnection()->connected()) { + continue; + } + if(!str_contains($e->getMessage(), "connection closed")) { + throw $e; + } + } if (($pos = strpos($line, "EXISTS")) !== false) { $msgn = (int)substr($line, 2, $pos - 2); @@ -485,14 +492,13 @@ class Folder { $message->setSequence($sequence); $callback($message); - $event = $this->getEvent("message", "new"); - $event::dispatch($message); + $this->dispatch("message", "new", $message); } } } /** - * Get folder status information + * Get folder status information from the EXAMINE command * * @return array * @throws ConnectionFailedException @@ -502,20 +508,39 @@ class Folder { * @throws AuthFailedException * @throws ResponseException */ - public function getStatus(): array { - return $this->examine(); + public function status(): array { + return $this->client->getConnection()->folderStatus($this->path)->validatedData(); } /** + * Get folder status information from the EXAMINE command + * + * @return array + * @throws AuthFailedException * @throws ConnectionFailedException * @throws ImapBadRequestException * @throws ImapServerErrorException - * @throws RuntimeException - * @throws AuthFailedException * @throws ResponseException + * @throws RuntimeException + * + * @deprecated Use Folder::status() instead + */ + public function getStatus(): array { + return $this->status(); + } + + /** + * Load folder status information from the EXAMINE command + * @return Folder + * @throws AuthFailedException + * @throws ConnectionFailedException + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws ResponseException + * @throws RuntimeException */ public function loadStatus(): Folder { - $this->status = $this->getStatus(); + $this->status = $this->examine(); return $this; } @@ -564,7 +589,7 @@ class Folder { */ public function setDelimiter($delimiter): void { if (in_array($delimiter, [null, '', ' ', false]) === true) { - $delimiter = ClientManager::get('options.delimiter', '/'); + $delimiter = $this->client->getConfig()->get('options.delimiter', '/'); } $this->delimiter = $delimiter; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Header.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Header.php index 9c8ae046c..d18e98a18 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Header.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Header.php @@ -14,8 +14,11 @@ namespace Webklex\PHPIMAP; use Carbon\Carbon; +use Webklex\PHPIMAP\Decoder\DecoderInterface; +use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException; use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; use Webklex\PHPIMAP\Exceptions\MethodNotFoundException; +use Webklex\PHPIMAP\Exceptions\SpoofingAttemptDetectedException; /** * Class Header @@ -41,26 +44,37 @@ class Header { /** * Config holder * - * @var array $config + * @var Config $config */ - protected array $config = []; + protected Config $config; /** - * Fallback Encoding + * Config holder * - * @var string + * @var array $options */ - public string $fallback_encoding = 'UTF-8'; + protected array $options = []; + + /** + * Decoder instance + * + * @var DecoderInterface $decoder + */ + protected DecoderInterface $decoder; /** * Header constructor. + * @param Config $config * @param string $raw_header * * @throws InvalidMessageDateException + * @throws DecoderNotFoundException */ - public function __construct(string $raw_header) { + public function __construct(string $raw_header, Config $config) { + $this->decoder = $config->getDecoder("header"); $this->raw = $raw_header; - $this->config = ClientManager::get('options'); + $this->config = $config; + $this->options = $this->config->get('options'); $this->parse(); } @@ -162,7 +176,7 @@ class Header { * @return string|null */ public function getBoundary(): ?string { - $regex = $this->config["boundary"] ?? "/boundary=(.*?(?=;)|(.*))/i"; + $regex = $this->options["boundary"] ?? "/boundary=(.*?(?=;)|(.*))/i"; $boundary = $this->find($regex); if ($boundary === null) { @@ -186,6 +200,7 @@ class Header { * Parse the raw headers * * @throws InvalidMessageDateException + * @throws SpoofingAttemptDetectedException */ protected function parse(): void { $header = $this->rfc822_parse_headers($this->raw); @@ -193,10 +208,10 @@ class Header { $this->extractAddresses($header); if (property_exists($header, 'subject')) { - $this->set("subject", $this->decode($header->subject)); + $this->set("subject", $this->decoder->decode($header->subject)); } if (property_exists($header, 'references')) { - $this->set("references", array_map(function ($item) { + $this->set("references", array_map(function($item) { return str_replace(['<', '>'], '', $item); }, explode(" ", $header->references))); } @@ -217,6 +232,11 @@ class Header { $this->extractHeaderExtensions(); $this->findPriority(); + + if($this->config->get('security.detect_spoofing', true)) { + // Detect spoofing + $this->detectSpoofing(); + } } /** @@ -229,7 +249,7 @@ class Header { public function rfc822_parse_headers($raw_headers): object { $headers = []; $imap_headers = []; - if (extension_loaded('imap') && $this->config["rfc822"]) { + if (extension_loaded('imap') && $this->options["rfc822"]) { $raw_imap_headers = (array)\imap_rfc822_parse_headers($raw_headers); foreach ($raw_imap_headers as $key => $values) { $key = strtolower(str_replace("-", "_", $key)); @@ -322,147 +342,6 @@ class Header { return (object)array_merge($headers, $imap_headers); } - /** - * Decode MIME header elements - * @link https://php.net/manual/en/function.imap-mime-header-decode.php - * @param string $text The MIME text - * - * @return array The decoded elements are returned in an array of objects, where each - * object has two properties, charset and text. - */ - public function mime_header_decode(string $text): array { - if (extension_loaded('imap')) { - $result = \imap_mime_header_decode($text); - return is_array($result) ? $result : []; - } - $charset = $this->getEncoding($text); - return [(object)[ - "charset" => $charset, - "text" => $this->convertEncoding($text, $charset) - ]]; - } - - /** - * Check if a given pair of strings has been decoded - * @param $encoded - * @param $decoded - * - * @return bool - */ - private function notDecoded($encoded, $decoded): bool { - return str_starts_with($decoded, '=?') - && strlen($decoded) - 2 === strpos($decoded, '?=') - && str_contains($encoded, $decoded); - } - - /** - * Convert the encoding - * @param $str - * @param string $from - * @param string $to - * - * @return mixed|string - */ - public function convertEncoding($str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed { - $from = EncodingAliases::get($from, $this->fallback_encoding); - $to = EncodingAliases::get($to, $this->fallback_encoding); - - if ($from === $to) { - return $str; - } - - return EncodingAliases::convert($str, $from, $to); - } - - /** - * Get the encoding of a given abject - * @param object|string $structure - * - * @return string - */ - public function getEncoding(object|string $structure): string { - if (property_exists($structure, 'parameters')) { - foreach ($structure->parameters as $parameter) { - if (strtolower($parameter->attribute) == "charset") { - return EncodingAliases::get($parameter->value, $this->fallback_encoding); - } - } - } elseif (property_exists($structure, 'charset')) { - return EncodingAliases::get($structure->charset, $this->fallback_encoding); - } elseif (is_string($structure) === true) { - $result = mb_detect_encoding($structure); - return $result === false ? $this->fallback_encoding : $result; - } - - return $this->fallback_encoding; - } - - /** - * Test if a given value is utf-8 encoded - * @param $value - * - * @return bool - */ - private function is_uft8($value): bool { - return str_starts_with(strtolower($value), '=?utf-8?'); - } - - /** - * Try to decode a specific header - * @param mixed $value - * - * @return mixed - */ - public function decode(mixed $value): mixed { - if (is_array($value)) { - return $this->decodeArray($value); - } - $original_value = $value; - $decoder = $this->config['decoder']['message']; - - if ($value !== null) { - if ($decoder === 'utf-8') { - $decoded_values = $this->mime_header_decode($value); - $tempValue = ""; - foreach ($decoded_values as $decoded_value) { - $tempValue .= $this->convertEncoding($decoded_value->text, $decoded_value->charset); - } - if ($tempValue) { - $value = $tempValue; - } else if (extension_loaded('imap')) { - $value = \imap_utf8($value); - }else if (function_exists('iconv_mime_decode')){ - $value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8"); - }else{ - $value = mb_decode_mimeheader($value); - } - }elseif ($decoder === 'iconv') { - $value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8"); - }else if ($this->is_uft8($value)) { - $value = mb_decode_mimeheader($value); - } - - if ($this->notDecoded($original_value, $value)) { - $value = $this->convertEncoding($original_value, $this->getEncoding($original_value)); - } - } - - return $value; - } - - /** - * Decode a given array - * @param array $values - * - * @return array - */ - private function decodeArray(array $values): array { - foreach ($values as $key => $value) { - $values[$key] = $this->decode($value); - } - return $values; - } - /** * Try to extract the priority from a given raw header string */ @@ -490,7 +369,7 @@ class Header { private function decodeAddresses($values): array { $addresses = []; - if (extension_loaded('mailparse') && $this->config["rfc822"]) { + if (extension_loaded('mailparse') && $this->options["rfc822"]) { foreach ($values as $address) { foreach (\mailparse_rfc822_parse_addresses($address) as $parsed_address) { if (isset($parsed_address['address'])) { @@ -510,7 +389,7 @@ class Header { } foreach ($values as $address) { - foreach (preg_split('/, (?=(?:[^"]*"[^"]*")*[^"]*$)/', $address) as $split_address) { + foreach (preg_split('/, ?(?=(?:[^"]*"[^"]*")*[^"]*$)/', $address) as $split_address) { $split_address = trim(rtrim($split_address)); if (strpos($split_address, ",") == strlen($split_address) - 1) { @@ -529,6 +408,24 @@ class Header { "mailbox" => $mailbox, "host" => $host, ]; + }elseif (preg_match( + '/^((?P.+)<)(?P[^<]+?)>$/', + $split_address, + $matches + )) { + $name = trim(rtrim($matches["name"])); + if(str_starts_with($name, "\"") && str_ends_with($name, "\"")) { + $name = substr($name, 1, -1); + }elseif(str_starts_with($name, "'") && str_ends_with($name, "'")) { + $name = substr($name, 1, -1); + } + $email = trim(rtrim($matches["email"])); + list($mailbox, $host) = array_pad(explode("@", $email), 2, null); + $addresses[] = (object)[ + "personal" => $name, + "mailbox" => $mailbox, + "host" => $host, + ]; } } } @@ -541,7 +438,7 @@ class Header { * @param object $header */ private function extractAddresses(object $header): void { - foreach (['from', 'to', 'cc', 'bcc', 'reply_to', 'sender'] as $key) { + foreach (['from', 'to', 'cc', 'bcc', 'reply_to', 'sender', 'return_path', 'envelope_from', 'envelope_to', 'delivered_to'] as $key) { if (property_exists($header, $key)) { $this->set($key, $this->parseAddresses($header->$key)); } @@ -558,7 +455,60 @@ class Header { $addresses = []; if (is_array($list) === false) { - return $addresses; + if(is_string($list)) { + if (preg_match( + '/^(?:(?P.+)\s)?(?(name)<|[^\s]+?)(?(name)>|>?)$/', + $list, + $matches + )) { + $name = trim(rtrim($matches["name"])); + $email = trim(rtrim($matches["email"])); + list($mailbox, $host) = array_pad(explode("@", $email), 2, null); + if($mailbox === ">") { // Fix trailing ">" in malformed mailboxes + $mailbox = ""; + } + if($name === "" && $mailbox === "" && $host === "") { + return $addresses; + } + $list = [ + (object)[ + "personal" => $name, + "mailbox" => $mailbox, + "host" => $host, + ] + ]; + }elseif (preg_match( + '/^((?P.+)<)(?P[^<]+?)>$/', + $list, + $matches + )) { + $name = trim(rtrim($matches["name"])); + $email = trim(rtrim($matches["email"])); + if(str_starts_with($name, "\"") && str_ends_with($name, "\"")) { + $name = substr($name, 1, -1); + }elseif(str_starts_with($name, "'") && str_ends_with($name, "'")) { + $name = substr($name, 1, -1); + } + list($mailbox, $host) = array_pad(explode("@", $email), 2, null); + if($mailbox === ">") { // Fix trailing ">" in malformed mailboxes + $mailbox = ""; + } + if($name === "" && $mailbox === "" && $host === "") { + return $addresses; + } + $list = [ + (object)[ + "personal" => $name, + "mailbox" => $mailbox, + "host" => $host, + ] + ]; + }else{ + return $addresses; + } + }else{ + return $addresses; + } } foreach ($list as $item) { @@ -573,28 +523,36 @@ class Header { if (!property_exists($address, 'personal')) { $address->personal = false; } else { - $personalParts = $this->mime_header_decode($address->personal); + $personal_slices = explode(" ", $address->personal); + $address->personal = ""; + foreach ($personal_slices as $slice) { + $personalParts = $this->decoder->mimeHeaderDecode($slice); - $address->personal = ''; - foreach ($personalParts as $p) { - $address->personal .= $this->convertEncoding($p->text, $this->getEncoding($p)); - } + $personal = ''; + foreach ($personalParts as $p) { + $personal .= $this->decoder->convertEncoding($p->text, $this->decoder->getEncoding($p)); + } - if (str_starts_with($address->personal, "'")) { - $address->personal = str_replace("'", "", $address->personal); + if (str_starts_with($personal, "'")) { + $personal = str_replace("'", "", $personal); + } + $personal = $this->decoder->decode($personal); + $address->personal .= $personal . " "; } + $address->personal = trim(rtrim($address->personal)); } if ($address->host == ".SYNTAX-ERROR.") { $address->host = ""; + }elseif ($address->host == "UNKNOWN") { + $address->host = ""; } if ($address->mailbox == "UNEXPECTED_DATA_AFTER_ADDRESS") { $address->mailbox = ""; + }elseif ($address->mailbox == "MISSING_MAILBOX_TERMINATOR") { + $address->mailbox = ""; } - $address->mail = ($address->mailbox && $address->host) ? $address->mailbox . '@' . $address->host : false; - $address->full = ($address->personal) ? $address->personal . ' <' . $address->mail . '>' : $address->mail; - $addresses[] = new Address($address); } @@ -612,63 +570,97 @@ class Header { $value = (string)$value; } // Only parse strings and don't parse any attributes like the user-agent - if (!in_array($key, ["user-agent", "subject"])) { - if (($pos = strpos($value, ";")) !== false) { - $original = substr($value, 0, $pos); - $this->set($key, trim(rtrim($original))); - - // Get all potential extensions - $extensions = explode(";", substr($value, $pos + 1)); - $previousKey = null; - $previousValue = ''; - - foreach ($extensions as $extension) { - if (($pos = strpos($extension, "=")) !== false) { - $key = substr($extension, 0, $pos); - $key = trim(rtrim(strtolower($key))); - - $matches = []; - - if (preg_match('/^(?P\w+)\*/', $key, $matches) !== 0) { - $key = $matches['key_name']; - $previousKey = $key; - - $value = substr($extension, $pos + 1); - $value = str_replace('"', "", $value); - $previousValue .= trim(rtrim($value)); - - continue; - } - - if ( - $previousKey !== null - && $previousKey !== $key - && isset($this->attributes[$previousKey]) === false - ) { - $this->set($previousKey, $previousValue); - - $previousValue = ''; - } - - if (isset($this->attributes[$key]) === false) { - $value = substr($extension, $pos + 1); - $value = str_replace('"', "", $value); - $value = trim(rtrim($value)); - - $this->set($key, $value); - } - - $previousKey = $key; + if (!in_array($key, ["user-agent", "subject", "received"])) { + if (str_contains($value, ";") && str_contains($value, "=")) { + $_attributes = $this->read_attribute($value); + foreach($_attributes as $_key => $_value) { + if($_value === "") { + $this->set($key, $_key); + } + if (!isset($this->attributes[$_key])) { + $this->set($_key, $_value); } - } - if ($previousValue !== '') { - $this->set($previousKey, $previousValue); } } } } } + /** + * Read a given attribute string + * - this isn't pretty, but it works - feel free to improve :) + * @param string $raw_attribute + * @return array + */ + private function read_attribute(string $raw_attribute): array { + $attributes = []; + $key = ''; + $value = ''; + $inside_word = false; + $inside_key = true; + $escaped = false; + foreach (str_split($raw_attribute) as $char) { + if($escaped) { + $escaped = false; + continue; + } + if($inside_word) { + if($char === '\\') { + $escaped = true; + }elseif($char === "\"" && $value !== "") { + $inside_word = false; + }else{ + $value .= $char; + } + }else{ + if($inside_key) { + if($char === '"') { + $inside_word = true; + }elseif($char === ';'){ + $attributes[$key] = $value; + $key = ''; + $value = ''; + $inside_key = true; + }elseif($char === '=') { + $inside_key = false; + }else{ + $key .= $char; + } + }else{ + if($char === '"' && $value === "") { + $inside_word = true; + }elseif($char === ';'){ + $attributes[$key] = $value; + $key = ''; + $value = ''; + $inside_key = true; + }else{ + $value .= $char; + } + } + } + } + $attributes[$key] = $value; + $result = []; + + foreach($attributes as $key => $value) { + if (($pos = strpos($key, "*")) !== false) { + $key = substr($key, 0, $pos); + } + $key = trim(rtrim(strtolower($key))); + + if(!isset($result[$key])) { + $result[$key] = ""; + } + $value = trim(rtrim(str_replace(["\r", "\n"], "", $value))); + if(str_starts_with($value, "\"") && str_ends_with($value, "\"")) { + $value = substr($value, 1, -1); + } + $result[$key] .= $value; + } + return $result; + } + /** * Exception handling for invalid dates * @@ -681,6 +673,7 @@ class Header { * | Thu, 31 May 2018 18:15:00 +0800 (added by) | Non-standard details added by the | Unknown * | | mail server | * | Sat, 31 Aug 2013 20:08:23 +0580 | Invalid timezone | PHPMailer bug https://sourceforge.net/p/phpmailer/mailman/message/6132703/ + * | Mi., 23 Apr. 2025 09:48:37 +0200 (MESZ) | Non-standard localized format | Aqua Mail S/MIME implementation * * Please report any new invalid timestamps to [#45](https://github.com/Webklex/php-imap/issues) * @@ -722,14 +715,14 @@ class Header { $date = Carbon::createFromFormat("d M Y H:i:s O", trim(implode(',', $array))); break; case preg_match('/([0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ UT)+$/i', $date) > 0: - case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ UT)+$/i', $date) > 0: + case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}\ [A-Z]{2,3}\ ([0-9]{2}|[0-9]{4})\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ UT)+$/i', $date) > 0: $date .= 'C'; break; case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}[\,]\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4})+$/i', $date) > 0: $date = str_replace(',', '', $date); break; - // match case for: Di., 15 Feb. 2022 06:52:44 +0100 (MEZ)/Di., 15 Feb. 2022 06:52:44 +0100 (MEZ) - case preg_match('/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))\/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))+$/i', $date) > 0: + // match case for: Di., 15 Feb. 2022 06:52:44 +0100 (MEZ)/Di., 15 Feb. 2022 06:52:44 +0100 (MEZ) and Mi., 23 Apr. 2025 09:48:37 +0200 (MESZ) + case preg_match('/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))(\/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))+)?$/i', $date) > 0: $dates = explode('/', $date); $date = array_shift($dates); $array = explode(',', $date); @@ -762,10 +755,10 @@ class Header { try { $parsed_date = Carbon::parse($date); } catch (\Exception $_e) { - if (!isset($this->config["fallback_date"])) { + if (!isset($this->options["fallback_date"])) { throw new InvalidMessageDateException("Invalid message date. ID:" . $this->get("message_id") . " Date:" . $header->date . "/" . $date, 1100, $e); } else { - $parsed_date = Carbon::parse($this->config["fallback_date"]); + $parsed_date = Carbon::parse($this->options["fallback_date"]); } } } @@ -800,9 +793,79 @@ class Header { * * @return Header */ - public function setConfig(array $config): Header { + public function setOptions(array $config): Header { + $this->options = $config; + return $this; + } + + /** + * Get the configuration used for parsing a raw header + * + * @return array + */ + public function getOptions(): array { + return $this->options; + } + + /** + * Set the configuration used for parsing a raw header + * @param Config $config + * + * @return Header + */ + public function setConfig(Config $config): Header { $this->config = $config; return $this; } + /** + * Get the configuration used for parsing a raw header + * + * @return Config + */ + public function getConfig(): Config { + return $this->config; + } + + /** + * Get the decoder instance + * + * @return DecoderInterface + */ + public function getDecoder(): DecoderInterface { + return $this->decoder; + } + + /** + * Set the decoder instance + * @param DecoderInterface $decoder + * + * @return $this + */ + public function setDecoder(DecoderInterface $decoder): static { + $this->decoder = $decoder; + return $this; + } + + /** + * Detect spoofing by checking the from, reply_to, return_path, sender and envelope_from headers + * @throws SpoofingAttemptDetectedException + */ + private function detectSpoofing(): void { + $header_keys = ["from", "reply_to", "return_path", "sender", "envelope_from"]; + $potential_senders = []; + foreach($header_keys as $key) { + $header = $this->get($key); + foreach ($header->toArray() as $address) { + $potential_senders[] = $address->mailbox . "@" . $address->host; + } + } + if(count($potential_senders) > 1) { + $this->set("spoofed", true); + if($this->config->get('security.detect_spoofing_exception', false)) { + throw new SpoofingAttemptDetectedException("Potential spoofing detected. Message ID: " . $this->get("message_id") . " Senders: " . implode(", ", $potential_senders)); + } + } + } + } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Message.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Message.php index 09a534f24..9d15a7b82 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Message.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Message.php @@ -12,10 +12,15 @@ namespace Webklex\PHPIMAP; +use Exception; +use Illuminate\Support\Str; use ReflectionClass; use ReflectionException; +use Webklex\PHPIMAP\Decoder\Decoder; +use Webklex\PHPIMAP\Decoder\DecoderInterface; use Webklex\PHPIMAP\Exceptions\AuthFailedException; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; +use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException; use Webklex\PHPIMAP\Exceptions\EventNotFoundException; use Webklex\PHPIMAP\Exceptions\FolderFetchingException; use Webklex\PHPIMAP\Exceptions\GetMessagesFailedException; @@ -34,7 +39,6 @@ use Webklex\PHPIMAP\Exceptions\RuntimeException; use Webklex\PHPIMAP\Support\AttachmentCollection; use Webklex\PHPIMAP\Support\FlagCollection; use Webklex\PHPIMAP\Support\Masks\MessageMask; -use Illuminate\Support\Str; use Webklex\PHPIMAP\Support\MessageCollection; use Webklex\PHPIMAP\Traits\HasEvents; @@ -43,22 +47,22 @@ use Webklex\PHPIMAP\Traits\HasEvents; * * @package Webklex\PHPIMAP * - * @property integer msglist - * @property integer uid - * @property integer msgn - * @property integer size - * @property Attribute subject - * @property Attribute message_id - * @property Attribute message_no - * @property Attribute references - * @property Attribute date - * @property Attribute from - * @property Attribute to - * @property Attribute cc - * @property Attribute bcc - * @property Attribute reply_to - * @property Attribute in_reply_to - * @property Attribute sender + * @property integer $msglist + * @property integer $uid + * @property integer $msgn + * @property integer $size + * @property Attribute $subject + * @property Attribute $message_id + * @property Attribute $message_no + * @property Attribute $references + * @property Attribute $date + * @property Attribute $from + * @property Attribute $to + * @property Attribute $cc + * @property Attribute $bcc + * @property Attribute $reply_to + * @property Attribute $in_reply_to + * @property Attribute $sender * * @method integer getMsglist() * @method integer setMsglist($msglist) @@ -87,7 +91,7 @@ class Message { * * @var ?Client */ - private ?Client $client = null; + private ?Client $client; /** * Default mask @@ -97,11 +101,25 @@ class Message { protected string $mask = MessageMask::class; /** - * Used config + * Used options * - * @var array $config + * @var array $options */ - protected array $config = []; + protected array $options = []; + + /** + * All library configs + * + * @var Config $config + */ + protected Config $config; + + /** + * Decoder instance + * + * @var DecoderInterface $decoder + */ + protected DecoderInterface $decoder; /** * Attribute holder @@ -204,8 +222,8 @@ class Message { * @throws RuntimeException * @throws ResponseException */ - public function __construct(int $uid, ?int $msglist, Client $client, int $fetch_options = null, bool $fetch_body = false, bool $fetch_flags = false, int $sequence = null) { - $this->boot(); + public function __construct(int $uid, ?int $msglist, Client $client, ?int $fetch_options = null, bool $fetch_body = false, bool $fetch_flags = false, ?int $sequence = null) { + $this->boot($client->getConfig()); $default_mask = $client->getDefaultMessageMask(); if ($default_mask != null) { @@ -269,7 +287,7 @@ class Message { $reflection = new ReflectionClass(self::class); /** @var Message $instance */ $instance = $reflection->newInstanceWithoutConstructor(); - $instance->boot(); + $instance->boot($client->getConfig()); $default_mask = $client->getDefaultMessageMask(); if ($default_mask != null) { @@ -296,29 +314,8 @@ class Message { /** * Create a new message instance by reading and loading a file or remote location - * - * @throws RuntimeException - * @throws MessageContentFetchingException - * @throws ResponseException - * @throws ImapBadRequestException - * @throws InvalidMessageDateException - * @throws ConnectionFailedException - * @throws ImapServerErrorException - * @throws ReflectionException - * @throws AuthFailedException - * @throws MaskNotFoundException - */ - public static function fromFile($filename): Message { - $blob = file_get_contents($filename); - if ($blob === false) { - throw new RuntimeException("Unable to read file"); - } - return self::fromString($blob); - } - - /** - * Create a new message instance by reading and loading a string - * @param string $blob + * @param string $filename + * @param ?Config $config * * @return Message * @throws AuthFailedException @@ -332,13 +329,38 @@ class Message { * @throws ResponseException * @throws RuntimeException */ - public static function fromString(string $blob): Message { + public static function fromFile(string $filename, ?Config $config = null): Message { + $blob = file_get_contents($filename); + if ($blob === false) { + throw new RuntimeException("Unable to read file"); + } + return self::fromString($blob, $config); + } + + /** + * Create a new message instance by reading and loading a string + * @param string $blob + * @param ?Config $config + * + * @return Message + * @throws AuthFailedException + * @throws ConnectionFailedException + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws InvalidMessageDateException + * @throws MaskNotFoundException + * @throws MessageContentFetchingException + * @throws ReflectionException + * @throws ResponseException + * @throws RuntimeException + */ + public static function fromString(string $blob, ?Config $config = null): Message { $reflection = new ReflectionClass(self::class); /** @var Message $instance */ $instance = $reflection->newInstanceWithoutConstructor(); - $instance->boot(); + $instance->boot($config); - $default_mask = ClientManager::getMask("message"); + $default_mask = $instance->getConfig()->getMask("message"); if($default_mask != ""){ $instance->setMask($default_mask); }else{ @@ -361,15 +383,20 @@ class Message { /** * Boot a new instance + * @param ?Config $config + * @throws DecoderNotFoundException */ - public function boot(): void { + public function boot(?Config $config = null): void { $this->attributes = []; + $this->client = null; + $this->config = $config ?? Config::make(); + $this->decoder = $this->config->getDecoder("message"); - $this->config = ClientManager::get('options'); - $this->available_flags = ClientManager::get('flags'); + $this->options = $this->config->get('options'); + $this->available_flags = $this->config->get('flags'); - $this->attachments = AttachmentCollection::make([]); - $this->flags = FlagCollection::make([]); + $this->attachments = AttachmentCollection::make(); + $this->flags = FlagCollection::make(); } /** @@ -529,7 +556,7 @@ class Message { */ private function parseHeader(): void { $sequence_id = $this->getSequenceId(); - $headers = $this->client->getConnection()->headers([$sequence_id], "RFC822", $this->sequence)->validatedData(); + $headers = $this->client->getConnection()->headers([$sequence_id], "RFC822", $this->sequence)->setCanBeEmpty(true)->validatedData(); if (!isset($headers[$sequence_id])) { throw new MessageHeaderFetchingException("no headers found", 0); } @@ -543,7 +570,7 @@ class Message { * @throws InvalidMessageDateException */ public function parseRawHeader(string $raw_header): void { - $this->header = new Header($raw_header); + $this->header = new Header($raw_header, $this->getConfig()); } /** @@ -551,7 +578,7 @@ class Message { * @param array $raw_flags */ public function parseRawFlags(array $raw_flags): void { - $this->flags = FlagCollection::make([]); + $this->flags = FlagCollection::make(); foreach ($raw_flags as $flag) { if (str_starts_with($flag, "\\")) { @@ -578,11 +605,11 @@ class Message { */ private function parseFlags(): void { $this->client->openFolder($this->folder_path); - $this->flags = FlagCollection::make([]); + $this->flags = FlagCollection::make(); $sequence_id = $this->getSequenceId(); try { - $flags = $this->client->getConnection()->flags([$sequence_id], $this->sequence)->validatedData(); + $flags = $this->client->getConnection()->flags([$sequence_id], $this->sequence)->setCanBeEmpty(true)->validatedData(); } catch (Exceptions\RuntimeException $e) { throw new MessageFlagException("flag could not be fetched", 0, $e); } @@ -612,9 +639,9 @@ class Message { $sequence_id = $this->getSequenceId(); try { - $contents = $this->client->getConnection()->content([$sequence_id], "RFC822", $this->sequence)->validatedData(); + $contents = $this->client->getConnection()->content([$sequence_id], $this->client->rfc, $this->sequence)->validatedData(); } catch (Exceptions\RuntimeException $e) { - throw new MessageContentFetchingException("failed to fetch content", 0); + throw new MessageContentFetchingException("failed to fetch content", 0, $e); } if (!isset($contents[$sequence_id])) { throw new MessageContentFetchingException("no content found", 0); @@ -717,9 +744,9 @@ class Message { if ($part->isAttachment()) { $this->fetchAttachment($part); } else { - $encoding = $this->getEncoding($part); + $encoding = $this->decoder->getEncoding($part); - $content = $this->decodeString($part->content, $part->encoding); + $content = $this->decoder->decode($part->content, $part->encoding); // We don't need to do convertEncoding() if charset is ASCII (us-ascii): // ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded @@ -733,7 +760,7 @@ class Message { // // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken. if ($encoding != 'us-ascii') { - $content = $this->convertEncoding($content, $encoding); + $content = $this->decoder->convertEncoding($content, $encoding); } $this->addBody($part->subtype ?? '', $content); @@ -786,7 +813,7 @@ class Message { if (is_long($option) === true) { $this->fetch_options = $option; } elseif (is_null($option) === true) { - $config = ClientManager::get('options.fetch', IMAP::FT_UID); + $config = $this->config->get('options.fetch', IMAP::FT_UID); $this->fetch_options = is_long($config) ? $config : 1; } @@ -803,7 +830,7 @@ class Message { if (is_long($sequence)) { $this->sequence = $sequence; } elseif (is_null($sequence)) { - $config = ClientManager::get('options.sequence', IMAP::ST_MSGN); + $config = $this->config->get('options.sequence', IMAP::ST_MSGN); $this->sequence = is_long($config) ? $config : IMAP::ST_MSGN; } @@ -820,7 +847,7 @@ class Message { if (is_bool($option)) { $this->fetch_body = $option; } elseif (is_null($option)) { - $config = ClientManager::get('options.fetch_body', true); + $config = $this->config->get('options.fetch_body', true); $this->fetch_body = is_bool($config) ? $config : true; } @@ -837,107 +864,13 @@ class Message { if (is_bool($option)) { $this->fetch_flags = $option; } elseif (is_null($option)) { - $config = ClientManager::get('options.fetch_flags', true); + $config = $this->config->get('options.fetch_flags', true); $this->fetch_flags = is_bool($config) ? $config : true; } return $this; } - /** - * Decode a given string - * @param $string - * @param $encoding - * - * @return string - */ - public function decodeString($string, $encoding): string { - switch ($encoding) { - case IMAP::MESSAGE_ENC_BINARY: - if (extension_loaded('imap')) { - return base64_decode(\imap_binary($string)); - } - return base64_decode($string); - case IMAP::MESSAGE_ENC_BASE64: - return base64_decode($string); - case IMAP::MESSAGE_ENC_QUOTED_PRINTABLE: - return quoted_printable_decode($string); - case IMAP::MESSAGE_ENC_8BIT: - case IMAP::MESSAGE_ENC_7BIT: - case IMAP::MESSAGE_ENC_OTHER: - default: - return $string; - } - } - - /** - * Convert the encoding - * @param $str - * @param string $from - * @param string $to - * - * @return mixed|string - */ - public function convertEncoding($str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed { - - $from = EncodingAliases::get($from); - $to = EncodingAliases::get($to); - - if ($from === $to) { - return $str; - } - - // We don't need to do convertEncoding() if charset is ASCII (us-ascii): - // ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded - // https://stackoverflow.com/a/11303410 - // - // us-ascii is the same as ASCII: - // ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA) - // prefers the updated name US-ASCII, which clarifies that this system was developed in the US and - // based on the typographical symbols predominantly in use there. - // https://en.wikipedia.org/wiki/ASCII - // - // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken. - if (strtolower($from ?? '') == 'us-ascii' && $to == 'UTF-8') { - return $str; - } - - if (function_exists('iconv') && !EncodingAliases::isUtf7($from) && !EncodingAliases::isUtf7($to)) { - try { - return iconv($from, $to.'//IGNORE', $str); - } catch (\Exception $e) { - return @iconv($from, $to, $str); - } - } else { - if (!$from) { - return mb_convert_encoding($str, $to); - } - return mb_convert_encoding($str, $to, $from); - } - } - - /** - * Get the encoding of a given abject - * @param object|string $structure - * - * @return string - */ - public function getEncoding(object|string $structure): string { - if (property_exists($structure, 'parameters')) { - foreach ($structure->parameters as $parameter) { - if (strtolower($parameter->attribute) == "charset") { - return EncodingAliases::get($parameter->value, "ISO-8859-2"); - } - } - } elseif (property_exists($structure, 'charset')) { - return EncodingAliases::get($structure->charset, "ISO-8859-2"); - } elseif (is_string($structure) === true) { - return EncodingAliases::detectEncoding($structure); - } - - return 'UTF-8'; - } - /** * Get the messages folder * @@ -970,10 +903,10 @@ class Message { * @throws RuntimeException * @throws ResponseException */ - public function thread(Folder $sent_folder = null, MessageCollection &$thread = null, Folder $folder = null): MessageCollection { - $thread = $thread ?: MessageCollection::make([]); + public function thread(?Folder $sent_folder = null, ?MessageCollection &$thread = null, ?Folder $folder = null): MessageCollection { + $thread = $thread ?: MessageCollection::make(); $folder = $folder ?: $this->getFolder(); - $sent_folder = $sent_folder ?: $this->client->getFolderByPath(ClientManager::get("options.common_folders.sent", "INBOX/Sent")); + $sent_folder = $sent_folder ?: $this->client->getFolderByPath($this->config->get("options.common_folders.sent", "INBOX/Sent")); /** @var Message $message */ foreach ($thread as $message) { @@ -1050,6 +983,7 @@ class Message { * Copy the current Messages to a mailbox * @param string $folder_path * @param boolean $expunge + * @param bool $utf7 * * @return null|Message * @throws AuthFailedException @@ -1066,7 +1000,7 @@ class Message { * @throws RuntimeException * @throws ResponseException */ - public function copy(string $folder_path, bool $expunge = false): ?Message { + public function copy(string $folder_path, bool $expunge = false, bool $utf7 = false): ?Message { $this->client->openFolder($folder_path); $status = $this->client->getConnection()->examineFolder($folder_path)->validatedData(); @@ -1077,7 +1011,7 @@ class Message { } /** @var Folder $folder */ - $folder = $this->client->getFolderByPath($folder_path); + $folder = $this->client->getFolderByPath($folder_path, $utf7); $this->client->openFolder($this->folder_path); if ($this->client->getConnection()->copyMessage($folder->path, $this->getSequenceId(), null, $this->sequence)->validatedData()) { @@ -1092,6 +1026,7 @@ class Message { * Move the current Messages to a mailbox * @param string $folder_path * @param boolean $expunge + * @param bool $utf7 * * @return Message|null * @throws AuthFailedException @@ -1108,7 +1043,7 @@ class Message { * @throws RuntimeException * @throws ResponseException */ - public function move(string $folder_path, bool $expunge = false): ?Message { + public function move(string $folder_path, bool $expunge = false, bool $utf7 = false): ?Message { $this->client->openFolder($folder_path); $status = $this->client->getConnection()->examineFolder($folder_path)->validatedData(); @@ -1119,7 +1054,7 @@ class Message { } /** @var Folder $folder */ - $folder = $this->client->getFolderByPath($folder_path); + $folder = $this->client->getFolderByPath($folder_path, $utf7); $this->client->openFolder($this->folder_path); if ($this->client->getConnection()->moveMessage($folder->path, $this->getSequenceId(), null, $this->sequence)->validatedData()) { @@ -1163,8 +1098,7 @@ class Message { } $message = $folder->query()->getMessage($sequence_id, null, $this->sequence); - $event = $this->getEvent("message", $event); - $event::dispatch($this, $message); + $this->dispatch("message", $event, $this, $message); return $message; } @@ -1190,7 +1124,7 @@ class Message { * @throws RuntimeException * @throws ResponseException */ - public function delete(bool $expunge = true, string $trash_path = null, bool $force_move = false): bool { + public function delete(bool $expunge = true, ?string $trash_path = null, bool $force_move = false): bool { $status = $this->setFlag("Deleted"); if ($force_move) { $trash_path = $trash_path === null ? $this->config["common_folders"]["trash"] : $trash_path; @@ -1198,8 +1132,7 @@ class Message { } if ($expunge) $this->client->expunge(); - $event = $this->getEvent("message", "deleted"); - $event::dispatch($this); + $this->dispatch("message", "deleted", $this); return $status; } @@ -1222,8 +1155,7 @@ class Message { $status = $this->unsetFlag("Deleted"); if ($expunge) $this->client->expunge(); - $event = $this->getEvent("message", "restored"); - $event::dispatch($this); + $this->dispatch("message", "restored", $this); return $status; } @@ -1253,8 +1185,7 @@ class Message { } $this->parseFlags(); - $event = $this->getEvent("flag", "new"); - $event::dispatch($this, $flag); + $this->dispatch("flag", "new", $this, $flag); return (bool)$status; } @@ -1285,8 +1216,7 @@ class Message { } $this->parseFlags(); - $event = $this->getEvent("flag", "deleted"); - $event::dispatch($this, $flag); + $this->dispatch("flag", "deleted", $this, $flag); return (bool)$status; } @@ -1465,7 +1395,7 @@ class Message { * @param null|Message $message * @return boolean */ - public function is(Message $message = null): bool { + public function is(?Message $message = null): bool { if (is_null($message)) { return false; } @@ -1547,11 +1477,11 @@ class Message { /** * Set the config - * @param array $config + * @param Config $config * * @return Message */ - public function setConfig(array $config): Message { + public function setConfig(Config $config): Message { $this->config = $config; return $this; @@ -1560,10 +1490,31 @@ class Message { /** * Get the config * + * @return Config + */ + public function getConfig(): Config { + return $this->config; + } + + /** + * Set the options + * @param array $options + * + * @return Message + */ + public function setOptions(array $options): Message { + $this->options = $options; + + return $this; + } + + /** + * Get the options + * * @return array */ - public function getConfig(): array { - return $this->config; + public function getOptions(): array { + return $this->options; } /** @@ -1651,7 +1602,7 @@ class Message { * * @return Message */ - public function setMsgn(int $msgn, int $msglist = null): Message { + public function setMsgn(int $msgn, ?int $msglist = null): Message { $this->msgn = $msgn; $this->msglist = $msglist; $this->uid = null; @@ -1682,7 +1633,7 @@ class Message { * @param $uid * @param int|null $msglist */ - public function setSequenceId($uid, int $msglist = null): void { + public function setSequenceId($uid, ?int $msglist = null): void { if ($this->getSequence() === IMAP::ST_UID) { $this->setUid($uid); $this->setMsglist($msglist); @@ -1691,6 +1642,26 @@ class Message { } } + /** + * Get the decoder instance + * + * @return DecoderInterface + */ + public function getDecoder(): DecoderInterface { + return $this->decoder; + } + + /** + * Set the decoder instance + * @param DecoderInterface $decoder + * + * @return $this + */ + public function setDecoder(DecoderInterface $decoder): static { + $this->decoder = $decoder; + return $this; + } + /** * Safe the entire message in a file * @param $filename diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Part.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Part.php index 1759b8de1..3c55bdfb9 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Part.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Part.php @@ -139,16 +139,23 @@ class Part { */ private ?Header $header; + /** + * @var Config $config + */ + protected Config $config; + /** * Part constructor. - * @param $raw_part + * @param string $raw_part + * @param Config $config * @param Header|null $header * @param integer $part_number * * @throws InvalidMessageDateException */ - public function __construct($raw_part, Header $header = null, int $part_number = 0) { + public function __construct(string $raw_part, Config $config, ?Header $header = null, int $part_number = 0) { $this->raw = $raw_part; + $this->config = $config; $this->header = $header; $this->part_number = $part_number; $this->parse(); @@ -211,7 +218,7 @@ class Part { $headers = substr($this->raw, 0, strlen($body) * -1); $body = substr($body, 0, -2); - $this->header = new Header($headers); + $this->header = new Header($headers, $this->config); return $body; } @@ -282,7 +289,7 @@ class Part { * @return bool */ public function isAttachment(): bool { - $valid_disposition = in_array(strtolower($this->disposition ?? ''), ClientManager::get('options.dispositions')); + $valid_disposition = in_array(strtolower($this->disposition ?? ''), $this->config->get('options.dispositions')); if ($this->type == IMAP::MESSAGE_TYPE_TEXT && ($this->ifdisposition == 0 || empty($this->disposition) || !$valid_disposition)) { if (($this->subtype == null || in_array((strtolower($this->subtype)), ["plain", "html"])) && $this->filename == null && $this->name == null) { @@ -305,4 +312,13 @@ class Part { return $this->header; } + /** + * Get the Config instance + * + * @return Config + */ + public function getConfig(): Config { + return $this->config; + } + } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/Query.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/Query.php index 727e641f0..bed64a95c 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/Query.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/Query.php @@ -18,7 +18,6 @@ use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use ReflectionException; use Webklex\PHPIMAP\Client; -use Webklex\PHPIMAP\ClientManager; use Webklex\PHPIMAP\Exceptions\AuthFailedException; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; use Webklex\PHPIMAP\Exceptions\EventNotFoundException; @@ -93,18 +92,19 @@ class Query { */ public function __construct(Client $client, array $extensions = []) { $this->setClient($client); + $config = $this->client->getConfig(); - $this->sequence = ClientManager::get('options.sequence', IMAP::ST_MSGN); - if (ClientManager::get('options.fetch') === IMAP::FT_PEEK) $this->leaveUnread(); + $this->sequence = $config->get('options.sequence', IMAP::ST_MSGN); + if ($config->get('options.fetch') === IMAP::FT_PEEK) $this->leaveUnread(); - if (ClientManager::get('options.fetch_order') === 'desc') { + if ($config->get('options.fetch_order') === 'desc') { $this->fetch_order = 'desc'; } else { $this->fetch_order = 'asc'; } - $this->date_format = ClientManager::get('date_format', 'd M y'); - $this->soft_fail = ClientManager::get('options.soft_fail', false); + $this->date_format = $config->get('date_format', 'd M y'); + $this->soft_fail = $config->get('options.soft_fail', false); $this->setExtensions($extensions); $this->query = new Collection(); @@ -164,7 +164,10 @@ class Query { if ($statement[1] === null) { $query .= $statement[0]; } else { - if (is_numeric($statement[1])) { + if (is_numeric($statement[1]) || ( + ($statement[0] === 'SINCE' || $statement[0] === 'BEFORE') && + $this->client->getConfig()->get('options.unescaped_search_dates', false) + )) { $query .= $statement[0] . ' ' . $statement[1]; } else { $query .= $statement[0] . ' "' . $statement[1] . '"'; @@ -190,7 +193,7 @@ class Query { * @throws ImapServerErrorException * @throws ResponseException */ - protected function search(): Collection { + public function search(): Collection { $this->generate_query(); try { @@ -235,6 +238,7 @@ class Query { $uids = $available_messages->forPage($this->page, $this->limit)->toArray(); $extensions = $this->getExtensions(); if (empty($extensions) === false && method_exists($this->client->getConnection(), "fetch")) { + // this polymorphic call is fine - the method exists at this point $extensions = $this->client->getConnection()->fetch($extensions, $uids, null, $this->sequence)->validatedData(); } $flags = $this->client->getConnection()->flags($uids, $this->sequence)->validatedData(); @@ -242,7 +246,7 @@ class Query { $contents = []; if ($this->getFetchBody()) { - $contents = $this->client->getConnection()->content($uids, "RFC822", $this->sequence)->validatedData(); + $contents = $this->client->getConnection()->content($uids, $this->client->rfc, $this->sequence)->validatedData(); } return [ @@ -314,7 +318,7 @@ class Query { if ($available_messages->count() > 0) { return $this->populate($available_messages); } - return MessageCollection::make([]); + return MessageCollection::make(); } catch (Exception $e) { throw new GetMessagesFailedException($e->getMessage(), 0, $e); } @@ -336,11 +340,12 @@ class Query { * @throws ResponseException */ protected function populate(Collection $available_messages): MessageCollection { - $messages = MessageCollection::make([]); + $messages = MessageCollection::make(); + $config = $this->client->getConfig(); $messages->total($available_messages->count()); - $message_key = ClientManager::get('options.message_key'); + $message_key = $config->get('options.message_key'); $raw_messages = $this->fetch($available_messages); @@ -395,8 +400,14 @@ class Query { * @throws ResponseException */ public function chunked(callable $callback, int $chunk_size = 10, int $start_chunk = 1): void { + $start_chunk = max($start_chunk,1); + $chunk_size = max($chunk_size,1); + $skipped_messages_count = $chunk_size * ($start_chunk-1); + $available_messages = $this->search(); - if (($available_messages_count = $available_messages->count()) > 0) { + $available_messages_count = max($available_messages->count() - $skipped_messages_count,0); + + if ($available_messages_count > 0) { $old_limit = $this->limit; $old_page = $this->page; @@ -640,7 +651,7 @@ class Query { * * @return $this */ - public function leaveUnread(): Query { + public function leaveUnread(): static { $this->setFetchOptions(IMAP::FT_PEEK); return $this; @@ -651,7 +662,7 @@ class Query { * * @return $this */ - public function markAsRead(): Query { + public function markAsRead(): static { $this->setFetchOptions(IMAP::FT_UID); return $this; @@ -663,7 +674,7 @@ class Query { * * @return $this */ - public function setSequence(int $sequence): Query { + public function setSequence(int $sequence): static { $this->sequence = $sequence; return $this; @@ -699,7 +710,7 @@ class Query { * * @return $this */ - public function limit(int $limit, int $page = 1): Query { + public function limit(int $limit, int $page = 1): static { if ($page >= 1) $this->page = $page; $this->limit = $limit; @@ -719,9 +730,9 @@ class Query { * Set all query parameters * @param array $query * - * @return Query + * @return $this */ - public function setQuery(array $query): Query { + public function setQuery(array $query): static { $this->query = new Collection($query); return $this; } @@ -739,9 +750,9 @@ class Query { * Set the raw query * @param string $raw_query * - * @return Query + * @return $this */ - public function setRawQuery(string $raw_query): Query { + public function setRawQuery(string $raw_query): static { $this->raw_query = $raw_query; return $this; } @@ -759,9 +770,9 @@ class Query { * Set all extensions that should be used * @param string[] $extensions * - * @return Query + * @return $this */ - public function setExtensions(array $extensions): Query { + public function setExtensions(array $extensions): static { $this->extensions = $extensions; if (count($this->extensions) > 0) { if (in_array("UID", $this->extensions) === false) { @@ -775,9 +786,9 @@ class Query { * Set the client instance * @param Client $client * - * @return Query + * @return $this */ - public function setClient(Client $client): Query { + public function setClient(Client $client): static { $this->client = $client; return $this; } @@ -795,9 +806,9 @@ class Query { * Set the fetch limit * @param int $limit * - * @return Query + * @return $this */ - public function setLimit(int $limit): Query { + public function setLimit(int $limit): static { $this->limit = $limit <= 0 ? null : $limit; return $this; } @@ -815,9 +826,9 @@ class Query { * Set the page * @param int $page * - * @return Query + * @return $this */ - public function setPage(int $page): Query { + public function setPage(int $page): static { $this->page = $page; return $this; } @@ -826,9 +837,9 @@ class Query { * Set the fetch option flag * @param int $fetch_options * - * @return Query + * @return $this */ - public function setFetchOptions(int $fetch_options): Query { + public function setFetchOptions(int $fetch_options): static { $this->fetch_options = $fetch_options; return $this; } @@ -837,9 +848,9 @@ class Query { * Set the fetch option flag * @param int $fetch_options * - * @return Query + * @return $this */ - public function fetchOptions(int $fetch_options): Query { + public function fetchOptions(int $fetch_options): static { return $this->setFetchOptions($fetch_options); } @@ -865,9 +876,9 @@ class Query { * Set the fetch body flag * @param boolean $fetch_body * - * @return Query + * @return $this */ - public function setFetchBody(bool $fetch_body): Query { + public function setFetchBody(bool $fetch_body): static { $this->fetch_body = $fetch_body; return $this; } @@ -876,9 +887,9 @@ class Query { * Set the fetch body flag * @param boolean $fetch_body * - * @return Query + * @return $this */ - public function fetchBody(bool $fetch_body): Query { + public function fetchBody(bool $fetch_body): static { return $this->setFetchBody($fetch_body); } @@ -895,9 +906,9 @@ class Query { * Set the fetch flag * @param bool $fetch_flags * - * @return Query + * @return $this */ - public function setFetchFlags(bool $fetch_flags): Query { + public function setFetchFlags(bool $fetch_flags): static { $this->fetch_flags = $fetch_flags; return $this; } @@ -906,9 +917,9 @@ class Query { * Set the fetch order * @param string $fetch_order * - * @return Query + * @return $this */ - public function setFetchOrder(string $fetch_order): Query { + public function setFetchOrder(string $fetch_order): static { $fetch_order = strtolower($fetch_order); if (in_array($fetch_order, ['asc', 'desc'])) { @@ -922,9 +933,9 @@ class Query { * Set the fetch order * @param string $fetch_order * - * @return Query + * @return $this */ - public function fetchOrder(string $fetch_order): Query { + public function fetchOrder(string $fetch_order): static { return $this->setFetchOrder($fetch_order); } @@ -940,36 +951,36 @@ class Query { /** * Set the fetch order to ascending * - * @return Query + * @return $this */ - public function setFetchOrderAsc(): Query { + public function setFetchOrderAsc(): static { return $this->setFetchOrder('asc'); } /** * Set the fetch order to ascending * - * @return Query + * @return $this */ - public function fetchOrderAsc(): Query { + public function fetchOrderAsc(): static { return $this->setFetchOrderAsc(); } /** * Set the fetch order to descending * - * @return Query + * @return $this */ - public function setFetchOrderDesc(): Query { + public function setFetchOrderDesc(): static { return $this->setFetchOrder('desc'); } /** * Set the fetch order to descending * - * @return Query + * @return $this */ - public function fetchOrderDesc(): Query { + public function fetchOrderDesc(): static { return $this->setFetchOrderDesc(); } @@ -977,9 +988,9 @@ class Query { * Set soft fail mode * @var boolean $state * - * @return Query + * @return $this */ - public function softFail(bool $state = true): Query { + public function softFail(bool $state = true): static { return $this->setSoftFail($state); } @@ -987,9 +998,9 @@ class Query { * Set soft fail mode * * @var boolean $state - * @return Query + * @return $this */ - public function setSoftFail(bool $state = true): Query { + public function setSoftFail(bool $state = true): static { $this->soft_fail = $state; return $this; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/WhereQuery.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/WhereQuery.php index b218e5456..5636cf355 100755 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/WhereQuery.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Query/WhereQuery.php @@ -132,7 +132,7 @@ class WhereQuery extends Query { * $query->where(["FROM" => "someone@email.tld", "SEEN"]); * $query->where("FROM", "someone@email.tld")->where("SEEN"); */ - public function where(mixed $criteria, mixed $value = null): WhereQuery { + public function where(mixed $criteria, mixed $value = null): static { if (is_array($criteria)) { foreach ($criteria as $key => $value) { if (is_numeric($key)) { @@ -155,7 +155,7 @@ class WhereQuery extends Query { * * @throws InvalidWhereQueryCriteriaException */ - protected function push_search_criteria(string $criteria, mixed $value){ + protected function push_search_criteria(string $criteria, mixed $value): void { $criteria = $this->validate_criteria($criteria); $value = $this->parse_value($value); @@ -171,7 +171,7 @@ class WhereQuery extends Query { * * @return $this */ - public function orWhere(Closure $closure = null): WhereQuery { + public function orWhere(?Closure $closure = null): static { $this->query->push(['OR']); if ($closure !== null) $closure($this); @@ -183,7 +183,7 @@ class WhereQuery extends Query { * * @return $this */ - public function andWhere(Closure $closure = null): WhereQuery { + public function andWhere(?Closure $closure = null): static { $this->query->push(['AND']); if ($closure !== null) $closure($this); @@ -191,38 +191,38 @@ class WhereQuery extends Query { } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereAll(): WhereQuery { + public function whereAll(): static { return $this->where('ALL'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereAnswered(): WhereQuery { + public function whereAnswered(): static { return $this->where('ANSWERED'); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereBcc(string $value): WhereQuery { + public function whereBcc(string $value): static { return $this->where('BCC', $value); } /** * @param mixed $value - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException * @throws MessageSearchValidationException */ - public function whereBefore(mixed $value): WhereQuery { + public function whereBefore(mixed $value): static { $date = $this->parse_date($value); return $this->where('BEFORE', $date); } @@ -230,121 +230,121 @@ class WhereQuery extends Query { /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereBody(string $value): WhereQuery { + public function whereBody(string $value): static { return $this->where('BODY', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereCc(string $value): WhereQuery { + public function whereCc(string $value): static { return $this->where('CC', $value); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereDeleted(): WhereQuery { + public function whereDeleted(): static { return $this->where('DELETED'); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereFlagged(string $value): WhereQuery { + public function whereFlagged(string $value): static { return $this->where('FLAGGED', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereFrom(string $value): WhereQuery { + public function whereFrom(string $value): static { return $this->where('FROM', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereKeyword(string $value): WhereQuery { + public function whereKeyword(string $value): static { return $this->where('KEYWORD', $value); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereNew(): WhereQuery { + public function whereNew(): static { return $this->where('NEW'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereNot(): WhereQuery { + public function whereNot(): static { return $this->where('NOT'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereOld(): WhereQuery { + public function whereOld(): static { return $this->where('OLD'); } /** * @param mixed $value * - * @return WhereQuery + * @return $this * @throws MessageSearchValidationException * @throws InvalidWhereQueryCriteriaException */ - public function whereOn(mixed $value): WhereQuery { + public function whereOn(mixed $value): static { $date = $this->parse_date($value); return $this->where('ON', $date); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereRecent(): WhereQuery { + public function whereRecent(): static { return $this->where('RECENT'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereSeen(): WhereQuery { + public function whereSeen(): static { return $this->where('SEEN'); } /** * @param mixed $value * - * @return WhereQuery + * @return $this * @throws MessageSearchValidationException * @throws InvalidWhereQueryCriteriaException */ - public function whereSince(mixed $value): WhereQuery { + public function whereSince(mixed $value): static { $date = $this->parse_date($value); return $this->where('SINCE', $date); } @@ -352,88 +352,88 @@ class WhereQuery extends Query { /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereSubject(string $value): WhereQuery { + public function whereSubject(string $value): static { return $this->where('SUBJECT', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereText(string $value): WhereQuery { + public function whereText(string $value): static { return $this->where('TEXT', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereTo(string $value): WhereQuery { + public function whereTo(string $value): static { return $this->where('TO', $value); } /** * @param string $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUnkeyword(string $value): WhereQuery { + public function whereUnkeyword(string $value): static { return $this->where('UNKEYWORD', $value); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUnanswered(): WhereQuery { + public function whereUnanswered(): static { return $this->where('UNANSWERED'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUndeleted(): WhereQuery { + public function whereUndeleted(): static { return $this->where('UNDELETED'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUnflagged(): WhereQuery { + public function whereUnflagged(): static { return $this->where('UNFLAGGED'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUnseen(): WhereQuery { + public function whereUnseen(): static { return $this->where('UNSEEN'); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereNoXSpam(): WhereQuery { + public function whereNoXSpam(): static { return $this->where("CUSTOM X-Spam-Flag NO"); } /** - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereIsXSpam(): WhereQuery { + public function whereIsXSpam(): static { return $this->where("CUSTOM X-Spam-Flag YES"); } @@ -442,10 +442,10 @@ class WhereQuery extends Query { * @param $header * @param $value * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereHeader($header, $value): WhereQuery { + public function whereHeader($header, $value): static { return $this->where("CUSTOM HEADER $header $value"); } @@ -453,10 +453,10 @@ class WhereQuery extends Query { * Search for a specific message id * @param $messageId * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereMessageId($messageId): WhereQuery { + public function whereMessageId($messageId): static { return $this->whereHeader("Message-ID", $messageId); } @@ -464,20 +464,20 @@ class WhereQuery extends Query { * Search for a specific message id * @param $messageId * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereInReplyTo($messageId): WhereQuery { + public function whereInReplyTo($messageId): static { return $this->whereHeader("In-Reply-To", $messageId); } /** * @param $country_code * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereLanguage($country_code): WhereQuery { + public function whereLanguage($country_code): static { return $this->where("Content-Language $country_code"); } @@ -486,10 +486,10 @@ class WhereQuery extends Query { * * @param int|string $uid * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUid(int|string $uid): WhereQuery { + public function whereUid(int|string $uid): static { return $this->where('UID', $uid); } @@ -498,10 +498,10 @@ class WhereQuery extends Query { * * @param array $uids * - * @return WhereQuery + * @return $this * @throws InvalidWhereQueryCriteriaException */ - public function whereUidIn(array $uids): WhereQuery { + public function whereUidIn(array $uids): static { $uids = implode(',', $uids); return $this->where('UID', $uids); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Structure.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Structure.php index 745a6234f..11f4cd66e 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Structure.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Structure.php @@ -50,11 +50,11 @@ class Structure { public array $parts = []; /** - * Config holder + * Options holder * - * @var array $config + * @var array $options */ - protected array $config = []; + protected array $options = []; /** * Structure constructor. @@ -67,7 +67,7 @@ class Structure { public function __construct($raw_structure, Header $header) { $this->raw = $raw_structure; $this->header = $header; - $this->config = ClientManager::get('options'); + $this->options = $header->getConfig()->get('options'); $this->parse(); } @@ -110,12 +110,17 @@ class Structure { $headers = substr($context, 0, strlen($body) * -1); $body = substr($body, 0, -2); - $headers = new Header($headers); + $config = $this->header->getConfig(); + $headers = new Header($headers, $config); if (($boundary = $headers->getBoundary()) !== null) { - return $this->detectParts($boundary, $body, $part_number); + $parts = $this->detectParts($boundary, $body, $part_number); + + if(count($parts) > 1) { + return $parts; + } } - return [new Part($body, $headers, $part_number)]; + return [new Part($body, $this->header->getConfig(), $headers, $part_number)]; } /** @@ -127,7 +132,10 @@ class Structure { * @throws InvalidMessageDateException */ private function detectParts(string $boundary, string $context, int $part_number = 0): array { - $base_parts = explode( $boundary, $context); + $base_parts = explode( "--".$boundary, $context); + if(count($base_parts) == 0) { + $base_parts = explode($boundary, $context); + } $final_parts = []; foreach($base_parts as $ctx) { $ctx = substr($ctx, 2); @@ -159,6 +167,6 @@ class Structure { return $this->detectParts($boundary, $this->raw); } - return [new Part($this->raw, $this->header)]; + return [new Part($this->raw, $this->header->getConfig(), $this->header)]; } } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/AttachmentMask.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/AttachmentMask.php index d79b948aa..2559c5b9b 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/AttachmentMask.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/AttachmentMask.php @@ -18,6 +18,7 @@ use Webklex\PHPIMAP\Attachment; * Class AttachmentMask * * @package Webklex\PHPIMAP\Support\Masks + * @mixin Attachment */ class AttachmentMask extends Mask { diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/MessageMask.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/MessageMask.php index 4cc3d5c05..aa3623f91 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/MessageMask.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Support/Masks/MessageMask.php @@ -19,6 +19,7 @@ use Webklex\PHPIMAP\Message; * Class MessageMask * * @package Webklex\PHPIMAP\Support\Masks + * @mixin Message */ class MessageMask extends Mask { diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/Traits/HasEvents.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/Traits/HasEvents.php index 3b6902edc..6dc382b76 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/Traits/HasEvents.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/Traits/HasEvents.php @@ -74,4 +74,13 @@ trait HasEvents { return $this->events; } + /** + * Dispatch a specific event. + * @throws EventNotFoundException + */ + public function dispatch(string $section, string $event, mixed ...$args): void { + $event = $this->getEvent($section, $event); + $event::dispatch(...$args); + } + } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/src/config/imap.php b/lam/lib/3rdParty/composer/webklex/php-imap/src/config/imap.php index 590d27cbf..abf8e6e62 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/src/config/imap.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/src/config/imap.php @@ -35,6 +35,32 @@ return [ */ 'default' => 'default', + /* + |-------------------------------------------------------------------------- + | Security options + |-------------------------------------------------------------------------- + | + | You can enable or disable certain security features here by setting them to true or false to enable or disable + | them. + | -detect_spoofing: + | Detect spoofing attempts by checking the message sender against the message headers. + | Default TRUE + | -detect_spoofing_exception: + | Throw an exception if a spoofing attempt is detected. + | Default FALSE + | -sanitize_filenames: + | Sanitize attachment filenames by removing any unwanted and potentially dangerous characters. This is not a + | 100% secure solution, but it should help to prevent some common attacks. Please sanitize the filenames + | again if you need a more secure solution. + | Default TRUE + | + */ + 'security' => [ + "detect_spoofing" => true, + "detect_spoofing_exception" => false, + "sanitize_filenames" => true, + ], + /* |-------------------------------------------------------------------------- | Available accounts @@ -55,6 +81,7 @@ return [ 'username' => 'root@example.com', 'password' => '', 'authentication' => null, + 'rfc' => 'RFC822', // If you are using iCloud, you might want to set this to 'BODY' 'proxy' => [ 'socket' => null, 'request_fulluri' => false, @@ -136,9 +163,6 @@ return [ | error: "Kerberos error: No credentials cache | file found (try running kinit) (...)" | or ['GSSAPI','PLAIN'] if you are using outlook mail - | -Decoder options (currently only the message subject and attachment name decoder can be set) - | 'utf-8' - Uses imap_utf8($string) to decode a string - | 'mimeheader' - Uses mb_decode_mimeheader($string) to decode a string | */ 'options' => [ @@ -150,6 +174,7 @@ return [ 'soft_fail' => false, 'rfc822' => true, 'debug' => false, + 'unescaped_search_dates' => false, 'uid_cache' => true, // 'fallback_date' => "01.01.1970 00:00:00", 'boundary' => '/boundary=(.*?(?=;)|(.*))/i', @@ -163,12 +188,35 @@ return [ "sent" => "INBOX/Sent", "trash" => "INBOX/Trash", ], - 'decoder' => [ + 'open' => [ + // 'DISABLE_AUTHENTICATOR' => 'GSSAPI' + ] + ], + + /** + * |-------------------------------------------------------------------------- + * | Available decoding options + * |-------------------------------------------------------------------------- + * | + * | Available php imap config parameters are listed below + * | -options: Decoder options (currently only the message subject and attachment name decoder can be set) + * | 'utf-8' - Uses imap_utf8($string) to decode a string + * | 'mimeheader' - Uses mb_decode_mimeheader($string) to decode a string + * | -decoder: Decoder to be used. Can be replaced by custom decoders if needed. + * | 'header' - HeaderDecoder + * | 'message' - MessageDecoder + * | 'attachment' - AttachmentDecoder + */ + 'decoding' => [ + 'options' => [ + 'header' => 'utf-8', // mimeheader 'message' => 'utf-8', // mimeheader 'attachment' => 'utf-8' // mimeheader ], - 'open' => [ - // 'DISABLE_AUTHENTICATOR' => 'GSSAPI' + 'decoder' => [ + 'header' => \Webklex\PHPIMAP\Decoder\HeaderDecoder::class, + 'message' => \Webklex\PHPIMAP\Decoder\MessageDecoder::class, + 'attachment' => \Webklex\PHPIMAP\Decoder\AttachmentDecoder::class ] ], diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/AttachmentTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/AttachmentTest.php new file mode 100644 index 000000000..c9ba2f173 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/AttachmentTest.php @@ -0,0 +1,37 @@ +getFixture("attachment_encoded_filename.eml"); + $this->attachment = $message->getAttachments()->first(); + } + /** + * @dataProvider decodeNameDataProvider + */ + public function testDecodeName(string $input, string $output): void + { + $name = $this->attachment->decodeName($input); + $this->assertEquals($output, $name); + } + + public function decodeNameDataProvider(): array + { + return [ + ['../../../../../../../../../../../var/www/shell.php', 'varwwwshell.php'], + ['test..xml', 'test.xml'], + [chr(0), ''], + ['C:\\file.txt', 'Cfile.txt'], + ]; + } +} diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientManagerTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientManagerTest.php index 80ec4ceb8..e7910cf1d 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientManagerTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientManagerTest.php @@ -15,6 +15,7 @@ namespace Tests; use PHPUnit\Framework\TestCase; use Webklex\PHPIMAP\Client; use Webklex\PHPIMAP\ClientManager; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\MaskNotFoundException; use Webklex\PHPIMAP\IMAP; @@ -38,10 +39,12 @@ class ClientManagerTest extends TestCase { * @return void */ public function testConfigAccessorAccount(): void { - self::assertSame("default", ClientManager::get("default")); - self::assertSame("d-M-Y", ClientManager::get("date_format")); - self::assertSame(IMAP::FT_PEEK, ClientManager::get("options.fetch")); - self::assertSame([], ClientManager::get("options.open")); + $config = $this->cm->getConfig(); + self::assertInstanceOf(Config::class, $config); + self::assertSame("default", $config->get("default")); + self::assertSame("d-M-Y", $config->get("date_format")); + self::assertSame(IMAP::FT_PEEK, $config->get("options.fetch")); + self::assertSame([], $config->get("options.open")); } /** @@ -59,12 +62,12 @@ class ClientManagerTest extends TestCase { * @throws MaskNotFoundException */ public function testAccountAccessor(): void { - self::assertSame("default", $this->cm->getDefaultAccount()); + self::assertSame("default", $this->cm->getConfig()->getDefaultAccount()); self::assertNotEmpty($this->cm->account("default")); - $this->cm->setDefaultAccount("foo"); - self::assertSame("foo", $this->cm->getDefaultAccount()); - $this->cm->setDefaultAccount("default"); + $this->cm->getConfig()->setDefaultAccount("foo"); + self::assertSame("foo", $this->cm->getConfig()->getDefaultAccount()); + $this->cm->getConfig()->setDefaultAccount("default"); } /** @@ -82,10 +85,10 @@ class ClientManagerTest extends TestCase { ]; $cm = new ClientManager($config); - self::assertSame("foo", $cm->getDefaultAccount()); + self::assertSame("foo", $cm->getConfig()->getDefaultAccount()); self::assertInstanceOf(Client::class, $cm->account("foo")); - self::assertSame(IMAP::ST_MSGN, $cm->get("options.fetch")); - self::assertSame(false, is_array($cm->get("options.open"))); + self::assertSame(IMAP::ST_MSGN, $cm->getConfig()->get("options.fetch")); + self::assertSame(false, is_array($cm->getConfig()->get("options.open"))); } } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientTest.php index 8d9f8e66d..73a01be70 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ClientTest.php @@ -15,6 +15,7 @@ namespace Tests; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Webklex\PHPIMAP\Client; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol; use Webklex\PHPIMAP\Connection\Protocols\Response; use Webklex\PHPIMAP\Exceptions\AuthFailedException; @@ -42,18 +43,22 @@ class ClientTest extends TestCase { * @throws MaskNotFoundException */ public function setUp(): void { - $this->client = new Client([ - 'protocol' => 'imap', - 'encryption' => 'ssl', - 'username' => 'foo@domain.tld', - 'password' => 'bar', - 'proxy' => [ - 'socket' => null, - 'request_fulluri' => false, - 'username' => null, - 'password' => null, - ], - ]); + $config = Config::make([ + "accounts" => [ + "default" => [ + 'protocol' => 'imap', + 'encryption' => 'ssl', + 'username' => 'foo@domain.tld', + 'password' => 'bar', + 'proxy' => [ + 'socket' => null, + 'request_fulluri' => false, + 'username' => null, + 'password' => null, + ], + ]] + ]); + $this->client = new Client($config); } /** @@ -78,6 +83,40 @@ class ClientTest extends TestCase { self::assertArrayHasKey("new", $this->client->getDefaultEvents("message")); } + /** + * @throws MaskNotFoundException + */ + public function testClientClone(): void { + $config = Config::make([ + "accounts" => [ + "default" => [ + 'host' => 'example.com', + 'port' => 993, + 'protocol' => 'imap', //might also use imap, [pop3 or nntp (untested)] + 'encryption' => 'ssl', // Supported: false, 'ssl', 'tls' + 'validate_cert' => true, + 'username' => 'root@example.com', + 'password' => 'foo', + 'authentication' => null, + 'rfc' => 'RFC822', // If you are using iCloud, you might want to set this to 'BODY' + 'proxy' => [ + 'socket' => null, + 'request_fulluri' => false, + 'username' => null, + 'password' => null, + ], + "timeout" => 30, + "extensions" => [] + ]] + ]); + $client = new Client($config); + $clone = $client->clone(); + self::assertInstanceOf(Client::class, $clone); + self::assertSame($client->getConfig(), $clone->getConfig()); + self::assertSame($client->getAccountConfig(), $clone->getAccountConfig()); + self::assertSame($client->host, $clone->host); + } + public function testClientLogout(): void { $this->createNewProtocolMockup(); @@ -274,18 +313,19 @@ class ClientTest extends TestCase { } public function testClientConfig(): void { - $config = $this->client->getConfig(); + $config = $this->client->getConfig()->get("accounts.".$this->client->getConfig()->getDefaultAccount()); self::assertSame("foo@domain.tld", $config["username"]); self::assertSame("bar", $config["password"]); self::assertSame("localhost", $config["host"]); self::assertSame(true, $config["validate_cert"]); self::assertSame(993, $config["port"]); - $this->client->setConfig([ - "host" => "domain.tld", - 'password' => 'bar', - ]); - $config = $this->client->getConfig(); + $this->client->getConfig()->set("accounts.".$this->client->getConfig()->getDefaultAccount(), [ + "host" => "domain.tld", + 'password' => 'bar', + ]); + $config = $this->client->getConfig()->get("accounts.".$this->client->getConfig()->getDefaultAccount()); + self::assertSame("bar", $config["password"]); self::assertSame("domain.tld", $config["host"]); self::assertSame(true, $config["validate_cert"]); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/HeaderTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/HeaderTest.php index 7afec065b..0ec60c6cf 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/HeaderTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/HeaderTest.php @@ -16,12 +16,25 @@ use Carbon\Carbon; use PHPUnit\Framework\TestCase; use Webklex\PHPIMAP\Address; use Webklex\PHPIMAP\Attribute; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; use Webklex\PHPIMAP\Header; use Webklex\PHPIMAP\IMAP; class HeaderTest extends TestCase { + /** @var Config $config */ + protected Config $config; + + /** + * Setup the test environment. + * + * @return void + */ + public function setUp(): void { + $this->config = Config::make(); + } + /** * Test parsing email headers * @@ -35,9 +48,9 @@ class HeaderTest extends TestCase { $raw_header = substr($email, 0, strpos($email, "\r\n\r\n")); - $header = new Header($raw_header); + $header = new Header($raw_header, $this->config); $subject = $header->get("subject"); - $returnPath = $header->get("Return-Path"); + $returnPath = $header->get("return_path"); /** @var Carbon $date */ $date = $header->get("date")->first(); /** @var Address $from */ @@ -46,14 +59,21 @@ class HeaderTest extends TestCase { $to = $header->get("to")->first(); self::assertSame($raw_header, $header->raw); + self::assertSame([ + 0 => 'from mx.domain.tld by localhost with LMTP id SABVMNfGqWP+PAAA0J78UA (envelope-from ) for ; Mon, 26 Dec 2022 17:07:51 +0100', + 1 => 'from localhost (localhost [127.0.0.1]) by mx.domain.tld (Postfix) with ESMTP id C3828140227 for ; Mon, 26 Dec 2022 17:07:51 +0100 (CET)', + 2 => 'from mx.domain.tld ([127.0.0.1]) by localhost (mx.domain.tld [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JcIS9RuNBTNx for ; Mon, 26 Dec 2022 17:07:21 +0100 (CET)', + 3 => 'from smtp.github.com (out-26.smtp.github.com [192.30.252.209]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx.domain.tld (Postfix) with ESMTPS id 6410B13FEB2 for ; Mon, 26 Dec 2022 17:07:21 +0100 (CET)', + 4 => 'from github-lowworker-891b8d2.va3-iad.github.net (github-lowworker-891b8d2.va3-iad.github.net [10.48.109.104]) by smtp.github.com (Postfix) with ESMTP id 176985E0200 for ; Mon, 26 Dec 2022 08:07:14 -0800 (PST)', + ], $header->get("received")->toArray()); self::assertInstanceOf(Attribute::class, $subject); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString()); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$header->subject); - self::assertSame("", $returnPath->toString()); + self::assertSame("noreply@github.com", $returnPath->toString()); self::assertSame("return_path", $returnPath->getName()); self::assertSame("-4.299", (string)$header->get("X-Spam-Score")); self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$header->get("Message-ID")); - self::assertSame(6, $header->get("received")->count()); + self::assertSame(5, $header->get("received")->count()); self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$header->get("priority")()); self::assertSame("Username", $from->personal); @@ -71,7 +91,7 @@ class HeaderTest extends TestCase { self::assertInstanceOf(Carbon::class, $date); self::assertSame("2022-12-26 08:07:14 GMT-0800", $date->format("Y-m-d H:i:s T")); - self::assertSame(48, count($header->getAttributes())); + self::assertSame(51, count($header->getAttributes())); } public function testRfc822ParseHeaders() { @@ -80,9 +100,9 @@ class HeaderTest extends TestCase { ->onlyMethods([]) ->getMock(); - $config = new \ReflectionProperty($mock, 'config'); + $config = new \ReflectionProperty($mock, 'options'); $config->setAccessible(true); - $config->setValue($mock, ['rfc822' => true]); + $config->setValue($mock, $this->config->get("options")); $mockHeader = "Content-Type: text/csv; charset=WINDOWS-1252; name*0=\"TH_Is_a_F ile name example 20221013.c\"; name*1=sv\r\nContent-Transfer-Encoding: quoted-printable\r\nContent-Disposition: attachment; filename*0=\"TH_Is_a_F ile name example 20221013.c\"; filename*1=\"sv\"\r\n"; @@ -139,4 +159,46 @@ class HeaderTest extends TestCase { $this->assertArrayHasKey('attribute_test', $mock->getAttributes()); $this->assertEquals('attribute_test_value', $mock->get('attribute_test')); } + + public function testExtractHeaderExtensions2() { + $mock = $this->getMockBuilder(Header::class) + ->disableOriginalConstructor() + ->onlyMethods([]) + ->getMock(); + + $method = new \ReflectionMethod($mock, 'extractHeaderExtensions'); + $method->setAccessible(true); + + $mockAttributes = [ + 'content_type' => new Attribute('content_type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; name="=?utf-8?Q?=D0=A2=D0=B8=D0=BF=D0=BE=D0=B2=D0=BE=D0=B9_?= =?utf-8?Q?=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82_=D0=BF?= =?utf-8?Q?=D0=BE=D1=82=D1=80=D0=B5=D0=B1=D0=BB=D0=B5=D0=BD?= =?utf-8?Q?=D0=B8=D1=8F_=D1=8D=D0=BB=D0=B5=D0=BA=D1=82?= =?utf-8?Q?=D1=80=D0=BE=D1=8D=D0=BD=D0=B5=D1=80=D0=B3=D0=B8=D0=B8_=D0=B2_?= =?utf-8?Q?=D0=9A=D0=9F_=D0=97=D0=B2=D0=B5=D0=B7=D0=B4?= =?utf-8?Q?=D0=BD=D1=8B=D0=B9=2Exlsx?="'), + 'content_transfer_encoding' => new Attribute('content_transfer_encoding', 'base64'), + 'content_disposition' => new Attribute('content_disposition', 'attachment; name*0*=utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20; name*1*=%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF; name*2*=%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD; name*3*=%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82; name*4*=%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8; name*5*=%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97%D0%B2%D0%B5%D0%B7%D0%B4; name*6*=%D0%BD%D1%8B%D0%B9.xlsx; filename*0*=utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20; filename*1*=%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF; filename*2*=%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD; filename*3*=%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82; filename*4*=%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8; filename*5*=%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97; filename*6*=%D0%B2%D0%B5%D0%B7%D0%B4%D0%BD%D1%8B%D0%B9.xlsx; attribute_test=attribute_test_value'), + ]; + + $attributes = new \ReflectionProperty($mock, 'attributes'); + $attributes->setAccessible(true); + $attributes->setValue($mock, $mockAttributes); + + $method->invoke($mock); + + $this->assertArrayHasKey('filename', $mock->getAttributes()); + $this->assertArrayNotHasKey('filename*0', $mock->getAttributes()); + $this->assertEquals('utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97%D0%B2%D0%B5%D0%B7%D0%B4%D0%BD%D1%8B%D0%B9.xlsx', $mock->get('filename')); + + $this->assertArrayHasKey('name', $mock->getAttributes()); + $this->assertArrayNotHasKey('name*0', $mock->getAttributes()); + $this->assertEquals('=?utf-8?Q?=D0=A2=D0=B8=D0=BF=D0=BE=D0=B2=D0=BE=D0=B9_?= =?utf-8?Q?=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82_=D0=BF?= =?utf-8?Q?=D0=BE=D1=82=D1=80=D0=B5=D0=B1=D0=BB=D0=B5=D0=BD?= =?utf-8?Q?=D0=B8=D1=8F_=D1=8D=D0=BB=D0=B5=D0=BA=D1=82?= =?utf-8?Q?=D1=80=D0=BE=D1=8D=D0=BD=D0=B5=D1=80=D0=B3=D0=B8=D0=B8_=D0=B2_?= =?utf-8?Q?=D0=9A=D0=9F_=D0=97=D0=B2=D0=B5=D0=B7=D0=B4?= =?utf-8?Q?=D0=BD=D1=8B=D0=B9=2Exlsx?=', $mock->get('name')); + + $this->assertArrayHasKey('content_type', $mock->getAttributes()); + $this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $mock->get('content_type')->last()); + + $this->assertArrayHasKey('content_transfer_encoding', $mock->getAttributes()); + $this->assertEquals('base64', $mock->get('content_transfer_encoding')); + + $this->assertArrayHasKey('content_disposition', $mock->getAttributes()); + $this->assertEquals('attachment', $mock->get('content_disposition')->last()); + + $this->assertArrayHasKey('attribute_test', $mock->getAttributes()); + $this->assertEquals('attribute_test_value', $mock->get('attribute_test')); + } } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ImapProtocolTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ImapProtocolTest.php index 4d7443327..30f3a200d 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/ImapProtocolTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/ImapProtocolTest.php @@ -13,11 +13,24 @@ namespace Tests; use PHPUnit\Framework\TestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; class ImapProtocolTest extends TestCase { + /** @var Config $config */ + protected Config $config; + + /** + * Setup the test environment. + * + * @return void + */ + public function setUp(): void { + $this->config = Config::make(); + } + /** * ImapProtocol test @@ -26,7 +39,7 @@ class ImapProtocolTest extends TestCase { */ public function testImapProtocol(): void { - $protocol = new ImapProtocol(false); + $protocol = new ImapProtocol($this->config, false); self::assertSame(false, $protocol->getCertValidation()); self::assertSame("", $protocol->getEncryption()); @@ -35,5 +48,17 @@ class ImapProtocolTest extends TestCase { self::assertSame(true, $protocol->getCertValidation()); self::assertSame("ssl", $protocol->getEncryption()); + + $protocol->setSslOptions([ + 'verify_peer' => true, + 'cafile' => '/dummy/path/for/testing', + 'peer_fingerprint' => ['md5' => 40], + ]); + + self::assertSame([ + 'verify_peer' => true, + 'cafile' => '/dummy/path/for/testing', + 'peer_fingerprint' => ['md5' => 40], + ], $protocol->getSslOptions()); } } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/MessageTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/MessageTest.php index 3f8549182..0ce55cd08 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/MessageTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/MessageTest.php @@ -18,6 +18,7 @@ use ReflectionException; use Webklex\PHPIMAP\Attachment; use Webklex\PHPIMAP\Attribute; use Webklex\PHPIMAP\Client; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Connection\Protocols\Response; use Webklex\PHPIMAP\Exceptions\EventNotFoundException; use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; @@ -51,21 +52,24 @@ class MessageTest extends TestCase { * Setup the test environment. * * @return void - * @throws MaskNotFoundException */ public function setUp(): void { - $this->client = new Client([ - 'protocol' => 'imap', - 'encryption' => 'ssl', - 'username' => 'foo@domain.tld', - 'password' => 'bar', - 'proxy' => [ - 'socket' => null, - 'request_fulluri' => false, - 'username' => null, - 'password' => null, - ], - ]); + $config = Config::make([ + "accounts" => [ + "default" => [ + 'protocol' => 'imap', + 'encryption' => 'ssl', + 'username' => 'foo@domain.tld', + 'password' => 'bar', + 'proxy' => [ + 'socket' => null, + 'request_fulluri' => false, + 'username' => null, + 'password' => null, + ], + ]] + ]); + $this->client = new Client($config); } /** @@ -116,11 +120,11 @@ class MessageTest extends TestCase { self::assertInstanceOf(Attribute::class, $subject); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString()); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$message->subject); - self::assertSame("", $returnPath->toString()); + self::assertSame("noreply@github.com", $returnPath->toString()); self::assertSame("return_path", $returnPath->getName()); self::assertSame("-4.299", (string)$message->get("X-Spam-Score")); self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$message->get("Message-ID")); - self::assertSame(6, $message->get("received")->count()); + self::assertSame(5, $message->get("received")->count()); self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$message->get("priority")()); } @@ -178,11 +182,11 @@ class MessageTest extends TestCase { self::assertInstanceOf(Attribute::class, $subject); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString()); self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$message->subject); - self::assertSame("", $returnPath->toString()); + self::assertSame("noreply@github.com", $returnPath->toString()); self::assertSame("return_path", $returnPath->getName()); self::assertSame("-4.299", (string)$message->get("X-Spam-Score")); self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$message->get("Message-ID")); - self::assertSame(6, $message->get("received")->count()); + self::assertSame(5, $message->get("received")->count()); self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$message->get("priority")()); self::assertNull($message->getClient()); @@ -197,11 +201,11 @@ class MessageTest extends TestCase { self::assertInstanceOf(Attribute::class, $subject); self::assertSame("ogqMVHhz7swLaq2PfSWsZj0k99w8wtMbrb4RuHdNg53i76B7icIIM0zIWpwGFtnk", $subject->toString()); self::assertSame("ogqMVHhz7swLaq2PfSWsZj0k99w8wtMbrb4RuHdNg53i76B7icIIM0zIWpwGFtnk", (string)$message->subject); - self::assertSame("", $returnPath->toString()); + self::assertSame("someone@domain.tld", $returnPath->toString()); self::assertSame("return_path", $returnPath->getName()); self::assertSame("1.103", (string)$message->get("X-Spam-Score")); self::assertSame("d3a5e91963cb805cee975687d5acb1c6@swift.generated", (string)$message->get("Message-ID")); - self::assertSame(5, $message->get("received")->count()); + self::assertSame(4, $message->get("received")->count()); self::assertSame(IMAP::MESSAGE_PRIORITY_HIGHEST, (int)$message->get("priority")()); self::assertNull($message->getClient()); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/PartTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/PartTest.php index f4653519e..8543c46b2 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/PartTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/PartTest.php @@ -14,6 +14,7 @@ namespace Tests; use Carbon\Carbon; use PHPUnit\Framework\TestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException; use Webklex\PHPIMAP\Header; @@ -23,6 +24,18 @@ use Webklex\PHPIMAP\IMAP; class PartTest extends TestCase { + /** @var Config $config */ + protected Config $config; + + /** + * Setup the test environment. + * + * @return void + */ + public function setUp(): void { + $this->config = Config::make(); + } + /** * Test parsing a text Part * @throws InvalidMessageDateException @@ -31,8 +44,8 @@ class PartTest extends TestCase { $raw_headers = "Content-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n"; $raw_body = "\r\nAny updates?"; - $headers = new Header($raw_headers); - $part = new Part($raw_body, $headers, 0); + $headers = new Header($raw_headers, $this->config); + $part = new Part($raw_body, $this->config, $headers, 0); self::assertSame("UTF-8", $part->charset); self::assertSame("text/plain", $part->content_type); @@ -53,8 +66,8 @@ class PartTest extends TestCase { $raw_headers = "Content-Type: text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n"; $raw_body = "\r\n

    \r\n

    Any updates?

    "; - $headers = new Header($raw_headers); - $part = new Part($raw_body, $headers, 0); + $headers = new Header($raw_headers, $this->config); + $part = new Part($raw_body, $this->config, $headers, 0); self::assertSame("UTF-8", $part->charset); self::assertSame("text/html", $part->content_type); @@ -75,8 +88,8 @@ class PartTest extends TestCase { $raw_headers = "Content-Type: application/octet-stream; name=6mfFxiU5Yhv9WYJx.txt\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=6mfFxiU5Yhv9WYJx.txt\r\n"; $raw_body = "em5rNTUxTVAzVFAzV1BwOUtsMWduTEVycldFZ2tKRkF0dmFLcWtUZ3JrM2RLSThkWDM4WVQ4QmFW\r\neFJjT0VSTg=="; - $headers = new Header($raw_headers); - $part = new Part($raw_body, $headers, 0); + $headers = new Header($raw_headers, $this->config); + $part = new Part($raw_body, $this->config, $headers, 0); self::assertSame("", $part->charset); self::assertSame("application/octet-stream", $part->content_type); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/StructureTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/StructureTest.php index a1df098b0..22d71bbf5 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/StructureTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/StructureTest.php @@ -13,6 +13,7 @@ namespace Tests; use PHPUnit\Framework\TestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException; use Webklex\PHPIMAP\Header; @@ -20,6 +21,18 @@ use Webklex\PHPIMAP\Structure; class StructureTest extends TestCase { + /** @var Config $config */ + protected Config $config; + + /** + * Setup the test environment. + * + * @return void + */ + public function setUp(): void { + $this->config = Config::make(); + } + /** * Test parsing email headers * @@ -35,7 +48,7 @@ class StructureTest extends TestCase { $raw_header = substr($email, 0, strpos($email, "\r\n\r\n")); $raw_body = substr($email, strlen($raw_header)+8); - $header = new Header($raw_header); + $header = new Header($raw_header, $this->config); $structure = new Structure($raw_body, $header); self::assertSame(2, count($structure->parts)); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/AttachmentLongFilenameTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/AttachmentLongFilenameTest.php index 650a2dcbd..5a3e00ed5 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/AttachmentLongFilenameTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/AttachmentLongFilenameTest.php @@ -53,7 +53,7 @@ class AttachmentLongFilenameTest extends FixtureTestCase { $attachment = $attachments[1]; self::assertInstanceOf(Attachment::class, $attachment); self::assertEquals('01_A€àäąбيد@Z-0123456789-qwertyuiopasdfghjklzxcvbnmopqrstuvz-0123456789-qwertyuiopasdfghjklzxcvbnmopqrstuvz-0123456789-qwertyuiopasdfghjklzxcvbnmopqrstuvz.txt', $attachment->name); - self::assertEquals("f7b5181985862431bfc443d26e3af2371e20a0afd676eeb9b9595a26d42e0b73", hash("sha256", $attachment->filename)); + self::assertEquals("cebd34e48eaa06311da3d3130d5a9b465b096dc1094a6548f8c94c24ca52f34e", hash("sha256", $attachment->filename)); self::assertEquals('text', $attachment->type); self::assertEquals('txt', $attachment->getExtension()); self::assertEquals("text/plain", $attachment->content_type); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BccTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BccTest.php index 8de14f62a..be8ef72ef 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BccTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BccTest.php @@ -24,11 +24,17 @@ class BccTest extends FixtureTestCase { * * @return void */ - public function testFixture() : void { + public function testFixture(): void { $message = $this->getFixture("bcc.eml"); self::assertEquals("test", $message->subject); - self::assertEquals("", $message->return_path); + self::assertSame([ + 'personal' => '', + 'mailbox' => 'return-path', + 'host' => 'here.com', + 'mail' => 'return-path@here.com', + 'full' => 'return-path@here.com', + ], $message->return_path->first()->toArray()); self::assertEquals("1.0", $message->mime_version); self::assertEquals("text/plain", $message->content_type); self::assertEquals("Hi!", $message->getTextBody()); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BooleanDecodedContentTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BooleanDecodedContentTest.php index e49229a48..5d15fe57d 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BooleanDecodedContentTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/BooleanDecodedContentTest.php @@ -48,7 +48,7 @@ class BooleanDecodedContentTest extends FixtureTestCase { self::assertEquals("application/pdf", $attachment->content_type); self::assertEquals("1c449aaab4f509012fa5eaa180fd017eb7724ccacabdffc1c6066d3756dcde5c", hash("sha256", $attachment->content)); self::assertEquals(53, $attachment->size); - self::assertEquals(3, $attachment->part_number); + self::assertEquals(2, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/DateTemplateTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/DateTemplateTest.php index 79f42dfe4..77dfd7bbc 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/DateTemplateTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/DateTemplateTest.php @@ -51,6 +51,7 @@ class DateTemplateTest extends FixtureTestCase { "Thur, 16 Mar 2023 15:33:07 +0400" => "2023-03-16 11:33:07", "fr., 25 nov. 2022 06:27:14 +0100/fr., 25 nov. 2022 06:27:14 +0100" => "2022-11-25 05:27:14", "Di., 15 Feb. 2022 06:52:44 +0100 (MEZ)/Di., 15 Feb. 2022 06:52:44 +0100 (MEZ)" => "2022-02-15 05:52:44", + "Mi., 23 Apr. 2025 09:48:37 +0200 (MESZ)" => "2025-04-23 07:48:37", ]; /** @@ -81,7 +82,7 @@ class DateTemplateTest extends FixtureTestCase { "fallback_date" => "2021-01-01 00:00:00", ], ]); - $message = $this->getFixture("date-template.eml"); + $message = $this->getFixture("date-template.eml", self::$manager->getConfig()); self::assertEquals("test", $message->subject); self::assertEquals("1.0", $message->mime_version); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmailAddressTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmailAddressTest.php index d4e403d7d..0f87cf6af 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmailAddressTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmailAddressTest.php @@ -12,6 +12,16 @@ namespace Tests\fixtures; +use Webklex\PHPIMAP\Exceptions\AuthFailedException; +use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; +use Webklex\PHPIMAP\Exceptions\ImapBadRequestException; +use Webklex\PHPIMAP\Exceptions\ImapServerErrorException; +use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; +use Webklex\PHPIMAP\Exceptions\MaskNotFoundException; +use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException; +use Webklex\PHPIMAP\Exceptions\ResponseException; +use Webklex\PHPIMAP\Exceptions\RuntimeException; + /** * Class EmailAddressTest * @@ -23,6 +33,16 @@ class EmailAddressTest extends FixtureTestCase { * Test the fixture email_address.eml * * @return void + * @throws \ReflectionException + * @throws AuthFailedException + * @throws ConnectionFailedException + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws InvalidMessageDateException + * @throws MaskNotFoundException + * @throws MessageContentFetchingException + * @throws ResponseException + * @throws RuntimeException */ public function testFixture() : void { $message = $this->getFixture("email_address.eml"); @@ -32,8 +52,8 @@ class EmailAddressTest extends FixtureTestCase { self::assertEquals("Hi\r\nHow are you?", $message->getTextBody()); self::assertFalse($message->hasHTMLBody()); self::assertFalse($message->date->first()); - self::assertEquals("no_host@UNKNOWN", (string)$message->from); + self::assertEquals("no_host", (string)$message->from); self::assertEquals("", $message->to); - self::assertEquals("This one: is \"right\" , No-address@UNKNOWN", $message->cc); + self::assertEquals("This one: is \"right\" , No-address", (string)$message->cc); } } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailTest.php index fb6e24922..024a88858 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailTest.php @@ -32,7 +32,6 @@ class EmbeddedEmailTest extends FixtureTestCase { self::assertEquals("embedded message", $message->subject); self::assertEquals([ 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz ; Fri, 29 Jan 2016 14:25:40 +0100', - 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz' ], $message->received->toArray()); self::assertEquals("7e5798da5747415e5b82fdce042ab2a6@cerstor.cz", $message->message_id); self::assertEquals("demo@cerstor.cz", $message->return_path); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionEmbeddedTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionEmbeddedTest.php index 7d3fb2d05..387b0de0d 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionEmbeddedTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionEmbeddedTest.php @@ -32,7 +32,6 @@ class EmbeddedEmailWithoutContentDispositionEmbeddedTest extends FixtureTestCase self::assertEquals("embedded_message_subject", $message->subject); self::assertEquals([ 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz ; Fri, 29 Jan 2016 14:25:40 +0100', - 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz' ], $message->received->toArray()); self::assertEquals("AC39946EBF5C034B87BABD5343E96979012671D40E38@VM002.cerk.cc", $message->message_id); self::assertEquals("pl-PL, nl-NL", $message->accept_language); @@ -56,7 +55,7 @@ class EmbeddedEmailWithoutContentDispositionEmbeddedTest extends FixtureTestCase self::assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $attachment->content_type); self::assertEquals("87737d24c106b96e177f9564af6712e2c6d3e932c0632bfbab69c88b0bb934dc", hash("sha256", $attachment->content)); self::assertEquals(40, $attachment->size); - self::assertEquals(3, $attachment->part_number); + self::assertEquals(2, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -68,7 +67,7 @@ class EmbeddedEmailWithoutContentDispositionEmbeddedTest extends FixtureTestCase self::assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $attachment->content_type); self::assertEquals("87737d24c106b96e177f9564af6712e2c6d3e932c0632bfbab69c88b0bb934dc", hash("sha256", $attachment->content)); self::assertEquals(40, $attachment->size); - self::assertEquals(4, $attachment->part_number); + self::assertEquals(3, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionTest.php index 603a956d8..2ec5a4fad 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/EmbeddedEmailWithoutContentDispositionTest.php @@ -32,7 +32,6 @@ class EmbeddedEmailWithoutContentDispositionTest extends FixtureTestCase { self::assertEquals("Subject", $message->subject); self::assertEquals([ 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz ; Fri, 29 Jan 2016 14:25:40 +0100', - 'from webmail.my-office.cz (localhost [127.0.0.1]) by keira.cofis.cz' ], $message->received->toArray()); self::assertEquals("AC39946EBF5C034B87BABD5343E96979012671D9F7E4@VM002.cerk.cc", $message->message_id); self::assertEquals("pl-PL, nl-NL", $message->accept_language); @@ -55,7 +54,7 @@ class EmbeddedEmailWithoutContentDispositionTest extends FixtureTestCase { self::assertEquals("image/jpeg", $attachment->content_type); self::assertEquals("6b7fa434f92a8b80aab02d9bf1a12e49ffcae424e4013a1c4f68b67e3d2bbcd0", hash("sha256", $attachment->content)); self::assertEquals(96, $attachment->size); - self::assertEquals(3, $attachment->part_number); + self::assertEquals(2, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -67,7 +66,7 @@ class EmbeddedEmailWithoutContentDispositionTest extends FixtureTestCase { self::assertEquals("message/rfc822", $attachment->content_type); self::assertEquals("2476c8b91a93c6b2fe1bfff593cb55956c2fe8e7ca6de9ad2dc9d101efe7a867", hash("sha256", $attachment->content)); self::assertEquals(2073, $attachment->size); - self::assertEquals(5, $attachment->part_number); + self::assertEquals(3, $attachment->part_number); self::assertNull($attachment->disposition); self::assertNotEmpty($attachment->id); @@ -79,7 +78,7 @@ class EmbeddedEmailWithoutContentDispositionTest extends FixtureTestCase { self::assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $attachment->content_type); self::assertEquals("87737d24c106b96e177f9564af6712e2c6d3e932c0632bfbab69c88b0bb934dc", hash("sha256", $attachment->content)); self::assertEquals(40, $attachment->size); - self::assertEquals(6, $attachment->part_number); + self::assertEquals(4, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -91,7 +90,7 @@ class EmbeddedEmailWithoutContentDispositionTest extends FixtureTestCase { self::assertEquals("application/x-zip-compressed", $attachment->content_type); self::assertEquals("87737d24c106b96e177f9564af6712e2c6d3e932c0632bfbab69c88b0bb934dc", hash("sha256", $attachment->content)); self::assertEquals(40, $attachment->size); - self::assertEquals(7, $attachment->part_number); + self::assertEquals(5, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ExampleBounceTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ExampleBounceTest.php index d2f418a90..8153518d2 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ExampleBounceTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ExampleBounceTest.php @@ -29,14 +29,19 @@ class ExampleBounceTest extends FixtureTestCase { public function testFixture(): void { $message = $this->getFixture("example_bounce.eml"); - self::assertEquals("<>", $message->return_path); + self::assertEquals([ + 'personal' => '', + 'mailbox' => '', + 'host' => '', + 'mail' => '', + 'full' => '', + ], (array)$message->return_path->first()); self::assertEquals([ 0 => 'from somewhere.your-server.de by somewhere.your-server.de with LMTP id 3TP8LrElAGSOaAAAmBr1xw (envelope-from <>); Thu, 02 Mar 2023 05:27:29 +0100', 1 => 'from somewhere06.your-server.de ([1b21:2f8:e0a:50e4::2]) by somewhere.your-server.de with esmtps (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.94.2) id 1pXaXR-0006xQ-BN for demo@foo.de; Thu, 02 Mar 2023 05:27:29 +0100', 2 => 'from [192.168.0.10] (helo=sslproxy01.your-server.de) by somewhere06.your-server.de with esmtps (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) id 1pXaXO-000LYP-9R for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', 3 => 'from localhost ([127.0.0.1] helo=sslproxy01.your-server.de) by sslproxy01.your-server.de with esmtps (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) id 1pXaXO-0008gy-7x for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', 4 => 'from Debian-exim by sslproxy01.your-server.de with local (Exim 4.92) id 1pXaXO-0008gb-6g for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', - 5 => 'from somewhere.your-server.de by somewhere.your-server.de with LMTP id 3TP8LrElAGSOaAAAmBr1xw (envelope-from <>)', ], $message->received->all()); self::assertEquals("demo@foo.de", $message->envelope_to); self::assertEquals("Thu, 02 Mar 2023 05:27:29 +0100", $message->delivery_date); @@ -50,7 +55,6 @@ class ExampleBounceTest extends FixtureTestCase { 2 => 'from [192.168.0.10] (helo=sslproxy01.your-server.de) by somewhere06.your-server.de with esmtps (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) id 1pXaXO-000LYP-9R for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', 3 => 'from localhost ([127.0.0.1] helo=sslproxy01.your-server.de) by sslproxy01.your-server.de with esmtps (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) id 1pXaXO-0008gy-7x for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', 4 => 'from Debian-exim by sslproxy01.your-server.de with local (Exim 4.92) id 1pXaXO-0008gb-6g for demo@foo.de; Thu, 02 Mar 2023 05:27:26 +0100', - 5 => 'from somewhere.your-server.de by somewhere.your-server.de with LMTP id 3TP8LrElAGSOaAAAmBr1xw (envelope-from <>)', ], $message->received->all()); self::assertEquals("ding@ding.de", $message->x_failed_recipients); self::assertEquals("auto-replied", $message->auto_submitted); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/FixtureTestCase.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/FixtureTestCase.php index 8660bedc0..cb64a9a67 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/FixtureTestCase.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/FixtureTestCase.php @@ -14,6 +14,7 @@ namespace Tests\fixtures; use PHPUnit\Framework\TestCase; use Webklex\PHPIMAP\ClientManager; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Exceptions\AuthFailedException; use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; use Webklex\PHPIMAP\Exceptions\ImapBadRequestException; @@ -83,9 +84,9 @@ abstract class FixtureTestCase extends TestCase { * @throws ResponseException * @throws RuntimeException */ - final public function getFixture(string $template) : Message { + final public function getFixture(string $template, ?Config $config = null) : Message { $filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "..", "messages", $template]); - $message = Message::fromFile($filename); + $message = Message::fromFile($filename, $config); self::assertInstanceOf(Message::class, $message); return $message; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipartWithoutBodyTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipartWithoutBodyTest.php index 9989b3e75..01112bb70 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipartWithoutBodyTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipartWithoutBodyTest.php @@ -37,7 +37,6 @@ class MultipartWithoutBodyTest extends FixtureTestCase { 0 => 'from AS8PR02MB6805.eurprd02.prod.outlook.com (2603:10a6:20b:252::8) by PA4PR02MB7071.eurprd02.prod.outlook.com with HTTPS; Sat, 11 Mar 2023 08:24:33 +0000', 1 => 'from omef0ahNgeoJu.eurprd02.prod.outlook.com (2603:10a6:10:33c::12) by AS8PR02MB6805.eurprd02.prod.outlook.com (2603:10a6:20b:252::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6178.19; Sat, 11 Mar 2023 08:24:31 +0000', 2 => 'from omef0ahNgeoJu.eurprd02.prod.outlook.com ([fe80::38c0:9c40:7fc6:93a7]) by omef0ahNgeoJu.eurprd02.prod.outlook.com ([fe80::38c0:9c40:7fc6:93a7%7]) with mapi id 15.20.6178.019; Sat, 11 Mar 2023 08:24:31 +0000', - 3 => 'from AS8PR02MB6805.eurprd02.prod.outlook.com (2603:10a6:20b:252::8) by PA4PR02MB7071.eurprd02.prod.outlook.com with HTTPS', ], $message->received->all()); self::assertEquals("This mail will not contain a body", $message->thread_topic); self::assertEquals("AdlT8uVmpHPvImbCRM6E9LODIvAcQA==", $message->thread_index); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleHtmlPartsAndAttachmentsTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleHtmlPartsAndAttachmentsTest.php index c08c03e0c..48bc0172f 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleHtmlPartsAndAttachmentsTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleHtmlPartsAndAttachmentsTest.php @@ -57,7 +57,7 @@ class MultipleHtmlPartsAndAttachmentsTest extends FixtureTestCase { self::assertEquals("application/pdf", $attachment->content_type); self::assertEquals("c162adf19e0f67e26ef0b7f791b33a60b2c23b175560a505dc7f9ec490206e49", hash("sha256", $attachment->content)); self::assertEquals(4814, $attachment->size); - self::assertEquals(4, $attachment->part_number); + self::assertEquals(2, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -69,7 +69,7 @@ class MultipleHtmlPartsAndAttachmentsTest extends FixtureTestCase { self::assertEquals("application/pdf", $attachment->content_type); self::assertEquals("a337b37e9d3edb172a249639919f0eee3d344db352046d15f8f9887e55855a25", hash("sha256", $attachment->content)); self::assertEquals(5090, $attachment->size); - self::assertEquals(6, $attachment->part_number); + self::assertEquals(4, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleNestedAttachmentsTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleNestedAttachmentsTest.php index 543c0e21e..a3cba097f 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleNestedAttachmentsTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/MultipleNestedAttachmentsTest.php @@ -50,7 +50,7 @@ class MultipleNestedAttachmentsTest extends FixtureTestCase { self::assertEquals("image/png", $attachment->content_type); self::assertEquals("e0e99b0bd6d5ea3ced99add53cc98b6f8eea6eae8ddd773fd06f3489289385fb", hash("sha256", $attachment->content)); self::assertEquals(114, $attachment->size); - self::assertEquals(5, $attachment->part_number); + self::assertEquals(3, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -62,7 +62,7 @@ class MultipleNestedAttachmentsTest extends FixtureTestCase { self::assertEquals("image/png", $attachment->content_type); self::assertEquals("e0e99b0bd6d5ea3ced99add53cc98b6f8eea6eae8ddd773fd06f3489289385fb", hash("sha256", $attachment->content)); self::assertEquals(114, $attachment->size); - self::assertEquals(8, $attachment->part_number); + self::assertEquals(4, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/NestesEmbeddedWithAttachmentTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/NestesEmbeddedWithAttachmentTest.php index c5c8c5616..e1ff57ea0 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/NestesEmbeddedWithAttachmentTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/NestesEmbeddedWithAttachmentTest.php @@ -50,7 +50,7 @@ class NestesEmbeddedWithAttachmentTest extends FixtureTestCase { self::assertEquals("message/rfc822", $attachment->content_type); self::assertEquals("From: from@there.com\r\nTo: to@here.com\r\nSubject: FIRST\r\nDate: Sat, 28 Apr 2018 14:37:16 -0400\r\nMIME-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"----=_NextPart_000_222_000\"\r\n\r\nThis is a multi-part message in MIME format.\r\n\r\n------=_NextPart_000_222_000\r\nContent-Type: multipart/alternative;\r\n boundary=\"----=_NextPart_000_222_111\"\r\n\r\n\r\n------=_NextPart_000_222_111\r\nContent-Type: text/plain;\r\n charset=\"UTF-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nPlease respond directly to this email to update your RMA\r\n\r\n\r\n2018-04-17T11:04:03-04:00\r\n------=_NextPart_000_222_111\r\nContent-Type: text/html;\r\n charset=\"UTF-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n\r\n
    Please respond directly to this =\r\nemail to=20\r\nupdate your RMA
    \r\n\r\n------=_NextPart_000_222_111--\r\n\r\n------=_NextPart_000_222_000\r\nContent-Type: image/png;\r\n name=\"chrome.png\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"chrome.png\"\r\n\r\niVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAB+FBMVEUAAAA/mUPidDHiLi5Cn0Xk\r\nNTPmeUrkdUg/m0Q0pEfcpSbwaVdKskg+lUP4zA/iLi3msSHkOjVAmETdJSjtYFE/lkPnRj3sWUs8\r\nkkLeqCVIq0fxvhXqUkbVmSjwa1n1yBLepyX1xxP0xRXqUkboST9KukpHpUbuvRrzrhF/ljbwalju\r\nZFM4jELaoSdLtElJrUj1xxP6zwzfqSU4i0HYnydMtUlIqUfywxb60AxZqEXaoifgMCXptR9MtklH\r\npEY2iUHWnSjvvRr70QujkC+pUC/90glMuEnlOjVMt0j70QriLS1LtEnnRj3qUUXfIidOjsxAhcZF\r\no0bjNDH0xxNLr0dIrUdmntVTkMoyfL8jcLBRuErhJyrgKyb4zA/5zg3tYFBBmUTmQTnhMinruBzv\r\nvhnxwxZ/st+Ktt5zp9hqota2vtK6y9FemNBblc9HiMiTtMbFtsM6gcPV2r6dwroseLrMrbQrdLGd\r\nyKoobKbo3Zh+ynrgVllZulTsXE3rV0pIqUf42UVUo0JyjEHoS0HmsiHRGR/lmRz/1hjqnxjvpRWf\r\nwtOhusaz0LRGf7FEfbDVmqHXlJeW0pbXq5bec3fX0nTnzmuJuWvhoFFhm0FtrziBsjaAaDCYWC+u\r\nSi6jQS3FsSfLJiTirCOkuCG1KiG+wSC+GBvgyhTszQ64Z77KAAAARXRSTlMAIQRDLyUgCwsE6ebm\r\n5ubg2dLR0byXl4FDQzU1NDEuLSUgC+vr6urq6ubb29vb2tra2tG8vLu7u7uXl5eXgYGBgYGBLiUA\r\nLabIAAABsElEQVQoz12S9VPjQBxHt8VaOA6HE+AOzv1wd7pJk5I2adpCC7RUcHd3d3fXf5PvLkxh\r\neD++z+yb7GSRlwD/+Hj/APQCZWxM5M+goF+RMbHK594v+tPoiN1uHxkt+xzt9+R9wnRTZZQpXQ0T\r\n5uP1IQxToyOAZiQu5HEpjeA4SWIoksRxNiGC1tRZJ4LNxgHgnU5nJZBDvuDdl8lzQRBsQ+s9PZt7\r\ns7Pz8wsL39/DkIfZ4xlB2Gqsq62ta9oxVlVrNZpihFRpGO9fzQw1ms0NDWZz07iGkJmIFH8xxkc3\r\na/WWlubmFkv9AB2SEpDvKxbjidN2faseaNV3zoHXvv7wMODJdkOHAegweAfFPx4G67KluxzottCU\r\n9n8CUqXzcIQdXOytAHqXxomvykhEKN9EFutG22p//0rbNvHVxiJywa8yS2KDfV1dfbu31H8jF1RH\r\niTKtWYeHxUvq3bn0pyjCRaiRU6aDO+gb3aEfEeVNsDgm8zzLy9egPa7Qt8TSJdwhjplk06HH43ZN\r\nJ3s91KKCHQ5x4sw1fRGYDZ0n1L4FKb9/BP5JLYxToheoFCVxz57PPS8UhhEpLBVeAAAAAElFTkSu\r\nQmCC\r\n\r\n------=_NextPart_000_222_000--", $attachment->content); self::assertEquals(2535, $attachment->size); - self::assertEquals(5, $attachment->part_number); + self::assertEquals(3, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -62,7 +62,7 @@ class NestesEmbeddedWithAttachmentTest extends FixtureTestCase { self::assertEquals("message/rfc822", $attachment->content_type); self::assertEquals("From: from@there.com\r\nTo: to@here.com\r\nSubject: SECOND\r\nDate: Sat, 28 Apr 2018 13:37:30 -0400\r\nMIME-Version: 1.0\r\nContent-Type: multipart/alternative;\r\n boundary=\"----=_NextPart_000_333_000\"\r\n\r\nThis is a multi-part message in MIME format.\r\n\r\n------=_NextPart_000_333_000\r\nContent-Type: text/plain;\r\n charset=\"UTF-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nT whom it may concern:\r\n------=_NextPart_000_333_000\r\nContent-Type: text/html;\r\n charset=\"UTF-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n\r\n
    T whom it may concern:
    \r\n\r\n\r\n------=_NextPart_000_333_000--", $attachment->content); self::assertEquals(631, $attachment->size); - self::assertEquals(6, $attachment->part_number); + self::assertEquals(4, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/PecTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/PecTest.php index 28ecb27bb..341ad1851 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/PecTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/PecTest.php @@ -51,7 +51,7 @@ class PecTest extends FixtureTestCase { self::assertEquals("application/xml", $attachment->content_type); self::assertEquals("", $attachment->content); self::assertEquals(8, $attachment->size); - self::assertEquals(4, $attachment->part_number); + self::assertEquals(3, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -63,7 +63,7 @@ class PecTest extends FixtureTestCase { self::assertEquals("message/rfc822", $attachment->content_type); self::assertEquals("To: test@example.com\r\nFrom: test@example.com\r\nSubject: test-subject\r\nDate: Mon, 2 Oct 2017 12:13:50 +0200\r\nContent-Type: text/plain; charset=iso-8859-15; format=flowed\r\nContent-Transfer-Encoding: 7bit\r\n\r\ntest-content", $attachment->content); self::assertEquals(216, $attachment->size); - self::assertEquals(5, $attachment->part_number); + self::assertEquals(4, $attachment->part_number); self::assertEquals("inline", $attachment->disposition); self::assertNotEmpty($attachment->id); @@ -75,7 +75,7 @@ class PecTest extends FixtureTestCase { self::assertEquals("application/x-pkcs7-signature", $attachment->content_type); self::assertEquals("1", $attachment->content); self::assertEquals(4, $attachment->size); - self::assertEquals(7, $attachment->part_number); + self::assertEquals(5, $attachment->part_number); self::assertEquals("attachment", $attachment->disposition); self::assertNotEmpty($attachment->id); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ReferencesTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ReferencesTest.php index 18473d614..c86aa96f3 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ReferencesTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/ReferencesTest.php @@ -34,8 +34,8 @@ class ReferencesTest extends FixtureTestCase { self::assertEquals("b9e87bd5e661a645ed6e3b832828fcc5@example.com", $message->in_reply_to); self::assertEquals("", $message->from->first()->personal); - self::assertEquals("UNKNOWN", $message->from->first()->host); - self::assertEquals("no_host@UNKNOWN", $message->from->first()->mail); + self::assertEquals("", $message->from->first()->host); + self::assertEquals("no_host", $message->from->first()->mail); self::assertFalse($message->to->first()); self::assertEquals([ @@ -45,7 +45,7 @@ class ReferencesTest extends FixtureTestCase { self::assertEquals([ 'This one: is "right" ', - 'No-address@UNKNOWN' + 'No-address' ], $message->cc->map(function($address){ /** @var \Webklex\PHPIMAP\Address $address */ return $address->full; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/UndefinedCharsetHeaderTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/UndefinedCharsetHeaderTest.php index acb3029cd..f7a51cb0a 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/UndefinedCharsetHeaderTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/fixtures/UndefinedCharsetHeaderTest.php @@ -26,7 +26,7 @@ class UndefinedCharsetHeaderTest extends FixtureTestCase { * * @return void */ - public function testFixture() : void { + public function testFixture(): void { $message = $this->getFixture("undefined_charset_header.eml"); self::assertEquals("", $message->get("x-real-to")); @@ -34,11 +34,16 @@ class UndefinedCharsetHeaderTest extends FixtureTestCase { self::assertEquals("Mon, 27 Feb 2017 13:21:44 +0930", $message->get("Resent-Date")); self::assertEquals("", $message->get("Resent-From")); self::assertEquals("BlaBla", $message->get("X-Stored-In")); - self::assertEquals("", $message->get("Return-Path")); + self::assertSame([ + 'personal' => '', + 'mailbox' => 'info', + 'host' => 'bla.bla', + 'mail' => 'info@bla.bla', + 'full' => 'info@bla.bla', + ], $message->get("Return-Path")->first()->toArray()); self::assertEquals([ - 'from by bla.bla (CommuniGate Pro RULE 6.1.13) with RULE id 14057804; Mon, 27 Feb 2017 13:21:44 +0930', - 'from by bla.bla (CommuniGate Pro RULE 6.1.13) with RULE id 14057804' - ], $message->get("Received")->all()); + 'from by bla.bla (CommuniGate Pro RULE 6.1.13) with RULE id 14057804; Mon, 27 Feb 2017 13:21:44 +0930', + ], $message->get("Received")->all()); self::assertEquals(")", $message->getHTMLBody()); self::assertFalse($message->hasTextBody()); self::assertEquals("2017-02-27 03:51:29", $message->date->first()->setTimezone('UTC')->format("Y-m-d H:i:s")); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue355Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue355Test.php index a61cd07aa..0fa6d07e8 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue355Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue355Test.php @@ -13,6 +13,7 @@ namespace Tests\issues; use PHPUnit\Framework\TestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Header; class Issue355Test extends TestCase { @@ -20,7 +21,7 @@ class Issue355Test extends TestCase { public function testIssue() { $raw_header = "Subject: =?UTF-8?Q?Re=3A_Uppdaterat_=C3=A4rende_=28447899=29=2C_kostnader_f=C3=B6r_hj=C3=A4?= =?UTF-8?Q?lp_med_stadge=C3=A4ndring_enligt_ny_lagstiftning?=\r\n"; - $header = new Header($raw_header); + $header = new Header($raw_header, Config::make()); $subject = $header->get("subject"); $this->assertEquals("Re: Uppdaterat ärende (447899), kostnader för hjälp med stadgeändring enligt ny lagstiftning", $subject->toString()); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue383Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue383Test.php index 0f20a396f..30cb3a9bd 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue383Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue383Test.php @@ -43,7 +43,7 @@ class Issue383Test extends LiveMailboxTestCase { $client = $this->getClient(); $client->connect(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'Entwürfe+']); $folder = $client->getFolder($folder_path); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue393Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue393Test.php index 73099e076..017ff5352 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue393Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue393Test.php @@ -43,7 +43,7 @@ class Issue393Test extends LiveMailboxTestCase { $client = $this->getClient(); $client->connect(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $pattern = implode($delimiter, ['doesnt_exist', '%']); $folder = $client->getFolder('doesnt_exist'); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue40Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue40Test.php new file mode 100644 index 000000000..7288484ca --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue40Test.php @@ -0,0 +1,74 @@ +getFixture("issue-40.eml"); + + self::assertSame("Zly from", (string)$message->subject); + self::assertSame([ + 'personal' => '', + 'mailbox' => 'faked_sender', + 'host' => 'sender_domain.pl', + 'mail' => 'faked_sender@sender_domain.pl', + 'full' => 'faked_sender@sender_domain.pl', + ], $message->from->first()->toArray()); + self::assertSame([ + 'personal' => '', + 'mailbox' => 'real_sender', + 'host' => 'sender_domain.pl', + 'mail' => 'real_sender@sender_domain.pl', + 'full' => ' ', + ], (array)$message->return_path->first()); + self::assertSame(true, $message->spoofed->first()); + + $config = $message->getConfig(); + self::assertSame(false, $config->get("security.detect_spoofing_exception")); + $config->set("security.detect_spoofing_exception", true); + self::assertSame(true, $config->get("security.detect_spoofing_exception")); + + $this->expectException(SpoofingAttemptDetectedException::class); + $this->getFixture("issue-40.eml", $config); + } + +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue410Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue410Test.php index d02724ca7..4f8b831d1 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue410Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue410Test.php @@ -13,14 +13,36 @@ namespace Tests\issues; use PHPUnit\Framework\TestCase; +use Tests\fixtures\FixtureTestCase; +use Webklex\PHPIMAP\Attachment; use Webklex\PHPIMAP\ClientManager; +use Webklex\PHPIMAP\Exceptions\AuthFailedException; +use Webklex\PHPIMAP\Exceptions\ConnectionFailedException; +use Webklex\PHPIMAP\Exceptions\ImapBadRequestException; +use Webklex\PHPIMAP\Exceptions\ImapServerErrorException; +use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException; +use Webklex\PHPIMAP\Exceptions\MaskNotFoundException; +use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException; +use Webklex\PHPIMAP\Exceptions\ResponseException; +use Webklex\PHPIMAP\Exceptions\RuntimeException; use Webklex\PHPIMAP\Message; -class Issue410Test extends TestCase { +class Issue410Test extends FixtureTestCase { + /** + * @throws RuntimeException + * @throws MessageContentFetchingException + * @throws ResponseException + * @throws ImapBadRequestException + * @throws InvalidMessageDateException + * @throws ConnectionFailedException + * @throws \ReflectionException + * @throws ImapServerErrorException + * @throws AuthFailedException + * @throws MaskNotFoundException + */ public function testIssueEmail() { - $filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "..", "messages", "issue-410.eml"]); - $message = Message::fromFile($filename); + $message = $this->getFixture("issue-410.eml"); self::assertSame("☆第132号 「ガーデン&エクステリア」専門店のためのQ&Aサロン 【月刊エクステリア・ワーク】", (string)$message->subject); @@ -33,9 +55,20 @@ class Issue410Test extends TestCase { self::assertSame("☆第132号 「ガーデン&エクステリア」専門店のためのQ&Aサロン 【月刊エクステリア・ワーク】", $attachment->name); } + /** + * @throws RuntimeException + * @throws MessageContentFetchingException + * @throws ResponseException + * @throws ImapBadRequestException + * @throws InvalidMessageDateException + * @throws ConnectionFailedException + * @throws \ReflectionException + * @throws ImapServerErrorException + * @throws AuthFailedException + * @throws MaskNotFoundException + */ public function testIssueEmailB() { - $filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "..", "messages", "issue-410b.eml"]); - $message = Message::fromFile($filename); + $message = $this->getFixture("issue-410b.eml"); self::assertSame("386 - 400021804 - 19., Heiligenstädter Straße 80 - 0819306 - Anfrage Vergabevorschlag", (string)$message->subject); @@ -49,4 +82,30 @@ class Issue410Test extends TestCase { self::assertSame("2021_Mängelliste_0819306.xlsx", $attachment->name); } + /** + * @throws RuntimeException + * @throws MessageContentFetchingException + * @throws ResponseException + * @throws ImapBadRequestException + * @throws ConnectionFailedException + * @throws InvalidMessageDateException + * @throws ImapServerErrorException + * @throws AuthFailedException + * @throws \ReflectionException + * @throws MaskNotFoundException + */ + public function testIssueEmailSymbols() { + $message = $this->getFixture("issue-410symbols.eml"); + + $attachments = $message->getAttachments(); + + self::assertSame(1, $attachments->count()); + + /** @var Attachment $attachment */ + $attachment = $attachments->first(); + self::assertSame("Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf", $attachment->description); + self::assertSame("Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf", $attachment->name); + self::assertSame("Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf", $attachment->filename); + } + } \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue412Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue412Test.php index 5d1055410..bfaa883df 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue412Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue412Test.php @@ -13,6 +13,7 @@ namespace Tests\issues; use PHPUnit\Framework\TestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Message; class Issue412Test extends TestCase { diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue413Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue413Test.php index cfdae5483..2162d6b5d 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue413Test.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue413Test.php @@ -14,6 +14,7 @@ namespace Tests\issues; use PHPUnit\Framework\TestCase; use Tests\live\LiveMailboxTestCase; +use Webklex\PHPIMAP\Config; use Webklex\PHPIMAP\Folder; use Webklex\PHPIMAP\Message; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue420Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue420Test.php new file mode 100644 index 000000000..0cac9b6e5 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue420Test.php @@ -0,0 +1,31 @@ +get("subject"); + + // Ticket No: [��17] Mailbox Inbox - (17) Incoming failed messages + $this->assertEquals('Ticket No: [??17] Mailbox Inbox - (17) Incoming failed messages', utf8_decode($subject->toString())); + } + +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue462Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue462Test.php new file mode 100644 index 000000000..e7fc2126a --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue462Test.php @@ -0,0 +1,48 @@ +set('options.rfc822', false); + $message = $this->getFixture("issue-462.eml", $config); + self::assertSame("Undeliverable: Some subject", (string)$message->subject); + self::assertSame("postmaster@ ", (string)$message->from->first()); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue469Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue469Test.php new file mode 100644 index 000000000..13bd841b9 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue469Test.php @@ -0,0 +1,42 @@ +createStub(Client::class); + $folder_name = '[Gmail]'; + $delimiter = '/'; + + $attributes = [ + '\NoInferiors', + '\NoSelect', + ]; + $folder = new Folder($client, $folder_name, $delimiter, $attributes); + + $attributes_lowercase = [ + '\Noinferiors', + '\Noselect', + ]; + $folder_lowercase = new Folder($client, $folder_name, $delimiter, $attributes_lowercase); + + self::assertSame( + $folder->no_inferiors, + $folder_lowercase->no_inferiors, + 'The parsed "\NoInferiors" attribute does not match the parsed "\Noinferiors" attribute' + ); + self::assertSame( + $folder->no_select, + $folder_lowercase->no_select, + 'The parsed "\NoSelect" attribute does not match the parsed "\Noselect" attribute' + ); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue511Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue511Test.php new file mode 100644 index 000000000..4782bace2 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue511Test.php @@ -0,0 +1,50 @@ +getFixture("issue-511.eml"); + self::assertSame("RE: [EXTERNAL] Re: Lorem Ipsum /40 one", (string)$message->subject); + self::assertSame("COMPANYNAME | usługi ", (string)$message->from->first()); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue544Test.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue544Test.php new file mode 100644 index 000000000..b8ee0e7e9 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/issues/Issue544Test.php @@ -0,0 +1,61 @@ +getFixture("issue-544.eml"); + + self::assertSame("Test bad boundary", (string)$message->subject); + + $attachments = $message->getAttachments(); + + self::assertSame(1, $attachments->count()); + + /** @var Attachment $attachment */ + $attachment = $attachments->first(); + self::assertSame("file.pdf", $attachment->name); + self::assertSame("file.pdf", $attachment->filename); + self::assertStringStartsWith("%PDF-1.4", $attachment->content); + self::assertStringEndsWith("%%EOF\n", $attachment->content); + self::assertSame(14938, $attachment->size); + } +} \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/ClientTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/ClientTest.php index 307894a7a..1d224d570 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/ClientTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/ClientTest.php @@ -187,7 +187,7 @@ class ClientTest extends LiveMailboxTestCase { public function testCreateFolder(): void { $client = $this->getClient()->connect(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', $this->getSpecialChars()]); $folder = $client->getFolder($folder_path); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/FolderTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/FolderTest.php index 78da70170..178329cfa 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/FolderTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/FolderTest.php @@ -79,7 +79,7 @@ class FolderTest extends LiveMailboxTestCase { $folder = $this->getFolder('INBOX'); self::assertInstanceOf(Folder::class, $folder); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $child_path = implode($delimiter, ['INBOX', 'test']); if ($folder->getClient()->getFolder($child_path) === null) { $folder->getClient()->createFolder($child_path, false); @@ -107,7 +107,7 @@ class FolderTest extends LiveMailboxTestCase { $folder = $this->getFolder('INBOX'); self::assertInstanceOf(Folder::class, $folder); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $child_path = implode($delimiter, ['INBOX', 'test']); if ($folder->getClient()->getFolder($child_path) === null) { $folder->getClient()->createFolder($child_path, false); @@ -137,7 +137,7 @@ class FolderTest extends LiveMailboxTestCase { $folder = $this->getFolder('INBOX'); self::assertInstanceOf(Folder::class, $folder); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $child_path = implode($delimiter, ['INBOX', 'test']); if ($folder->getClient()->getFolder($child_path) === null) { $folder->getClient()->createFolder($child_path, false); @@ -167,7 +167,7 @@ class FolderTest extends LiveMailboxTestCase { public function testMove(): void { $client = $this->getClient(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'test']); $folder = $client->getFolder($folder_path); @@ -208,7 +208,7 @@ class FolderTest extends LiveMailboxTestCase { public function testDelete(): void { $client = $this->getClient(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'test']); $folder = $client->getFolder($folder_path); @@ -347,6 +347,31 @@ class FolderTest extends LiveMailboxTestCase { self::assertTrue(str_starts_with($status[0], 'OK')); } + /** + * Test Folder::status() + * + * @return void + * @throws AuthFailedException + * @throws ConnectionFailedException + * @throws FolderFetchingException + * @throws ImapBadRequestException + * @throws ImapServerErrorException + * @throws MaskNotFoundException + * @throws ResponseException + * @throws RuntimeException + */ + public function testStatus(): void { + $folder = $this->getFolder('INBOX'); + self::assertInstanceOf(Folder::class, $folder); + + $status = $folder->status(); + self::assertEquals(0, $status['messages']); + self::assertEquals(0, $status['recent']); + self::assertEquals(0, $status['unseen']); + self::assertGreaterThan(0, $status['uidnext']); + self::assertGreaterThan(0, $status['uidvalidity']); + } + /** * Test Folder::examine() * @@ -414,7 +439,7 @@ class FolderTest extends LiveMailboxTestCase { $folder->setDelimiter("."); self::assertEquals(".", $folder->delimiter); - $default_delimiter = $this->getManager()->get("options.delimiter", "/"); + $default_delimiter = $this->getManager()->getConfig()->get("options.delimiter", "/"); $folder->setDelimiter(null); self::assertEquals($default_delimiter, $folder->delimiter); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LegacyTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LegacyTest.php index 85fa44481..3e385eb0f 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LegacyTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LegacyTest.php @@ -98,7 +98,7 @@ class LegacyTest extends TestCase { */ public function testSizes(): void { - $delimiter = ClientManager::get("options.delimiter"); + $delimiter = self::$client->getConfig()->get("options.delimiter"); $child_path = implode($delimiter, ['INBOX', 'test']); if (self::$client->getFolder($child_path) === null) { self::$client->createFolder($child_path, false); @@ -236,7 +236,7 @@ class LegacyTest extends TestCase { * @throws ResponseException * @throws RuntimeException */ - final protected function deleteFolder(Folder $folder = null): bool { + final protected function deleteFolder(?Folder $folder = null): bool { $response = $folder?->delete(false); if (is_array($response)) { $valid_response = false; @@ -276,7 +276,7 @@ class LegacyTest extends TestCase { * @throws MessageSearchValidationException */ public function testQueryWhere(): void { - $delimiter = ClientManager::get("options.delimiter"); + $delimiter = self::$client->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'search']); $folder = self::$client->getFolder($folder_path); @@ -423,7 +423,7 @@ class LegacyTest extends TestCase { * @throws ResponseException * @throws RuntimeException */ - protected function assertWhereSearchCriteria(Folder $folder, string $criteria, Carbon|string $value = null, bool $date = false): void { + protected function assertWhereSearchCriteria(Folder $folder, string $criteria, Carbon|string|null $value = null, bool $date = false): void { $query = $folder->query()->where($criteria, $value); self::assertInstanceOf(WhereQuery::class, $query); @@ -431,7 +431,7 @@ class LegacyTest extends TestCase { $criteria = str_replace("CUSTOM ", "", $criteria); $expected = $value === null ? [$criteria] : [$criteria, $value]; if ($date === true && $value instanceof Carbon) { - $date_format = ClientManager::get('date_format', 'd M y'); + $date_format = $folder->getClient()->getConfig()->get('date_format', 'd M y'); $expected[1] = $value->format($date_format); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LiveMailboxTestCase.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LiveMailboxTestCase.php index c59e67739..d0f1b680b 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LiveMailboxTestCase.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/LiveMailboxTestCase.php @@ -200,7 +200,7 @@ abstract class LiveMailboxTestCase extends TestCase { * @throws ResponseException * @throws RuntimeException */ - final protected function deleteFolder(Folder $folder = null): bool { + final protected function deleteFolder(?Folder $folder = null): bool { $response = $folder?->delete(false); if (is_array($response)) { $valid_response = false; diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/MessageTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/MessageTest.php index 31b155794..841b125b5 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/MessageTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/MessageTest.php @@ -97,7 +97,7 @@ class MessageTest extends LiveMailboxTestCase { */ public function testConvertEncoding(): void { $message = $this->getDefaultMessage(); - self::assertEquals("Entwürfe+", $message->convertEncoding("Entw&APw-rfe+", "UTF7-IMAP", "UTF-8")); + self::assertEquals("Entwürfe+", $message->getDecoder()->convertEncoding("Entw&APw-rfe+", "UTF7-IMAP", "UTF-8")); // Cleanup self::assertTrue($message->delete()); @@ -126,7 +126,7 @@ class MessageTest extends LiveMailboxTestCase { public function testThread(): void { $client = $this->getClient(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'thread']); $folder = $client->getFolder($folder_path); @@ -420,7 +420,7 @@ class MessageTest extends LiveMailboxTestCase { public function testGetMsgn(): void { $client = $this->getClient(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'test']); $folder = $client->getFolder($folder_path); @@ -830,13 +830,13 @@ class MessageTest extends LiveMailboxTestCase { public function testSetConfig(): void { $message = $this->getDefaultMessage(); - $config = $message->getConfig(); - self::assertIsArray($config); + $options = $message->getOptions(); + self::assertIsArray($options); - $message->setConfig(["foo" => "bar"]); - self::assertArrayHasKey("foo", $message->getConfig()); + $message->setOptions(["foo" => "bar"]); + self::assertArrayHasKey("foo", $message->getOptions()); - $message->setConfig($config); + $message->setOptions($options); // Cleanup self::assertTrue($message->delete()); @@ -961,7 +961,7 @@ class MessageTest extends LiveMailboxTestCase { $message = $this->getDefaultMessage(); $string = '

    Test

    '; - self::assertEquals('

    Test

    ', $message->decodeString($string, IMAP::MESSAGE_ENC_QUOTED_PRINTABLE)); + self::assertEquals('

    Test

    ', $message->getDecoder()->decode($string, IMAP::MESSAGE_ENC_QUOTED_PRINTABLE)); // Cleanup self::assertTrue($message->delete()); @@ -1406,7 +1406,7 @@ class MessageTest extends LiveMailboxTestCase { $client = $message->getClient(); self::assertInstanceOf(Client::class, $client); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'test']); $folder = $client->getFolder($folder_path); @@ -2161,7 +2161,7 @@ class MessageTest extends LiveMailboxTestCase { $client = $message->getClient(); self::assertInstanceOf(Client::class, $client); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'test']); $folder = $client->getFolder($folder_path); diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/QueryTest.php b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/QueryTest.php index af651ef41..194d804ea 100644 --- a/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/QueryTest.php +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/live/QueryTest.php @@ -86,7 +86,7 @@ class QueryTest extends LiveMailboxTestCase { public function testQueryWhere(): void { $client = $this->getClient(); - $delimiter = $this->getManager()->get("options.delimiter"); + $delimiter = $this->getManager()->getConfig()->get("options.delimiter"); $folder_path = implode($delimiter, ['INBOX', 'search']); $folder = $client->getFolder($folder_path); @@ -231,7 +231,7 @@ class QueryTest extends LiveMailboxTestCase { * @throws ResponseException * @throws RuntimeException */ - protected function assertWhereSearchCriteria(Folder $folder, string $criteria, Carbon|string $value = null, bool $date = false): void { + protected function assertWhereSearchCriteria(Folder $folder, string $criteria, Carbon|string|null $value = null, bool $date = false): void { $query = $folder->query()->where($criteria, $value); self::assertInstanceOf(WhereQuery::class, $query); @@ -239,7 +239,7 @@ class QueryTest extends LiveMailboxTestCase { $criteria = str_replace("CUSTOM ", "", $criteria); $expected = $value === null ? [$criteria] : [$criteria, $value]; if ($date === true && $value instanceof Carbon) { - $date_format = ClientManager::get('date_format', 'd M y'); + $date_format = $folder->getClient()->getConfig()->get('date_format', 'd M y'); $expected[1] = $value->format($date_format); } diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-40.eml b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-40.eml new file mode 100644 index 000000000..52e7ff9a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-40.eml @@ -0,0 +1,39 @@ +Return-Path: +Delivered-To: receipent@receipent_domain.pl +Received: from h2.server.pl +\tby h2.server.pl with LMTP +\tid 4IDTIEUkm18ZSSkA87l24w +\t(envelope-from ) +\tfor ; Thu, 29 Oct 2020 21:21:25 +0100 +Return-path: +Envelope-to: receipent@receipent_domain.pl +Delivery-date: Thu, 29 Oct 2020 21:21:25 +0100 +Received: from sender_domain.pl ([server ip]) +\tby h2.server.pl with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +\t(Exim 4.94) +\t(envelope-from ) +\tid 1kYEQG-00BPgD-S0 +\tfor receipent@receipent_domain.pl; Thu, 29 Oct 2020 21:21:25 +0100 +Received: by sender_domain.pl (Postfix, from userid 1000) +\tid 57DADAB; Thu, 29 Oct 2020 21:21:23 +0100 (CET) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=sender_domain.pl; s=default; +\tt=1604002883; bh=CsZufJouWdjY/W12No6MSSMwbp0VaS8EOMGg9WptEaI=; +\th=From:To:Subject:Date; +\tb=v0NAncnNT/w+gInANxAkMt20ktM4LZquuwlokUmLpPyO3++8dy112olu63Dkn9L2E +\t GwfHGqW+8f7g494UK6asUKqTx8fHxlEJbHqAiEV5QrlynSeZDFXsKvGDW8XNMFBKop +\t sAjvp8NTUiNcA4MTbFaZ7RX15A/9d9QVEynU8MaNP2ZYKnq9J/JXgUjjMnx+FiULqf +\t xJN/5rjwHRx7f6JQoXXUxuck6Zh4tSDiLLnDFasrSxed6sTNfnZMAggCyb1++estNk +\t q6HNBwp85Az3ELo10RbBF/WM2FhxxFz1khncRtCyLXLUZ2lzhjan765KXpeYg7FUa9 +\t zItPWVTaTzTEg== +From: faked_sender@sender_domain.pl +To: receipent@receipent_domain.pl +Subject: Zly from +Message-Id: <20201029202123.57DADAB@sender_domain.pl> +Date: Thu, 29 Oct 2020 21:21:01 +0100 (CET) +Forward-Confirmed-ReverseDNS: Reverse and forward lookup success on server ip, -10 Spam score +SPFCheck: Server passes SPF test, -30 Spam score +X-DKIM: signer='sender_domain.pl' status='pass' reason='' +DKIMCheck: Server passes DKIM test, -20 Spam score +X-Spam-Score: -0.2 (/) + +Test message diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-410symbols.eml b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-410symbols.eml new file mode 100644 index 000000000..b83a2f265 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-410symbols.eml @@ -0,0 +1,22 @@ +From: from@there.com +To: to@here.com +Subject: =?iso-8859-1?Q?386_-_400021804_-_19.,_Heiligenst=E4dter_Stra=DFe_80_-_081?= + =?iso-8859-1?Q?9306_-_Anfrage_Vergabevorschlag?= +Date: Wed, 13 Sep 2017 13:05:45 +0200 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------B832AF745285AEEC6D5AEE42" + +Hi +--------------B832AF745285AEEC6D5AEE42 +Content-Type: application/pdf; name="Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf" +Content-Description: Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf +Content-Disposition: attachment; + filename="Checkliste 10.,DAVIDGASSE 76-80;2;2.pdf"; size=3439313; + creation-date="Tue, 12 Sep 2023 06:53:03 GMT"; + modification-date="Tue, 12 Sep 2023 08:18:16 GMT" +Content-ID: <34A0EDD24A954140A472605B7526F190@there.com> +Content-Transfer-Encoding: base64 + +SGkh +--------------B832AF745285AEEC6D5AEE42-- \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-462.eml b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-462.eml new file mode 100644 index 000000000..d13b3cf1a --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-462.eml @@ -0,0 +1,5 @@ +From: "postmaster@" +To: receipent@receipent_domain.tld +Subject: Undeliverable: Some subject + +Test message diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-511.eml b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-511.eml new file mode 100644 index 000000000..7cd61faa3 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-511.eml @@ -0,0 +1,5 @@ +From: COMPANYNAME | =?iso-8859-2?q?us=B3ugi?= +To: receipent@receipent_domain.tld +Subject: =?utf-8?B?UkU6IFtFWFRFUk5BTF0gUmU6IExvcmVtIElwc3VtIC8=?= =?utf-8?Q?40_one?= + +Test message diff --git a/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-544.eml b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-544.eml new file mode 100644 index 000000000..96e2c48c1 --- /dev/null +++ b/lam/lib/3rdParty/composer/webklex/php-imap/tests/messages/issue-544.eml @@ -0,0 +1,220 @@ +Sender: "test@mail.com" +From: "test@mail.com" +Subject: Test bad boundary +To: "test_1@mail.com" +Cc: +Bcc: +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="-" + +This is a multi-part message in MIME format. + +--- +Content-Type: text/plain + +This message may contain an attachment in a PDF format. + +Special Comments +- +See attached document + +--- +Content-Type: application/pdf; name="file.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="file.pdf" +Content-MD5: MLGn6wT7mIo/SUBWQ/mmng== + +JVBERi0xLjQKJdPr6eEKMSAwIG9iago8PC9UaXRsZSAoZmlsZS0xLnBkZikKL1Byb2R1Y2VyIChT +a2lhL1BERiBtMTE5IEdvb2dsZSBEb2NzIFJlbmRlcmVyKT4+CmVuZG9iagozIDAgb2JqCjw8L2Nh +IDEKL0JNIC9Ob3JtYWw+PgplbmRvYmoKNSAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9M +ZW5ndGggMTkzPj4gc3RyZWFtCnicdZBNDgIhDIX3PUUvILZDoZAYFxrHtYYb+JeYuHC8fyIwo2NM +oASa99FHgZFyLDgvGjs8PeAJRl1VP3sWGUsc9zgmww2We4u3FxQe2COT8zhc4AqHPwftysweVKXs +MSazxybBshdkMb4MxXQFnvsyojGw2oipmCzYmk7Vig2YzrgikrjGdAcxpBzVaa6ZwLaCfN55lmhn +0LdAqCAYdsyk4QuYpjtCIC/uB0irghtdOduoEG2B8YG7lD/3DS1VWPgKZW5kc3RyZWFtCmVuZG9i +agoyIDAgb2JqCjw8L1R5cGUgL1BhZ2UKL1Jlc291cmNlcyA8PC9Qcm9jU2V0IFsvUERGIC9UZXh0 +IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJXQovRXh0R1N0YXRlIDw8L0czIDMgMCBSPj4KL0ZvbnQg +PDwvRjQgNCAwIFI+Pj4+Ci9NZWRpYUJveCBbMCAwIDYxMiA3OTJdCi9Db250ZW50cyA1IDAgUgov +U3RydWN0UGFyZW50cyAwCi9QYXJlbnQgNiAwIFI+PgplbmRvYmoKNiAwIG9iago8PC9UeXBlIC9Q +YWdlcwovQ291bnQgMQovS2lkcyBbMiAwIFJdPj4KZW5kb2JqCjcgMCBvYmoKPDwvVHlwZSAvQ2F0 +YWxvZwovUGFnZXMgNiAwIFI+PgplbmRvYmoKOCAwIG9iago8PC9MZW5ndGgxIDE3ODUyCi9GaWx0 +ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggODc4OD4+IHN0cmVhbQp4nO16C3wURdbvqerueSWTzOT9 +mGQ6DAmSAQJ5kBAimZAHaowECJggSAJEAogEAoiPlbgughGF9VNUdAXf+GQSIgbUJauuu6IIq6gr +PoiIiroI+ikqSPr7V80EQtR75d7vPvz9tpvzr1NVp05Vn3PqdE0HYkQUCVBp6JiS0jI2n80g4nFo +zR9TOXbCssvWX0SkiHrLmAkTR9v+bF5FxPyoDx07ISNzqefpNMhXoV47qaSiuvKWOd8SZZ9F5Lx1 +xry6RraXf4X+dvTPnLFkkX6v6+0viEwHQFWXNM6a9+oVNeuI7HmoXzarrqmR4sgK/QWQd8y69IpL +Si/57HmiAZgvdEnDzHlL93yTeTsWvJHIck5Dfd3MrqiXoI91QX54AxoisqxJqGON1L9h3qKl/ZZo +DiLtVrRVXjp/Rl32j8Ma8DwPoP/ReXVLG7VN9mb0nY+6flndvPrY2mHvwxiVaCtpnN+0yEinteAv +Ff2NC+sbU9+q2E6UeIQo5M9oU8hCnJzEDAO8sGUVfU0F9Ccyo91BGTQJ2h6HrIa6QvIyBgidP3Nh +vHlU9wVU7KBjm45d6ZAtp11VssVGQ3BrdQvrppM+44qFl5I+a2H9XNIb6qcvJP3SukWXkX5KJ2nx +6+4qOfz2tPCCby2JFtl830cD0kX5SuXILcc2nZjlIEsoqtaTM4oyNMhzPE2gzSGelaJwMxpD5wLP +x81oLG5GE3CLcYqykq3BE1u0dVoWhiUGSuUfdAmPsGg8xKRycanSgr2uirEXjCUfDaYntDe6x7Es +8yjW5hPGNWDFNO0Z4QVS5YoCI6OCVo9Ca6WIGdyifQgNo0toNl1KjfSEGA2dw2jmqRbjo173jJ/Y +mYJ2Hk1TSJEWHhSwsLRtlFwDQS/DSk7xrBeP9c2tXwjZ3hjUK+Q4IodJCgs+kYtipL4oaddzjXeF +pY0GuZro/8mdhzgT9zv/N252kB9SHhS3ukrcWmHgNo2UazXTZOEVFfuY5lBzkGew5pIgz/HMDUFe +gb/PCvJqLxmNEiAV4E3giIpoIfxXBw9WYB9MonrUm9Ayn0S050ifD0V/hWyZT4voCvi6Hn3n0jy0 +z4LsZUAdsaD30qbTeEjNosXg69B6eu2U3COQzMQMw3DrWEGD1P3T2YpRWwheYB3aAyscIue8NDjf +bMzQgL6m4OxN8mmWAGfSENPPhOOZXPxRKuIjaFtPXW2iff9bCv8/uvAsZaByPF9kTxv7G63sxV/X +R36Fto3iQQnawxSvpuENQ8anoIOi7J5tHBT9ouSfY0BHkIg20hNsNj1B2+l5dgSjNtFWaqe/UyyV +0N10Nd1KKxCZk9FyA3w4HhFbQreyeKMdWf9eRO69tBOyF9I18EQMizM+o2W0XHkDo5aTnfohGioR +GTex843FyDL71OsoF7n0MmpkzUa1cbNxi/EAPUhblb8bJygEu2EG7p3Gl9o/jfcQwVPoNrqT9rFb +rE9hB12IfbZV+RNiaJ0yVWXGLOMYVpBCl2MNKmJ0J+vkXmivp09ZHLtaKYaW+w2/8SKkXDQVsbiO +trEcNoanaFOMCmMnctFgWgqtd1IbbcHdQc/RXhaqHTEeMI5QPA3CrloGe7zGOpXuE9d2F8JiGqw0 +kEagZz79mf5Gu5mH/YXP10K1TM2nXWnsQW4bRhOx2ocx8hP2Hb8G9zLlJbXMGI09vpz+KKxNf6UP +WQLLYGPZJD6Qz+f3KAuRKQfJnSdy+A10B7R/wLxsCw/lu5T71cfU46ak7i4jDB5Jo7vw/v0Ls+NJ +ddbEfs/eYh/xYj6N38X3K7eqj6ivm+vw1BcjK9xEj9F3LILlsXHsItbArmYr2B/ZnWwn240sV8Sr ++Fx+WGlQFijPqaNxT1Cb1Ou067UbTQe7q7tf7P5H93dGpnE9jUM8XIvV30b34Mm20i6ZKffRfqax +EBaGW2cpbCK7Cvc17CZ2H9vIHmHtmGU3288+Y1+zb9lxjsTITTyRp/B+uD18Ib+c38rv5rtw7+b/ +4j8osUo/xavkKAVKjTIfq1qhrMH9lPKhmqDuUg3YOVNbq63XNmqPac9rR0yh5t9byPLqj/efSD/x +QTd1r+xe293W3W58iHdGPGLKRW6cVsYhT9UhVy/FueRBxPkbLBS2S2DpbBQ7H5aZxuawBWwpLPkH +to49KNf+JHsWVnqbHcaa7dwl1zyE5/DRfCzui3k9X8DX8Ft4O3+LH1PMSogSrkQr6coYZapSryxS +rlDWKn7lVeV9Zb9yVPkRt6HaVLfaT01TveoYdZq6WL1H/VT9VJuivaJ9bLKZ5pmuN3WYvjIPN48y +V5rHmaeaV5u3mPdYahGdL9BT9HTvfc+6lGuVUuUpuplnqfH8Nf4a4nkazVQqOCKVb2Qr+e9YO++v +LTWN5CPZBXRETYOtX+Lr+VE+Uqlg5WwCzeHDAtpMUeqjKArUF+iQ+iye7TVoXmoKZdfww6ZQasNr +ewTm/KsyVPUqr9BeZR8zq/fSu6qNxbJD/GGlElHwnDpKq6YU5W56UlnAfkdP8VIcMY5bViGOL2CP +Ii9UsUz2vYKTJL8AUZSrfIRcNpf/kw5hH6+k29lMdRbdTFnsavqUHsKuGKhdZko3RbOX+Wy1hUey +duLqI3i6Eaw/U7Qo+gObqqwzHebv4G22S7XRB8rjWP0u/qRSoR7RxrMG7IDf0fW0wLiWrtCq1dfZ +LFLYJEpVu5DdrlYy1RSUy5BVpiCnbcHu3oY8UKRUoCUOkXM+4mIiMsQ63HcgT6iIoNnY4xcii71G +7aYq3kGztDCGrINM/Er3eJpsPER3GrPoMuMWGox8sMK4Gho30se0mjay5d1X4b2ZjJ3zATtfK+O7 +tDJjMG/h7/AJfO3p/oW1U1kcfY77SVRG4WzYor6N82ehscp4E9F9FjLsnTSdzqMDeMovMcM5Sidl +dV/AW40ypRHPu4/GGQ8bbmajBuNSnF+fpQfNGtWZvfCxn72O572K6vl4Y5FS3z0bdlgNK/hgrcXI +Pzf4iidWFfkKR51dMDJ/RF5uTnZW5rChGUMGD/KmDzxrQFpqf0+/FN2dnORKTIiPi42JjoqMcDrC +w+yhITarxWzSVIUzGlTqKavV/Wm1fjXNc845g0XdU4eGul4NtX4dTWWny/j1Wimmny7pg+QlfSR9 +AUnfSUnm0AuoYPAgvdSj+3eWePQONnlcNfibSjw1uv+Q5Cskv0bydvApKRigl8Y1lOh+VquX+suW +NLSU1pZAXWuIrdhTXG8bPIhabSFgQ8D5Yz2NrSx2FJMMjy3Nb8WJ145F+RM8JaX+eE+JWIFfSS2t +m+mvHFddWpKYklIzeJCfFc/wTPeTZ7Q/3CtFqFhO4zcV+81yGn22eBq6UW8d1NmyqsNB02u9oTM9 +M+umVPuVuhoxh9OLeUv8sVceiDtVhfKI4uoVvXsTlZbSuNm6qLa0rND9G8ZV9+5NEVhTAx0Yy1PL +alvKMPUqGLF8go7Z+PKaaj9bjil18STiqQLPV+8pFS21c3S/1TPa09AypxauSWjx0/grUtoSEnxb +jS5KKNVbqqo9Kf7CRE9NXYmrNYpaxl+xOd6nx5/eM3hQq8MZMGxrWHiQCbX3ZupP9klOiguufPxJ +yzKxIs+5CAi/PkPHSqo9eKY8AfV51DIjD2K4ahhG+WfCI7P91uLaFke+aBfj/Vqqw6O3fEuIAM+h +f53eUhdsMaU6viXBijg5GWro7+H9Xq8/PV2EiLkYPsUaR8l6zuBBSzq4x9Po0FHAfFQJ29bV5GfA +/CkpwsE3dvhoOir+5nHVgbpO0xPbyJfhrfHzWtHT2dMTPVH0NPf0nBxe60Ekt8sTdrTfknbyX7gj +JrK0Id/PYv4H3fWB/vIJnvJxk6v10pbaoG3Lq06rBfrzTvYFOX9kcbWSyIMcT1RkL4JyyklhUakO +9aup+GeSQT2zw2xBVMoWppf5HbXnBLDGlpLyKwd1GEfEKFmcGhZcpj/fe3p95Gn105YX2qJgwXhV +lldNbmmxndaHUAtMeG6wQMRTVXWKXuynidiZqfjXYXTmCapJ9PtgsmIhgPgLNAWrpwkmBvkaXCI6 +Bw8qQ6JraSnz6GUttS11HUbzdI/u8LRs5c/z51saS2t7AqfD2HZjor9sVQ1s1cDysSk4jW71sJXj +Wn1s5YTJ1VsdRPrKquo2znhx7eia1v7oq96qE/lkKxetolFUdFGhcoaHbOMWKZ+41UfULHtV2SDr +MzoYyTZLTxujGR080OboaeNoUwNtPtkmLpFjiquqe0eP3JI1g+ULT3yDqw6xWPr+IlJwPjmDX1DB +y2RS5WcU8SUFw0Ot1p/Raz5zvWazIj/NiK8wGG632frqVf879IaHhPQR0KC3r21+xWWxqCf1Yrgj +NLSPgNDb1za/4rJaVfFRVerFcKfd3kfApP0v6tV6640MC/sZvX1t8yuukBCT1Cu+RWF4tMPRR8Bs +OvVB8Ez0hprED8MevXEREX0ELCJKzlxvmN0s9YrQhwkSo6L6CFjhzfAz1xsebpZKhV4MT4qJ6SNg +E1Fy5nodDosMXBH6IvHExfURCIE3+9rmV1xOp+2kXidRSnz8f4/eiF56MTzV5eojEGoTnyXP+IqO +OqUXw9N1vY9AGIIs9sz1xsbaxQdb8U8MH+Lx9BEIR3/CmetNSAg7qRfDM9PS+gg40d/XNr/icrnC +5H4SWwrDhw8c2EcgAtGXfOZ6k5PD5X4SWwrD8wcN6iMQKaLvzPXquuOkXgwvzszsIxATiSg5c72p +qZFyo4mtiuHleXl9BOJFlJy53vT0aLkhnCSHTxg1qo+AS0TJmesdMiRObgixpTB8SmlpHwE3oiTr +zPVmZSWKP2PIvxFg+Mzy8j4CKYiSvrb5FVdeXhJ8I/+J4VupSjlrc1qce/ezykDqAnFlYJs3yb1V +GaAktY10+zoUz+aI6MzwosGKjrNLhkQdOB+0CbRdEX+DmaYki78HAZeBmkGbQNtBu0HInkDRq4Pm +g9aDukSPkqS42nS3o2iAEo+x8TiBhCuxdBhkgBRyAzNAY0HTQKtB60EmKSda5oOWgbaDjsgenxLb +dksW1h7bdqMsNs+5NFNW6wLVKVNldfOFNYGyYlygLDk3IJYfEBuWHWgeMjpQDhgUKCNSM5tFabNn +dhbFKDF4yBgsvBHI+IsUzhi5aYMSTX4QV0zBFp8Ssbl/Wub67YpKTOEKo5nkNjoV1mZ3ZhbZuMEP +I5Dc/Et+KNDDD20Oc2auLzqP76dNoO0ghe/H/SH/kJbxLmFzYCFoPWg7aBfoMMjEu3Dvw/0B/4DC ++fuUASoETQOtB20HHQaZ+ftAB39P/M6RKPhCEOfvAR38XTzWu8BwvhfcXr4XS3ujLXdE5lbJeDOC +jDs1yMQmBpmImMwO/nrbDwMRUWnwNCLqGaUfjaIspV9b6jB3hxLXVjDb3cE/2qx73RuKhvI95AeJ +o+gezLyHdFAlqBbUCDKBewvcW9QMWgPaAPKDEGVAB0jnO0Cvgt6ioSAfqBJk4bvbME0H39WWNtpd +FMNf43/D68HNd/K/y/JV/pIsX+F/leXLKJNR7uAvtSW7qSgE/YQxDpQOlBno1/hfNvePcBtFTr4d +tnMDM0CFoLGgaaDVIBPfzvu1zXRHQMkztAOvfzdvo89k+RDdZyHfHLcvrRgBqAtIyz8bHGC9vj6N ++9LW3omqgLSbbwEnIO0Pq8AJSLvyWnAC0i5dAk5A2sw54ASkTZ4GTkDa2CpwgA5+z9P9B7hzx85l +elE4vxxWuhxWuhxWupxUfrm46QdVrO2utvR0WGydzzsw3d28jTU/y5rHs+b7WHM9a76GNV/LmgtY +88Ws2cuaXaw5mTX7WPMzLA+maGa+9tOqI3xxrHkHa36CNTex5jTWnMqa+7NmneX6OnhK27lZsiiV +xeYiselQnj0K2Secp8CiKYj5FOSE7cBdIEPWfBDS+wWE45NF2W9zemGgPiQ/c37ROfwFDHwBbniB +9oFUOOgFhNELUPICFIQDC0HTQJ2gwyADZIJ0Pyx8tcRwYAaoEDQNtAx0GGSSyzkM4jQ/uMRNcmEZ +wUWPFTX+Am7xIT+Fp/iSHC6H13GOstrFwpPZ2GQjmeeSPFtGOC3ODmbf8p39++/sZC2y8pv5akqC +I9YEy9VtPyS5O9gdbWnPuIui2e2UrCLq2AhKY6ko86hJ1nPIZRFlNrn4Yygz21yTMCy8LW2QexsL +E6O2uH9wHXB/5urgYA+6nnG/rXeorM39Jloe2+Le47rB/XJGhwUtz6Z1MBTbdCm61ZXnfmKHFL0W +Heva3NeIYov7d64x7rku2VEf6Li4CTVfuHt82mT3OdBX4pru9jVB5xZ3oetid0FAKkeM2eIeiiV4 +A2w6FjvQJSf1JEuFE3M7WINvkHmtudo81jzcnGkeZE4xu81J5kRzlCXC4rCEWUItNovFYrKoFm4h +S1SH0eXzir+vR5nkf54Qv3EZqZJ3cJJ/Xpd/gufMwuk88kcq5bx8wmhW7u+cQeXTdf/RCZ4OZhs3 +2a95RjN/RDmVV43253nLO8zGeH+ut9xvrryoupWxm2vQ6ucr8Wu/qrqDGaJpeaL4vriVGHMuvylR +lGctv6mmhuJilhTGFUaMco4oK/kZqA2i99QVdxqf5F9bPqHa/2hSjT9TMEZSTbn/P8QHyK3sa3ak +tGQr+0oUNdVblVHs69Lxol0ZVVJTU97BJkk50tlXkEPEfCXlLHgxCznSLckBuXUBuVSMh1x/UUDO +aqVUKZdqtUo5lQm51qb+pSWt/ftLmVidmqRMU6zeW2ZHKmRSU6VMTDPtkDI7YpqFjH+UFHG5IJLs +kiIsgVxSxMUSpMikUyIZQZEbTorcIGdS2CkZV0DG3tUjY++CjPfXXvWjvV62eWTNjCni422tp7Qe +VOu/cUlDnL95uq63zqgJftVNq50+o0GUdfX+Gk99iX+Gp0RvHTnlZ7qniO6RnpJWnBOrqlun+OpL +2kb6RpZ66kpqNo+pzM49ba4bTs6VXfkzyiqFsmwx15jcn+nOFd1jxFy5Yq5cMdcY3xg5F8kYr6xu +tdDomuIpgXIzD7EhXmsTU2pGxzgaR8ngHZkSd03iNpxWNlKIt8Yf6hntt4NE1+CiwUWiC3tKdIWJ +L/TBrrhrRqYkbmMbg10ONDs9o8m7aHHTYoornV0S+NeEC02LFguDB9Db9EsX+kr9vrqSpkX4VeBP +n1DuLxw3ubrVbEZrrXgkf35PW0hIaYfRGWgcgsZ80agoJwVFW4Fos1qDgj/1/+JgWSx2QTN/ZjPz +JbNF1FSj+JPLqzhSQVXwU+g2nKXE66GpBg/YxLysqUdHcNleLwXqJJ65hxYtDnJBWywKloGRGNLU +Y5KTlzCW96TFFkGhyFwkvnto4gsQfkOnOFOcqQDxX4p+1JXOH30aHSdd7RRproh18Dl8HiQH+eIb +eaPCK1gF58xDPEFrhEC82nhTnPcCx4Gpjk8oo+LQsKG0gE2NzEmJLuIDWcdTTwkt2wAraCe0pPri +eAHZeME0mk/LaBOpG9C/Qb33jjiv4+jUqYeoECqycrKit+3cuVOM3YcFH9c68et5r6/EFhoaOnoi +SbSFhYSAl2iz2O3gJSo+uzN7rrqMr+Z3WtTHVWYlk8YVq8ZCOdthI7jPZ0vxZA8lJn6XIOG3Oxx8 +IpjPfc7wcHCu0FBgmN0uW4/44sPDTRPFdz2BdjswIVTz2cOzNaErTOjSmK75NK7Fh2xjBWw5BUyy +wIuHCnoClYKKEwVUWBg7gjlHDBvKptJULwt0pnicJpM5Z/jw3Cx+vL3ojarb92csUq8adbX7yTE7 +puGVU2YcVPZp2/BbNIlt911t46o91Z5tL7FrOVE5rgt5lW181ATXLD5Tq7fOiKp1dbr3aG9Gvh// +ceTHUYdjv4j/OKnLbbhj3G5vQkFMQUJ5QqN7jds8hPe3D4nJ5zn2cl5qL4s613WhbZJ9lv1j06cx +x9g3YQ4WrYSFOMIp0RVidpIt2qWExHUY37cLOwvmaeGIuCxhxa+flu5IdYb3CID5pl0IgPnaN0B0 +h6c6HLudzOH0OWudzU7V7QsJ4RPdPmFqZ4RwgxODAm5wmsLCgHGyT2gICQkxTXSGORwmUf+yXfjD +GZgswPhqxWzORREyDiJklETI+Ijob3aImtkherabd5n3mQ2z6jYX4lygmJPFKsxxwu3mZDGfOVTM +ZQ4Vms0JYiJzfHJ2pfDqNyfd6a04BOZEr902dUGBQ7Q5TngLDmCvFR4qLBDkHOGMgMdpKlswlRak +5Jg8/dLScrIjhmdlxsQ6s5wsKiYrc3hOdpqnn0nJq39x2ZuL5+y5rnZtxuYT+uOLlzy48aql915/ +z6rj969nSsu4Ih52rIxHvLrjLy/tffVF8f293DioJqujKBrRcY8v1k2uaD5RmapNtU4MqVfmavOt +9SGW6A7jQI+pDvjGCy7JJXBAxDvasaijCeqwiPz4Ya6iiIqEIte4iCnx4111EfMS6lxLTUujj/Kj +cQ6KYeH22NjKmNqYRvyEdYWvcWxwcIdDTXTZzLSNP0rM6JS7icmdIVzlYIzdFulSQ2KxlWQ4gPm6 +XXgFzPdbhENiffYO4712YXm78KxYFZjPpYvtQpV1QHq2387sCW7UNqemZYvy6WTsPDdzx3QYP/qm +CEUxWQ6LmMIhve6QceDob/b1T8/u8bWMCuFZoN7L7y7p9zDpd5f0eIz0Pvye28vvcLK3Qvj8ANoQ +A0cXiDYZCXD3ianoKDwUMSJjasGJBQUMbh8R0bPXcTpYsJDFmuB9cjooK5OcUeaUGOF6lpI2QDr/ +4m2Dvtz6WfdhFvXemyyM/XjQ1rZ8xqoTe/m40LxJN1z9CJsUe387czOFhbKzuj/o/sGhb9rWwG67 +vrjhIZEtIxEOzdobFMsG+pKjrCw8PiN+aDxSd/xdoXfbH7FbEuxn2f3xnfFqvDCrL8GdnWSxK6Hh +LhuL5t6oSFUxkW19FIsyIqUNI31qrGRipTFjpfliU1X8OLmFiX3fuXlYXrZMql6XO3sNsXif2L3x +Pjt2L0XJ1HqWTKv9xH6mQcG0iv0s02yUsLhIvu0iWsB80i7TbYdx7GmZce+Pi3+WbaMUOspsyKve +o703nNdb4PimwFEgd90h76GpyK8FBQUnsO1GiCRbfIUvyuE0Wc0mi4mbHNaIRHKawhPxyvWmX3st +82I/LsxyenKycrJzh2M7xpqFG6Kjs6I9zrb16yMTrlty/pTEvMzxJbt2KetWLZibXXZhxJ9sZbXT +V/14CXbeSvE/zZGX8SZlD/viuU2YSpFokmiWiO3wowx56mG0HkYVwZskOB4ibKtINEk0S8TgE3Lj +UA+j9TAYfMKXJDi8EMS7T6JJolminFm+HHsYrYeRM+cLzjpcbISx1jXWDVa/tdO6z3rEaiar29po +bbauDzZ1WQ2rzW1lxMwqXqcmRfh8sJz1GvxO0kyqzWRO1Uhdr25Q/Wqn2qWaOtUjKidVV3ejpqoi +WYuAAHPMFyvCQVVFEKg2Mb8qQ0HtCQUw3TITyHXaRCyoF1jGVMadeqci4S4skO9U+Nsrd5sgsd8W +LviFU7rXG4nThYKsu7K9vV39Yteu49Fq2vG9YvdcB8gV3mQVPntvX57mP5+zr7dO85DP2dcfp/nA +FyKdIC0uzg+bc/PkOWJzdk6gHDosUPZLDZwvUqNjs8M1t7Ze26epYwFHNMWtNWrNmqHhVzsOU0pq +YCPmBjdiNKJ5PbFOOiJ+rOq0m7pwtusxvthZviS5F6XxSRo/uA8twU0YsDwYQ+ZgOukCukA93QXC +B9iF0gvC8KLW98qCta9r17YdKxNvqxXds9UUvK0iKJmt9S0KdQx2nO0od6iFul/nbn1gqCcpMzoz +aXRSo75Gt+TH5ieeF3teYo3lotApsVMS51jmhs52zIudm9ipvxH1ftz7CW8kH4g6kNylG3qMR/U6 +vNE5ar6jTD3PMdnxccgXSd2OEGcYXlYuk5mZYlxhIRQW3/MGiu85osSL44NbeCa+/24bc9h8tlpb +s03V5QFFlwcUG3KTL0SkMltcsH6sXVjQJt5Zwnw2oU5kLzAHfTnCXrZFLDKLZwWPJIHDSOBgkkrU +ydgatoH52RGmulkhG4u8LtOB8A5ziEmYQ8zAHGIZTJ5KIHFUbhApGiOmY6FiKhYhfMbi3WNy41jv +N5bcJhUO8db65oDjxKnWwFsLJ5TCQ84RwRMKZGlBpDMrWqTDmJjoKC5OKwOcSq8zyooH8m9pWLl7 +zuJ9V01ePcT50JKljz28qKm1e7b2XMu4cauMO+7vPn7j+fknjisP7HzxlTdf2fF24C8JCnaWuDRF +YRxvjzjtXyGd9L3FIAtZjG6yktU4gZO+Tf5/5RBgKIUC7WQHhkkMpzCgg8KBTuCPiCMnMJIigFEU +CYwGHqcYigLGUjQwDniM4ikWfALFg0+kBKBLYhIlApPJZfxAbok6JQFTyA3sRzrQA/ye+lMKMJX6 +AdOA39EA8gDPov7AgZQGTJfopQHGURpEZwEHSxxC6cAM8gKH0mDgMOC3lElDgFmUAcymocY3lCNx +OA0D5lIWMI+yjf+kERLzKQc4UmIBDQeeTbnAUZQHLKQRxtfko3xgEY0EjqYCYDHwKyqhs4GlNApY +RoXGERpDPuA5VAQ8l0YDz5NYTsXA86kEWIHfH4fpAoljaQywks4BjqNzjS9pvMQJdB6wCmfRQzSR +KoCTJF5IFwCraazxL6qhSuBk4CG6iMaBn0ITgFOpCnixxGk00fiCamkSsI4uBE4Hfk4zqAY4kyYD +6+ki4CU0xfiMZklsoKnA2XSxcZDmUC34uRIvpTrgPJqO9stoBnC+xEaaaXxKC6geuJBmAZskLqIG +4xNaTLOBS2gO8HLgx7SU5gKvoHnAK+ky4FUSr6b5wN9RI/AaWmAcwI9agc3UBLyWFgF/T4sN8f9w +lwD/IHE5XW7sp+tpKXAFXQFcSVcCb6CrjA+pha4G3ki/Q8sq4Id0E10DvJmWAVfTtcA1wC76I/0e +eAtdB/wP+oOxj26VeBstB66lFcDbaSV67wDuozvpBuA6ajE+oLvoRuDdtAr4J4n30M3A9bQauIHW +AO8Fvk/30R+B99MtwAfoP4AP0q3Ge/QQ3Wa8Sw/TWuBGuh34iMRH6Q7gY3Qn8HG6C/iExCfpbuAm ++hPQT/cAW4F7qY3WAzfTBmA73We8Q0/R/cY/aYvEp+kBYAc9CNxKDwG3SXyGNgKfpUeMt+k5ehT4 +Z4nb6TFgJz0O/As9AXyengS+QJuMt+hF8gP/Sq3Gm/SSxL9RG/DvtNnYQy9TO3AHPQV8hbYAX6Wn +gTvx/ttDr9FW4C6Ju2kb8B/0LPB1es54g94Avk576M/AN2k78C3qNP5Bb0v8Jz0PfIdeAO6lF4Hv +SnyP/gp8n14CfkB/M3bTPold9LKxiz6kHcD99ArwI4kH6FXgx7QT+Am9BvyUdhuv0UGJn9E/gJ/T +68ZO+oLeAP5L4iHaA/yS3jJepcP0NvCIxK/on8Cv6R3gf9Je4DcSv6X3jFfoKL0P/I4+AH4P3EE/ +0D7gMeoCHqcPgT9KPEEfGS9TNx0AGvQx8N85/f98Tv/qN57Tv/jVOf2zX8jpn/0kpx/8hZz+6U9y ++ie/IqcfOJnTF56W0z/6hZz+kczpH/0kp++XOX1/r5y+X+b0/TKn7++V0z/8SU7vkjm9S+b0rt9g +Tn/n/1FO3/PvnP7vnP6by+m/9XP6bzen/9I5/d85/d85/edz+t9/+zn9vwCXmHoeCmVuZHN0cmVh +bQplbmRvYmoKOSAwIG9iago8PC9UeXBlIC9Gb250RGVzY3JpcHRvcgovRm9udE5hbWUgL0FBQUFB +QStBcmlhbE1UCi9GbGFncyA0Ci9Bc2NlbnQgOTA1LjI3MzQ0Ci9EZXNjZW50IC0yMTEuOTE0MDYK +L1N0ZW1WIDQ1Ljg5ODQzOAovQ2FwSGVpZ2h0IDcxNS44MjAzMQovSXRhbGljQW5nbGUgMAovRm9u +dEJCb3ggWy02NjQuNTUwNzggLTMyNC43MDcwMyAyMDAwIDEwMDUuODU5MzhdCi9Gb250RmlsZTIg +OCAwIFI+PgplbmRvYmoKMTAgMCBvYmoKPDwvVHlwZSAvRm9udAovRm9udERlc2NyaXB0b3IgOSAw +IFIKL0Jhc2VGb250IC9BQUFBQUErQXJpYWxNVAovU3VidHlwZSAvQ0lERm9udFR5cGUyCi9DSURU +b0dJRE1hcCAvSWRlbnRpdHkKL0NJRFN5c3RlbUluZm8gPDwvUmVnaXN0cnkgKEFkb2JlKQovT3Jk +ZXJpbmcgKElkZW50aXR5KQovU3VwcGxlbWVudCAwPj4KL1cgWzE2IFszMzMuMDA3ODEgMjc3Ljgz +MjAzXSAyMCA3MiA1NTYuMTUyMzQgNzMgWzI3Ny44MzIwM10gNzYgNzkgMjIyLjE2Nzk3IDgzIFs1 +NTYuMTUyMzRdXQovRFcgNzUwPj4KZW5kb2JqCjExIDAgb2JqCjw8L0ZpbHRlciAvRmxhdGVEZWNv +ZGUKL0xlbmd0aCAyNzE+PiBzdHJlYW0KeJxdkdtqxCAQhu99irncXizRbNplIQSWLAu56IGmfQCj +k1RojBhzkbevhzSFCiofM//vzJjVza3RykH2ZifRooNeaWlxnhYrEDoclCYsB6mE2yieYuSGZF7c +rrPDsdH9RMoSIHv30dnZFQ5XOXX4QLJXK9EqPcDhs249t4sx3ziidkBJVYHE3js9c/PCR4Qsyo6N +9HHl1qPX/GV8rAYhj8xSNWKSOBsu0HI9ICmpXxWUd78qglr+ixdJ1fXii9uQzQqfTemJVYGKOtLT +JdE9UR3p8RTpTKPv5pD/+u3PMxrTGItXfktO50jFJRkWm0UShSrDNPcRiMVa330ceWw7NKw07r9i +JhNUYf8AtiGI+QplbmRzdHJlYW0KZW5kb2JqCjQgMCBvYmoKPDwvVHlwZSAvRm9udAovU3VidHlw +ZSAvVHlwZTAKL0Jhc2VGb250IC9BQUFBQUErQXJpYWxNVAovRW5jb2RpbmcgL0lkZW50aXR5LUgK +L0Rlc2NlbmRhbnRGb250cyBbMTAgMCBSXQovVG9Vbmljb2RlIDExIDAgUj4+CmVuZG9iagp4cmVm +CjAgMTIKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDA0MDEg +MDAwMDAgbiAKMDAwMDAwMDEwMSAwMDAwMCBuIAowMDAwMDEwNDU5IDAwMDAwIG4gCjAwMDAwMDAx +MzggMDAwMDAgbiAKMDAwMDAwMDYwOSAwMDAwMCBuIAowMDAwMDAwNjY0IDAwMDAwIG4gCjAwMDAw +MDA3MTEgMDAwMDAgbiAKMDAwMDAwOTU4NSAwMDAwMCBuIAowMDAwMDA5ODE5IDAwMDAwIG4gCjAw +MDAwMTAxMTcgMDAwMDAgbiAKdHJhaWxlcgo8PC9TaXplIDEyCi9Sb290IDcgMCBSCi9JbmZvIDEg +MCBSPj4Kc3RhcnR4cmVmCjEwNTk4CiUlRU9GCg== + +----- diff --git a/lam/lib/3rdParty/tcpdf/CHANGELOG.TXT b/lam/lib/3rdParty/tcpdf/CHANGELOG.TXT index 8fb0afae5..fd4c141cd 100644 --- a/lam/lib/3rdParty/tcpdf/CHANGELOG.TXT +++ b/lam/lib/3rdParty/tcpdf/CHANGELOG.TXT @@ -1,3 +1,37 @@ +6.9.3 (2025-04-20) + - New fix for "Deserialization of untrusted data" (check on valid protocols). + - Removed global phar configuration. + +6.9.2 (2025-04-18) + - Quick fix for "Deserialization of untrusted data" security vulnerability reported by Positive Technologies. + - Disable phar protocol globally. + +6.9.1 (2025-04-03) + - Fixed "Path Traversal" security vulnerability reported by Positive Technologies. + +6.9.0 (2025-03-30) + - Added PHP 8.4 testing. + - Removed tcpdf_import.php and tcpdf_parser.php files (for a parser check the tc-lib-pdf-parser project instead). + - Fix composer.json. + +6.8.2 (2025-01-26) + - Fix some annotation flags values. + - Remove examples from packaging. + +6.8.1 (2025-01-26) - UNTAGGED + - Check relative paths on SVG images. + +6.8.0 (2024-12-23) + - Requires PHP 7.1+ and curl extension. + - Escape error message. + - Use strict time-constant function to compare TCPDF-tag hashes. + - Add K_CURLOPTS config array to set custom cURL options (NOTE: some defaults have changed). + - Add some addTTFfont fixes from tc-lib-pdf-font. + +6.7.8 (2024-12-13) + - Improve SVG detection by checking for (mandatory) namespace. + - Use late state binding now that minimum PHP version is 5.5. + 6.7.7 (2024-10-26) - Update regular expression to avoid ReDoS (CVE-2024-22641) - [PHP 8.4] Fix: Curl CURLOPT_BINARYTRANSFER deprecated #675 diff --git a/lam/lib/3rdParty/tcpdf/README.md b/lam/lib/3rdParty/tcpdf/README.md index f59f66339..81f2ca6e0 100644 --- a/lam/lib/3rdParty/tcpdf/README.md +++ b/lam/lib/3rdParty/tcpdf/README.md @@ -6,7 +6,7 @@ * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2024 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2025 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF diff --git a/lam/lib/3rdParty/tcpdf/VERSION b/lam/lib/3rdParty/tcpdf/VERSION index 38f118fae..5f54f91ea 100644 --- a/lam/lib/3rdParty/tcpdf/VERSION +++ b/lam/lib/3rdParty/tcpdf/VERSION @@ -1 +1 @@ -6.7.7 +6.9.3 diff --git a/lam/lib/3rdParty/tcpdf/composer.json b/lam/lib/3rdParty/tcpdf/composer.json index 666dac3fd..06688693f 100644 --- a/lam/lib/3rdParty/tcpdf/composer.json +++ b/lam/lib/3rdParty/tcpdf/composer.json @@ -12,7 +12,7 @@ "barcodes" ], "homepage": "http://www.tcpdf.org/", - "version": "6.7.7", + "version": "6.9.3", "license": "LGPL-3.0-or-later", "authors": [ { @@ -22,15 +22,14 @@ } ], "require": { - "php": ">=5.5.0" + "php": ">=7.1.0", + "ext-curl": "*" }, "autoload": { "classmap": [ "config", "include", "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", "tcpdf_barcodes_1d.php", "tcpdf_barcodes_2d.php", "include/tcpdf_colors.php", @@ -43,10 +42,5 @@ "include/barcodes/pdf417.php", "include/barcodes/qrcode.php" ] - }, - "archive": { - "exclude": [ - "/examples" - ] } } diff --git a/lam/lib/3rdParty/tcpdf/include/tcpdf_fonts.php b/lam/lib/3rdParty/tcpdf/include/tcpdf_fonts.php index a71c84b7e..fbe7009c6 100644 --- a/lam/lib/3rdParty/tcpdf/include/tcpdf_fonts.php +++ b/lam/lib/3rdParty/tcpdf/include/tcpdf_fonts.php @@ -1,13 +1,13 @@ 0) { + if (preg_match_all('#dup[\s]([0-9]+)[\s]*+/([^\s]*+)[\s]put#sU', $font, $fmap, PREG_SET_ORDER) > 0) { foreach ($fmap as $v) { $imap[$v[2]] = $v[1]; } @@ -229,22 +230,22 @@ class TCPDF_FONTS { $eplain .= chr($chr ^ ($r >> 8)); $r = ((($chr + $r) * $c1 + $c2) % 65536); } - if (preg_match('#/ForceBold[\s]*([^\s]*)#', $eplain, $matches) > 0) { + if (preg_match('#/ForceBold[\s]*+([^\s]*+)#', $eplain, $matches) > 0) { if ($matches[1] == 'true') { $fmetric['Flags'] |= 0x40000; } } - if (preg_match('#/StdVW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) { + if (preg_match('#/StdVW[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) { $fmetric['StemV'] = intval($matches[1]); } else { $fmetric['StemV'] = 70; } - if (preg_match('#/StdHW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) { + if (preg_match('#/StdHW[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) { $fmetric['StemH'] = intval($matches[1]); } else { $fmetric['StemH'] = 30; } - if (preg_match('#/BlueValues[\s]*\[([^\]]*)#', $eplain, $matches) > 0) { + if (preg_match('#/BlueValues[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) { $bv = explode(' ', $matches[1]); if (count($bv) >= 6) { $v1 = intval($bv[2]); @@ -265,7 +266,7 @@ class TCPDF_FONTS { $fmetric['CapHeight'] = 700; } // get the number of random bytes at the beginning of charstrings - if (preg_match('#/lenIV[\s]*([0-9]*)#', $eplain, $matches) > 0) { + if (preg_match('#/lenIV[\s]*+([\d]*+)#', $eplain, $matches) > 0) { $lenIV = intval($matches[1]); } else { $lenIV = 4; @@ -273,7 +274,7 @@ class TCPDF_FONTS { $fmetric['Leading'] = 0; // get charstring data $eplain = substr($eplain, (strpos($eplain, '/CharStrings') + 1)); - preg_match_all('#/([A-Za-z0-9\.]*)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER); + preg_match_all('#/([A-Za-z0-9\.]*+)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER); if (!empty($enc) AND isset(TCPDF_FONT_DATA::$encmap[$enc])) { $enc_map = TCPDF_FONT_DATA::$encmap[$enc]; } else { @@ -1780,9 +1781,9 @@ class TCPDF_FONTS { */ public static function UTF8ArrayToUniArray($ta, $isunicode=true) { if ($isunicode) { - return array_map(get_called_class().'::unichrUnicode', $ta); + return array_map(static::class.'::unichrUnicode', $ta); } - return array_map(get_called_class().'::unichrASCII', $ta); + return array_map(static::class.'::unichrASCII', $ta); } /** @@ -2002,7 +2003,7 @@ class TCPDF_FONTS { if ($isunicode) { // requires PCRE unicode support turned on $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY); - $carr = array_map(get_called_class().'::uniord', $chars); + $carr = array_map(static::class.'::uniord', $chars); } else { $chars = str_split($str); $carr = array_map('ord', $chars); diff --git a/lam/lib/3rdParty/tcpdf/include/tcpdf_static.php b/lam/lib/3rdParty/tcpdf/include/tcpdf_static.php index ac9c3e1fd..956f34a48 100644 --- a/lam/lib/3rdParty/tcpdf/include/tcpdf_static.php +++ b/lam/lib/3rdParty/tcpdf/include/tcpdf_static.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 1.1.2 + * @version 1.1.5 */ /** @@ -46,7 +46,7 @@ * Static methods used by the TCPDF class. * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 1.1.1 + * @version 1.1.5 * @author Nicola Asuni - info@tecnick.com */ class TCPDF_STATIC { @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.7.7'; + private static $tcpdf_version = '6.9.3'; /** * String alias for total number of pages. @@ -106,6 +106,31 @@ class TCPDF_STATIC { */ public static $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'); + /** + * Array of default cURL options for curl_setopt_array. + * + * @var array cURL options. + */ + protected const CURLOPT_DEFAULT = [ + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_MAXREDIRS => 5, + CURLOPT_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS, + CURLOPT_SSL_VERIFYHOST => 2, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_TIMEOUT => 30, + CURLOPT_USERAGENT => 'tcpdf', + ]; + + /** + * Array of fixed cURL options for curl_setopt_array. + * + * @var array cURL options. + */ + protected const CURLOPT_FIXED = [ + CURLOPT_FAILONERROR => true, + CURLOPT_RETURNTRANSFER => true, + ]; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /** @@ -1823,23 +1848,19 @@ class TCPDF_STATIC { */ public static function url_exists($url) { $crs = curl_init(); - // encode query params in URL to get right response form the server - $url = self::encodeUrlQuery($url); - curl_setopt($crs, CURLOPT_URL, $url); - curl_setopt($crs, CURLOPT_NOBODY, true); - curl_setopt($crs, CURLOPT_FAILONERROR, true); - if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) { - curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true); - } - curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($crs, CURLOPT_TIMEOUT, 30); - curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); - curl_setopt($crs, CURLOPT_MAXREDIRS, 5); - if (defined('CURLOPT_PROTOCOLS')) { - curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); - } + $curlopts = []; + if ( + (ini_get('open_basedir') == '') + && (ini_get('safe_mode') === '' + || ini_get('safe_mode') === false) + ) { + $curlopts[CURLOPT_FOLLOWLOCATION] = true; + } + $curlopts = array_replace($curlopts, self::CURLOPT_DEFAULT); + $curlopts = array_replace($curlopts, K_CURLOPTS); + $curlopts = array_replace($curlopts, self::CURLOPT_FIXED); + $curlopts[CURLOPT_URL] = $url; + curl_setopt_array($crs, $curlopts); curl_exec($crs); $code = curl_getinfo($crs, CURLINFO_HTTP_CODE); curl_close($crs); @@ -1960,21 +1981,19 @@ class TCPDF_STATIC { ) { // try to get remote file data using cURL $crs = curl_init(); - curl_setopt($crs, CURLOPT_URL, $path); - curl_setopt($crs, CURLOPT_FAILONERROR, true); - curl_setopt($crs, CURLOPT_RETURNTRANSFER, true); - if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) { - curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true); - } - curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5); - curl_setopt($crs, CURLOPT_TIMEOUT, 30); - curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); - curl_setopt($crs, CURLOPT_MAXREDIRS, 5); - if (defined('CURLOPT_PROTOCOLS')) { - curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); + $curlopts = []; + if ( + (ini_get('open_basedir') == '') + && (ini_get('safe_mode') === '' + || ini_get('safe_mode') === false) + ) { + $curlopts[CURLOPT_FOLLOWLOCATION] = true; } + $curlopts = array_replace($curlopts, self::CURLOPT_DEFAULT); + $curlopts = array_replace($curlopts, K_CURLOPTS); + $curlopts = array_replace($curlopts, self::CURLOPT_FIXED); + $curlopts[CURLOPT_URL] = $url; + curl_setopt_array($crs, $curlopts); $ret = curl_exec($crs); curl_close($crs); if ($ret !== false) { @@ -2633,7 +2652,6 @@ class TCPDF_STATIC { return $page_mode; } - } // END OF TCPDF_STATIC CLASS //============================================================+ diff --git a/lam/lib/3rdParty/tcpdf/tcpdf.php b/lam/lib/3rdParty/tcpdf/tcpdf.php index 48ae2b908..deefe4a29 100644 --- a/lam/lib/3rdParty/tcpdf/tcpdf.php +++ b/lam/lib/3rdParty/tcpdf/tcpdf.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 6.6.5 + * @version 6.9.3 */ // TCPDF configuration @@ -128,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php'); * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
    * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 6.7.7 + * @version 6.9.3 * @author Nicola Asuni - info@tecnick.com * @IgnoreAnnotation("protected") * @IgnoreAnnotation("public") @@ -3007,6 +3007,7 @@ class TCPDF { public function Error($msg) { // unset all class variables $this->_destroy(true); + $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8'); if (defined('K_TCPDF_THROW_EXCEPTION_ERROR') AND !K_TCPDF_THROW_EXCEPTION_ERROR) { die('TCPDF ERROR: '.$msg); } else { @@ -6988,7 +6989,7 @@ class TCPDF { unset($imgdata); $imsize = @getimagesize($file); if ($imsize === FALSE) { - unlink($file); + $this->_unlink($file); $file = $original_file; } } @@ -7221,7 +7222,7 @@ class TCPDF { $tempname = TCPDF_STATIC::getObjFilename('img', $this->file_id); $img->writeImage($tempname); $info = TCPDF_IMAGES::_parsejpeg($tempname); - unlink($tempname); + $this->_unlink($tempname); $img->destroy(); } catch(Exception $e) { $info = false; @@ -7857,15 +7858,16 @@ class TCPDF { if ($handle = @opendir(K_PATH_CACHE)) { while ( false !== ( $file_name = readdir( $handle ) ) ) { if (strpos($file_name, '__tcpdf_'.$this->file_id.'_') === 0) { - unlink(K_PATH_CACHE.$file_name); + $this->_unlink(K_PATH_CACHE.$file_name); } } closedir($handle); } if (isset($this->imagekeys)) { foreach($this->imagekeys as $file) { - if (strpos($file, K_PATH_CACHE) === 0 && TCPDF_STATIC::file_exists($file)) { - @unlink($file); + if ((strpos($file, K_PATH_CACHE.'__tcpdf_'.$this->file_id.'_') === 0) + && TCPDF_STATIC::file_exists($file)) { + $this->_unlink($file); } } } @@ -8310,15 +8312,15 @@ class TCPDF { break; } case 'locked': { - $fval += 1 << 8; + $fval += 1 << 7; break; } case 'togglenoview': { - $fval += 1 << 9; + $fval += 1 << 8; break; } case 'lockedcontents': { - $fval += 1 << 10; + $fval += 1 << 9; break; } default: { @@ -17259,7 +17261,7 @@ class TCPDF { $hlen = intval(substr($data, 0, $hpos)); $hash = substr($data, $hpos + 1, $hlen); $encoded = substr($data, $hpos + 2 + $hlen); - if ($hash != $this->hashTCPDFtag($encoded)) { + if (!hash_equals( $this->hashTCPDFtag($encoded), $hash)) { $this->Error('Invalid parameters'); } return json_decode(urldecode($encoded), true); @@ -18867,6 +18869,29 @@ class TCPDF { unset($dom); } + /** + * Check if the path is relative. + * @param string $path path to check + * @return boolean true if the path is relative + * @protected + * @since 6.9.1 + */ + protected function isRelativePath($path) { + return (strpos(str_ireplace('%2E', '.', $this->unhtmlentities($path)), '..') !== false); + } + + /** + * Check if it contains a non-allowed external protocol. + * @param string $path path to check + * @return boolean true if the protocol is not allowed. + * @protected + * @since 6.9.3 + */ + protected function hasExtForbiddenProtocol($path) { + return ((strpos($path, '://') !== false) + && (preg_match('|^https?://|', $path) !== 1)); + } + /** * Process opening tags. * @param array $dom html dom array @@ -19055,17 +19080,19 @@ class TCPDF { if ($imgsrc[0] === '@') { // data stream $imgsrc = '@'.base64_decode(substr($imgsrc, 1)); - $type = preg_match('/]*)>/si', $imgsrc) ? 'svg' : ''; + $type = preg_match('/]*[^>]*>.*<\/svg>/is', $imgsrc) ? 'svg' : ''; } else if (preg_match('@^data:image/([^;]*);base64,(.*)@', $imgsrc, $reg)) { $imgsrc = '@'.base64_decode($reg[2]); $type = $reg[1]; - } elseif (strpos($imgsrc, '../') !== false) { + } elseif ($this->isRelativePath($imgsrc)) { // accessing parent folders is not allowed break; } elseif ( $this->allowLocalFiles && substr($imgsrc, 0, 7) === 'file://') { // get image type from a local file path $imgsrc = substr($imgsrc, 7); $type = TCPDF_IMAGES::getImageFileType($imgsrc); + } elseif ($this->hasExtForbiddenProtocol($imgsrc)) { + break; } else { if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) { // fix image path @@ -19124,7 +19151,7 @@ class TCPDF { $imglink = ''; if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) { $imglink = $this->HREF['url']; - if ($imglink[0] == '#') { + if ($imglink[0] == '#' AND is_numeric($imglink[1])) { // convert url to internal link $lnkdata = explode(',', $imglink); if (isset($lnkdata[0])) { @@ -23485,7 +23512,7 @@ class TCPDF { if (preg_match('/font-family[\s]*:[\s]*([^\;\"]*)/si', $svgstyle['font'], $regs)) { $font_family = $this->getFontFamilyName($regs[1]); } else { - $font_family = $svgstyle['font-family']; + $font_family = $this->getFontFamilyName($svgstyle['font-family']); } if (preg_match('/font-size[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) { $font_size = trim($regs[1]); @@ -24466,6 +24493,9 @@ class TCPDF { $img = '@'.base64_decode(substr($img, strlen($m[0]))); } else { // fix image path + if ($this->isRelativePath($img) || $this->hasExtForbiddenProtocol($img)) { + break; + } if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) { // replace relative path with full server path $img = $this->svgdir.'/'.$img; @@ -24786,6 +24816,20 @@ class TCPDF { return TCPDF_STATIC::file_exists($file); } + /** + * Wrapper for unlink with disabled protocols. + * @param string $file + * @return bool + */ + protected function _unlink($file) + { + if ((strpos($file, '://') !== false) && ((substr($file, 0, 7) !== 'file://') || (!$this->allowLocalFiles))) { + // forbidden protocol + return false; + } + return @unlink($file); + } + } // END OF TCPDF CLASS //============================================================+ diff --git a/lam/lib/3rdParty/tcpdf/tcpdf_autoconfig.php b/lam/lib/3rdParty/tcpdf/tcpdf_autoconfig.php index 2bcfccb82..d31ee87ed 100644 --- a/lam/lib/3rdParty/tcpdf/tcpdf_autoconfig.php +++ b/lam/lib/3rdParty/tcpdf/tcpdf_autoconfig.php @@ -3,11 +3,11 @@ // File name : tcpdf_autoconfig.php // Version : 1.1.1 // Begin : 2013-05-16 -// Last Update : 2014-12-18 +// Last Update : 2025-04-18 // Authors : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- -// Copyright (C) 2011-2014 Nicola Asuni - Tecnick.com LTD +// Copyright (C) 2011-2025 Nicola Asuni - Tecnick.com LTD // // This file is part of TCPDF software library. // @@ -37,9 +37,14 @@ * @file * Try to automatically configure some TCPDF constants if not defined. * @package com.tecnick.tcpdf - * @version 1.1.1 + * @version 1.2.1 */ +// Disable phar stream wrapper globally. +// if (in_array('phar', stream_get_wrappers(), true)) { +// stream_wrapper_unregister('phar'); +// } + // DOCUMENT_ROOT fix for IIS Webserver if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) { if(isset($_SERVER['SCRIPT_FILENAME'])) { @@ -240,6 +245,11 @@ if (!defined('K_TIMEZONE')) { define('K_TIMEZONE', @date_default_timezone_get()); } +// Custom cURL options for curl_setopt_array. +if (!defined('K_CURLOPTS')) { + define('K_CURLOPTS', array()); +} + //============================================================+ // END OF FILE //============================================================+ diff --git a/lam/lib/3rdParty/tcpdf/tcpdf_import.php b/lam/lib/3rdParty/tcpdf/tcpdf_import.php deleted file mode 100644 index 57f9f4f4b..000000000 --- a/lam/lib/3rdParty/tcpdf/tcpdf_import.php +++ /dev/null @@ -1,104 +0,0 @@ -. -// -// See LICENSE.TXT file for more information. -// ------------------------------------------------------------------- -// -// Description : This is a PHP class extension of the TCPDF library to -// import existing PDF documents. -// -//============================================================+ - -/** - * @file - * !!! THIS CLASS IS UNDER DEVELOPMENT !!! - * This is a PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.
    - * @package com.tecnick.tcpdf - * @author Nicola Asuni - * @version 1.0.001 - */ - -// include the TCPDF class -require_once(dirname(__FILE__).'/tcpdf.php'); -// include PDF parser class -require_once(dirname(__FILE__).'/tcpdf_parser.php'); - -/** - * @class TCPDF_IMPORT - * !!! THIS CLASS IS UNDER DEVELOPMENT !!! - * PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.
    - * @package com.tecnick.tcpdf - * @brief PHP class extension of the TCPDF library to import existing PDF documents. - * @version 1.0.001 - * @author Nicola Asuni - info@tecnick.com - */ -class TCPDF_IMPORT extends TCPDF { - - /** - * Import an existing PDF document - * @param string $filename Filename of the PDF document to import. - * @return void - * @public - * @since 1.0.000 (2011-05-24) - */ - public function importPDF($filename) { - // load document - $rawdata = file_get_contents($filename); - if ($rawdata === false) { - $this->Error('Unable to get the content of the file: '.$filename); - } - // configuration parameters for parser - $cfg = array( - 'die_for_errors' => false, - 'ignore_filter_decoding_errors' => true, - 'ignore_missing_filter_decoders' => true, - ); - try { - // parse PDF data - $pdf = new TCPDF_PARSER($rawdata, $cfg); - } catch (Exception $e) { - die($e->getMessage()); - } - // get the parsed data - $data = $pdf->getParsedData(); - // release some memory - unset($rawdata); - - // ... - - - print_r($data); // DEBUG - - - unset($pdf); - } - -} // END OF CLASS - -//============================================================+ -// END OF FILE -//============================================================+ diff --git a/lam/lib/3rdParty/tcpdf/tcpdf_parser.php b/lam/lib/3rdParty/tcpdf/tcpdf_parser.php deleted file mode 100644 index 4156230a3..000000000 --- a/lam/lib/3rdParty/tcpdf/tcpdf_parser.php +++ /dev/null @@ -1,815 +0,0 @@ -. -// -// See LICENSE.TXT file for more information. -// ------------------------------------------------------------------- -// -// Description : This is a PHP class for parsing PDF documents. -// -//============================================================+ - -/** - * @file - * This is a PHP class for parsing PDF documents.
    - * @package com.tecnick.tcpdf - * @author Nicola Asuni - * @version 1.0.15 - */ - -// include class for decoding filters -require_once(dirname(__FILE__).'/include/tcpdf_filters.php'); - -/** - * @class TCPDF_PARSER - * This is a PHP class for parsing PDF documents.
    - * @package com.tecnick.tcpdf - * @brief This is a PHP class for parsing PDF documents.. - * @version 1.0.15 - * @author Nicola Asuni - info@tecnick.com - */ -class TCPDF_PARSER { - - /** - * Raw content of the PDF document. - * @private - */ - private $pdfdata = ''; - - /** - * XREF data. - * @protected - */ - protected $xref = array(); - - /** - * Array of PDF objects. - * @protected - */ - protected $objects = array(); - - /** - * Class object for decoding filters. - * @private - */ - private $FilterDecoders; - - /** - * Array of configuration parameters. - * @private - */ - private $cfg = array( - 'die_for_errors' => false, - 'ignore_filter_decoding_errors' => true, - 'ignore_missing_filter_decoders' => true, - ); - -// ----------------------------------------------------------------------------- - - /** - * Parse a PDF document an return an array of objects. - * @param string $data PDF data to parse. - * @param array $cfg Array of configuration parameters: - * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception; - * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors; - * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors. - * @public - * @since 1.0.000 (2011-05-24) - */ - public function __construct($data, $cfg=array()) { - if (empty($data)) { - $this->Error('Empty PDF data.'); - } - // find the pdf header starting position - if (($trimpos = strpos($data, '%PDF-')) === FALSE) { - $this->Error('Invalid PDF data: missing %PDF header.'); - } - // get PDF content string - $this->pdfdata = substr($data, $trimpos); - // get length - $pdflen = strlen($this->pdfdata); - // set configuration parameters - $this->setConfig($cfg); - // get xref and trailer data - $this->xref = $this->getXrefData(); - // parse all document objects - $this->objects = array(); - foreach ($this->xref['xref'] as $obj => $offset) { - if (!isset($this->objects[$obj]) AND ($offset > 0)) { - // decode objects with positive offset - $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true); - } - } - // release some memory - unset($this->pdfdata); - $this->pdfdata = ''; - } - - /** - * Set the configuration parameters. - * @param array $cfg Array of configuration parameters: - * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception; - * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors; - * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors. - * @public - */ - protected function setConfig($cfg) { - if (isset($cfg['die_for_errors'])) { - $this->cfg['die_for_errors'] = !!$cfg['die_for_errors']; - } - if (isset($cfg['ignore_filter_decoding_errors'])) { - $this->cfg['ignore_filter_decoding_errors'] = !!$cfg['ignore_filter_decoding_errors']; - } - if (isset($cfg['ignore_missing_filter_decoders'])) { - $this->cfg['ignore_missing_filter_decoders'] = !!$cfg['ignore_missing_filter_decoders']; - } - } - - /** - * Return an array of parsed PDF document objects. - * @return array Array of parsed PDF document objects. - * @public - * @since 1.0.000 (2011-06-26) - */ - public function getParsedData() { - return array($this->xref, $this->objects); - } - - /** - * Get Cross-Reference (xref) table and trailer data from PDF document data. - * @param int $offset xref offset (if know). - * @param array $xref previous xref array (if any). - * @return array containing xref and trailer data. - * @protected - * @since 1.0.000 (2011-05-24) - */ - protected function getXrefData($offset=0, $xref=array()) { - if ($offset == 0) { - // find last startxref - if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) { - $this->Error('Unable to find startxref'); - } - $matches = array_pop($matches); - $startxref = $matches[1]; - } elseif (strpos($this->pdfdata, 'xref', $offset) == $offset) { - // Already pointing at the xref table - $startxref = $offset; - } elseif (preg_match('/([0-9]+[\s][0-9]+[\s]obj)/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) { - // Cross-Reference Stream object - $startxref = $offset; - } elseif (preg_match('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) { - // startxref found - $startxref = $matches[1][0]; - } else { - $this->Error('Unable to find startxref'); - } - // check xref position - if (strpos($this->pdfdata, 'xref', $startxref) == $startxref) { - // Cross-Reference - $xref = $this->decodeXref($startxref, $xref); - } else { - // Cross-Reference Stream - $xref = $this->decodeXrefStream($startxref, $xref); - } - if (empty($xref)) { - $this->Error('Unable to find xref'); - } - return $xref; - } - - /** - * Decode the Cross-Reference section - * @param int $startxref Offset at which the xref section starts (position of the 'xref' keyword). - * @param array $xref Previous xref array (if any). - * @return array containing xref and trailer data. - * @protected - * @since 1.0.000 (2011-06-20) - */ - protected function decodeXref($startxref, $xref=array()) { - $startxref += 4; // 4 is the length of the word 'xref' - // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP) - $offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref); - // initialize object number - $obj_num = 0; - // search for cross-reference entries or subsection - while (preg_match('/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { - if ($matches[0][1] != $offset) { - // we are on another section - break; - } - $offset += strlen($matches[0][0]); - if ($matches[3][0] == 'n') { - // create unique object index: [object number]_[generation number] - $index = $obj_num.'_'.intval($matches[2][0]); - // check if object already exist - if (!isset($xref['xref'][$index])) { - // store object offset position - $xref['xref'][$index] = intval($matches[1][0]); - } - ++$obj_num; - } elseif ($matches[3][0] == 'f') { - ++$obj_num; - } else { - // object number (index) - $obj_num = intval($matches[1][0]); - } - } - // get trailer data - if (preg_match('/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { - $trailer_data = $matches[1][0]; - if (!isset($xref['trailer']) OR empty($xref['trailer'])) { - // get only the last updated version - $xref['trailer'] = array(); - // parse trailer_data - if (preg_match('/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) { - $xref['trailer']['size'] = intval($matches[1]); - } - if (preg_match('/Root[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) { - $xref['trailer']['root'] = intval($matches[1]).'_'.intval($matches[2]); - } - if (preg_match('/Encrypt[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) { - $xref['trailer']['encrypt'] = intval($matches[1]).'_'.intval($matches[2]); - } - if (preg_match('/Info[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) { - $xref['trailer']['info'] = intval($matches[1]).'_'.intval($matches[2]); - } - if (preg_match('/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) { - $xref['trailer']['id'] = array(); - $xref['trailer']['id'][0] = $matches[1]; - $xref['trailer']['id'][1] = $matches[2]; - } - } - if (preg_match('/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) { - // get previous xref - $xref = $this->getXrefData(intval($matches[1]), $xref); - } - } else { - $this->Error('Unable to find trailer'); - } - return $xref; - } - - /** - * Decode the Cross-Reference Stream section - * @param int $startxref Offset at which the xref section starts. - * @param array $xref Previous xref array (if any). - * @return array containing xref and trailer data. - * @protected - * @since 1.0.003 (2013-03-16) - */ - protected function decodeXrefStream($startxref, $xref=array()) { - // try to read Cross-Reference Stream - $xrefobj = $this->getRawObject($startxref); - $xrefcrs = $this->getIndirectObject($xrefobj[1], $startxref, true); - if (!isset($xref['trailer']) OR empty($xref['trailer'])) { - // get only the last updated version - $xref['trailer'] = array(); - $filltrailer = true; - } else { - $filltrailer = false; - } - if (!isset($xref['xref'])) { - $xref['xref'] = array(); - } - $valid_crs = false; - $columns = 0; - $sarr = $xrefcrs[0][1]; - if (!is_array($sarr)) { - $sarr = array(); - } - foreach ($sarr as $k => $v) { - if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) { - $valid_crs = true; - } elseif (($v[0] == '/') AND ($v[1] == 'Index') AND (isset($sarr[($k +1)]))) { - // first object number in the subsection - $index_first = intval($sarr[($k +1)][1][0][1]); - // number of entries in the subsection - $index_entries = intval($sarr[($k +1)][1][1][1]); - } elseif (($v[0] == '/') AND ($v[1] == 'Prev') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) { - // get previous xref offset - $prevxref = intval($sarr[($k +1)][1]); - } elseif (($v[0] == '/') AND ($v[1] == 'W') AND (isset($sarr[($k +1)]))) { - // number of bytes (in the decoded stream) of the corresponding field - $wb = array(); - $wb[0] = intval($sarr[($k +1)][1][0][1]); - $wb[1] = intval($sarr[($k +1)][1][1][1]); - $wb[2] = intval($sarr[($k +1)][1][2][1]); - } elseif (($v[0] == '/') AND ($v[1] == 'DecodeParms') AND (isset($sarr[($k +1)][1]))) { - $decpar = $sarr[($k +1)][1]; - foreach ($decpar as $kdc => $vdc) { - if (($vdc[0] == '/') AND ($vdc[1] == 'Columns') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) { - $columns = intval($decpar[($kdc +1)][1]); - } elseif (($vdc[0] == '/') AND ($vdc[1] == 'Predictor') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) { - $predictor = intval($decpar[($kdc +1)][1]); - } - } - } elseif ($filltrailer) { - if (($v[0] == '/') AND ($v[1] == 'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) { - $xref['trailer']['size'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { - $xref['trailer']['root'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { - $xref['trailer']['info'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) { - $xref['trailer']['encrypt'] = $sarr[($k +1)][1]; - } elseif (($v[0] == '/') AND ($v[1] == 'ID') AND (isset($sarr[($k +1)]))) { - $xref['trailer']['id'] = array(); - $xref['trailer']['id'][0] = $sarr[($k +1)][1][0][1]; - $xref['trailer']['id'][1] = $sarr[($k +1)][1][1][1]; - } - } - } - // decode data - if ($valid_crs AND isset($xrefcrs[1][3][0])) { - // number of bytes in a row - $rowlen = ($columns + 1); - // convert the stream into an array of integers - $sdata = unpack('C*', $xrefcrs[1][3][0]); - // split the rows - $sdata = array_chunk($sdata, $rowlen); - // initialize decoded array - $ddata = array(); - // initialize first row with zeros - $prev_row = array_fill (0, $rowlen, 0); - // for each row apply PNG unpredictor - foreach ($sdata as $k => $row) { - // initialize new row - $ddata[$k] = array(); - // get PNG predictor value - $predictor = (10 + $row[0]); - // for each byte on the row - for ($i=1; $i<=$columns; ++$i) { - // new index - $j = ($i - 1); - $row_up = $prev_row[$j]; - if ($i == 1) { - $row_left = 0; - $row_upleft = 0; - } else { - $row_left = $row[($i - 1)]; - $row_upleft = $prev_row[($j - 1)]; - } - switch ($predictor) { - case 10: { // PNG prediction (on encoding, PNG None on all rows) - $ddata[$k][$j] = $row[$i]; - break; - } - case 11: { // PNG prediction (on encoding, PNG Sub on all rows) - $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff); - break; - } - case 12: { // PNG prediction (on encoding, PNG Up on all rows) - $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff); - break; - } - case 13: { // PNG prediction (on encoding, PNG Average on all rows) - $ddata[$k][$j] = (($row[$i] + (($row_left + $row_up) / 2)) & 0xff); - break; - } - case 14: { // PNG prediction (on encoding, PNG Paeth on all rows) - // initial estimate - $p = ($row_left + $row_up - $row_upleft); - // distances - $pa = abs($p - $row_left); - $pb = abs($p - $row_up); - $pc = abs($p - $row_upleft); - $pmin = min($pa, $pb, $pc); - // return minimum distance - switch ($pmin) { - case $pa: { - $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff); - break; - } - case $pb: { - $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff); - break; - } - case $pc: { - $ddata[$k][$j] = (($row[$i] + $row_upleft) & 0xff); - break; - } - } - break; - } - default: { // PNG prediction (on encoding, PNG optimum) - $this->Error('Unknown PNG predictor'); - break; - } - } - } - $prev_row = $ddata[$k]; - } // end for each row - // complete decoding - $sdata = array(); - // for every row - foreach ($ddata as $k => $row) { - // initialize new row - $sdata[$k] = array(0, 0, 0); - if ($wb[0] == 0) { - // default type field - $sdata[$k][0] = 1; - } - $i = 0; // count bytes in the row - // for every column - for ($c = 0; $c < 3; ++$c) { - // for every byte on the column - for ($b = 0; $b < $wb[$c]; ++$b) { - if (isset($row[$i])) { - $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8)); - } - ++$i; - } - } - } - $ddata = array(); - // fill xref - if (isset($index_first)) { - $obj_num = $index_first; - } else { - $obj_num = 0; - } - foreach ($sdata as $k => $row) { - switch ($row[0]) { - case 0: { // (f) linked list of free objects - break; - } - case 1: { // (n) objects that are in use but are not compressed - // create unique object index: [object number]_[generation number] - $index = $obj_num.'_'.$row[2]; - // check if object already exist - if (!isset($xref['xref'][$index])) { - // store object offset position - $xref['xref'][$index] = $row[1]; - } - break; - } - case 2: { // compressed objects - // $row[1] = object number of the object stream in which this object is stored - // $row[2] = index of this object within the object stream - $index = $row[1].'_0_'.$row[2]; - $xref['xref'][$index] = -1; - break; - } - default: { // null objects - break; - } - } - ++$obj_num; - } - } // end decoding data - if (isset($prevxref)) { - // get previous xref - $xref = $this->getXrefData($prevxref, $xref); - } - return $xref; - } - - /** - * Get object type, raw value and offset to next object - * @param int $offset Object offset. - * @return array containing object type, raw value and offset to next object - * @protected - * @since 1.0.000 (2011-06-20) - */ - protected function getRawObject($offset=0) { - $objtype = ''; // object type to be returned - $objval = ''; // object value to be returned - // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP) - $offset += strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $offset); - // get first char - $char = $this->pdfdata[$offset]; - // get object type - switch ($char) { - case '%': { // \x25 PERCENT SIGN - // skip comment and search for next token - $next = strcspn($this->pdfdata, "\r\n", $offset); - if ($next > 0) { - $offset += $next; - return $this->getRawObject($offset); - } - break; - } - case '/': { // \x2F SOLIDUS - // name object - $objtype = $char; - ++$offset; - if (preg_match('/^([^\x00\x09\x0a\x0c\x0d\x20\s\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+)/', substr($this->pdfdata, $offset, 256), $matches) == 1) { - $objval = $matches[1]; // unescaped value - $offset += strlen($objval); - } - break; - } - case '(': // \x28 LEFT PARENTHESIS - case ')': { // \x29 RIGHT PARENTHESIS - // literal string object - $objtype = $char; - ++$offset; - $strpos = $offset; - if ($char == '(') { - $open_bracket = 1; - while ($open_bracket > 0) { - if (!isset($this->pdfdata[$strpos])) { - break; - } - $ch = $this->pdfdata[$strpos]; - switch ($ch) { - case '\\': { // REVERSE SOLIDUS (5Ch) (Backslash) - // skip next character - ++$strpos; - break; - } - case '(': { // LEFT PARENHESIS (28h) - ++$open_bracket; - break; - } - case ')': { // RIGHT PARENTHESIS (29h) - --$open_bracket; - break; - } - } - ++$strpos; - } - $objval = substr($this->pdfdata, $offset, ($strpos - $offset - 1)); - $offset = $strpos; - } - break; - } - case '[': // \x5B LEFT SQUARE BRACKET - case ']': { // \x5D RIGHT SQUARE BRACKET - // array object - $objtype = $char; - ++$offset; - if ($char == '[') { - // get array content - $objval = array(); - do { - // get element - $element = $this->getRawObject($offset); - $offset = $element[2]; - $objval[] = $element; - } while ($element[0] != ']'); - // remove closing delimiter - array_pop($objval); - } - break; - } - case '<': // \x3C LESS-THAN SIGN - case '>': { // \x3E GREATER-THAN SIGN - if (isset($this->pdfdata[($offset + 1)]) AND ($this->pdfdata[($offset + 1)] == $char)) { - // dictionary object - $objtype = $char.$char; - $offset += 2; - if ($char == '<') { - // get array content - $objval = array(); - do { - // get element - $element = $this->getRawObject($offset); - $offset = $element[2]; - $objval[] = $element; - } while ($element[0] != '>>'); - // remove closing delimiter - array_pop($objval); - } - } else { - // hexadecimal string object - $objtype = $char; - ++$offset; - if (($char == '<') AND (preg_match('/^([0-9A-Fa-f\x09\x0a\x0c\x0d\x20]+)>/iU', substr($this->pdfdata, $offset), $matches) == 1)) { - // remove white space characters - $objval = strtr($matches[1], "\x09\x0a\x0c\x0d\x20", ''); - $offset += strlen($matches[0]); - } elseif (($endpos = strpos($this->pdfdata, '>', $offset)) !== FALSE) { - $offset = $endpos + 1; - } - } - break; - } - default: { - if (substr($this->pdfdata, $offset, 6) == 'endobj') { - // indirect object - $objtype = 'endobj'; - $offset += 6; - } elseif (substr($this->pdfdata, $offset, 4) == 'null') { - // null object - $objtype = 'null'; - $offset += 4; - $objval = 'null'; - } elseif (substr($this->pdfdata, $offset, 4) == 'true') { - // boolean true object - $objtype = 'boolean'; - $offset += 4; - $objval = 'true'; - } elseif (substr($this->pdfdata, $offset, 5) == 'false') { - // boolean false object - $objtype = 'boolean'; - $offset += 5; - $objval = 'false'; - } elseif (substr($this->pdfdata, $offset, 6) == 'stream') { - // start stream object - $objtype = 'stream'; - $offset += 6; - if (preg_match('/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) { - $offset += strlen($matches[0]); - if (preg_match('/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) { - $objval = substr($this->pdfdata, $offset, $matches[0][1]); - $offset += $matches[1][1]; - } - } - } elseif (substr($this->pdfdata, $offset, 9) == 'endstream') { - // end stream object - $objtype = 'endstream'; - $offset += 9; - } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) { - // indirect object reference - $objtype = 'objref'; - $offset += strlen($matches[0]); - $objval = intval($matches[1]).'_'.intval($matches[2]); - } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) { - // object start - $objtype = 'obj'; - $objval = intval($matches[1]).'_'.intval($matches[2]); - $offset += strlen ($matches[0]); - } elseif (($numlen = strspn($this->pdfdata, '+-.0123456789', $offset)) > 0) { - // numeric object - $objtype = 'numeric'; - $objval = substr($this->pdfdata, $offset, $numlen); - $offset += $numlen; - } - break; - } - } - return array($objtype, $objval, $offset); - } - - /** - * Get content of indirect object. - * @param string $obj_ref Object number and generation number separated by underscore character. - * @param int $offset Object offset. - * @param boolean $decoding If true decode streams. - * @return array containing object data. - * @protected - * @since 1.0.000 (2011-05-24) - */ - protected function getIndirectObject($obj_ref, $offset=0, $decoding=true) { - $obj = explode('_', $obj_ref); - if (($obj === false) OR (count($obj) != 2)) { - $this->Error('Invalid object reference: '.$obj); - return; - } - $objref = $obj[0].' '.$obj[1].' obj'; - // ignore leading zeros - $offset += strspn($this->pdfdata, '0', $offset); - if (strpos($this->pdfdata, $objref, $offset) != $offset) { - // an indirect reference to an undefined object shall be considered a reference to the null object - return array('null', 'null', $offset); - } - // starting position of object content - $offset += strlen($objref); - // get array of object content - $objdata = array(); - $i = 0; // object main index - do { - $oldoffset = $offset; - // get element - $element = $this->getRawObject($offset); - $offset = $element[2]; - // decode stream using stream's dictionary information - if ($decoding AND ($element[0] == 'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] == '<<')) { - $element[3] = $this->decodeStream($objdata[($i - 1)][1], $element[1]); - } - $objdata[$i] = $element; - ++$i; - } while (($element[0] != 'endobj') AND ($offset != $oldoffset)); - // remove closing delimiter - array_pop($objdata); - // return raw object content - return $objdata; - } - - /** - * Get the content of object, resolving indect object reference if necessary. - * @param string $obj Object value. - * @return array containing object data. - * @protected - * @since 1.0.000 (2011-06-26) - */ - protected function getObjectVal($obj) { - if ($obj[0] == 'objref') { - // reference to indirect object - if (isset($this->objects[$obj[1]])) { - // this object has been already parsed - return $this->objects[$obj[1]]; - } elseif (isset($this->xref[$obj[1]])) { - // parse new object - $this->objects[$obj[1]] = $this->getIndirectObject($obj[1], $this->xref[$obj[1]], false); - return $this->objects[$obj[1]]; - } - } - return $obj; - } - - /** - * Decode the specified stream. - * @param array $sdic Stream's dictionary array. - * @param string $stream Stream to decode. - * @return array containing decoded stream data and remaining filters. - * @protected - * @since 1.0.000 (2011-06-22) - */ - protected function decodeStream($sdic, $stream) { - // get stream length and filters - $slength = strlen($stream); - if ($slength <= 0) { - return array('', array()); - } - $filters = array(); - foreach ($sdic as $k => $v) { - if ($v[0] == '/') { - if (($v[1] == 'Length') AND (isset($sdic[($k + 1)])) AND ($sdic[($k + 1)][0] == 'numeric')) { - // get declared stream length - $declength = intval($sdic[($k + 1)][1]); - if ($declength < $slength) { - $stream = substr($stream, 0, $declength); - $slength = $declength; - } - } elseif (($v[1] == 'Filter') AND (isset($sdic[($k + 1)]))) { - // resolve indirect object - $objval = $this->getObjectVal($sdic[($k + 1)]); - if ($objval[0] == '/') { - // single filter - $filters[] = $objval[1]; - } elseif ($objval[0] == '[') { - // array of filters - foreach ($objval[1] as $flt) { - if ($flt[0] == '/') { - $filters[] = $flt[1]; - } - } - } - } - } - } - // decode the stream - $remaining_filters = array(); - foreach ($filters as $filter) { - if (in_array($filter, TCPDF_FILTERS::getAvailableFilters())) { - try { - $stream = TCPDF_FILTERS::decodeFilter($filter, $stream); - } catch (Exception $e) { - $emsg = $e->getMessage(); - if ((($emsg[0] == '~') AND !$this->cfg['ignore_missing_filter_decoders']) - OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) { - $this->Error($e->getMessage()); - } - } - } else { - // add missing filter to array - $remaining_filters[] = $filter; - } - } - return array($stream, $remaining_filters); - } - - /** - * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true. - * @param string $msg The error message - * @public - * @since 1.0.000 (2011-05-23) - */ - public function Error($msg) { - if ($this->cfg['die_for_errors']) { - die('TCPDF_PARSER ERROR: '.$msg); - } else { - throw new Exception('TCPDF_PARSER ERROR: '.$msg); - } - } - -} // END OF TCPDF_PARSER CLASS - -//============================================================+ -// END OF FILE -//============================================================+ diff --git a/lam/lib/account.inc b/lam/lib/account.inc index 4ba08b22d..003c46be8 100644 --- a/lam/lib/account.inc +++ b/lam/lib/account.inc @@ -3,7 +3,7 @@ This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) Copyright (C) 2003 - 2006 Tilo Lutz - 2009 - 2024 Roland Gruber + 2009 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,15 +31,18 @@ */ use LAM\PLUGINS\EXTRA_INVALID_CREDENTIALS\ExtraInvalidCredentials; +use LAM\PLUGINS\SMS\SmsService; use LAM\TYPES\TypeManager; +use LDAP\Connection; /** * This function will return all values from $array without values of $values. * - * @param array $values list of values which should be removed - * @param array $array list of original values - * @return array list of remaining values + * @template T + * @param T[] $values list of values which should be removed + * @param T[]|null $array list of original values + * @return T[] list of remaining values */ function array_delete($values, $array) { // Loop for every entry and check if it should be removed @@ -59,8 +62,8 @@ function array_delete($values, $array) { /** * Checks if a string exists in an array, ignoring case. * - * @param String $needle search string - * @param array $haystack array + * @param string|null $needle search string + * @param array|null $haystack array */ function in_array_ignore_case($needle, $haystack) { if (!is_array($haystack)) { @@ -77,6 +80,18 @@ function in_array_ignore_case($needle, $haystack) { return false; } +/** + * Checks if two arrays have the same content. + * + * @param array $array1 array 1 + * @param array $array2 array 2 + * @return bool same content + */ +function areArrayContentsEqual(array $array1, array $array2): bool { + $intersect = array_intersect($array1, $array2); + return ((count($array1) === count($array2)) && (count($intersect) === count($array1))); +} + /** * Sorts an array in natural order by its keys. * @@ -93,58 +108,10 @@ function natCaseKeySort(array $toSort): array { return $newElements; } -/** - * This function will return the days from 1.1.1970 until now. - * - * @return number of days - */ -function getdays() { - $days = time() / 86400; - settype($days, 'integer'); - return $days; -} - -/** - * Takes a list of Samba flags and creates the corresponding flag string. - * - * @param array $input is an array of Samba flags (e.g. X or D) - * @return string Samba flag string - */ -function smbflag($input) { - // Start character - $flag = "["; - // Add Options - if ($input['W']) { - $flag .= "W"; - } - else { - $flag .= "U"; - } - if ($input['D']) { - $flag .= "D"; - } - if ($input['X']) { - $flag .= "X"; - } - if ($input['N']) { - $flag .= "N"; - } - if ($input['S']) { - $flag .= "S"; - } - if ($input['H']) { - $flag .= "H"; - } - // Expand string to fixed length - $flag = str_pad($flag, 12); - // End character - return $flag . "]"; -} - /** * Generates the NT hash of a password. * - * @param string password original password + * @param string $password password original password * @return string password hash */ function ntPassword($password) { @@ -153,16 +120,17 @@ function ntPassword($password) { /** * Returns the hash value of a plain text password. - * @param string $password the password string + * + * @param string|null $password the password string * @param boolean $enabled marks the hash as enabled/disabled (e.g. by prefixing "!") * @param string $hashType password hash type (CRYPT, CRYPT-SHA512, SHA, SSHA, MD5, SMD5, PLAIN, K5KEY) * @return string the password hash - * @see getSupportedHashTypes() * + * @see getSupportedHashTypes() */ function pwd_hash($password, $enabled = true, $hashType = 'SSHA') { // check for empty password - if (!$password || ($password == "")) { + if (($password === null) || ($password === "")) { return ""; } switch ($hashType) { @@ -273,22 +241,19 @@ function pwd_enable($hash) { if ((str_starts_with($hash, "!{")) || (str_starts_with($hash, "*{"))) { return substr($hash, 1, strlen($hash)); } - // check for "!" or "*" at beginning of password hash - else { - if (str_starts_with($hash, "{")) { - $pos = strpos($hash, "}"); - if ((substr($hash, $pos + 1, 1) == "!") || (substr($hash, $pos + 1, 1) == "*")) { - // enable hash - return substr($hash, 0, $pos + 1) . substr($hash, $pos + 2, strlen($hash)); - } - else { - return $hash; // not disabled - } + elseif (str_starts_with($hash, "{")) { + $pos = strpos($hash, "}"); + if ((substr($hash, $pos + 1, 1) === "!") || (substr($hash, $pos + 1, 1) === "*")) { + // enable hash + return substr($hash, 0, $pos + 1) . substr($hash, $pos + 2, strlen($hash)); } else { - return $hash; // password is plain text + return $hash; // not disabled } } + else { + return $hash; // password is plain text + } } /** @@ -302,22 +267,19 @@ function pwd_disable($hash) { if ((str_starts_with($hash, "!{")) || (str_starts_with($hash, "*{"))) { return $hash; } - // check for "!" or "*" at beginning of password hash - else { - if (str_starts_with($hash, "{")) { - $pos = strpos($hash, "}"); - if ((substr($hash, $pos + 1, 1) == "!") || (substr($hash, $pos + 1, 1) == "*")) { - // hash already disabled - return $hash; - } - else { - return substr($hash, 0, $pos + 1) . "!" . substr($hash, $pos + 1, strlen($hash)); // not disabled - } + elseif (str_starts_with($hash, "{")) { + $pos = strpos($hash, "}"); + if ((substr($hash, $pos + 1, 1) === "!") || (substr($hash, $pos + 1, 1) === "*")) { + // hash already disabled + return $hash; } else { - return $hash; // password is plain text + return substr($hash, 0, $pos + 1) . "!" . substr($hash, $pos + 1, strlen($hash)); // not disabled } } + else { + return $hash; // password is plain text + } } /** @@ -335,7 +297,7 @@ function pwd_is_lockable($password) { if (str_starts_with($password, '{SASL}')) { return false; } - return ((str_starts_with($password, "{")) || (substr($password, 1, 1) == "{")) && (strpos($password, "}") > 3); + return ((str_starts_with($password, "{")) || (substr($password, 1, 1) === "{")) && (strpos($password, "}") > 3); } /** @@ -363,14 +325,15 @@ function pwd_is_enabled($hash) { * Generates a random password with 14 digits by default. * * @param int $length length of password (defaults to 14) - * @param bool $checkStrength check if password matches the policy + * @param bool $checkStrength check if the password matches the policy * @return String password */ function generateRandomPassword($length = 14, bool $checkStrength = true): string { $list = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_'; $minLength = $_SESSION['cfgMain']->passwordMinLength; - if ($minLength > $length) { - $length = $minLength; + $length = max($length, $minLength); + if (isset($_SESSION['config']) && is_numeric($_SESSION['config']->getPwdPolicyMinLength())) { + $length = max($length, $_SESSION['config']->getPwdPolicyMinLength()); } for ($x = 0; $x < 10000; $x++) { $password = ''; @@ -378,7 +341,7 @@ function generateRandomPassword($length = 14, bool $checkStrength = true): strin $rand = abs(getRandomNumber() % 65); $password .= $list[$rand]; } - if (!$checkStrength || checkPasswordStrength($password, null, null) === true) { + if (!$checkStrength || checkPasswordStrength($password, null, []) === true) { break; } } @@ -404,7 +367,7 @@ function generateRandomText($length = 20): string { /** * Checks if the given password matches the crypto hash. * - * @param String type hash type (must be one of getSupportedHashTypes()) + * @param string $type type hash type (must be one of getSupportedHashTypes()) * @param string $hash password hash value * @param string $password plain text password to check * @return bool hash matches @@ -428,18 +391,18 @@ function checkPasswordHash($type, $hash, $password) { return (strcmp($hash, base64_encode(hex2bin(md5($password)))) == 0); case 'CRYPT': $parts = explode('$', $hash); - if (sizeof($parts) === 1) { + if (count($parts) === 1) { $salt = substr($hash, 0, 2); $pwdHash = crypt($password, $salt); return (strcmp($hash, $pwdHash) == 0); } - if (sizeof($parts) === 4) { + if (count($parts) === 4) { $version = $parts[1]; $salt = $parts[2]; $pwdHash = crypt($password, '$' . $version . '$' . $salt); return (strcmp($hash, $pwdHash) == 0); } - elseif (sizeof($parts) === 5) { + elseif (count($parts) === 5) { $version = $parts[1]; $rounds = $parts[2]; $salt = $parts[3]; @@ -459,7 +422,7 @@ function checkPasswordHash($type, $hash, $password) { /** * Returns the number of character classes in a password. * - * @param string $password password + * @param string|null $password password * @return int number of classes */ function getNumberOfCharacterClasses($password): int { @@ -467,16 +430,16 @@ function getNumberOfCharacterClasses($password): int { return 0; } $classesCount = 0; - if (preg_match("/[a-z]/", $password)) { + if (preg_match('/[a-z]/', $password)) { $classesCount++; } - if (preg_match("/[A-Z]/", $password)) { + if (preg_match('/[A-Z]/', $password)) { $classesCount++; } - if (preg_match("/[0-9]/", $password)) { + if (preg_match('/\d/', $password)) { $classesCount++; } - if (preg_match("/[^a-z0-9]/i", $password)) { + if (preg_match('/[^a-z0-9]/i', $password)) { $classesCount++; } return $classesCount; @@ -485,7 +448,7 @@ function getNumberOfCharacterClasses($password): int { /** * Returns an array with all Samba 3 domain entries under the given suffix * - * @param handle LDAP handle (if null then $_SESSION['ldap']->server() is used) + * @param Connection|null $server LDAP handle (if null then $_SESSION['ldap']->server() is used) * @param String $suffix LDAP suffix to search (if null then $_SESSION['config']->get_Suffix('smbDomain') is used) * @return array list of samba3domain objects */ @@ -502,9 +465,9 @@ function search_domains($server = null, $suffix = null) { $server = $_SESSION['ldap']->server(); } $filter = '(objectclass=sambaDomain)'; - $units = searchLDAPPaged($server, $suffix, $filter, $attr, false, 0); + $units = searchLDAPPaged($server, $suffix, $filter, $attr, 0, 0); // extract attributes - for ($i = 0; $i < sizeof($units); $i++) { + for ($i = 0; $i < count($units); $i++) { $ret[$i] = new samba3domain(); $ret[$i]->dn = $units[$i]['dn']; $ret[$i]->name = $units[$i]['sambadomainname'][0]; @@ -584,55 +547,55 @@ function get_preg($argument, $regexp) { $pregexpr = ''; switch ($regexp) { case 'password': - $pregexpr = '/^([[:alnum:]\\^\\ \\|\\#\\*\\,\\.\\;\\:\\_\\+\\!\\%\\&\\/\\?\\{\\(\\)\\}\\[\\]\\$§°@=-])*$/u'; + $pregexpr = '/^([[:alnum:]^ |#*,.;:_+!%&\/?{()}\[\]$§°@=-])*$/u'; break; case 'groupname': // all letters, numbers, space and ._- are allowed characters case 'username': case 'hostname': - $pregexpr = '/^([[:alnum:]%#@\\.\\ \\_\\$-])+$/u'; + $pregexpr = '/^([[:alnum:]%#@. _$-])+$/u'; break; case 'krbUserName': - $pregexpr = '/^([[:alnum:]#@\\/\\.\\ \\_\\$-])+$/u'; + $pregexpr = '/^([[:alnum:]#@\/. _$-])+$/u'; break; case 'hostObject': - $pregexpr = '/^[!]?([[:alnum:]@\\.\\ \\_\\$\\:*-])+$/u'; + $pregexpr = '/^!?([[:alnum:]@. _$:*-])+$/u'; break; - case 'usernameList': // comma separated list of user names + case 'usernameList': // comma separated list of usernames case 'groupnameList': // comma separated list of group names - $pregexpr = '/^([[:alnum:]%#@\\.\\ \\_-])+(,([[:alnum:]%#@\\.\\ \\_-])+)*$/u'; + $pregexpr = '/^([[:alnum:]%#@. _-])+(,([[:alnum:]%#@. _-])+)*$/u'; break; case 'realname': // Allow all but \, <, >, =, $, ? case 'cn': - $pregexpr = '/^[^\\\<>=\\$\\?]+(\\$)?$/'; + $pregexpr = '/^[^\\\\<>=$?]+(\$)?$/'; break; case "telephone": // Allow letters, numbers, space, brackets, /-+. - $pregexpr = '/^(\\+)*([0-9a-zA-Z\\.\\ \\(\\)\\/-])*$/'; + $pregexpr = '/^(\+)*([0-9a-zA-Z. ()\/-])*$/'; break; case "email": - $pregexpr = '/^([0-9a-zA-Z\'!~#+*%\\$\\/\\._-])+[@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*$/'; + $pregexpr = '/^([0-9a-zA-Z\'!~#+*%$\/._-])+[@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*$/'; break; case "emailWithName": - $pregexpr = '/^([[:alnum:] \'!~#+*%\\$\\(\\)_-])+ <([0-9a-zA-Z\'!~#+*%\\$\\/\\._-])+[@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*>$/u'; + $pregexpr = '/^([[:alnum:] \'!~#+*%$()_-])+ <([0-9a-zA-Z\'!~#+*%$\/._-])+[@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*>$/u'; break; case "mailLocalAddress": - $pregexpr = '/^([0-9a-zA-Z+\\/\\._-])*([@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*)?$/'; + $pregexpr = '/^([0-9a-zA-Z+\\/._-])*([@]([0-9a-zA-Z-])+([.]([0-9a-zA-Z-])+)*)?$/'; break; case 'kolabEmailPrefix': - $pregexpr = '/^([-])?([0-9a-zA-Z+\\/\\._-])*([@]([0-9a-zA-Z\\.-])*)?$/'; + $pregexpr = '/^([-])?([0-9a-zA-Z+\\/._-])*([@]([0-9a-zA-Z.-])*)?$/'; break; case "postalAddress": // Allow all but \, <, >, =, ? - $pregexpr = '/^[^\\\<>=\\?]*$/'; + $pregexpr = '/^[^\\\<>=?]*$/'; break; case "postalCode": // Allow all but \, <, >, =, ? case "street": case "title": case "employeeType": case "businessCategory": - $pregexpr = '/^[^\\\<>=\\$\\?]*$/'; + $pregexpr = '/^[^\\\<>=$?]*$/'; break; case "homeDirectory": // Home path, /path/...... case "filePath": - $pregexpr = '/^([\/]([[:alnum:]@\\$\\.\\ \\_-])+)+(\/)?$/u'; + $pregexpr = '/^([\/]([[:alnum:]@$. _-])+)+(\/)?$/u'; break; case "digit": // Normal number $pregexpr = '/^[[:digit:]]*$/'; @@ -644,49 +607,52 @@ function get_preg($argument, $regexp) { $pregexpr = '/^[[:digit:]]+(\\.[[:digit:]]+)?$/'; break; case "UNC": // UNC Path, e.g. \\server\share\folder\... - $pregexpr = '/^((([\\\][\\\])|(%))([a-zA-Z0-9@%\\.-])+)([\\\]([[:alnum:]@%\\.\\$\\ \\_-])+)+$/u'; + $pregexpr = '/^((([\\\][\\\])|(%))([a-zA-Z0-9@%.-])+)([\\\]([[:alnum:]@%.$ _-])+)+$/u'; break; case "logonscript": // path to login-script. normal unix file - $pregexpr = '/^(([\/\\\])*([[:alnum:]%\\.\\ \\$\\_-])+([\/\\\]([[:alnum:]%\\.\\ \\$\\_-])+)*((\\.bat)|(\\.cmd)|(\\.exe)|(\\.vbs)))*$/u'; + $pregexpr = '/^(([\/\\\])*([[:alnum:]%. $_-])+([\/\\\]([[:alnum:]%. $_-])+)*((\\.bat)|(\\.cmd)|(\\.exe)|(\\.vbs)))*$/u'; break; case "workstations": // comma separated list with windows-hosts - $pregexpr = '/^(([a-zA-Z0-9\\.\\_-])+(,[a-zA-Z0-9\\.\\_-])*)*$/'; + $pregexpr = '/^(([a-zA-Z0-9._-])+(,[a-zA-Z0-9._-])*)*$/'; break; case "domainname": // Windows Domainname - $pregexpr = '/^([A-Za-z0-9\\.\\_-])+$/'; + $pregexpr = '/^([A-Za-z0-9._-])+$/'; break; case "unixhost": // Unix hosts - $pregexpr = '/^([a-z0-9,\\.\\*_-])*$/'; + $pregexpr = '/^([a-z0-9,.*_-])*$/'; break; case 'digit2': // Same as digit but also -1 $pregexpr = '/^(([-][1])|([[:digit:]]*))$/'; break; case 'gecos': - $pregexpr = '/^[[:alnum:] \\._-]+([,][[:alnum:] \\._-]+)*$/u'; + $pregexpr = '/^[[:alnum:] ._-]+([,][[:alnum:] ._-]+)*$/u'; break; case 'macAddress': $pregexpr = '/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}$/'; break; case 'date': // 31-12-2012 - $pregexpr = '/^((0?[1-9])|([1-2][0-9])|30|31)\\-((0?[1-9])|(1[0-2]))\\-[1-3][0-9][0-9][0-9]$/'; - break; - case 'date2': - $pregexpr = '/^((0[1-9])|([1-2][0-9])|30|31)\\.((0[1-9])|(1[0-2]))\\.[1-3][0-9][0-9][0-9]$/'; + $pregexpr = '/^((0?[1-9])|([1-2]\d)|30|31)-((0?[1-9])|(1[0-2]))-[1-3]\d\d\d$/'; break; case 'dateTime': - $pregexpr = '/^[1-3][0-9][0-9][0-9]\\-((0[1-9])|(1[0-2]))\\-((0[1-9])|([1-2][0-9])|30|31) ((0[0-9])|([1][0-9])|20|21|22|23):((0[0-9])|([1-5][0-9])):((0[0-9])|([1-5][0-9]))$/'; + $pregexpr = '/^[1-3]\d\d\d\-((0[1-9])|(1[0-2]))-((0[1-9])|([1-2]\d)|30|31) ((0\d)|([1]\d)|20|21|22|23):((0\d)|([1-5]\d)):((0\d)|([1-5]\d))$/'; break; case 'sambaLogonHours': $pregexpr = '/^[0-9a-fA-F]{42}$/'; break; - case 'DNSname': + case 'DNSname': // server.example.com $pregexpr = '/^[0-9a-zA-Z_-]+(\\.[0-9a-zA-Z_-]+)*$/'; break; + case 'DNSnameAbsolute': // server.example.com. + $pregexpr = '/^[0-9a-zA-Z_-]+(\\.[0-9a-zA-Z_-]+)*\\.$/'; + break; + case 'DNSnameRelativeOrAbsolute': // server.example.com. or server.example.com + $pregexpr = '/^[0-9a-zA-Z_-]+(\\.[0-9a-zA-Z_-]+)*(\\.)?$/'; + break; case 'nis_alias': - $pregexpr = '/^([[:alnum:]@\\.\\ \\_-])+$/u'; + $pregexpr = '/^([[:alnum:]@. _-])+$/u'; break; case 'nis_recipient': - $pregexpr = '/^([[:alnum:]+@\\.\\ \\_-])+$/u'; + $pregexpr = '/^([[:alnum:]+@. _-])+$/u'; break; case 'country': // Allow all letters and space $pregexpr = '/^[[:alpha:]]([[:alpha:] ])+$/u'; @@ -695,10 +661,10 @@ function get_preg($argument, $regexp) { $pregexpr = '/^([^=,]+=[^=,]+)(,([^=,]+=[^=,]+))*$/'; break; case 'domainSID': // Samba domain SID - $pregexpr = "/^S\\-[0-9]\\-[0-9]\\-[0-9]{2,2}\\-[0-9]+\\-[0-9]+\\-[0-9]+$/"; + $pregexpr = "/^S-\\d-\\d-\\d{2,2}-\\d+-\\d+-\\d+\$/"; break; case 'ip': // IP address - $pregexpr = '/^[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}$/'; + $pregexpr = '/^\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3}$/'; break; case 'ip6': // IPv6 address (only basic check) $pregexpr = '/^[0-9a-f:]+$/i'; @@ -713,16 +679,16 @@ function get_preg($argument, $regexp) { $pregexpr = '/^[[:digit:]]+[KMGTkmgt]?$/'; break; case 'hostAndPort': - $pregexpr = '/^[[:alnum:]\\._-]+:[[:digit:]]+$/'; + $pregexpr = '/^[[:alnum:]._-]+:[[:digit:]]+$/'; break; case 'ldapDateAndTime': - $pregexpr = '/^[0-9]{14}Z$/'; + $pregexpr = '/^\d{14}Z$/'; break; case 'guacamoleProtocol': $pregexpr = '/^(rdp|vnc)$/'; break; } - if (($pregexpr != '') && preg_match($pregexpr, $argument)) { + if (($pregexpr !== '') && preg_match($pregexpr, $argument)) { return true; } // Now we check "negative" cases, characters which are not allowed @@ -738,10 +704,7 @@ function get_preg($argument, $regexp) { $pregexpr = '/[[:digit:]]/'; break; } - if (($pregexpr != '') && !preg_match($pregexpr, $argument)) { - return true; - } - return false; + return ($pregexpr !== '') && !preg_match($pregexpr, $argument); } /** @@ -791,9 +754,9 @@ function connectToLDAP($serverURL, $startTLS) { /** * This will search the given LDAP suffix for all entries which have the given attribute. * - * @param String $name attribute name (may be null) - * @param String $value attribute value - * @param String $objectClass object class (may be null) + * @param string|null $name attribute name + * @param string|null $value attribute value (may be null if $name is null) + * @param string|null $objectClass object class * @param array $attributes list of attributes to return * @param array $scopes account types * @return array list of found entries @@ -803,16 +766,16 @@ function searchLDAPByAttribute($name, $value, $objectClass, $attributes, $scopes // build filter $filter = ''; $filterParts = []; - if ($name != null) { + if ($name !== null) { $filterParts[] = '(' . $name . '=' . ldap_escape($value, '*', LDAP_ESCAPE_FILTER) . ')'; } - if ($objectClass != null) { + if ($objectClass !== null) { $filterParts[] = '(objectClass=' . $objectClass . ')'; } - if (sizeof($filterParts) == 1) { + if (count($filterParts) === 1) { $filter = $filterParts[0]; } - elseif (sizeof($filterParts) > 1) { + elseif (count($filterParts) > 1) { $filter = '(& ' . implode(' ', $filterParts) . ')'; } $typeManager = new TypeManager(); @@ -882,7 +845,7 @@ function searchLDAPByFilter($filter, $attributes, $scopes, $attrsOnly = false) { */ function searchLDAP($suffix, $filter, $attributes, $limit = -1) { if ($limit === -1) { - $limit = !empty($_SESSION['config']) ? $_SESSION['config']->get_searchLimit() : 0; + $limit = empty($_SESSION['config']) ? 0 : $_SESSION['config']->get_searchLimit(); } $return = searchLDAPPaged(getLDAPServerHandle(), $suffix, $filter, $attributes, 0, $limit); @@ -895,7 +858,7 @@ function searchLDAP($suffix, $filter, $attributes, $limit = -1) { /** * Returns the LDAP server handle. * - * @return handle LDAP handle + * @return Connection LDAP handle */ function getLDAPServerHandle() { if (!empty($_SESSION['ldap'])) { @@ -903,7 +866,7 @@ function getLDAPServerHandle() { return $_SESSION['ldap']->server(); } else { - // self service + // self-service return $_SESSION['ldapHandle']->getServer(); } } @@ -911,17 +874,17 @@ function getLDAPServerHandle() { /** * Runs an LDAP search and uses paging if configured. * - * @param handle $server LDAP connection handle + * @param Connection $server LDAP connection handle * @param String $dn DN * @param String $filter filter * @param array $attributes attribute list - * @param boolean $attrsOnly return only attribute names + * @param int $attrsOnly return only attribute names (1) or also the values (0) * @param int $limit size limit * @return array results */ function searchLDAPPaged($server, $dn, $filter, $attributes, $attrsOnly, $limit) { if (empty($_SESSION['config']) || ($_SESSION['config']->getPagedResults() !== 'true')) { - $sr = @ldap_search($server, $dn, $filter, $attributes, $attrsOnly, $limit, 0, LDAP_DEREF_NEVER); + $sr = @ldap_search($server, $dn, $filter, $attributes, $attrsOnly, $limit, 0, LDAP_DEREF_NEVER, getCommonLdapControls()); if ($sr) { $entries = ldap_get_entries($server, $sr); if (!$entries) { @@ -946,6 +909,10 @@ function searchLDAPPaged($server, $dn, $filter, $attributes, $attrsOnly, $limit) 'cookie' => $cookie] ] ]; + $commonControls = getCommonLdapControls(); + if ($commonControls !== null) { + $controls += $commonControls; + } $sr = @ldap_search($server, $dn, $filter, $attributes, $attrsOnly, $limit, 0, LDAP_DEREF_NEVER, $controls); if (!$sr) { @@ -974,7 +941,7 @@ function searchLDAPPaged($server, $dn, $filter, $attributes, $attrsOnly, $limit) * * @param String $dn DN * @param array $attributes list of attributes to fetch - * @param handle $handle LDAP handle (optional for admin interface pages) + * @param Connection $handle LDAP handle (optional for admin interface pages) * @return ?array attributes or null if not found */ function ldapGetDN($dn, $attributes = ['dn'], $handle = null): ?array { @@ -982,7 +949,7 @@ function ldapGetDN($dn, $attributes = ['dn'], $handle = null): ?array { $handle = getLDAPServerHandle(); } $return = null; - $sr = @ldap_read($handle, $dn, '(objectClass=*)', $attributes, 0, 0, 0, LDAP_DEREF_NEVER); + $sr = @ldap_read($handle, $dn, '(objectClass=*)', $attributes, 0, 0, 0, LDAP_DEREF_NEVER, getCommonLdapControls()); if ($sr) { $entries = ldap_get_entries($handle, $sr); if ($entries) { @@ -1000,19 +967,19 @@ function ldapGetDN($dn, $attributes = ['dn'], $handle = null): ?array { * @param String $dn DN * @param String $filter LDAP filter * @param array $attributes list of attributes to fetch - * @param handle $handle LDAP handle (optional for admin interface pages) + * @param Connection|null $handle LDAP handle (optional for admin interface pages) * @param int $limit result limit * @return array attributes or null if not found */ function ldapListDN($dn, $filter = '(objectclass=*)', $attributes = ['dn'], $handle = null, $limit = -1) { if ($limit === -1) { - $limit = !empty($_SESSION['config']) ? $_SESSION['config']->get_searchLimit() : 0; + $limit = empty($_SESSION['config']) ? 0 : $_SESSION['config']->get_searchLimit(); } if ($handle == null) { $handle = $_SESSION['ldap']->server(); } $return = null; - $sr = @ldap_list($handle, $dn, $filter, $attributes, 0, $limit, 0, LDAP_DEREF_NEVER); + $sr = @ldap_list($handle, $dn, $filter, $attributes, 0, $limit, 0, LDAP_DEREF_NEVER, getCommonLdapControls()); if ($sr) { $entries = ldap_get_entries($handle, $sr); if ($entries) { @@ -1027,25 +994,25 @@ function ldapListDN($dn, $filter = '(objectclass=*)', $attributes = ['dn'], $han /** * Deletes a DN and all child entries. * - * @param string $dn DN to delete + * @param string|null $dn DN to delete * @param boolean $recursive recursive delete also child entries * @return array error messages */ function deleteDN($dn, $recursive) { $errors = []; - if (($dn == null) || ($dn == '')) { + if (($dn === null) || ($dn === '')) { $errors[] = ['ERROR', _('Entry does not exist')]; return $errors; } if ($recursive) { - $sr = @ldap_list($_SESSION['ldap']->server(), $dn, '(objectClass=*)', ['dn'], 0, 0, 0, LDAP_DEREF_NEVER); + $sr = @ldap_list($_SESSION['ldap']->server(), $dn, '(objectClass=*)', ['dn'], 0, 0, 0, LDAP_DEREF_NEVER, getCommonLdapControls()); if ($sr) { $entries = ldap_get_entries($_SESSION['ldap']->server(), $sr); cleanLDAPResult($entries); - for ($i = 0; $i < sizeof($entries); $i++) { + for ($i = 0; $i < count($entries); $i++) { // delete recursively $subErrors = deleteDN($entries[$i]['dn'], $recursive); - for ($e = 0; $e < sizeof($subErrors); $e++) { + for ($e = 0; $e < count($subErrors); $e++) { $errors[] = $subErrors[$e]; } } @@ -1067,6 +1034,18 @@ function deleteDN($dn, $recursive) { return $errors; } +/** + * Returns a list of LDAP controls for all LDAP calls. + * + * @return array|null controls + */ +function getCommonLdapControls(): ?array { + if (isset($_SESSION['config']) && ($_SESSION['config']->getAdShowDeleted() === 'true')) { + return [['oid' => '1.2.840.113556.1.4.417']]; + } + return null; +} + /** * Performs a recursive copy from old DN under target DN. * @@ -1122,7 +1101,7 @@ function moveDn(string $oldDn, string $targetDn): void { /** * Returns the parameters for a StatusMessage of the last LDAP search. * - * @return array parameters for StatusMessage or null if all was ok + * @return array|null parameters for StatusMessage or null if all was ok */ function getLastLDAPError() { $errorNumber = ldap_errno($_SESSION["ldap"]->server()); @@ -1155,7 +1134,7 @@ function cleanLDAPResult(&$entries) { unset($entries['count']); } // iterate over all results - $count = sizeof($entries); + $count = count($entries); for ($e = 0; $e < $count; $e++) { // remove 'count' entries and numerical entries for ($i = 0; $i < $entries[$e]['count']; $i++) { @@ -1165,7 +1144,7 @@ function cleanLDAPResult(&$entries) { } unset($entries[$e]['count']); $attrNames = array_keys($entries[$e]); - $attrCount = sizeof($attrNames); + $attrCount = count($attrNames); for ($i = 0; $i < $attrCount; $i++) { if (is_array($entries[$e][$attrNames[$i]])) { unset($entries[$e][$attrNames[$i]]['count']); @@ -1191,9 +1170,9 @@ function getAbstractDN($dn) { $dn = str_replace($partToCut, '', $dn); } $parts = explode(',', $dn); - for ($i = 0; $i < sizeof($parts); $i++) { + for ($i = 0; $i < count($parts); $i++) { $subparts = explode('=', $parts[$i]); - if (sizeof($subparts) == 2) { + if (count($subparts) == 2) { $parts[$i] = $subparts[1]; } } @@ -1232,8 +1211,8 @@ function compareDN($a, $b): int { // split DNs $array_a = explode(",", strtolower($a)); $array_b = explode(",", strtolower($b)); - $len_a = sizeof($array_a); - $len_b = sizeof($array_b); + $len_a = count($array_a); + $len_b = count($array_b); // check how many parts to compare $len = min($len_a, $len_b); // compare from last part on @@ -1246,7 +1225,7 @@ function compareDN($a, $b): int { $part_b = explode('=', $part_b); $part_b = $part_b[1] ?? $part_b[0]; // compare parts - if ($part_a == $part_b) { // part is identical + if ($part_a === $part_b) { // part is identical if ($i == ($len - 1)) { return $len_a <=> $len_b; } @@ -1327,10 +1306,11 @@ function parseLDAPTimestamp($time) { /** * Simple function to obfuscate strings. * - * @param String $text text to obfuscate + * @param string|null $text text to obfuscate + * @return string|null obfuscated text */ function obfuscateText($text) { - if (($text == null) || ($text == '')) { + if (($text === null) || ($text === '')) { return $text; } return str_rot13(base64_encode('LAM_OBFUSCATE:' . $text)); @@ -1339,10 +1319,11 @@ function obfuscateText($text) { /** * Simple function to deobfuscate strings. * - * @param String $text text to deobfuscate + * @param string|null $text text to deobfuscate + * @return string|null deobfuscated text */ function deobfuscateText($text) { - if (($text == null) || ($text == '')) { + if (($text === null) || ($text === '')) { return $text; } if (!isObfuscatedText($text)) { @@ -1354,11 +1335,11 @@ function deobfuscateText($text) { /** * Checks if the given text is obfuscated. * - * @param String $text text to check - * @return boolean obfuscated or not + * @param string|null $text text to check + * @return bool obfuscated or not */ -function isObfuscatedText($text) { - if (($text == null) || ($text == '')) { +function isObfuscatedText($text): bool { + if (($text === null) || ($text === '')) { return false; } $deob = base64_decode(str_rot13($text)); @@ -1368,8 +1349,8 @@ function isObfuscatedText($text) { /** * Extracts the RDN attribute name from a given DN. * - * @param String $dn DN - * @return String RDN attribute name + * @param string $dn DN + * @return string|null RDN attribute name */ function extractRDNAttribute($dn) { $rdn = extractRDN($dn); @@ -1383,8 +1364,8 @@ function extractRDNAttribute($dn) { /** * Extracts the RDN attribute value from a given DN. * - * @param String $dn DN - * @return String RDN attribute value + * @param string $dn DN + * @return string|null RDN attribute value */ function extractRDNValue($dn) { $rdn = extractRDN($dn); @@ -1418,11 +1399,11 @@ function extractRDN(?string $dn): ?string { * Extracts the DN suffix from a given DN. * E.g. ou=people,dc=test,dc=com will result in dc=test,dc=com. * - * @param String $dn DN - * @return String DN suffix + * @param string|null $dn DN + * @return string|null DN suffix */ function extractDNSuffix($dn) { - if ($dn == null) { + if ($dn === null) { return null; } $dn = convertCommaEscaping($dn); @@ -1432,7 +1413,7 @@ function extractDNSuffix($dn) { } unset($parts['count']); array_shift($parts); - for ($i = 0; $i < sizeof($parts); $i++) { + for ($i = 0; $i < count($parts); $i++) { $parts[$i] = unescapeLdapSpecialCharacters($parts[$i]); $parts[$i] = str_replace(',', '\\2C', $parts[$i]); } @@ -1455,7 +1436,7 @@ function testSmtpConnection(string $server, string $user, string $password, stri $mailer->isSMTP(); $serverParts = explode(':', $server); $mailer->Host = $serverParts[0]; - $mailer->Port = $serverParts[1]; + $mailer->Port = (int) $serverParts[1]; if (!empty($user)) { $mailer->SMTPAuth = true; $mailer->Username = $user; @@ -1476,7 +1457,7 @@ function testSmtpConnection(string $server, string $user, string $password, stri $mailer->smtpConnect(); } catch (Exception $e) { - throw new LAMException(null, $e->getMessage()); + throw new LAMException(null, $e->getMessage(), $e); } } @@ -1519,12 +1500,7 @@ function sendPasswordMail($pwd, $user, $recipient = null) { $attr = str_replace('@', '', $results[0]); $value = ''; if (isset($user[strtolower($attr)][0])) { - if (is_array($user[strtolower($attr)])) { - $value = $user[strtolower($attr)][0]; - } - else { - $value = $user[strtolower($attr)]; - } + $value = is_array($user[strtolower($attr)]) ? $user[strtolower($attr)][0] : $user[strtolower($attr)]; } $body = str_replace('@@' . $attr . '@@', $value, $body); $found = preg_match('/\@\@[^\@]+\@\@/', $body, $results); @@ -1560,7 +1536,7 @@ function sendEMail($to, $subject, $text, $from, $isHTML, $replyTo = null, $cc = include_once __DIR__ . '/3rdParty/composer/autoload.php'; $returnPath = empty($replyTo) ? $from : $replyTo; $returnPathParsed = PHPMailer\PHPMailer\PHPMailer::parseAddresses($returnPath); - logNewMessage(LOG_DEBUG, "Send mail to " . print_r($to, true) . "\n" . $text); + logNewMessage(LOG_DEBUG, "Send mail from " . $from . " to " . print_r($to, true) . "\n" . $text); $mailer = new PHPMailer\PHPMailer\PHPMailer(true); try { $cfgMain = $_SESSION['cfgMain']; @@ -1568,7 +1544,7 @@ function sendEMail($to, $subject, $text, $from, $isHTML, $replyTo = null, $cc = $mailer->isSMTP(); $serverParts = explode(':', $cfgMain->mailServer); $mailer->Host = $serverParts[0]; - $mailer->Port = $serverParts[1]; + $mailer->Port = (int) $serverParts[1]; if (!empty($cfgMain->mailUser)) { $mailer->SMTPAuth = true; $mailer->Username = $cfgMain->mailUser; @@ -1651,6 +1627,72 @@ function isCommandlineSafeEmailAddress($address) { return true; } +/** + * Sends the password SMS. + * + * @param string $pwd new password + * @param array $user LDAP attributes of user + * @return array list of arrays that can be used to create status messages + */ +function sendPasswordSms(string $pwd, array $user): array { + $errors = []; + $phoneNumber = getSmsPhoneNumber($user); + include_once __DIR__ . '/plugins/sms/SmsService.inc'; + $smsService = new SmsService(); + try { + $smsService->sendSms(sprintf(_('Your new password: %s'), $pwd), $phoneNumber); + } + catch (LAMException $e) { + logNewMessage(LOG_ERR, 'SMS sending failed: ' . $e->getMessage()); + $errors[] = ['ERROR', _('Unable to send SMS.'), $e->getMessage()]; + } + return $errors; +} + +/** + * Sends an SMS test message. + * + * @param string $providerId SMS provider ID + * @param string|null $apiKey API key + * @param string|null $apiToken API token + * @param string|null $accountId account ID + * @param string|null $region region + * @param string|null $from from + * @param string $number mobile phone number + * @throws LAMException error during SMS connection + */ +function sendSmsTestMessage(string $providerId, ?string $apiKey, ?string $apiToken, ?string $accountId, + ?string $region, ?string $from, string $number): void { + include_once __DIR__ . '/plugins/sms/SmsService.inc'; + $smsService = new SmsService(); + try { + $smsService->sendSms(_('LAM test message'), $number, $providerId, $apiKey, $apiToken, $accountId, $region, $from); + } + catch (Exception $e) { + throw new LAMException(null, $e->getMessage(), $e); + } +} + +/** + * Returns the SMS phone number of a user. + * + * @param array $attributes LDAP attributes + * @return string|null phone number if found + */ +function getSmsPhoneNumber(array $attributes): ?string { + if (empty($_SESSION['cfgMain']->smsProvider)) { + return null; + } + $phoneAttributes = array_change_key_case($_SESSION['cfgMain']->getSmsAttributes()); + $attributes = array_change_key_case($attributes); + foreach ($phoneAttributes as $phoneAttribute) { + if (!empty($attributes[$phoneAttribute][0])) { + return $attributes[$phoneAttribute][0]; + } + } + return null; +} + /** * Caches module objects. * This improves performance if the same module does not need to be created multiple times (calling get_metaData() each time). @@ -1665,8 +1707,8 @@ class moduleCache { /** * Returns a new/cached module with the given name and scope. * - * @param String $name module name - * @param String $scope module scope (e.g. user) + * @param string $name module name + * @param string|null $scope module scope (e.g. user) * @return null|baseModule module object */ public static function getModule($name, $scope): ?object { @@ -1690,7 +1732,7 @@ class moduleCache { * * @return int random number */ -function getRandomNumber() { +function getRandomNumber(): int { return abs(hexdec(bin2hex(openssl_random_pseudo_bytes(6)))); } @@ -1702,10 +1744,7 @@ function getRandomNumber() { * @return mixed false on error and certificate if extracted successfully */ function getLDAPSSLCertificate($server, $port) { - $stream = @stream_context_create(["ssl" => ["capture_peer_cert_chain" => true, "verify_peer" => false, "allow_self_signed" => true]]); - if (!$stream) { - return false; - } + $stream = stream_context_create(["ssl" => ["capture_peer_cert_chain" => true, "verify_peer" => false, "allow_self_signed" => true]]); $client = @stream_socket_client('ssl://' . $server . ':' . $port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream); if (!$client) { return false; @@ -1715,7 +1754,7 @@ function getLDAPSSLCertificate($server, $port) { return false; } $finalPEM = ''; - for ($i = 0; $i < sizeof($context['options']['ssl']['peer_certificate_chain']); $i++) { + for ($i = 0; $i < count($context['options']['ssl']['peer_certificate_chain']); $i++) { $cert = $context['options']['ssl']['peer_certificate_chain'][$i]; $pemData = null; $pemResult = @openssl_x509_export($cert, $pemData); @@ -1732,7 +1771,7 @@ function getLDAPSSLCertificate($server, $port) { /** * Returns the extended LDAP error message if any. * - * @param handle $server LDAP server handle + * @param Connection $server LDAP server handle * @return String error message */ function getExtendedLDAPErrorMessage($server) { @@ -1748,7 +1787,7 @@ function getExtendedLDAPErrorMessage($server) { * Returns the default error message to display on the web page. * HTML special characters are already escaped. * - * @param handle $server LDAP server handle + * @param Connection $server LDAP server handle * @return String error message */ function getDefaultLDAPErrorString($server) { @@ -1786,7 +1825,7 @@ function getDefaultLDAPErrorString($server) { } $genericErrorMessage = ldap_error($server); $message = _('LDAP error, server says:') . ' ' . $genericErrorMessage; - if (!empty($extError) && ($genericErrorMessage != $extError)) { + if (!empty($extError) && ($genericErrorMessage !== $extError)) { $message .= ' - ' . $extError; } return $message; @@ -1814,7 +1853,7 @@ function ldapIsPasswordExpired($server): bool { /** * Tries to get additional information why invalid credentials was returned. E.g. account is locked. * - * @param handle $ldap LDAP object to connect for getting extra data + * @param LDAP\Connection $ldap LDAP object to connect for getting extra data * @param string $userDn failed DN * @return string extra message */ @@ -1828,10 +1867,10 @@ function getExtraInvalidCredentialsMessage($ldap, $userDn) { * Returns the URL under which the page was loaded. * This includes any GET parameters set. * - * @param $baseUrl base URL (e.g. http://www.example.com) - * @return String URL + * @param $baseUrl string base URL (e.g. http://www.example.com) + * @return string|null URL */ -function getCallingURL($baseUrl = '') { +function getCallingURL($baseUrl = ''): ?string { $url = null; if (!empty($baseUrl) && !empty($_SERVER['REQUEST_URI'])) { $url = $baseUrl . $_SERVER['REQUEST_URI']; @@ -1850,9 +1889,9 @@ function getCallingURL($baseUrl = '') { } /** - * Returns the offset in hours from configured time zone to GMT. + * Returns the offset in hours from the configured time zone to GMT. * - * @return int offset + * @return float offset */ function getTimeZoneOffsetHours() { $dtz = getTimeZone(); @@ -1878,7 +1917,7 @@ function getTimeZone() { /** * Returns the current time in formatted form. * - * @param unknown $format format to use (e.g. 'Y-m-d H:i:s') + * @param string $format format to use (e.g. 'Y-m-d H:i:s') */ function getFormattedTime($format) { $time = new DateTime('now', getTimeZone()); @@ -1889,8 +1928,8 @@ function getFormattedTime($format) { * Formats a number of seconds to a more human readable format with minutes, hours, etc. * E.g. 70 seconds will return 1m10s. * - * @param int $numSeconds number of seconds - * @return String formatted number + * @param int|string $numSeconds number of seconds + * @return string formatted number */ function formatSecondsToShortFormat($numSeconds) { if (($numSeconds === '0') || ($numSeconds === 0)) { @@ -1905,7 +1944,7 @@ function formatSecondsToShortFormat($numSeconds) { $years = ''; if ($numSeconds >= 31536000) { $years = floor($numSeconds / 31536000); - $numSeconds = $numSeconds - ($years * 31536000); + $numSeconds -= $years * 31536000; $years .= 'y'; } $seconds = $numSeconds % 60; @@ -1924,15 +1963,15 @@ function formatSecondsToShortFormat($numSeconds) { /** * Unformats text like 1m10s back to number of seconds. * - * @param String $text formatted text - * @return int number of seconds + * @param string $text formatted text + * @return int|string number of seconds */ function unformatShortFormatToSeconds($text) { if (empty($text)) { return $text; } $matches = []; - if (preg_match('/^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?$/', $text, $matches)) { + if (preg_match('/^((\d+)y)?((\d+)w)?((\d+)d)?((\d+)h)?((\d+)m)?((\d+)s)?$/', $text, $matches)) { $newValue = 0; if (!empty($matches[2])) { $newValue += $matches[2] * 31536000; @@ -2026,16 +2065,16 @@ function printJsIncludes($prefix) { } /** - * Converts an UTF-8 string to UTF16LE. + * Converts a UTF-8 string to UTF16LE. * - * @param string $input UTF-8 value + * @param string|null $input UTF-8 value */ function convertUtf8ToUtf16Le($input) { - if (($input == null) || (strlen($input) == 0)) { + if (($input === null) || ($input === '')) { return $input; } $output = iconv('UTF-8', 'UTF-16LE', $input); - if (($output == '')) { + if ($output == '') { $output = mb_convert_encoding($input, 'UTF-8', 'UTF-16LE'); } return $output; @@ -2057,10 +2096,10 @@ function getLAMVersionText() { /** * Returns if the given release is a developer version. * - * @param string version + * @param string $version version * @return bool is developer version */ -function isDeveloperVersion($version) { +function isDeveloperVersion($version): bool { return str_contains($version, 'DEV'); } @@ -2071,20 +2110,20 @@ function isDeveloperVersion($version) { */ class LAMException extends Exception { - private $title; + private ?string $title; private $ldapErrorCode; /** * Constructor. * - * @param string $title title + * @param string|null $title title * @param string $message message (optional) - * @param Exception $cause (optional) - * @param int $ldapErrorCode original LDAP error code + * @param Exception|null $cause (optional) + * @param int|null $ldapErrorCode original LDAP error code */ public function __construct($title, $message = '', $cause = null, $ldapErrorCode = null) { - Exception::__construct($message, 0, $cause); + parent::__construct($message, 0, $cause); $this->title = $title; $this->ldapErrorCode = $ldapErrorCode; } @@ -2092,16 +2131,16 @@ class LAMException extends Exception { /** * Returns the message title. * - * @return string title + * @return string|null title */ - public function getTitle() { + public function getTitle(): ?string { return $this->title; } /** * Returns the original LDAP error code. * - * @return int error code + * @return int|null error code */ public function getLdapErrorCode() { return $this->ldapErrorCode; diff --git a/lam/lib/adminHeader.inc b/lam/lib/adminHeader.inc index 83833a06c..51aef433a 100644 --- a/lam/lib/adminHeader.inc +++ b/lam/lib/adminHeader.inc @@ -97,7 +97,7 @@ function printHeader(string $headerPrefix): void { } asort($toSort); $tools = []; - foreach ($toSort as $key => $value) { + foreach (array_keys($toSort) as $key) { $tools[] = new $key(); } $userData = $_SESSION['ldap']->getUserName(); @@ -122,7 +122,7 @@ function printHeader(string $headerPrefix): void { $serverProfilesPersistenceManager = new ServerProfilePersistenceManager(); try { $serverProfileNames = $serverProfilesPersistenceManager->getProfiles(); - if (sizeof($serverProfileNames) < 2) { + if (count($serverProfileNames) < 2) { $serverProfileLabel = ''; } } @@ -166,7 +166,7 @@ function printHeader(string $headerPrefix): void { parseHtml(null, $accountTypesGroup, [], false, null); } - if (sizeof($tools) > 0) { + if ($tools !== []) { $toolGroup = new htmlGroup(); $toolLink = new htmlLink(_('Tools'), "javascript:void(0);"); $toolLink->setOnClick("window.lam.topmenu.openSubmenu(event, 'lam-navigation-tools', window.lam.topmenu.subMenuCloseListenerTools);"); diff --git a/lam/lib/baseModule.inc b/lam/lib/baseModule.inc index 1c7bfa619..764b8d11f 100644 --- a/lam/lib/baseModule.inc +++ b/lam/lib/baseModule.inc @@ -1,5 +1,7 @@ |null contains all ldap attributes which should be written */ protected $attributes; - /** contains all ldap attributes which are loaded from ldap */ + /** @var array|null contains all ldap attributes which are loaded from LDAP */ protected $orig; /** contains all error messages of a module */ @@ -103,7 +104,7 @@ abstract class baseModule { /** * Creates a new base module class * - * @param string $scope the account type (user, group, host) + * @param string|null $scope the account type (user, group, host) */ public function __construct($scope) { $this->scope = $scope; @@ -145,7 +146,7 @@ abstract class baseModule { $this->orig['objectClass'] = []; if ($this->autoAddObjectClasses === true) { $objectClasses = $this->getManagedObjectClasses($this->getAccountContainer()->get_type()->getId()); - for ($i = 0; $i < sizeof($objectClasses); $i++) { + for ($i = 0; $i < count($objectClasses); $i++) { if (!in_array($objectClasses[$i], $this->attributes['objectClass'])) { $this->attributes['objectClass'][] = $objectClasses[$i]; } @@ -179,7 +180,7 @@ abstract class baseModule { // add object classes if needed if ($this->autoAddObjectClasses === true) { $objectClasses = $this->getManagedObjectClasses($typeId); - for ($i = 0; $i < sizeof($objectClasses); $i++) { + for ($i = 0; $i < count($objectClasses); $i++) { if (!in_array($objectClasses[$i], $this->attributes['objectClass'])) { $this->attributes['objectClass'][] = $objectClasses[$i]; } @@ -189,7 +190,7 @@ abstract class baseModule { $attributeNames = array_merge($this->getManagedAttributes($typeId), $this->getManagedHiddenAttributes($typeId)); $attributeNames = array_unique($attributeNames); $attributeNames = array_values($attributeNames); - for ($i = 0; $i < sizeof($attributeNames); $i++) { + for ($i = 0; $i < count($attributeNames); $i++) { if (isset($attributes[$attributeNames[$i]])) { $this->attributes[$attributeNames[$i]] = $attributes[$attributeNames[$i]]; $this->orig[$attributeNames[$i]] = $attributes[$attributeNames[$i]]; @@ -475,12 +476,12 @@ abstract class baseModule { * Example: return array('or' => '(objectClass=posixAccount)', 'and' => '(!(uid=*$))') * * @param string $typeId account type id - * @return string LDAP filter + * @return array LDAP filter * * @see baseModule::get_metaData() */ public function get_ldap_filter($typeId) { - return $this->meta['ldap_filter'] ?? ""; + return $this->meta['ldap_filter'] ?? []; } /** @@ -553,10 +554,10 @@ abstract class baseModule { * (e.g. posixAccount_homeDirectory) to avoid naming conflicts. * * @param string $typeId type id (user, group, host, ...) - * @return htmlElement meta HTML object + * @return htmlResponsiveRow|null meta HTML object * * @see baseModule::get_metaData() - * @see htmlElement + * @see htmlResponsiveRow */ public function get_profileOptions($typeId) { return $this->meta['profile_options'] ?? null; @@ -616,21 +617,23 @@ abstract class baseModule { break; // check by integer comparison (greater) case 'int_greater': - $val1 = $options[$check['cmp_name1']][0]; - $val2 = $options[$check['cmp_name2']][0]; - // ignore if both fields are empty - if (!(empty($val1) && empty($val2)) - && (($val1 == '') || ($val2 == '') || !(intval($val1) > intval($val2)))) { + $val1 = $options[$check['cmp_name1']][0] ?? ''; + $val2 = $options[$check['cmp_name2']][0] ?? ''; + // ignore if both fields or minimum are empty + if (!empty($val1) + && ($val2 !== '') + && (intval($val1) <= intval($val2))) { $errors[] = $check['error_message']; } break; // check by integer comparison (greater or equal) case 'int_greaterOrEqual': - $val1 = $options[$check['cmp_name1']][0]; - $val2 = $options[$check['cmp_name2']][0]; + $val1 = $options[$check['cmp_name1']][0] ?? ''; + $val2 = $options[$check['cmp_name2']][0] ?? ''; // ignore if both fields are empty - if (!(empty($val1) && empty($val2)) - && (($val1 == '') || ($val2 == '') || !(intval($val1) >= intval($val2)))) { + if (!empty($val1) + && ($val2 !== '') + && (intval($val1) < intval($val2))) { $errors[] = $check['error_message']; } break; @@ -656,7 +659,7 @@ abstract class baseModule { public function load_profile($profile) { if (isset($this->meta['profile_mappings'])) { $identifiers = array_keys($this->meta['profile_mappings']); - for ($i = 0; $i < sizeof($identifiers); $i++) { + for ($i = 0; $i < count($identifiers); $i++) { if (isset($profile[$identifiers[$i]])) { $this->attributes[$this->meta['profile_mappings'][$identifiers[$i]]] = $profile[$identifiers[$i]]; } @@ -681,7 +684,7 @@ abstract class baseModule { */ public function get_configOptions($scopes, $allScopes) { $return = []; - for ($i = 0; $i < sizeof($scopes); $i++) { + for ($i = 0; $i < count($scopes); $i++) { if (isset($this->meta['config_options'][$scopes[$i]])) { if (is_array($this->meta['config_options'][$scopes[$i]])) { $return = array_merge($return, $this->meta['config_options'][$scopes[$i]]); @@ -733,7 +736,7 @@ abstract class baseModule { foreach ($scopes as $scope) { if (isset($this->meta['config_checks'][$scope]) && is_array($this->meta['config_checks'][$scope])) { $identifiers = array_keys($this->meta['config_checks'][$scope]); - for ($i = 0; $i < sizeof($identifiers); $i++) { + for ($i = 0; $i < count($identifiers); $i++) { // check if option is required if (isset($this->meta['config_checks'][$scope][$identifiers[$i]]['required']) && ($this->meta['config_checks'][$scope][$identifiers[$i]]['required']) && ($options[$identifiers[$i]][0] == '')) { $messages[] = $this->meta['config_checks'][$scope][$identifiers[$i]]['required_message']; @@ -781,7 +784,7 @@ abstract class baseModule { break; } // compare - if (!(intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name1']][0]) > intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name2']][0]))) { + if (intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name1']][0]) <= intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name2']][0])) { $messages[] = $this->meta['config_checks'][$scope][$identifiers[$i]]['error_message']; } break; @@ -797,7 +800,7 @@ abstract class baseModule { break; } // compare - if (!(intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name1']][0]) >= intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name2']][0]))) { + if (intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name1']][0]) < intval($options[$this->meta['config_checks'][$scope][$identifiers[$i]]['cmp_name2']][0])) { $messages[] = $this->meta['config_checks'][$scope][$identifiers[$i]]['error_message']; } break; @@ -846,7 +849,6 @@ abstract class baseModule { * Runs any global cron actions. * * @param bool $isDryRun dry-run active - * @throws LAMException error during execution */ public function runGlobalCronActions(bool $isDryRun): void { // needs to be implemented by submodule if needed @@ -935,11 +937,10 @@ abstract class baseModule { * Adds an image to the PDF. * * @param array $result result array (entry will be added here) - * @param String $attrName attribute name - * @param PDFTable $table table + * @param string $attrName attribute name */ public function addPDFImage(&$result, $attrName) { - if (isset($this->attributes[$attrName]) && (sizeof($this->attributes[$attrName]) > 0)) { + if (isset($this->attributes[$attrName]) && (count($this->attributes[$attrName]) > 0)) { $result[static::class . '_' . $attrName][] = new PDFImage($this->attributes[$attrName][0]); } } @@ -1013,7 +1014,7 @@ abstract class baseModule { * @param array $rawAccounts the user input data, contains one subarray for each account. * @param array $ids list of IDs for column position (e.g. "posixAccount_uid" => 5) * @param array $partialAccounts list of hash arrays (name => value) which are later added to LDAP - * @param String $position current position in CSV + * @param int $position current position in CSV * @param String $colName column name * @param String $attrName LDAP attribute name * @param String|String[] $regex for get_preg() (e.g. 'ascii') @@ -1032,14 +1033,14 @@ abstract class baseModule { if (!empty($regex)) { $this->checkUploadRegex($regexIDs, $rawAccounts[$position][$ids[$colName]], $message, $position, $errors); } - $partialAccounts[$position][$attrName] = trim($rawAccounts[$position][$ids[$colName]]); + $partialAccounts[$position][$attrName] = [trim($rawAccounts[$position][$ids[$colName]])]; } // multi-value else { $list = preg_split($regexSplit, trim($rawAccounts[$position][$ids[$colName]])); $partialAccounts[$position][$attrName] = $list; if (!empty($regex)) { - for ($x = 0; $x < sizeof($list); $x++) { + for ($x = 0; $x < count($list); $x++) { if (!$this->checkUploadRegex($regexIDs, $list[$x], $message, $position, $errors)) { break; } @@ -1057,7 +1058,7 @@ abstract class baseModule { * @param array $message error message array if not matching * @param int $position upload position * @param array $errors error messages - * @return value is ok + * @return bool value is ok * @see get_preg() */ private function checkUploadRegex($regexIDs, $value, $message, $position, &$errors) { @@ -1098,7 +1099,7 @@ abstract class baseModule { * array('Headline' => 'This is the head line', 'Text' => 'Help content', 'SeeAlso' => array('text' => 'LAM homepage', 'link' => 'http://www.ldap-account-manager.org/')) * * @param string $id The id string for the help entry needed. - * @return array The desired help entry. + * @return array|null The desired help entry. * * @see baseModule::get_metaData() */ @@ -1110,7 +1111,7 @@ abstract class baseModule { return $this->meta['help'][$this->scope][$id]; } else { - return false; + return null; } } @@ -1124,7 +1125,7 @@ abstract class baseModule { * input, otherwise false.
    * This method's return value defaults to true. * - * @return boolean true, if page can be displayed + * @return bool true, if page can be displayed */ public function module_ready() { return true; @@ -1303,7 +1304,7 @@ abstract class baseModule { * This can be used to interact with the user, e.g. should the home directory be deleted? The output * of all modules is displayed on a single page. * - * @return htmlElement meta HTML object + * @return htmlElement|null meta HTML object * @see htmlElement */ public function display_html_delete() { @@ -1337,7 +1338,7 @@ abstract class baseModule { * * Calling this method requires the existence of an enclosing {@link accountContainer}. * - * @return htmlElement meta HTML object + * @return htmlElement|htmlElement[] meta HTML object * * @see htmlElement */ @@ -1398,7 +1399,7 @@ abstract class baseModule { $val = implode('
    ', $values); } $labelBox = new htmlOutputText($label); - if (!empty($this->attributes[$attrName]) && (sizeof($this->attributes[$attrName]) > 1)) { + if (!empty($this->attributes[$attrName]) && (count($this->attributes[$attrName]) > 1)) { $labelBox->alignment = htmlElement::ALIGN_TOP; } $container->addLabel($labelBox); @@ -1441,10 +1442,10 @@ abstract class baseModule { * A new line will also be added after this entry so multiple calls will show the fields one below the other. * * @param htmlResponsiveRow $container parent container - * @param String $attrName attribute name - * @param String $label label name + * @param string $attrName attribute name + * @param string|null $label label name * @param boolean $required this is a required field (default false) - * @param integer $length field length + * @param int|null $length field length * @param boolean $isTextArea show as text area (default false) * @param array $autoCompleteValues values for auto-completion * @param integer $fieldSize field size @@ -1457,10 +1458,18 @@ abstract class baseModule { if (isset($this->attributes[$attrName][0])) { $values = $this->attributes[$attrName]; } - if (sizeof($values) == 0) { + if (count($values) === 0) { $values[] = ''; } natcasesort($values); + $first = array_shift($values); + // shift empty value to the end + if ($first === '') { + $values[] = $first; + } + else { + array_unshift($values, $first); + } $values = array_values($values); if ($label !== null) { $labelTextOut = new htmlOutputText($label, true, $required); @@ -1472,7 +1481,7 @@ abstract class baseModule { $subContainer = new htmlTable(); $subContainer->setCSSClasses(['fullwidth']); $subContainer->alignment = htmlElement::ALIGN_TOP; - for ($i = 0; $i < sizeof($values); $i++) { + for ($i = 0; $i < count($values); $i++) { if (!$isTextArea) { $input = new htmlInputField($attrName . '_' . $i, $values[$i]); $input->setAccessibilityLabel($label); @@ -1534,19 +1543,19 @@ abstract class baseModule { * * @param String $attrName attribute name * @param array $errors errors array where to put validation errors - * @param String $validationID validation ID for function get_preg() (default: null, null means no validation) + * @param string|null $validationID validation ID for function get_preg() (default: null, null means no validation) * @param bool $required the field is required (default: false) */ protected function processMultiValueInputTextField($attrName, &$errors, $validationID = null, $required = false) { $counter = 0; while (isset($_POST[$attrName . '_' . $counter])) { $this->attributes[$attrName][$counter] = trim($_POST[$attrName . '_' . $counter]); - if (($this->attributes[$attrName][$counter] == '') || isset($_POST['del_' . $attrName . '_' . $counter])) { + if (($this->attributes[$attrName][$counter] === '') || isset($_POST['del_' . $attrName . '_' . $counter])) { unset($this->attributes[$attrName][$counter]); } - elseif (($validationID != null) && ($this->attributes[$attrName][$counter] != '') && !get_preg($this->attributes[$attrName][$counter], $validationID)) { + elseif (($validationID !== null) && !get_preg($this->attributes[$attrName][$counter], $validationID)) { $msg = $this->messages[$attrName][0]; - if (sizeof($msg) < 3) { + if (count($msg) < 3) { $msg[] = htmlspecialchars($this->attributes[$attrName][$counter]); } else { @@ -1575,8 +1584,8 @@ abstract class baseModule { * A new line will also be added after this entry so multiple calls will show the fields one below the other. * * @param htmlResponsiveRow $container parent container - * @param String $attrName attribute name - * @param String $label label name + * @param string $attrName attribute name + * @param string|null $label label name * @param array $options options for the selects * @param boolean $hasDescriptiveOptions has descriptive options * @param boolean $required this is a required field (default false) @@ -1589,7 +1598,7 @@ abstract class baseModule { if (isset($this->attributes[$attrName][0])) { $values = $this->attributes[$attrName]; } - if (sizeof($values) == 0) { + if (count($values) == 0) { $values[] = ''; } natcasesort($values); @@ -1601,7 +1610,7 @@ abstract class baseModule { } $subContainer = new htmlTable(); $subContainer->alignment = htmlElement::ALIGN_TOP; - for ($i = 0; $i < sizeof($values); $i++) { + for ($i = 0; $i < count($values); $i++) { $input = new htmlSelect($attrName . '_' . $i, $options, [$values[$i]], $fieldSize); $input->setHasDescriptiveElements($hasDescriptiveOptions); $subContainer->addElement($input); @@ -1630,7 +1639,7 @@ abstract class baseModule { $counter = 0; while (isset($_POST[$attrName . '_' . $counter])) { $this->attributes[$attrName][$counter] = trim($_POST[$attrName . '_' . $counter]); - if (($this->attributes[$attrName][$counter] == '') || isset($_POST['del_' . $attrName . '_' . $counter])) { + if (($this->attributes[$attrName][$counter] === '') || isset($_POST['del_' . $attrName . '_' . $counter])) { unset($this->attributes[$attrName][$counter]); } $counter++; @@ -1763,17 +1772,15 @@ abstract class baseModule { $field->setFieldSize(null); } elseif ($isTextArea && !in_array($name, $readOnlyFields)) { - $field = new htmlInputTextarea(static::class . '_' . $name, $value, null, null); + $field = new htmlInputTextarea(static::class . '_' . $name, $value, 100, 3); + } + elseif (!$isTextArea) { + $field = new htmlOutputText($value); } else { - if (!$isTextArea) { - $field = new htmlOutputText($value); - } - else { - $value = htmlspecialchars($value); - $value = str_replace("\n", '
    ', $value); - $field = new htmlOutputText($value, false); - } + $value = htmlspecialchars($value); + $value = str_replace("\n", '
    ', $value); + $field = new htmlOutputText($value, false); } $row = new htmlResponsiveRow(); $fieldLabel = new htmlLabel(static::class . '_' . $name, $this->getSelfServiceLabel($name, $label)); @@ -1791,7 +1798,7 @@ abstract class baseModule { * @param array $container return value of checkSelfServiceOptions() * @param String $name attribute name * @param array $attributes LDAP attributes - * @param string $fields input fields + * @param array $fields input fields * @param array $readOnlyFields list of read-only fields * @param String $validationID validation ID for get_preg() * @param array $validationMessage validation message data (defaults to $this->messages[$name][0]) @@ -1805,29 +1812,20 @@ abstract class baseModule { $ldapAttrName = $attributeName ?? $name; if (!empty($_POST[$fieldName])) { if (($validationID != null) && !get_preg($_POST[$fieldName], $validationID)) { - if ($validationMessage !== null) { - $container['messages'][] = $validationMessage; - } - else { - $container['messages'][] = $this->messages[$name][0]; - } + $container['messages'][] = $validationMessage ?? $this->messages[$name][0]; } - else { - if (isset($attributes[$ldapAttrName]) && ($attributes[$ldapAttrName][0] != $_POST[$fieldName])) { - $container['mod'][$ldapAttrName] = [$_POST[$fieldName]]; - } - elseif (!isset($attributes[$ldapAttrName])) { - $container['add'][$ldapAttrName] = [$_POST[$fieldName]]; - } + elseif (isset($attributes[$ldapAttrName]) && ($attributes[$ldapAttrName][0] != $_POST[$fieldName])) { + $container['mod'][$ldapAttrName] = [$_POST[$fieldName]]; + } + elseif (!isset($attributes[$ldapAttrName])) { + $container['add'][$ldapAttrName] = [$_POST[$fieldName]]; } } + elseif ($requiredMessage !== null) { + $container['messages'][] = $requiredMessage; + } elseif (isset($attributes[$ldapAttrName])) { - if ($requiredMessage !== null) { - $container['messages'][] = $requiredMessage; - } - else { - $container['del'][$ldapAttrName] = $attributes[$ldapAttrName]; - } + $container['del'][$ldapAttrName] = $attributes[$ldapAttrName]; } } } @@ -1863,7 +1861,7 @@ abstract class baseModule { if (empty($values)) { $values[] = ''; } - for ($i = 0; $i < sizeof($values); $i++) { + for ($i = 0; $i < count($values); $i++) { $fieldRow = new htmlResponsiveRow(); $value = $values[$i]; if (!$isTextArea) { @@ -1884,7 +1882,7 @@ abstract class baseModule { $delLink->setTitle(_('Delete')); $linkGroup->addElement($delLink); } - if ($i === (sizeof($values) - 1)) { + if ($i === (count($values) - 1)) { $addLink = new htmlLink(null, '#', '../../graphics/add.svg'); $addLink->setOnClick('window.lam.selfservice.addMultiValue(\'' . $fieldNamePrefix . '\', this); return false;'); $addLink->setCSSClasses(['add-link icon', 'margin-left5']); @@ -1923,7 +1921,7 @@ abstract class baseModule { * @param array $container return value of checkSelfServiceOptions() * @param String $name attribute name * @param array $attributes LDAP attributes - * @param string $fields input fields + * @param string[] $fields input fields * @param array $readOnlyFields list of read-only fields * @param String $validationID validation ID for get_preg() * @param array $validationMessage validation message data (defaults to $this->messages[$name][0]) @@ -1944,12 +1942,7 @@ abstract class baseModule { continue; } if (($validationID != null) && !get_preg($postValue, $validationID)) { - if ($validationMessage !== null) { - $container['messages'][] = $validationMessage; - } - else { - $container['messages'][] = $this->messages[$name][0]; - } + $container['messages'][] = $validationMessage ?? $this->messages[$name][0]; return; } $valuesNew[] = $postValue; @@ -1958,8 +1951,7 @@ abstract class baseModule { $container['messages'][] = $requiredMessage; } $valuesOld = $attributes[$ldapAttrName] ?? []; - $intersect = array_intersect($valuesOld, $valuesNew); - if ((sizeof($valuesOld) != sizeof($valuesNew)) || (sizeof($intersect) != sizeof($valuesOld))) { + if (!areArrayContentsEqual($valuesOld, $valuesNew)) { $container['mod'][$ldapAttrName] = $valuesNew; } } @@ -2233,12 +2225,12 @@ abstract class baseModule { /** * This allows modules to create a link to a module specific page - * for the self service. - * The link is shown on the login page of the self service. You + * for the self-service. + * The link is shown on the login page of the self-service. You * can use this to provide e.g. a page to reset passwords. * - * @param array $settings self service settings - * @return String link text (null if no special page used) + * @param array $settings self-service settings + * @return string|null link text (null if no special page used) */ public function getLinkToSpecialSelfServicePage($settings) { return null; @@ -2246,10 +2238,10 @@ abstract class baseModule { /** * This function creates meta HTML code to display the module specific page - * for the self service. + * for the self-service. * - * @param selfServiceProfile $profile self service settings - * @return htmlElement meta HTML object + * @param selfServiceProfile $profile self-service settings + * @return htmlElement|null meta HTML object * * @see htmlElement */ @@ -2265,7 +2257,7 @@ abstract class baseModule { * @see accountContainer */ protected function getAccountContainer(): ?accountContainer { - if (isset($this->base) && isset($_SESSION[$this->base])) { + if ($this->base !== null && isset($_SESSION[$this->base])) { return $_SESSION[$this->base]; } else { @@ -2331,6 +2323,7 @@ abstract class baseModule { * Returns a list of jobs that can be run. * * @param LAMConfig $config configuration + * @return Job[] jobs */ public function getSupportedJobs(&$config) { return []; @@ -2350,7 +2343,7 @@ abstract class baseModule { */ protected function isBooleanConfigOptionSet($optionName, $default = false) { // abort if configuration is not available - if (!isset($this->moduleSettings) || !is_array($this->moduleSettings) || !isset($this->moduleSettings[$optionName][0])) { + if ($this->moduleSettings === null || !is_array($this->moduleSettings) || !isset($this->moduleSettings[$optionName][0])) { return $default; } return ($this->moduleSettings[$optionName][0] == 'true'); diff --git a/lam/lib/baseType.inc b/lam/lib/baseType.inc index 2c00b13ac..612cfd9b0 100644 --- a/lam/lib/baseType.inc +++ b/lam/lib/baseType.inc @@ -5,7 +5,7 @@ use LAM\TYPES\ConfiguredType; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2005 - 2024 Roland Gruber + Copyright (C) 2005 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,9 +48,9 @@ class baseType { /** * Creates a new type object. * - * @param ConfiguredType $type configuration + * @param ConfiguredType|null $type configuration */ - public function __construct($type) { + public function __construct(?ConfiguredType $type) { $this->type = $type; $this->LABEL_CREATE_ANOTHER_ACCOUNT = _('Create another account'); $this->LABEL_BACK_TO_ACCOUNT_LIST = _('Back to account list'); @@ -123,10 +123,10 @@ class baseType { } /** - * Returns the the title text for the title bar on the new/edit page. + * Returns the title text for the title bar on the new/edit page. * * @param accountContainer $container account container - * @return String title text + * @return string|null title text */ public function getTitleBarTitle($container) { if ($container->dn_orig == null) { @@ -136,13 +136,13 @@ class baseType { } /** - * Returns the the title text for the title bar on the new/edit page. + * Returns the title text for the title bar on the new/edit page. * * @param accountContainer $container account container - * @return String title text + * @return string title text */ - public function getTitleBarSubtitle($container) { - return null; + public function getTitleBarSubtitle($container): string { + return ''; } /** @@ -157,8 +157,7 @@ class baseType { $lockableOptions = []; $statusSupported = false; foreach ($container->getAccountModules() as $module) { - $interfaces = class_implements($module); - if (!in_array('AccountStatusProvider', $interfaces)) { + if (!($module instanceof AccountStatusProvider)) { continue; } $statusSupported = true; @@ -235,7 +234,7 @@ class baseType { */ private function buildAccountStatusDialogDiv(AccountStatus $accountStatus, array $lockableOptions): htmlElement { $hasLockOptions = !empty($lockableOptions); - $hasUnlockOptions = $accountStatus->isLocked() || $accountStatus->isPartiallyLocked(); + $hasUnlockOptions = $accountStatus->isLocked() || $accountStatus->isPartiallyLocked() || $accountStatus->isPartiallyExpired(); $container = new htmlResponsiveRow(); $container->add(new htmlTitle(_('Change account status'))); @@ -354,8 +353,7 @@ class baseType { } } foreach ($container->getAccountModules() as $module) { - $interfaces = class_implements($module); - if (!in_array('AccountStatusProvider', $interfaces)) { + if (!($module instanceof AccountStatusProvider)) { continue; } $dummyAttributes = null; @@ -371,8 +369,7 @@ class baseType { } } foreach ($container->getAccountModules() as $module) { - $interfaces = class_implements($module); - if (!in_array('AccountStatusProvider', $interfaces)) { + if (!($module instanceof AccountStatusProvider)) { continue; } $dummyAttributes = null; diff --git a/lam/lib/checkEnvironment.inc b/lam/lib/checkEnvironment.inc index 4edaaf6b2..2919e393f 100644 --- a/lam/lib/checkEnvironment.inc +++ b/lam/lib/checkEnvironment.inc @@ -10,7 +10,7 @@ use function LAM\LOGIN\displayLoginHeader; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2010 - 2024 Roland Gruber + Copyright (C) 2010 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ include_once(__DIR__ . "/../lib/config.inc"); include_once(__DIR__ . "/../lib/persistence.inc"); // check PHP version -if (version_compare(phpversion(), '8.1') < 0) { +if (version_compare(phpversion(), '8.1.10') < 0) { echo "\n\n"; echo "\n\n"; echo "\n"; @@ -55,7 +55,7 @@ if (version_compare(phpversion(), '8.1') < 0) { echo "\n \n"; printHeaderContents('LDAP Account Manager', '..'); echo "\n"; - StatusMessage("ERROR", "LAM needs a PHP version which is greater or equal than 8.1.", "Please upgrade your PHP installation. The found version is " . phpversion()); + StatusMessage("ERROR", "LAM needs a PHP version which is greater or equal than 8.1.10.", "Please upgrade your PHP installation. The found version is " . phpversion()); echo "

    "; echo ""; exit(); @@ -117,7 +117,7 @@ if (!extension_loaded('filter')) { } // check file permissions $writableDirs = ['sess', 'tmp']; -for ($i = 0; $i < sizeof($writableDirs); $i++) { +for ($i = 0; $i < count($writableDirs); $i++) { $path = realpath('../') . "/" . $writableDirs[$i]; if (!is_writable($path)) { $criticalErrors[] = ["ERROR", 'The directory %s is not writable for the web server. Please change your file permissions.', '', [$path]]; @@ -130,7 +130,7 @@ if (ini_get("session.auto_start") == "1") { // check memory limit $memLimit = ini_get('memory_limit'); if (($memLimit != '') - && (substr(strtoupper($memLimit), strlen($memLimit) - 1) == 'M') + && (substr(strtoupper($memLimit), strlen($memLimit) - 1) === 'M') && (intval(substr($memLimit, 0, strlen($memLimit) - 1)) < 128)) { $criticalErrors[] = ["ERROR", "Please increase the \"memory_limit\" parameter in your php.ini to at least \"128M\".", "Your current memory limit is $memLimit."]; @@ -158,7 +158,7 @@ catch (Exception $e) { $criticalErrors[] = ['ERROR', _('Unable to connect to configuration database.')]; } // stop login if errors occurred -if (!empty($criticalErrors)) { +if (!empty($criticalErrors[0])) { echo "\n\n"; echo "\n\n"; echo "\n"; diff --git a/lam/lib/config.inc b/lam/lib/config.inc index 120468e60..60eba5621 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -12,7 +12,7 @@ use function LAM\TYPES\getScopeFromTypeId; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2003 - 2024 Roland Gruber + Copyright (C) 2003 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,16 +39,41 @@ use function LAM\TYPES\getScopeFromTypeId; * @author Thomas Manninger */ +/** + * Defines the possible LAM user interfaces. + */ +enum LAM_INTERFACE { + /** admin pages to manage any type aof entry */ + case ADMIN; + /** user self-service to manage own data */ + case SELF_SERVICE; + /** white-pages to display users */ + case WHITE_PAGES; +} + /** persistence */ -include_once 'persistence.inc'; +include_once __DIR__ . '/persistence.inc'; /** Used to print messages. */ -include_once "status.inc"; +include_once __DIR__ . "/status.inc"; /** Used to get module information. */ -include_once "modules.inc"; +include_once __DIR__ . "/modules.inc"; /** Used to get type information. */ -include_once "types.inc"; +include_once __DIR__ . "/types.inc"; /** 2-factor */ -include_once '2factor.inc'; +include_once __DIR__ . '/2factor.inc'; + +/** + * Checks if the configuration password is secure. + * + * @param string $password password + * @return bool is secure + */ +function isValidConfigurationPassword(string $password): bool { + return preg_match('/[a-zA-Z]/', $password) + && preg_match('/\d/', $password) + && preg_match('/[^a-zA-Z0-9]/', $password) + && (strlen($password) >= 8); +} /** * Sets the environment variables for custom SSL CA certificates. @@ -107,9 +132,9 @@ function setlanguage() { * @param string $target owner, group or other * @param string $chmod the chmod rights * - * @return true, if the chmod $right for $target were set + * @return bool true, if the chmod $right for $target were set */ -function checkChmod($right, $target, $chmod) { +function checkChmod($right, $target, $chmod): bool { $right_arr = ["read", "write", "execute"]; $target_arr = ["owner", "group", "other"]; @@ -120,13 +145,13 @@ function checkChmod($right, $target, $chmod) { $chmod_num = -1; // owner: - if ($target == "owner") { + if ($target === "owner") { $chmod_num = 0; } - if ($target == "group") { + if ($target === "group") { $chmod_num = 1; } - if ($target == "other") { + if ($target === "other") { $chmod_num = 2; } @@ -140,12 +165,9 @@ function checkChmod($right, $target, $chmod) { $write = [2, 3, 6, 7]; // What numbers allow "execute" $execute = [1, 3, 5, 7]; - if ((($right == "read") && in_array($chmod_num, $read)) - || (($right == "write") && in_array($chmod_num, $write)) - || (($right == "execute") && in_array($chmod_num, $execute))) { - return true; - } - return false; + return (($right === "read") && in_array($chmod_num, $read)) + || (($right === "write") && in_array($chmod_num, $write)) + || (($right === "execute") && in_array($chmod_num, $execute)); } /** @@ -190,12 +212,7 @@ function extractConfigOptionsFromPOST($confTypes) { } // checkboxes elseif ($type == "checkbox") { - if (isset($_POST[$element]) && ($_POST[$element] == "on")) { - $options[$element] = ['true']; - } - else { - $options[$element] = ['false']; - } + $options[$element] = isset($_POST[$element]) && ($_POST[$element] == "on") ? ['true'] : ['false']; } // dropdownbox elseif ($type == "select") { @@ -267,7 +284,7 @@ function getLanguages() { $file = fopen($languagefile, "r"); while (!feof($file)) { $line = fgets($file, 1024); - if ($line == "" || $line == "\n" || $line[0] == "#") { + if ($line == "" || $line === "\n" || $line[0] === "#") { continue; // ignore comment and empty lines } $value = explode(":", $line); @@ -373,7 +390,7 @@ class ServerProfilePersistenceManager { $ext = substr($entry, strlen($entry) - 12, 12); $name = substr($entry, 0, strlen($entry) - 12); // check if extension is right, add to profile list - if ($ext == ".sample.conf") { + if ($ext === ".sample.conf") { $ret[$pos] = $name; $pos++; } @@ -550,7 +567,7 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS $ext = substr($entry, strlen($entry) - 5, 5); $name = substr($entry, 0, strlen($entry) - 5); // check if extension is right, add to profile list - if (($ext == ".conf") && (!str_contains($name, '.sample')) && is_readable($dirName . '/' . $entry)) { + if (($ext === ".conf") && (!str_contains($name, '.sample')) && is_readable($dirName . '/' . $entry)) { $ret[] = $name; } } @@ -565,66 +582,19 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS $config = new LAMConfig(); $confFilePath = $this->getPath($name); if (!is_file($confFilePath)) { + logNewMessage(LOG_ERR, 'No such file ' . $confFilePath); throw new LAMException(_('Unable to read file.')); } $file = @fopen($confFilePath, "r"); if (!$file) { + logNewMessage(LOG_ERR, 'Unable to open for reading: ' . $confFilePath); throw new LAMException(_('Unable to read file.')); } $json = fread($file, 1000000); $data = json_decode($json, true); if ($data === null) { - fclose($file); - $file = @fopen($confFilePath, "r"); - $data = []; - $moduleSettings = []; - $typeSettings = []; - $toolSettings = []; - $jobSettings = []; - while (!feof($file)) { - $line = fgets($file, 1000000); - $line = trim($line); // remove spaces at the beginning and end - if (($line == "") || ($line[0] == "#")) { - continue; // ignore comments and empty lines - } - // search keywords - $parts = explode(': ', $line); - $keyword = $parts[0]; - $keyword = trim($keyword, ':'); - $startIndex = strlen($keyword) + 2; - $value = (sizeof($parts) > 1) ? substr($line, $startIndex) : ''; - if (!in_array($keyword, ['modules', 'types', 'tools', 'jobs'])) { - $data[$keyword] = $value; - } - else { - $subKeyword = $parts[1]; - $startIndex = $startIndex + strlen($subKeyword) + 2; - $option = substr($line, $startIndex); - if (empty($option)) { - continue; - } - // module settings - if ($keyword == 'modules') { - $moduleSettings[$subKeyword] = explode(LAMConfig::LINE_SEPARATOR, $option); - } - // type settings - if ($keyword == 'types') { - $typeSettings[$subKeyword] = $option; - } - // tool settings - if ($keyword == 'tools') { - $toolSettings[$subKeyword] = $option; - } - // job settings - if ($keyword == 'jobs') { - $jobSettings[$subKeyword] = explode(LAMConfig::LINE_SEPARATOR, $option); - } - } - } - $data['moduleSettings'] = $moduleSettings; - $data['typeSettings'] = $typeSettings; - $data['toolSettings'] = $toolSettings; - $data['jobSettings'] = $jobSettings; + logNewMessage(LOG_ERR, 'Unable to read JSON from ' . $confFilePath); + throw new LAMException(_('Unable to read file.')); } fclose($file); $config->importData($data); @@ -645,7 +615,7 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS if (is_file($confFile) && is_readable($confFile)) { $file = @fopen($confFile, "w"); if ($file) { - fputs($file, json_encode($profile->exportData(), JSON_PRETTY_PRINT)); + fwrite($file, json_encode($profile->exportData(), JSON_PRETTY_PRINT)); fclose($file); @chmod($confFile, 0600); } @@ -693,11 +663,11 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS $dir . 'pdf/' . $name, $dir . 'profiles/' . $name ]; - for ($i = 0; $i < sizeof($subDirs); $i++) { + for ($i = 0; $i < count($subDirs); $i++) { if (is_dir($subDirs[$i]) && is_readable($subDirs[$i])) { $dirHandle = @opendir($subDirs[$i]); while (false !== ($path = readdir($dirHandle))) { - if (($path != '.') && ($path != '..') && !@unlink($subDirs[$i] . '/' . $path)) { + if (($path !== '.') && ($path !== '..') && !@unlink($subDirs[$i] . '/' . $path)) { logNewMessage(LOG_ERR, 'Unable to delete ' . $subDirs[$i] . '/' . $path); throw new LAMException(_("Unable to delete profile!")); } @@ -721,7 +691,7 @@ class ServerProfilePersistenceStrategyFiles implements ServerProfilePersistenceS * @inheritDoc */ public function isWritable(string $name): bool { - return is_writeable($this->getPath($name)); + return is_writable($this->getPath($name)); } /** @@ -863,23 +833,25 @@ class ServerProfilePersistenceStrategyPdo implements ServerProfilePersistenceStr class LAMConfig { /* access levels */ - const ACCESS_ALL = 100; - const ACCESS_PASSWORD_CHANGE = 20; - const ACCESS_READ_ONLY = 0; + public const ACCESS_ALL = 100; + public const ACCESS_PASSWORD_CHANGE = 20; + public const ACCESS_READ_ONLY = 0; /* login method: predefined list or LDAP search */ - const LOGIN_LIST = 'list'; - const LOGIN_SEARCH = 'search'; + public const LOGIN_LIST = 'list'; + public const LOGIN_SEARCH = 'search'; /** line separator */ - const LINE_SEPARATOR = '+::+'; + public const LINE_SEPARATOR = '+::+'; /** show password on screen by default */ - const PWDRESET_DEFAULT_SCREEN = 1; + public const PWDRESET_DEFAULT_SCREEN = 1; /** send password via email by default */ - const PWDRESET_DEFAULT_MAIL = 2; + public const PWDRESET_DEFAULT_MAIL = 2; + /** send password via SMS by default */ + public const PWDRESET_DEFAULT_SMS = 4; /** show password on screen and send via email by default */ - const PWDRESET_DEFAULT_BOTH = 3; + public const PWDRESET_DEFAULT_ALL = 3; /** Server address (e.g. ldap://127.0.0.1:389) */ private $ServerURL; @@ -896,6 +868,9 @@ class LAMConfig { /** use paged results */ private $pagedResults = 'false'; + /** Active Directory: show deleted entries */ + private $adShowDeleted = 'false'; + /** overlay for referential integrity is activated */ private $referentialIntegrityOverlay = 'false'; @@ -968,10 +943,10 @@ class LAMConfig { private $name; /** access level */ - private $accessLevel = LAMconfig::ACCESS_ALL; + private $accessLevel = LAMConfig::ACCESS_ALL; /** login method */ - private $loginMethod = LAMconfig::LOGIN_LIST; + private $loginMethod = LAMConfig::LOGIN_LIST; /** search suffix for login */ private $loginSearchSuffix = 'dc=yourdomain,dc=org'; @@ -1009,7 +984,7 @@ class LAMConfig { private $pwdResetForcePasswordChange = 'true'; /** password reset page: default selection for password output * PWDRESET_DEFAULT_SCREEN, PWDRESET_DEFAULT_MAIL, PWDRESET_DEFAULT_BOTH */ - private $pwdResetDefaultPasswordOutput = LAMconfig::PWDRESET_DEFAULT_MAIL; + private $pwdResetDefaultPasswordOutput = LAMConfig::PWDRESET_DEFAULT_MAIL; /** LDAP user for jobs */ private $jobsBindUser; @@ -1021,6 +996,8 @@ class LAMConfig { private $jobsDBHost; /** port of job database */ private $jobsDBPort; + /** CA path of job database */ + private $jobsDBCaPath; /** user of job database */ private $jobsDBUser; /** password of job database */ @@ -1053,13 +1030,13 @@ class LAMConfig { private $pwdPolicyMinSymbolic = ''; /** List of all settings in config file */ - private $settings = ["ServerURL", "useTLS", "followReferrals", 'pagedResults', "Passwd", "Admins", + private $settings = ["ServerURL", "useTLS", "followReferrals", 'pagedResults', 'adShowDeleted', "Passwd", "Admins", "defaultLanguage", "scriptPath", "scriptServer", "scriptRights", 'serverDisplayName', "modules", "activeTypes", "types", "tools", "accessLevel", 'loginMethod', 'loginSearchSuffix', 'loginSearchFilter', 'searchLimit', 'lamProMailFrom', 'lamProMailReplyTo', 'lamProMailSubject', 'lamProMailText', 'lamProMailIsHTML', 'lamProMailAllowAlternateAddress', 'httpAuthentication', 'loginSearchDN', 'loginSearchPassword', 'timeZone', 'jobsBindUser', 'jobsBindPassword', 'jobsDatabase', 'jobs', - 'jobsDBHost', 'jobsDBPort', 'jobsDBUser', 'jobsDBPassword', 'jobsDBName', 'pwdResetAllowSpecificPassword', + 'jobsDBHost', 'jobsDBPort', 'jobsDBCaPath', 'jobsDBUser', 'jobsDBPassword', 'jobsDBName', 'pwdResetAllowSpecificPassword', 'pwdResetAllowScreenPassword', 'pwdResetForcePasswordChange', 'pwdResetDefaultPasswordOutput', 'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL', 'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional', @@ -1129,7 +1106,7 @@ class LAMConfig { public function removeInvalidTypes() { $allTypes = LAM\TYPES\getTypes(); $activeTypes = $this->get_ActiveTypes(); - for ($i = 0; $i < sizeof($activeTypes); $i++) { + for ($i = 0; $i < count($activeTypes); $i++) { if (!in_array(getScopeFromTypeId($activeTypes[$i]), $allTypes)) { unset($activeTypes[$i]); } @@ -1155,7 +1132,7 @@ class LAMConfig { $available = $availableByScope[$scope]; // only return available modules $ret = []; - for ($i = 0; $i < sizeof($modules); $i++) { + for ($i = 0; $i < count($modules); $i++) { if (in_array($modules[$i], $available)) { $ret[] = $modules[$i]; } @@ -1207,7 +1184,7 @@ class LAMConfig { /** * Sets the server address * - * @param string $value new server address + * @param string|null $value new server address * @return boolean true if $value has correct format */ public function set_ServerURL($value) { @@ -1242,7 +1219,7 @@ class LAMConfig { /** * Sets the server display name * - * @param string $value new server display name + * @param string|null $value new server display name * @return boolean true if $value has correct format */ public function setServerDisplayName($value) { @@ -1312,6 +1289,24 @@ class LAMConfig { $this->pagedResults = $pagedResults; } + /** + * Returns if deleted entries should be shown. + * + * @return string true or false + */ + public function getAdShowDeleted(): string { + return $this->adShowDeleted; + } + + /** + * Sets if deleted entries should be shown. + * + * @param string $adShowDeleted true or false + */ + public function setAdShowDeleted(string $adShowDeleted) { + $this->adShowDeleted = $adShowDeleted; + } + /** * Returns if referential integrity overlay is in place. * @@ -1387,7 +1382,7 @@ class LAMConfig { /** * Sets the admin string * - * @param string $value new admin string that contains all admin users separated by semicolons + * @param string|null $value new admin string that contains all admin users separated by semicolons * @return boolean true if $value has correct format */ public function set_Adminstring($value) { @@ -1428,7 +1423,7 @@ class LAMConfig { /** * Sets the preferences wizard password * - * @param string $value new password + * @param string|null $value new password * @return boolean true if $value has correct format */ public function set_Passwd($value) { @@ -1461,6 +1456,15 @@ class LAMConfig { return "{CRYPT-SHA512}" . crypt($password, '$6$' . $salt) . " " . base64_encode($salt); } + /** + * Returns if the server profile has a password set. + * + * @return bool password is set + */ + public function hasPasswordSet(): bool { + return ($this->Passwd !== null) && ($this->Passwd !== ''); + } + /** * Returns the LDAP suffix for the given account type * @@ -1475,16 +1479,13 @@ class LAMConfig { * Sets the LDAP suffix where accounts are saved * * @param string $scope account type - * @param string $value new LDAP suffix + * @param string|null $value new LDAP suffix * @return boolean true if $value has correct format */ public function set_Suffix($scope, $value) { - if (!$value) { + if ($value === null) { $value = ""; } - elseif (!is_string($value)) { - return false; - } $this->typeSettings['suffix_' . $scope] = $value; return true; } @@ -1502,7 +1503,7 @@ class LAMConfig { /** * Sets the list of attributes to show in user list * - * @param string $value new attribute string + * @param string|null $value new attribute string * @param string $scope account type * @return boolean true if $value has correct format */ @@ -1528,7 +1529,7 @@ class LAMConfig { /** * Sets the default language string * - * @param string $value new default language + * @param string|null $value new default language * @return boolean true if $value has correct format */ public function set_defaultLanguage($value) { @@ -1546,15 +1547,15 @@ class LAMConfig { * * @return string time zone */ - public function getTimeZone() { + public function getTimeZone(): string { return ($this->timeZone == null) ? 'Europe/London' : $this->timeZone; } /** * Sets the time zone name. * - * @param string $value new time zone - * @return boolean true if $value has correct format + * @param string|null $value new time zone + * @return bool true if $value has correct format */ public function setTimeZone($value) { if (is_string($value)) { @@ -1576,14 +1577,14 @@ class LAMConfig { /** * Sets the path to the external script * - * @param string $value new script path + * @param string|null $value new script path * @return boolean true if $value has correct format */ public function set_scriptPath($value) { - if (!$value) { + if (($value === null) || ($value === '')) { $this->scriptPath = ""; // optional parameter } - elseif (is_string($value) && preg_match("/^\\/([a-z0-9_-])+(\\/([a-z0-9_\\.-])+)+$/i", $value)) { + elseif (preg_match("/^\\/([a-z0-9_-])+(\\/([a-z0-9_\\.-])+)+$/i", $value)) { $this->scriptPath = $value; } else { @@ -1644,7 +1645,7 @@ class LAMConfig { * Returns the script server object for the given name. * * @param string $serverName server name - * @return RemoteServerConfiguration server + * @return RemoteServerConfiguration|null server */ public function getScriptServerByName($serverName) { $serverList = $this->getConfiguredScriptServers(); @@ -1674,57 +1675,52 @@ class LAMConfig { /** * Parses the script server value from input field. * - * @param $value input field value + * @param string $value input field value * @return string|false value to store in configuration */ public static function parseScriptServerValue($value) { - if (!$value) { + if (empty($value)) { return ""; // optional parameter } // Explode the value to an array $array_string = explode(";", $value); - if (count($array_string) > 0) { - // Check all IPs in the exploded Array - $valid_ips = []; - foreach ($array_string as $arr_value) { - // Explode name and IP, if a name exists - if (str_contains($arr_value, ":")) { - $arr_value_explode = explode(":", $arr_value); - $servername = $arr_value_explode[0]; - $label = $arr_value_explode[1]; - $homedirPrefix = $arr_value_explode[2] ?? ''; - } - else { - $servername = $arr_value; - $label = ''; - $homedirPrefix = ''; - } - if (preg_match("/^[a-z0-9-]+(\\.[a-z0-9-]+)*(,[0-9]+)?$/i", $servername)) { - $serverData = [$servername]; - if (!empty($label)) { - $serverData[] = $label; - } - if (!empty($homedirPrefix)) { - $serverData[] = $homedirPrefix; - } - $serverChunk = implode(':', $serverData); - $valid_ips[] = $serverChunk; - } - else { - // wrong format - return false; - } - } - // Check that the array is not empty - if (!empty($array_string)) { - return implode(";", $valid_ips); + // Check all IPs in the exploded Array + $valid_ips = []; + foreach ($array_string as $arr_value) { + // Explode name and IP, if a name exists + if (str_contains($arr_value, ":")) { + $arr_value_explode = explode(":", $arr_value); + $servername = $arr_value_explode[0]; + $label = $arr_value_explode[1]; + $homedirPrefix = $arr_value_explode[2] ?? ''; } else { - // The array is empty, there was no valid IP + $servername = $arr_value; + $label = ''; + $homedirPrefix = ''; + } + if (preg_match("/^[a-z0-9-]+(\\.[a-z0-9-]+)*(,[0-9]+)?$/i", $servername)) { + $serverData = [$servername]; + if (!empty($label)) { + $serverData[] = $label; + } + if (!empty($homedirPrefix)) { + $serverData[] = $homedirPrefix; + } + $serverChunk = implode(':', $serverData); + $valid_ips[] = $serverChunk; + } + else { + // wrong format return false; } } + // Check that the array is not empty + if ($valid_ips !== []) { + return implode(";", $valid_ips); + } else { + // The array is empty, there was no valid IP return false; } } @@ -1735,7 +1731,7 @@ class LAMConfig { * @return string rights */ public function get_scriptRights() { - if (!isset($this->scriptRights)) { + if ($this->scriptRights === null) { return '755'; } return $this->scriptRights; @@ -1824,11 +1820,11 @@ class LAMConfig { /** * Sets the LDAP search limit. * - * @param integer $value new search limit - * @return boolean true if $value has correct format + * @param int $value new search limit + * @return bool true if $value has correct format */ - public function set_searchLimit($value) { - if (is_numeric($value) && ($value > -1)) { + public function set_searchLimit(int $value): bool { + if ($value > -1) { $this->searchLimit = $value; return true; } @@ -1839,14 +1835,14 @@ class LAMConfig { * Returns an array of all selected account modules * * @param string $scope account type - * @return array user modules + * @return class-string[] user modules */ public function get_AccountModules($scope) { if (isset($this->typeSettings["modules_" . $scope])) { $modulesTmp = explode(",", $this->typeSettings["modules_" . $scope]); $modules = []; foreach ($modulesTmp as $mod) { - if (trim($mod) != '') { + if (trim($mod) !== '') { $modules[] = $mod; } } @@ -1857,47 +1853,13 @@ class LAMConfig { } } - /** - * Sets the selected account modules - * - * @param array $modules array with module names (not aliases!) - * @param string $scope account type - * @return boolean true if $modules has correct format - */ - public function set_AccountModules($modules, $scope) { - if (!is_array($modules)) { - return false; - } - // check module names - $available = getAvailableModules($scope); - for ($i = 0; $i < sizeof($modules); $i++) { - if (!in_array($modules[$i], $available)) { - return false; - } - } - // check depends/conflicts - if (check_module_conflicts($modules, getModulesDependencies($scope))) { - return false; - } - if (check_module_depends($modules, getModulesDependencies($scope))) { - return false; - } - $this->typeSettings["modules_" . $scope] = implode(",", $modules); - return true; - } - /** * Sets the settings for the account modules. * * @param array $settings list of module setting [name => value] - * @return boolean true if $settings has correct format */ - public function set_moduleSettings($settings) { - if (!is_array($settings)) { - return false; - } + public function set_moduleSettings(array $settings): void { $this->moduleSettings = $settings; - return true; } /** @@ -1905,8 +1867,8 @@ class LAMConfig { * * @return array list of settings: [name => value] */ - public function get_moduleSettings() { - return $this->moduleSettings; + public function get_moduleSettings(): array { + return $this->moduleSettings ?? []; } /** @@ -1915,7 +1877,7 @@ class LAMConfig { * @return string[] list of types */ public function get_ActiveTypes() { - if (($this->activeTypes == '') || !isset($this->activeTypes)) { + if (($this->activeTypes === '') || ($this->activeTypes === null)) { return []; } else { @@ -1935,7 +1897,7 @@ class LAMConfig { /** * Sets the list of active types. * - * @param string[] list of types + * @param string[] $types list of types */ public function set_ActiveTypes($types) { $this->activeTypes = implode(",", $types); @@ -1945,14 +1907,9 @@ class LAMConfig { * Sets the settings for the account types. * * @param array $settings list of type setting [name => value] - * @return boolean true if $settings has correct format */ - public function set_typeSettings($settings) { - if (!is_array($settings)) { - return false; - } + public function set_typeSettings(array $settings): void { $this->typeSettings = $settings; - return true; } /** @@ -1960,8 +1917,8 @@ class LAMConfig { * * @return array list of settings: [name => value] */ - public function get_typeSettings() { - return $this->typeSettings; + public function get_typeSettings(): array { + return $this->typeSettings ?? []; } /** @@ -1977,14 +1934,9 @@ class LAMConfig { * Sets the tool settings. * * @param array $toolSettings tool settings - * @return boolean true if ok */ - public function setToolSettings($toolSettings) { - if (!is_array($toolSettings)) { - return false; - } + public function setToolSettings(array $toolSettings): void { $this->toolSettings = $toolSettings; - return true; } /** @@ -2079,10 +2031,7 @@ class LAMConfig { */ public function setLoginSearchDN($loginSearchDN) { $this->loginSearchDN = $loginSearchDN; - if (($loginSearchDN == '') || get_preg($loginSearchDN, 'dn')) { - return true; - } - return false; + return ($loginSearchDN == '') || get_preg($loginSearchDN, 'dn'); } /** @@ -2338,7 +2287,7 @@ class LAMConfig { /** * Returns the port. * - * @return String port + * @return int|null port */ public function getJobsDBPort() { return $this->jobsDBPort; @@ -2347,12 +2296,30 @@ class LAMConfig { /** * Sets the port. * - * @param int $jobsDBPort port + * @param int|null $jobsDBPort port */ public function setJobsDBPort($jobsDBPort) { $this->jobsDBPort = $jobsDBPort; } + /** + * Returns the CA certificate path. + * + * @return string path + */ + public function getJobsDBCaPath() { + return $this->jobsDBCaPath; + } + + /** + * Sets the CA certificate path. + * + * @param string $jobsDBCaPath path + */ + public function setJobsDBCaPath($jobsDBCaPath) { + $this->jobsDBCaPath = $jobsDBCaPath; + } + /** * Returns the DB user. * @@ -2411,14 +2378,9 @@ class LAMConfig { * Sets the settings for the jobs. * * @param array $settings list of job settings [name => value] - * @return boolean true if $settings has correct format */ - public function setJobSettings($settings) { - if (!is_array($settings)) { - return false; - } + public function setJobSettings(array $settings): void { $this->jobSettings = $settings; - return true; } /** @@ -2882,7 +2844,7 @@ class LAMCfgMain { const ERROR_REPORTING_DEFAULT = 'default'; /** PHP error reporting setting from php.ini */ const ERROR_REPORTING_SYSTEM = 'system'; - /** PHP error reporting setting as E_ALL | E_STRICT */ + /** PHP error reporting setting as E_ALL */ const ERROR_REPORTING_ALL = 'all'; /** send license warnings via email */ @@ -2909,6 +2871,8 @@ class LAMCfgMain { public const MAIL_ATTRIBUTE_DEFAULT = 'mail'; public const MAIL_BACKUP_ATTRIBUTE_DEFAULT = 'passwordselfresetbackupmail'; + public const SMS_ATTRIBUTES_DEFAULT = 'mobileTelephoneNumber;mobile'; + /** Default profile */ public $default; @@ -2916,22 +2880,22 @@ class LAMCfgMain { private $password; /** Time of inactivity before session times out (minutes) */ - public $sessionTimeout; + public $sessionTimeout = 30; /** @var string hides detail messages for login errors */ public string $hideLoginErrorDetails = 'false'; /** log level */ - public $logLevel; + public $logLevel = LOG_NOTICE; /** log destination ("SYSLOG":syslog, "/...":file, "NONE":none, "REMOTE":server:port) */ - public $logDestination; + public $logDestination = "SYSLOG"; /** list of hosts which may access LAM */ - public $allowedHosts; + public $allowedHosts = ""; /** list of hosts which may access LAM Pro self service */ - public $allowedHostsSelfService; + public $allowedHostsSelfService = ''; /** minimum length for passwords */ public $passwordMinLength = 0; @@ -3014,6 +2978,30 @@ class LAMCfgMain { */ public string $mailBackupAttribute = self::MAIL_BACKUP_ATTRIBUTE_DEFAULT; + /** @var string SMS provider ID */ + public string $smsProvider = ''; + + /** @var string SMS API key */ + public string $smsApiKey = ''; + + /** @var string SMS token */ + public string $smsToken = ''; + + /** @var string SMS account ID */ + public string $smsAccountId = ''; + + /** @var string SMS region */ + public string $smsRegion = ''; + + /** @var string SMS from */ + public string $smsFrom = ''; + + /** @var string SMS number attributes */ + public string $smsAttributes = self::SMS_ATTRIBUTES_DEFAULT; + + /** @var string default country prefix */ + public string $smsDefaultCountryPrefix = ''; + /** database type */ public $configDatabaseType = self::DATABASE_FILE_SYSTEM; @@ -3032,6 +3020,9 @@ class LAMCfgMain { /** database password */ public $configDatabasePassword = ''; + /** database options */ + public $configDatabaseSSLCA = ''; + /** database password */ private $moduleSettings = ''; @@ -3048,14 +3039,15 @@ class LAMCfgMain { 'mailAttribute', 'mailBackupAttribute', 'configDatabaseType', 'configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', - 'configDatabasePassword', 'moduleSettings' + 'configDatabasePassword', 'configDatabaseSSLCA', 'moduleSettings', + 'smsProvider', 'smsApiKey', 'smsToken', 'smsAccountId', 'smsRegion', 'smsFrom', 'smsAttributes', 'smsDefaultCountryPrefix' ]; /** persistence settings are always stored on local file system */ private $persistenceSettings = [ 'configDatabaseType', 'configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', - 'configDatabasePassword', 'license' + 'configDatabasePassword', 'configDatabaseSSLCA', 'license' ]; /** @@ -3064,20 +3056,7 @@ class LAMCfgMain { * @param string $fileName file path for config file */ function __construct($fileName = null) { - if ($fileName === null) { - $this->conffile = __DIR__ . "/../config/config.cfg"; - } - else { - $this->conffile = $fileName; - } - // set default values - $this->sessionTimeout = 30; - $this->hideLoginErrorDetails = 'false'; - $this->logLevel = LOG_NOTICE; - $this->logDestination = "SYSLOG"; - $this->allowedHosts = ""; - $this->allowedHostsSelfService = ''; - $this->moduleSettings = ''; + $this->conffile = $fileName ?? __DIR__ . "/../config/config.cfg"; try { $this->reload(); } @@ -3128,7 +3107,6 @@ class LAMCfgMain { public function importData($data) { foreach ($data as $dataKey => $dataValue) { if (!in_array($dataKey, $this->settings)) { - logNewMessage(LOG_WARNING, 'Ignored setting during import: ' . $dataKey); continue; } if (!(($dataValue === null) || is_array($dataValue) || is_string($dataValue) || is_int($dataValue) || is_bool($dataValue))) { @@ -3172,12 +3150,12 @@ class LAMCfgMain { $fileName = $this->getInternalSSLCaCertFileName(); $handle = @fopen($fileName, "wb"); if ($handle) { - fputs($handle, $certsContent); + fwrite($handle, $certsContent); fclose($handle); @chmod($fileName, 0600); } else { - throw new LAMException(printf(_('Unable to write file %s.'), $fileName)); + throw new LAMException(sprintf(_('Unable to write file %s.'), $fileName)); } } @@ -3198,25 +3176,7 @@ class LAMCfgMain { $this->importData($data); } else { - // fallback to old format - fclose($file); - $file = @fopen($this->conffile, "r"); - while (!feof($file)) { - $line = fgets($file, 1000000); - $line = trim($line); // remove spaces at the beginning and end - if (($line == "") || ($line[0] == "#")) { - continue; // ignore comments - } - // search keywords - for ($i = 0; $i < sizeof($this->settings); $i++) { - $keyword = $this->settings[$i]; - $keylen = strlen($keyword); - if (strtolower(substr($line, 0, $keylen + 2)) == strtolower($keyword . ": ")) { - $this->$keyword = substr($line, $keylen + 2, strlen($line) - $keylen - 2); - break; - } - } - } + throw new LAMException(_('The config file is not readable.')); } fclose($file); } @@ -3229,7 +3189,6 @@ class LAMCfgMain { * Loads the settings from the database. * Persistence settings are ignored as they must be on local file system. * - * @return bool true when ok * @throws LAMException error reading config */ private function loadFromDb(): void { @@ -3256,18 +3215,19 @@ class LAMCfgMain { } catch (PDOException $e) { syslog(LOG_ERR, 'Unable to read main config: ' . $e->getMessage()); - throw new LAMException(_('Unable to connect to configuration database.')); + throw new LAMException(_('Unable to connect to configuration database.'), '', $e); } catch (LAMException $e) { syslog(LOG_ERR, 'Unable to import main config: ' . $e->getMessage()); - throw new LAMException(_('Unable to connect to configuration database.')); + throw new LAMException(_('Unable to connect to configuration database.'), '', $e); } } /** * Saves the configuration to the persistence layer. + * @throws LAMException error saving config */ - public function save() { + public function save(): void { if ($this->configDatabaseType === self::DATABASE_MYSQL) { $this->saveLocal(true); $this->saveDb(); @@ -3280,12 +3240,12 @@ class LAMCfgMain { $sslPath = $this->getInternalSSLCaCertFileName(); $file = @fopen($sslPath, "w"); if ($file) { - fputs($file, $this->uploadedSSLCaCert); + fwrite($file, $this->uploadedSSLCaCert); fclose($file); @chmod($sslPath, 0600); } else { - StatusMessage("ERROR", _("Cannot write certificate file. Please check the permissions of config/serverCerts.pem.")); + throw new LAMException(_("Cannot write certificate file. Please check the permissions of config/serverCerts.pem.")); } } // delete SSL certificate @@ -3293,7 +3253,7 @@ class LAMCfgMain { $sslPath = $this->getInternalSSLCaCertFileName(); $result = @unlink($sslPath); if (!$result) { - StatusMessage("ERROR", _("Cannot write certificate file. Please check the permissions of config/serverCerts.pem.")); + throw new LAMException(_("Cannot write certificate file. Please check the permissions of config/serverCerts.pem.")); } } } @@ -3320,27 +3280,32 @@ class LAMCfgMain { * Saves preferences to config file config.cfg * * @param bool $persistenceOnly store only persistence related data + * @throws LAMException error saving config */ public function saveLocal(bool $persistenceOnly): void { - if ($persistenceOnly) { - $data = $this->exportPersistenceData(); - } - else { - $data = $this->exportData(); - } + $data = $persistenceOnly ? $this->exportPersistenceData() : $this->exportData(); $json = json_encode($data, JSON_PRETTY_PRINT); $file = @fopen($this->conffile, "w"); if ($file) { - fputs($file, $json); + fwrite($file, $json); fclose($file); chmod($this->conffile, 0600); } else { - StatusMessage("ERROR", "", _("Cannot open config file!") . " (" . $this->conffile . ")"); + throw new LAMException(_("Cannot open config file!") . " (" . $this->conffile . ")"); } } + /** + * Returns if the main config has a password set. + * + * @return bool password is set + */ + public function hasPasswordSet(): bool { + return ($this->password !== null) && ($this->password !== ''); + } + /** * Sets a new config password. * @@ -3393,7 +3358,7 @@ class LAMCfgMain { * @return boolean writable */ public function isWritable(): bool { - return is_writeable($this->conffile); + return is_writable($this->conffile); } /** @@ -3418,9 +3383,9 @@ class LAMCfgMain { /** * Returns the path to the SSL CA certificate file that overrides the system certificates. * - * @return String path to certificate file or null if certificate is not overridden + * @return string|null path to certificate file or null if certificate is not overridden */ - public function getSSLCaCertPath() { + public function getSSLCaCertPath(): ?string { $path = $this->getInternalSSLCaCertFileName(); if (file_exists($path)) { return $path; @@ -3441,7 +3406,7 @@ class LAMCfgMain { * Uploads a new SSL CA cert. * * @param String $cert file content in DER/PEM format - * @return mixed TRUE if format is correct, error message if file is not accepted + * @return true|string true if format is correct, error message if file is not accepted */ public function uploadSSLCaCert($cert) { if (!str_contains($cert, '-----BEGIN CERTIFICATE-----')) { @@ -3491,7 +3456,7 @@ class LAMCfgMain { $temporaryFilesManager = new LamTemporaryFilesManager(); $fileName = $temporaryFilesManager->registerTemporaryFile('.pem'); $handle = $temporaryFilesManager->openTemporaryFileForWrite($fileName); - fputs($handle, $content); + fwrite($handle, $content); fclose($handle); return $fileName; } @@ -3516,7 +3481,7 @@ class LAMCfgMain { $content = $this->getSSLCaCertificateContent(); $list = $this->splitSSLCaCertificateContent($content); unset($list[$index]); - if (sizeof($list) < 1) { + if (count($list) < 1) { $this->delSSLCaCert = true; $this->uploadedSSLCaCert = null; } @@ -3539,7 +3504,7 @@ class LAMCfgMain { return []; } $list = $this->splitSSLCaCertificateContent($content); - for ($i = 0; $i < sizeof($list); $i++) { + for ($i = 0; $i < count($list); $i++) { $list[$i] = @openssl_x509_parse($list[$i]); } return $list; @@ -3548,9 +3513,9 @@ class LAMCfgMain { /** * Returns the content of the certificate file or uploaded data. * - * @return String null or certificate content + * @return string|null null or certificate content */ - private function getSSLCaCertificateContent() { + private function getSSLCaCertificateContent(): ?string { $content = null; if ($this->delSSLCaCert) { return null; @@ -3580,9 +3545,6 @@ class LAMCfgMain { return []; } $content = str_replace("\n\n", "\n", $content); - if (empty($content)) { - return []; - } if (!(str_starts_with($content, '-----BEGIN CERTIFICATE-----'))) { return []; } @@ -3604,7 +3566,7 @@ class LAMCfgMain { /** * Returns the license key as multiple lines. * - * @return String license + * @return string[] license */ public function getLicenseLines() { return explode(LAMConfig::LINE_SEPARATOR, $this->license); @@ -3613,7 +3575,7 @@ class LAMCfgMain { /** * Sets the license key as multiple lines. * - * @param String[] $licenseLines license lines + * @param string[] $licenseLines license lines */ public function setLicenseLines($licenseLines) { $this->license = implode(LAMConfig::LINE_SEPARATOR, $licenseLines); @@ -3696,6 +3658,18 @@ class LAMCfgMain { return self::MAIL_BACKUP_ATTRIBUTE_DEFAULT; } + /** + * Returns the SMS attributes. + * + * @return string[] attribute names + */ + public function getSmsAttributes(): array { + if (!empty($this->smsAttributes)) { + return preg_split('/;[ ]*/', $this->smsAttributes); + } + return preg_split('/;[ ]*/', self::SMS_ATTRIBUTES_DEFAULT); + } + /** * Returns a list of module settings. * diff --git a/lam/lib/configPages.inc b/lam/lib/configPages.inc index f54bd1f5e..8fca768fe 100644 --- a/lam/lib/configPages.inc +++ b/lam/lib/configPages.inc @@ -3,7 +3,7 @@ namespace LAM\CONFIG; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2017 - 2024 Roland Gruber + Copyright (C) 2017 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,8 +45,6 @@ class ConfigurationPageTab { const MODULE_SETTINGS = 'moduleSettings'; /** jobs */ const JOBS = 'jobs'; - /** job history */ - const JOB_HISTORY = 'jobHistory'; } @@ -97,7 +95,7 @@ function printConfigurationPageHeaderBar($conf) { /** * Prints the tab list. * - * @param ConfigurationPageTab $active active tab + * @param string $active active tab */ function printConfigurationPageTabs($active) { $tabs = [ diff --git a/lam/lib/cronRunner.inc b/lam/lib/cronRunner.inc index d96ca4372..649c68eb2 100644 --- a/lam/lib/cronRunner.inc +++ b/lam/lib/cronRunner.inc @@ -6,7 +6,7 @@ namespace LAM\Cron; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2024 Roland Gruber + Copyright (C) 2024 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -140,10 +140,10 @@ class CronRunner { $pdo = $cronDatabase->getPdo(); } catch (PDOException $e) { - throw new LAMException("Unable to connect to database. " . $e->getMessage()); + throw new LAMException("Unable to connect to database. " . $e->getMessage(), '', $e); } catch (LAMException $e) { - throw new LAMException("Unable to connect to database. " . $e->getTitle()); + throw new LAMException("Unable to connect to database. " . $e->getTitle(), '', $e); } // get jobs to run if (empty($cronDatabase->getJobs())) { diff --git a/lam/lib/export.inc b/lam/lib/export.inc index 0b1cae01d..981d659e7 100644 --- a/lam/lib/export.inc +++ b/lam/lib/export.inc @@ -9,7 +9,7 @@ use LamTemporaryFilesManager; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2018 - 2024 Roland Gruber + Copyright (C) 2018 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ use LamTemporaryFilesManager; */ /** LDAP handle */ -include_once('ldap.inc'); +include_once(__DIR__ . '/ldap.inc'); /** * Creates LDAP accounts for file upload. @@ -197,7 +197,7 @@ class Exporter { /** * Converts the given LDAP entries to CSV format. * - * @param string $entries entries + * @param array $entries entries * @param string $lineEnding line ending */ private function getCsvOutput(&$entries, $lineEnding) { @@ -258,7 +258,7 @@ class Exporter { $output .= '# ' . _('Base DN') . ': ' . $this->baseDn . $lineEnding; $output .= '# ' . _('Search scope') . ': ' . $this->searchScope . $lineEnding; $output .= '# ' . _('Search filter') . ': ' . $this->filter . $lineEnding; - $output .= '# ' . _('Total entries') . ': ' . sizeof($entries) . $lineEnding; + $output .= '# ' . _('Total entries') . ': ' . count($entries) . $lineEnding; $output .= '#' . $lineEnding; $output .= '# Generated by LDAP Account Manager on ' . date('Y-m-d H:i:s') . $lineEnding; $output .= $lineEnding; @@ -299,7 +299,7 @@ class Exporter { } $wrappedContent = substr($content, 0, $line_length) . $lineEnding; $contentLeft = substr($content, $line_length); - $line_length = $line_length - 1; + $line_length -= 1; $lines = str_split($contentLeft, $line_length); foreach ($lines as $line) { $wrappedContent .= ' ' . $line . $lineEnding; diff --git a/lam/lib/html.inc b/lam/lib/html.inc index 79feaae87..b304a583f 100644 --- a/lam/lib/html.inc +++ b/lam/lib/html.inc @@ -2,7 +2,7 @@ /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2010 - 2024 Roland Gruber + Copyright (C) 2010 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -84,7 +84,7 @@ abstract class htmlElement { /** * Prints the HTML code for this element. * - * @param string $module Name of account module + * @param string|null $module Name of account module * @param array $input List of meta-HTML elements * @param array $values List of values which override the defaults in $input (name => value) * @param boolean $restricted If true then no buttons will be displayed @@ -282,7 +282,7 @@ class htmlTable extends htmlElement { $colspan = $element->getColspanString(); $rowspan = $element->getRowspanString(); $css = ''; - if (sizeof($element->getTableCellCSSClasses()) > 0) { + if (count($element->getTableCellCSSClasses()) > 0) { $css = 'class="' . implode(' ', $element->getTableCellCSSClasses()) . '"'; } $tagName = 'td'; @@ -301,12 +301,7 @@ class htmlTable extends htmlElement { * Adds another line to the table. */ public function addNewLine() { - if (!$this->rowOpen) { - $this->elements[] = "\n"; - } - else { - $this->elements[] = self::NEWLINE; - } + $this->elements[] = $this->rowOpen ? self::NEWLINE : "\n"; } /** @@ -348,22 +343,19 @@ class htmlTable extends htmlElement { $id = ' id="' . $this->id . '"'; } $classAttr = ''; - if (sizeof($this->cssClasses) > 0) { + if (count($this->cssClasses) > 0) { $classAttr = ' class="' . implode(' ', $this->cssClasses) . '"'; } echo "\n"; // print all contained elements - for ($i = 0; $i < sizeof($this->elements); $i++) { + for ($i = 0; $i < count($this->elements); $i++) { // print htmlElement objects if ($this->elements[$i] instanceof htmlElement) { $fields = $this->elements[$i]->generateHTML($module, $input, $values, $restricted, $scope); $return = array_merge($return, $fields); } - // print simple Strings - else { - if ($i != (sizeof($this->elements) - 1) || !($this->elements[$i] == self::NEWLINE)) { - echo $this->elements[$i]; - } + elseif ($i !== count($this->elements) - 1 || ($this->elements[$i] != self::NEWLINE)) { + echo $this->elements[$i]; } } if ($this->rowOpen) { @@ -380,8 +372,8 @@ class htmlTable extends htmlElement { */ public function mergeTableElements(htmlTable $table) { // remove obsolete new lines at the end - if ($table->elements[sizeof($table->elements) - 1] == self::NEWLINE) { - unset($table->elements[sizeof($table->elements) - 1]); + if ($table->elements[count($table->elements) - 1] == self::NEWLINE) { + unset($table->elements[count($table->elements) - 1]); } // close last row of other table if needed if ($table->rowOpen) { @@ -389,8 +381,8 @@ class htmlTable extends htmlElement { } // close last own row if needed if ($this->rowOpen) { - if ($this->elements[sizeof($this->elements) - 1] == self::NEWLINE) { - unset($this->elements[sizeof($this->elements) - 1]); + if ($this->elements[count($this->elements) - 1] == self::NEWLINE) { + unset($this->elements[count($this->elements) - 1]); } else { $this->elements[] = "\n"; @@ -435,7 +427,7 @@ class htmlDataTable extends htmlElement { */ function generateHTML($module, $input, $values, $restricted, $scope) { echo ''; - echo ''; + echo ''; echo '
    getDataAttributesAsString() . '>
    '; $columnOptions = []; foreach ($this->columns as $column) { @@ -575,9 +567,9 @@ class htmlInputField extends htmlElement { /** * Constructor * - * @param String $fieldName unique field name - * @param String $fieldValue value of input field (optional) - * @param String $fieldSize input field length (default 30) + * @param string $fieldName unique field name + * @param string $fieldValue value of input field (optional) + * @param int|null $fieldSize input field length (default 30) */ function __construct($fieldName, $fieldValue = null, $fieldSize = null) { if (isObfuscatedText($fieldValue)) { @@ -640,15 +632,15 @@ class htmlInputField extends htmlElement { $idValue = $this->id ?? $this->fieldName; $id = ' id="' . $idValue . '"'; $value = ''; - if ($this->fieldValue != null) { + if ($this->fieldValue !== null) { $value = ' value="' . $this->fieldValue . '"'; } $maxLength = ''; - if ($this->fieldMaxLength != null) { + if ($this->fieldMaxLength !== null) { $maxLength = ' maxlength="' . $this->fieldMaxLength . '"'; } $size = ''; - if ($this->fieldSize != null) { + if ($this->fieldSize !== null) { $size = ' size="' . $this->fieldSize . '"'; } $inputType = $this->type; @@ -785,7 +777,7 @@ class htmlInputField extends htmlElement { /** * Sets the field size (default is 30). * - * @param int $fieldSize size + * @param int|null $fieldSize size */ public function setFieldSize($fieldSize) { $this->fieldSize = $fieldSize; @@ -1032,6 +1024,9 @@ class htmlHelpLink extends htmlElement { * @return array List of input field names and their type (name => type) */ function generateHTML($module, $input, $values, $restricted, $scope) { + if ($this->helpID === null) { + return []; + } // overwrite module and scope if needed if ($this->module != null) { $module = $this->module; @@ -1077,9 +1072,9 @@ class htmlButton extends htmlElement { /** * Constructor. * - * @param String $name button name - * @param String $value button text or image (16x16px, relative to graphics folder) - * @param String $isImageButton image or text button (default text) + * @param string $name button name + * @param string $value button text or image (16x16px, relative to graphics folder) + * @param bool $isImageButton image or text button (default text) */ function __construct($name, $value, $isImageButton = false) { $this->name = htmlspecialchars($name); @@ -1130,12 +1125,7 @@ class htmlButton extends htmlElement { if ($this->noFormValidation) { $noFormValidation = ' formnovalidate="formnovalidate"'; } - if ($this->type == null) { - $type = ' type="submit"'; - } - else { - $type = ' type="' . $this->type . '"'; - } + $type = $this->type == null ? ' type="submit"' : ' type="' . $this->type . '"'; $onClick = ''; if ($this->onClick != null) { if ($this->type == null) { @@ -1158,7 +1148,7 @@ class htmlButton extends htmlElement { /** * Sets the button title (tooltip). * - * @param String $title title + * @param string|null $title title */ public function setTitle($title) { if ($title !== null) { @@ -1296,7 +1286,7 @@ class htmlSelect extends htmlElement { if ($selectedElements != null) { $this->selectedElements = $selectedElements; } - $this->size = htmlspecialchars($size); + $this->size = htmlspecialchars((string) $size); } /** @@ -1345,7 +1335,7 @@ class htmlSelect extends htmlElement { $onchange = ' onchange="' . $onchange . '"'; } // hide select boxes that contain less than 2 elements - if ((sizeof($this->elements) < 2) && !$this->multiSelect && !$this->containsOptgroups && $this->transformSingleSelect) { + if ((count($this->elements) < 2) && !$this->multiSelect && !$this->containsOptgroups && $this->transformSingleSelect) { echo ''; - if (sizeof($this->elements) == 1) { + if (count($this->elements) == 1) { echo ' '; if ($this->hasDescriptiveElements) { $keys = array_keys($this->elements); @@ -1565,7 +1555,7 @@ class htmlSelect extends htmlElement { * @param String $onChange onChange code */ private function printCodeForShowHideTableRows(&$onChange) { - if ((sizeof($this->tableRowsToHide) == 0) && (sizeof($this->tableRowsToShow) == 0)) { + if ((count($this->tableRowsToHide) == 0) && (count($this->tableRowsToShow) == 0)) { return; } $values = []; @@ -1575,18 +1565,19 @@ class htmlSelect extends htmlElement { if (!empty($this->tableRowsToShow)) { $values = array_merge($values, array_keys($this->tableRowsToShow)); } + $values = array_unique($values); $selector = $this->getShowHideSelector(); - // build Java script to show/hide depending fields + // build JavaScript to show/hide depending on fields foreach ($values as $val) { // build onChange listener $onChange .= 'if (document.getElementById(\'' . $this->name . '\').value == \'' . $val . '\') {'; if (isset($this->tableRowsToShow[$val])) { - for ($i = 0; $i < sizeof($this->tableRowsToShow[$val]); $i++) { + for ($i = 0; $i < count($this->tableRowsToShow[$val]); $i++) { $onChange .= 'document.getElementById(\'' . $this->tableRowsToShow[$val][$i] . '\')?.closest(\'' . $selector . '\').classList.remove(\'hidden\');'; } } if (isset($this->tableRowsToHide[$val])) { - for ($i = 0; $i < sizeof($this->tableRowsToHide[$val]); $i++) { + for ($i = 0; $i < count($this->tableRowsToHide[$val]); $i++) { $onChange .= 'document.getElementById(\'' . $this->tableRowsToHide[$val][$i] . '\')?.closest(\'' . $selector . '\').classList.add(\'hidden\');'; } } @@ -1595,13 +1586,13 @@ class htmlSelect extends htmlElement { // build script to set initial state $script = ''; } // build Java script to enable/disable elements - if ((sizeof($this->elementsToEnable) > 0) || (sizeof($this->elementsToDisable) > 0)) { + if ((count($this->elementsToEnable) > 0) || (count($this->elementsToDisable) > 0)) { // build onChange listener $onChange .= 'if (document.querySelector(\'#' . $this->name . ':checked\') !== null) {'; - for ($i = 0; $i < sizeof($this->elementsToEnable); $i++) { + for ($i = 0; $i < count($this->elementsToEnable); $i++) { $onChange .= 'document.getElementById(\'' . $this->elementsToEnable[$i] . '\').disabled = false;'; } - for ($i = 0; $i < sizeof($this->elementsToDisable); $i++) { + for ($i = 0; $i < count($this->elementsToDisable); $i++) { $onChange .= 'document.getElementById(\'' . $this->elementsToDisable[$i] . '\').disabled = true;'; } $onChange .= '}'; $onChange .= 'else {'; - for ($i = 0; $i < sizeof($this->elementsToEnable); $i++) { + for ($i = 0; $i < count($this->elementsToEnable); $i++) { $onChange .= 'document.getElementById(\'' . $this->elementsToEnable[$i] . '\').disabled = true;'; } - for ($i = 0; $i < sizeof($this->elementsToDisable); $i++) { + for ($i = 0; $i < count($this->elementsToDisable); $i++) { $onChange .= 'document.getElementById(\'' . $this->elementsToDisable[$i] . '\').disabled = false;'; } $onChange .= '};'; // build script to set initial state $script .= ' - - - + + + + list of errors + * @return array list of errors */ function checkInput(): array { $conf = &$_SESSION['conf_config']; @@ -644,19 +654,25 @@ function checkInput(): array { else { $conf->setPagedResults('false'); } + if (isset($_POST['adShowDeleted']) && ($_POST['adShowDeleted'] == 'on')) { + $conf->setAdShowDeleted('true'); + } + else { + $conf->setAdShowDeleted('false'); + } if (isset($_POST['referentialIntegrityOverlay']) && ($_POST['referentialIntegrityOverlay'] == 'on')) { $conf->setReferentialIntegrityOverlay('true'); } else { $conf->setReferentialIntegrityOverlay('false'); } - if (isset($_POST['hidePasswordPromptForExpiredPasswords']) && ($_POST['hidePasswordPromptForExpiredPasswords'] == 'on')) { - $conf->setHidePasswordPromptForExpiredPasswords('true'); - } - else { - $conf->setHidePasswordPromptForExpiredPasswords('false'); - } - $conf->set_searchLimit($_POST['searchLimit']); + if (isset($_POST['hidePasswordPromptForExpiredPasswords']) && ($_POST['hidePasswordPromptForExpiredPasswords'] == 'on')) { + $conf->setHidePasswordPromptForExpiredPasswords('true'); + } + else { + $conf->setHidePasswordPromptForExpiredPasswords('false'); + } + $conf->set_searchLimit((int) $_POST['searchLimit']); $conf->setHideDnPart($_POST['hideDnPart']); if (isLAMProVersion()) { $conf->setAccessLevel($_POST['accessLevel']); @@ -684,7 +700,7 @@ function checkInput(): array { } if (!empty($_POST['pwdResetMail_subject']) && empty($_POST['pwdResetMail_from'])) { $errors[] = ["ERROR", _("From address for password mails is invalid."), htmlspecialchars($_POST['pwdResetMail_from'])]; - } + } if (!$conf->setLamProMailReplyTo($_POST['pwdResetMail_replyTo'])) { $errors[] = ["ERROR", _("Reply-to address for password mails is invalid."), htmlspecialchars($_POST['pwdResetMail_replyTo'])]; } @@ -706,9 +722,9 @@ function checkInput(): array { $adminText = $_POST['admins']; $adminText = explode("\n", $adminText); $adminTextNew = []; - for ($i = 0; $i < sizeof($adminText); $i++) { - if (trim($adminText[$i]) == "") { - continue; + for ($i = 0; $i < count($adminText); $i++) { + if (trim($adminText[$i]) === "") { + continue; } $adminTextNew[] = trim($adminText[$i]); } @@ -717,10 +733,10 @@ function checkInput(): array { $conf->setLoginSearchSuffix($_POST['loginSearchSuffix']); $conf->setLoginSearchPassword($_POST['loginSearchPassword']); $conf->setLoginSearchDN($_POST['loginSearchDN']); - if ($_POST['loginMethod'] == LAMConfig::LOGIN_SEARCH) { // check only if search method - if (!$conf->setLoginSearchDN($_POST['loginSearchDN'])) { - $errors[] = ["ERROR", _("Please enter a valid bind user.")]; - } + // check only if search method + if (($_POST['loginMethod'] == LAMConfig::LOGIN_SEARCH) + && !$conf->setLoginSearchDN($_POST['loginSearchDN'])) { + $errors[] = ["ERROR", _("Please enter a valid bind user.")]; } if (isset($_POST['httpAuthentication']) && ($_POST['httpAuthentication'] == 'on')) { $conf->setHttpAuthentication('true'); @@ -779,12 +795,12 @@ function checkInput(): array { $conf->setScriptSSHKey($_POST['scriptkey']); $conf->setScriptSSHKeyPassword($_POST['scriptkeypassword']); if (!empty($_POST['scriptkey'])) { - include_once '../../lib/remote.inc'; - $remote = new \LAM\REMOTE\Remote(); + include_once __DIR__ . '/../../lib/remote.inc'; + $remote = new Remote(); try { $remote->loadKey($conf->getScriptSSHKey(), $conf->getScriptSSHKeyPassword()); } - catch (\LAMException $e) { + catch (LAMException $e) { $errors[] = ['ERROR', _('SSH key file'), $e->getTitle()]; } } @@ -792,30 +808,22 @@ function checkInput(): array { $tools = getTools(); $toolSettings = extractConfigOptionsFromPOST($_SESSION['confmain_toolTypes']); foreach ($toolSettings as $key => $value) { - $toolSettings[$key] = implode(LAMConfig::LINE_SEPARATOR, $value); - } + $toolSettings[$key] = implode(LAMConfig::LINE_SEPARATOR, $value); + } foreach ($tools as $tool) { - $toolClass = $tool::class; - if ($toolClass === false) { - continue; - } - $toolName = substr($toolClass, strrpos($toolClass, '\\') + 1); + $toolClass = $tool::class; + $toolName = substr($toolClass, strrpos($toolClass, '\\') + 1); $toolConfigID = 'tool_hide_' . $toolName; - if ((isset($_POST[$toolConfigID])) && ($_POST[$toolConfigID] == 'on')) { - $toolSettings[$toolConfigID] = 'true'; - } - else { - $toolSettings[$toolConfigID] = 'false'; - } + $toolSettings[$toolConfigID] = (isset($_POST[$toolConfigID])) && ($_POST[$toolConfigID] == 'on') ? 'true' : 'false'; $toolErrors = $tool->checkConfigurationOptions($toolSettings); if (!empty($toolErrors)) { - $errors = array_merge($errors, $toolErrors); - } + $errors = array_merge($errors, $toolErrors); + } } $conf->setToolSettings($toolSettings); // password policy override - $conf->setPwdPolicyMinLength($_POST['pwdPolicyMinLength']); + $conf->setPwdPolicyMinLength($_POST['pwdPolicyMinLength']); $conf->setPwdPolicyMinLowercase($_POST['pwdPolicyMinLowercase']); $conf->setPwdPolicyMinUppercase($_POST['pwdPolicyMinUppercase']); $conf->setPwdPolicyMinNumeric($_POST['pwdPolicyMinNumeric']); @@ -843,10 +851,13 @@ function checkInput(): array { $conf->setTwoFactorRememberDevicePassword($_POST['twoFactorRememberDevicePassword']); } // check if password was changed - if (isset($_POST['passwd1']) && ($_POST['passwd1'] != '')) { - if ($_POST['passwd1'] != $_POST['passwd2']) { + if (!empty($_POST['passwd1'])) { + if ($_POST['passwd1'] !== $_POST['passwd2']) { $errors[] = ["ERROR", _("Passwords are different!")]; } + elseif (!isValidConfigurationPassword($_POST['passwd1'])) { + $errors[] = ["ERROR", _('Profile password'), _('Please enter at least 8 characters including letters, a number and a symbol.')]; + } else { // set new password $conf->set_Passwd($_POST['passwd1']); diff --git a/lam/templates/config/confmodules.php b/lam/templates/config/confmodules.php index 0dd9e43a7..cfc54b1b4 100644 --- a/lam/templates/config/confmodules.php +++ b/lam/templates/config/confmodules.php @@ -1,23 +1,29 @@ getConfiguredTypes(); $container = new htmlResponsiveRow(); @@ -137,10 +145,10 @@ foreach ($types as $type) { $legendContainer = new htmlGroup(); $legendContainer->addElement(new htmlOutputText("* " . _("Base module"))); -$legendContainer->addElement(new \htmlSpacer('2rem', null)); +$legendContainer->addElement(new htmlSpacer('2rem', null)); $legendContainer->addElement(new htmlHelpLink('237')); -$container->add($legendContainer, 12); -$container->add(new htmlHiddenInput('postAvailable', 'yes'), 12); +$container->add($legendContainer); +$container->add(new htmlHiddenInput('postAvailable', 'yes')); parseHtml(null, $container, [], false, 'user'); @@ -157,7 +165,7 @@ $buttonContainer->addElement(new htmlSpacer(null, '10px'), true); if (empty($errorsToDisplay) && isset($_POST['scrollPositionTop']) && isset($_POST['scrollPositionLeft'])) { // scroll to last position - $buttonContainer->addElement(new htmlJavaScript('window.lam.utility.restoreScrollPosition(' . $_POST['scrollPositionTop'] .', ' . $_POST['scrollPositionLeft'] . ')')); + $buttonContainer->addElement(new htmlJavaScript('window.lam.utility.restoreScrollPosition(' . $_POST['scrollPositionTop'] . ', ' . $_POST['scrollPositionLeft'] . ')')); } parseHtml(null, $buttonContainer, [], false, 'user'); @@ -168,56 +176,56 @@ echo "\n"; /** -* Displays the module selection boxes and checks if dependencies are fulfilled. -* -* @param \LAM\TYPES\ConfiguredType $type account type -* @param htmlResponsiveRow $container meta HTML container -*/ -function config_showAccountModules($type, &$container): void { + * Displays the module selection boxes and checks if dependencies are fulfilled. + * + * @param ConfiguredType $type account type + * @param htmlResponsiveRow $container meta HTML container + */ +function config_showAccountModules($type, $container): void { // account modules $available = getAvailableModules($type->getScope(), true); $selected = $type->getModules(); $sortedAvailable = []; - for ($i = 0; $i < sizeof($available); $i++) { + for ($i = 0; $i < count($available); $i++) { $sortedAvailable[$available[$i]] = getModuleAlias($available[$i], $type->getScope()); } natcasesort($sortedAvailable); // build options for selected and available modules $selOptions = []; - for ($i = 0; $i < sizeof($selected); $i++) { + for ($i = 0; $i < count($selected); $i++) { if (in_array($selected[$i], $available)) { // selected modules must be available if (is_base_module($selected[$i], $type->getScope())) { // mark base modules - $selOptions[getModuleAlias($selected[$i], $type->getScope()) . " (" . $selected[$i] . ")*"] = $selected[$i]; + $selOptions[getModuleAlias($selected[$i], $type->getScope()) . " (" . $selected[$i] . ")*"] = $selected[$i]; } else { - $selOptions[getModuleAlias($selected[$i], $type->getScope()) . " (" . $selected[$i] . ")"] = $selected[$i]; + $selOptions[getModuleAlias($selected[$i], $type->getScope()) . " (" . $selected[$i] . ")"] = $selected[$i]; } } } $availOptions = []; foreach ($sortedAvailable as $key => $value) { - if (! in_array($key, $selected)) { // display non-selected modules + if (!in_array($key, $selected)) { // display non-selected modules if (is_base_module($key, $type->getScope())) { // mark base modules - $availOptions[$value . " (" . $key . ")*"] = $key; + $availOptions[$value . " (" . $key . ")*"] = $key; } else { - $availOptions[$value . " (" . $key . ")"] = $key; + $availOptions[$value . " (" . $key . ")"] = $key; } } } // add account module selection - $container->add(new htmlSubTitle($type->getAlias(), '../../graphics/' . $type->getIcon()), 12); - if (sizeof($selOptions) > 0) { + $container->add(new htmlSubTitle($type->getAlias(), '../../graphics/' . $type->getIcon())); + if ($selOptions !== []) { $container->add(new htmlOutputText(_("Selected modules")), 12, 6); } - if (sizeof($availOptions) > 0) { + if ($availOptions !== []) { $container->add(new htmlOutputText(_("Available modules")), 0, 6); } $container->addVerticalSpacer('1rem'); // selected modules - if (sizeof($selOptions) > 0) { + if ($selOptions !== []) { $listElements = []; foreach ($selOptions as $key => $value) { $el = new htmlTable('100%'); @@ -241,7 +249,7 @@ function config_showAccountModules($type, &$container): void { $container->add(new htmlOutputText(''), 12, 6); } // available modules - if (sizeof($availOptions) > 0) { + if ($availOptions !== []) { $container->add(new htmlSpacer(null, '2rem'), 12, 0, 0, 'hide-on-tablet'); $container->add(new htmlOutputText(_("Available modules")), 12, 0, 0, 'hide-on-tablet'); $container->add(new htmlSpacer(null, '1rem'), 12, 0, 0, 'hide-on-tablet'); @@ -261,7 +269,7 @@ function config_showAccountModules($type, &$container): void { $availDiv->alignment = htmlElement::ALIGN_TOP; $availDiv->setCSSClasses(['confModList']); $availRow->add($availDiv); - if (sizeof($availOptions) >= 10) { + if (count($availOptions) >= 10) { $availRow->addVerticalSpacer('1rem'); $filterGroup = new htmlGroup(); $filterGroup->addElement(new htmlOutputText(_('Filter'))); @@ -274,10 +282,10 @@ function config_showAccountModules($type, &$container): void { $container->add($availRow, 12, 6); } $positions = []; - for ($i = 0; $i < sizeof($selOptions); $i++) { + for ($i = 0; $i < count($selOptions); $i++) { $positions[] = $i; } - $container->add(new htmlHiddenInput('positions_' . $type->getId(), implode(',', $positions)), 12); + $container->add(new htmlHiddenInput('positions_' . $type->getId(), implode(',', $positions))); // spacer to next account type $container->addVerticalSpacer('2rem'); } @@ -285,16 +293,16 @@ function config_showAccountModules($type, &$container): void { /** * Checks user input and saves the entered settings. * - * @return array list of errors + * @param LAMConfig $conf config + * @return array list of errors */ -function checkInput(): array { +function checkModuleInput(LAMConfig $conf): array { if (!isset($_POST['postAvailable'])) { return []; } $errors = []; - $conf = &$_SESSION['conf_config']; $typeSettings = $conf->get_typeSettings(); - $typeManager = new \LAM\TYPES\TypeManager($conf); + $typeManager = new TypeManager($conf); $accountTypes = $typeManager->getConfiguredTypes(); foreach ($accountTypes as $type) { $scope = $type->getScope(); @@ -304,7 +312,7 @@ function checkInput(): array { $selected_temp = explode(',', $selected_temp); $selected = []; // only use available modules as selected - for ($i = 0; $i < sizeof($selected_temp); $i++) { + for ($i = 0; $i < count($selected_temp); $i++) { if (in_array($selected_temp[$i], $available)) { $selected[] = $selected_temp[$i]; } @@ -321,7 +329,7 @@ function checkInput(): array { } // remove modules from selection $new_selected = []; - for ($i = 0; $i < sizeof($selected); $i++) { + for ($i = 0; $i < count($selected); $i++) { if (!isset($_POST['del_' . $typeId . '_' . $selected[$i]])) { $new_selected[] = $selected[$i]; } @@ -339,7 +347,7 @@ function checkInput(): array { // check dependencies $depends = check_module_depends($selected, getModulesDependencies($scope)); if ($depends !== false) { - for ($i = 0; $i < sizeof($depends); $i++) { + for ($i = 0; $i < count($depends); $i++) { $errors[] = ['ERROR', $type->getAlias(), _("Unsolved dependency:") . ' ' . $depends[$i][0] . " (" . $depends[$i][1] . ")"]; } @@ -347,14 +355,14 @@ function checkInput(): array { // check conflicts $conflicts = check_module_conflicts($selected, getModulesDependencies($scope)); if ($conflicts !== false) { - for ($i = 0; $i < sizeof($conflicts); $i++) { + for ($i = 0; $i < count($conflicts); $i++) { $errors[] = ['ERROR', $type->getAlias(), _("Conflicting module:") . ' ' . $conflicts[$i][0] . " (" . $conflicts[$i][1] . ")"]; } } // check for base module $baseCount = 0; - for ($i = 0; $i < sizeof($selected); $i++) { + for ($i = 0; $i < count($selected); $i++) { if (is_base_module($selected[$i], $scope)) { $baseCount++; } diff --git a/lam/templates/config/confsave.php b/lam/templates/config/confsave.php index 6b95518eb..a997b6f66 100644 --- a/lam/templates/config/confsave.php +++ b/lam/templates/config/confsave.php @@ -55,7 +55,7 @@ setlanguage(); if (!isset($_SESSION['conf_isAuthenticated']) || ($_SESSION['conf_config']->getName() !== $_SESSION['conf_isAuthenticated'])) { $_SESSION['conf_message'] = new htmlStatusMessage('ERROR', _("No password was entered!")); /** go back to login if password is empty */ - require('conflogin.php'); + require(__DIR__ . '/conflogin.php'); exit; } @@ -82,7 +82,7 @@ catch (LAMException $e) { finally { // remove settings from session $sessionKeys = array_keys($_SESSION); - for ($i = 0; $i < sizeof($sessionKeys); $i++) { + for ($i = 0; $i < count($sessionKeys); $i++) { if (str_starts_with($sessionKeys[$i], "conf_")) { unset($_SESSION[$sessionKeys[$i]]); } diff --git a/lam/templates/config/conftypes.php b/lam/templates/config/conftypes.php index 5fbddd267..4cd1318d1 100644 --- a/lam/templates/config/conftypes.php +++ b/lam/templates/config/conftypes.php @@ -1,20 +1,26 @@ get_ActiveTypes(); - for ($i = 0; $i < sizeof($activeTypes); $i++) { - $selectedModules = $conf->get_AccountModules($activeTypes[$i]); - if (sizeof($selectedModules) == 0) { - // go to module selection - metaRefresh("confmodules.php"); - exit; - } - } - // go to final page - if (isset($_POST['saveSettings'])) { - metaRefresh("confsave.php"); - exit; - } - // go to modules page - elseif (isset($_POST['editmodules'])) { +if ((isset($_POST['saveSettings']) || isset($_POST['editmodules']) + || isset($_POST['edittypes']) || isset($_POST['generalSettingsButton']) + || isset($_POST['moduleSettings']) || isset($_POST['jobs'])) + && (count($errorsToDisplay) == 0)) { + // check if all types have modules + $activeTypes = $conf->get_ActiveTypes(); + for ($i = 0; $i < count($activeTypes); $i++) { + $selectedModules = $conf->get_AccountModules($activeTypes[$i]); + if (count($selectedModules) == 0) { + // go to module selection metaRefresh("confmodules.php"); exit; } - // go to general page - elseif (isset($_POST['generalSettingsButton'])) { - metaRefresh("confmain.php"); - exit; - } - // go to module settings page - elseif (isset($_POST['moduleSettings'])) { - metaRefresh("moduleSettings.php"); - exit; - } - // go to jobs page - elseif (isset($_POST['jobs'])) { - metaRefresh("jobs.php"); - exit; - } + } + // go to final page + if (isset($_POST['saveSettings'])) { + metaRefresh("confsave.php"); + exit; + } + // go to modules page + elseif (isset($_POST['editmodules'])) { + metaRefresh("confmodules.php"); + exit; + } + // go to general page + elseif (isset($_POST['generalSettingsButton'])) { + metaRefresh("confmain.php"); + exit; + } + // go to module settings page + elseif (isset($_POST['moduleSettings'])) { + metaRefresh("moduleSettings.php"); + exit; + } + // go to jobs page + elseif (isset($_POST['jobs'])) { + metaRefresh("jobs.php"); + exit; } } $typeSettings = $conf->get_typeSettings(); -$allScopes = \LAM\TYPES\getTypes(); -$typeManager = new \LAM\TYPES\TypeManager($conf); +$allScopes = getTypes(); +$typeManager = new TypeManager($conf); $activeTypes = $typeManager->getConfiguredTypes(); $activeScopes = []; foreach ($activeTypes as $activeType) { @@ -143,7 +151,7 @@ printJsIncludes('../..'); printConfigurationPageHeaderBar($conf); // print error messages -for ($i = 0; $i < sizeof($errorsToDisplay); $i++) { +for ($i = 0; $i < count($errorsToDisplay); $i++) { call_user_func_array(StatusMessage(...), $errorsToDisplay[$i]); } @@ -154,8 +162,8 @@ printConfigurationPageTabs(ConfigurationPageTab::TYPES); $row = new htmlResponsiveRow(); // show available types -if (sizeof($availableScopes) > 0) { - $row->add(new htmlSubTitle(_("Available account types")), 12); +if ($availableScopes !== []) { + $row->add(new htmlSubTitle(_("Available account types"))); foreach ($availableScopes as $availableScope) { $availableLabelGroup = new htmlGroup(); $availableLabelGroup->addElement(new htmlImage('../../graphics/' . $availableScope->getIcon(), '16px', '16px')); @@ -179,8 +187,8 @@ $container = new htmlResponsiveRow(); $_SESSION['conftypes_optionTypes'] = []; // show active types -if (sizeof($activeTypes) > 0) { - $container->add(new htmlSubTitle(_("Active account types")), 12); +if (count($activeTypes) > 0) { + $container->add(new htmlSubTitle(_("Active account types"))); $index = 0; foreach ($activeTypes as $activeType) { // title @@ -196,19 +204,19 @@ if (sizeof($activeTypes) > 0) { $buttons = new htmlGroup(); // move buttons if ($index > 0) { - $upButton = new htmlButton('moveup_'. $activeType->getId(), 'up.svg', true); + $upButton = new htmlButton('moveup_' . $activeType->getId(), 'up.svg', true); $upButton->setTitle(_("Up")); $upButton->setCSSClasses(['size16']); $buttons->addElement($upButton); } - if ($index < (sizeof($activeTypes) - 1)) { - $upButton = new htmlButton('movedown_'. $activeType->getId(), 'down.svg', true); + if ($index < (count($activeTypes) - 1)) { + $upButton = new htmlButton('movedown_' . $activeType->getId(), 'down.svg', true); $upButton->setTitle(_("Down")); $upButton->setCSSClasses(['size16']); $buttons->addElement($upButton); } // delete button - $delButton = new htmlButton('rem_'. $activeType->getId(), 'del.svg', true); + $delButton = new htmlButton('rem_' . $activeType->getId(), 'del.svg', true); $delButton->setTitle(_("Remove this account type")); $delButton->setCSSClasses(['size16']); $buttons->addElement($delButton); @@ -222,36 +230,31 @@ if (sizeof($activeTypes) > 0) { $suffix = $typeSettings['suffix_' . $activeType->getId()]; } $suffixInput = new htmlResponsiveInputField(_("LDAP suffix"), 'suffix_' . $activeType->getId(), $suffix, '202', true); - $container->add($suffixInput, 12); + $container->add($suffixInput); // list attributes - if (isset($typeSettings['attr_' . $activeType->getId()])) { - $attributes = $typeSettings['attr_' . $activeType->getId()]; - } - else { - $attributes = $activeType->getBaseType()->getDefaultListAttributes(); - } + $attributes = $typeSettings['attr_' . $activeType->getId()] ?? $activeType->getBaseType()->getDefaultListAttributes(); $attrsInput = new htmlResponsiveInputField(_("List attributes"), 'attr_' . $activeType->getId(), $attributes, '206'); $attrsInput->setFieldMaxLength(1000); - $container->add($attrsInput, 12); + $container->add($attrsInput); // custom label $customLabel = ''; if (isset($typeSettings['customLabel_' . $activeType->getId()])) { $customLabel = $typeSettings['customLabel_' . $activeType->getId()]; } $customLabelInput = new htmlResponsiveInputField(_('Custom label'), 'customLabel_' . $activeType->getId(), $customLabel, '264'); - $container->add($customLabelInput, 12); + $container->add($customLabelInput); // LDAP filter $filter = ''; if (isset($typeSettings['filter_' . $activeType->getId()])) { $filter = $typeSettings['filter_' . $activeType->getId()]; } $filterInput = new htmlResponsiveInputField(_("Additional LDAP filter"), 'filter_' . $activeType->getId(), $filter, '260'); - $container->add($filterInput, 12); + $container->add($filterInput); // type options $typeConfigOptions = $activeType->getBaseType()->get_configOptions(); if (!empty($typeConfigOptions)) { foreach ($typeConfigOptions as $typeConfigOption) { - $container->add($typeConfigOption, 12); + $container->add($typeConfigOption); } // save option types to session ob_start(); @@ -269,29 +272,29 @@ if (sizeof($activeTypes) > 0) { } $readOnly = new htmlResponsiveInputCheckbox('readOnly_' . $activeType->getId(), $isReadOnly, _('Read-only'), '265'); $readOnly->setElementsToDisable(['hideNewButton_' . $activeType->getId(), 'hideDeleteButton_' . $activeType->getId()]); - $advancedOptions->add($readOnly, 12); + $advancedOptions->add($readOnly); } // hidden type $hidden = false; if (isset($typeSettings['hidden_' . $activeType->getId()])) { $hidden = $typeSettings['hidden_' . $activeType->getId()]; } - $advancedOptions->add(new htmlResponsiveInputCheckbox('hidden_' . $activeType->getId(), $hidden, _('Hidden'), '261'), 12); + $advancedOptions->add(new htmlResponsiveInputCheckbox('hidden_' . $activeType->getId(), $hidden, _('Hidden'), '261')); if (isLAMProVersion() && ($conf->getAccessLevel() == LAMConfig::ACCESS_ALL)) { // hide button to create new accounts $hideNewButton = false; if (isset($typeSettings['hideNewButton_' . $activeType->getId()])) { $hideNewButton = $typeSettings['hideNewButton_' . $activeType->getId()]; } - $advancedOptions->add(new htmlResponsiveInputCheckbox('hideNewButton_' . $activeType->getId(), $hideNewButton, _('No new entries'), '262'), 12); + $advancedOptions->add(new htmlResponsiveInputCheckbox('hideNewButton_' . $activeType->getId(), $hideNewButton, _('No new entries'), '262')); // hide button to delete accounts $hideDeleteButton = false; if (isset($typeSettings['hideDeleteButton_' . $activeType->getId()])) { $hideDeleteButton = $typeSettings['hideDeleteButton_' . $activeType->getId()]; } - $advancedOptions->add(new htmlResponsiveInputCheckbox('hideDeleteButton_' . $activeType->getId(), $hideDeleteButton, _('Disallow delete'), '263'), 12); + $advancedOptions->add(new htmlResponsiveInputCheckbox('hideDeleteButton_' . $activeType->getId(), $hideDeleteButton, _('Disallow delete'), '263')); } - $container->add($advancedOptions, 12); + $container->add($advancedOptions); $container->addVerticalSpacer('2rem'); $index++; @@ -328,19 +331,19 @@ echo "\n"; /** * Checks user input and saves the entered settings. * - * @return array list of errors + * @param LAMConfig $conf config + * @return array list of errors */ -function checkInput(): array { +function checkTypeInput(LAMConfig $conf): array { if (!isset($_POST['postAvailable'])) { return []; } $errors = []; - $conf = &$_SESSION['conf_config']; - $typeManager = new \LAM\TYPES\TypeManager($conf); + $typeManager = new TypeManager($conf); $typeSettings = $conf->get_typeSettings(); $accountTypes = $conf->get_ActiveTypes(); $postKeys = array_keys($_POST); - for ($i = 0; $i < sizeof($postKeys); $i++) { + for ($i = 0; $i < count($postKeys); $i++) { $key = $postKeys[$i]; // check if remove button was pressed if (str_starts_with($key, "rem_")) { @@ -350,7 +353,7 @@ function checkInput(): array { $accountTypes = array_flip($accountTypes); $accountTypes = array_values($accountTypes); } - // check if up button was pressed + // check if up button was pressed elseif (str_starts_with($key, "moveup_")) { $type = substr($key, 7); $pos = array_search($type, $accountTypes); @@ -370,6 +373,9 @@ function checkInput(): array { elseif (str_starts_with($key, "suffix_")) { $typeSettings[$key] = trim($_POST[$key]); $type = $typeManager->getConfiguredType(substr($postKeys[$i], 7)); + if ($type === null) { + continue; + } if (strlen($_POST[$key]) < 1) { $errors[] = ["ERROR", _("LDAP Suffix is invalid!"), $type->getAlias()]; } @@ -378,12 +384,15 @@ function checkInput(): array { elseif (str_starts_with($key, "attr_")) { $typeSettings[$key] = $_POST[$key]; $type = $typeManager->getConfiguredType(substr($postKeys[$i], 5)); + if ($type === null) { + continue; + } if (!is_string($_POST[$key]) || !preg_match("/^((#[^:;]+)|([^:;]*:[^:;]+))(;((#[^:;]+)|([^:;]*:[^:;]+)))*$/", $_POST[$key])) { $errors[] = ["ERROR", _("List attributes are invalid!"), $type->getAlias()]; } } // set filter - elseif (substr($key, 0, strlen('filter_')) == "filter_") { + elseif (substr($key, 0, strlen('filter_')) === "filter_") { $typeSettings[$key] = $_POST[$key]; } // set custom label @@ -447,10 +456,10 @@ function checkInput(): array { /** * Compares types by alias for sorting. * - * @param \baseType $a first type - * @param \baseType $b second type + * @param baseType $a first type + * @param baseType $b second type * @return int comparison result */ -function compareTypesByAlias(\baseType $a, \baseType $b): int { +function compareTypesByAlias(baseType $a, baseType $b): int { return strnatcasecmp($a->getAlias(), $b->getAlias()); } diff --git a/lam/templates/config/index.php b/lam/templates/config/index.php index 60b3b2836..c524b601b 100644 --- a/lam/templates/config/index.php +++ b/lam/templates/config/index.php @@ -33,7 +33,7 @@ use htmlResponsiveRow; /** Access to config functions */ -include_once('../../lib/config.inc'); +include_once(__DIR__ . '/../../lib/config.inc'); // start session if (isFileBasedSession()) { diff --git a/lam/templates/config/mainlogin.php b/lam/templates/config/mainlogin.php index 1c1f6df5c..533ed0a6f 100644 --- a/lam/templates/config/mainlogin.php +++ b/lam/templates/config/mainlogin.php @@ -22,17 +22,17 @@ /** -* Login page to change the main preferences. -* -* @package configuration -* @author Roland Gruber -*/ + * Login page to change the main preferences. + * + * @package configuration + * @author Roland Gruber + */ /** Access to config functions */ -include_once('../../lib/config.inc'); +include_once(__DIR__ . '/../../lib/config.inc'); /** Used to print status messages */ -include_once('../../lib/status.inc'); +include_once(__DIR__ . '/../../lib/status.inc'); if (isLAMProVersion()) { include_once(__DIR__ . "/../../lib/env.inc"); } @@ -47,7 +47,9 @@ session_regenerate_id(true); setlanguage(); // remove settings from session -if (isset($_SESSION["mainconf_password"])) unset($_SESSION["mainconf_password"]); +if (isset($_SESSION["mainconf_password"])) { + unset($_SESSION["mainconf_password"]); +} if (isset($_SESSION['cfgMain'])) { unset($_SESSION['cfgMain']); } @@ -69,109 +71,117 @@ if (isset($_SESSION['header'])) { } printHeaderContents(_("Login"), '../..'); ?> - - - -
    -
    - - help - + + + + -
    - isWritable()) { - StatusMessage('WARN', _('The config file is not writable.'), _('Your changes cannot be saved until you make the file writable for the webserver user.')); - } - if (!empty($_GET['invalidLicense']) && ($_GET['invalidLicense'] == '1')) { - StatusMessage('WARN', _('Invalid licence'), _('Please setup your licence data.')); - } - if (!empty($_GET['invalidLicense']) && ($_GET['invalidLicense'] == '2')) { - StatusMessage('WARN', _('Expired licence'), _('Please setup your licence data.')); - } + +
    + -
    - -
    - - + + + + +
    - - + +
    + + menu +   + + + + add(new htmlOutputText(_("Please enter the master password to change the general preferences:")), 12); - $group->addElement($row); - // print message if login was incorrect or no config profiles are present - if (isset($message)) { - $messageField = new htmlStatusMessage('ERROR', $message); - $row = new htmlResponsiveRow(); - $row->add($messageField, 12); - $group->addElement($spacer); - $group->addElement($row); - } - $group->addElement($spacer); - // password input - $label = new htmlOutputText(_('Master password')); - $passwordGroup = new htmlGroup(); - $passwordField = new htmlInputField('passwd'); - $passwordField->setFieldSize(15); - $passwordField->setIsPassword(true); - $passwordField->setCSSClasses(['lam-initial-focus']); - $passwordGroup->addElement($passwordField); - $passwordGroup->addElement(new htmlHelpLink('236')); - $passwordDiv = new htmlDiv(null, $passwordGroup); - $passwordDiv->setCSSClasses(['nowrap']); - $row = new htmlResponsiveRow($label, $passwordDiv); - $group->addElement($row); - // button - $group->addElement($spacer); - $okButton = new htmlButton('submit', _("Ok")); - $okButton->setCSSClasses(['lam-primary']); - $row = new htmlResponsiveRow(); - $row->add($okButton, 12); - $row->setCSSClasses(['']); - $group->addElement($row); + } + ?> + +
    +isWritable()) { + StatusMessage('WARN', _('The config file is not writable.'), _('Your changes cannot be saved until you make the file writable for the webserver user.')); +} +if (!empty($_GET['invalidLicense']) && ($_GET['invalidLicense'] == '1')) { + StatusMessage('WARN', _('Invalid licence'), _('Please setup your licence data.')); +} +if (!empty($_GET['invalidLicense']) && ($_GET['invalidLicense'] == '2')) { + StatusMessage('WARN', _('Expired licence'), _('Please setup your licence data.')); +} +?> +
    + + + + + - -
    + + + -
    + add(new htmlOutputText(_("Please enter the master password to change the general preferences:")), 12); + $group->addElement($row); + // print message if login was incorrect or no config profiles are present + if (isset($message)) { + $messageField = new htmlStatusMessage('ERROR', $message); + $row = new htmlResponsiveRow(); + $row->add($messageField, 12); + $group->addElement($spacer); + $group->addElement($row); + } + $group->addElement($spacer); + // password input + $label = new htmlOutputText(_('Master password')); + $passwordGroup = new htmlGroup(); + $passwordField = new htmlInputField('passwd'); + $passwordField->setFieldSize(15); + $passwordField->setIsPassword(true); + $passwordField->setCSSClasses(['lam-initial-focus']); + $passwordGroup->addElement($passwordField); + $passwordGroup->addElement(new htmlHelpLink('236')); + $passwordDiv = new htmlDiv(null, $passwordGroup); + $passwordDiv->setCSSClasses(['nowrap']); + $row = new htmlResponsiveRow($label, $passwordDiv); + $group->addElement($row); + // button + $group->addElement($spacer); + $okButton = new htmlButton('submit', _("Ok")); + $okButton->setCSSClasses(['lam-primary']); + $row = new htmlResponsiveRow(); + $row->add($okButton, 12); + $row->setCSSClasses(['']); + $group->addElement($row); - $div = new htmlDiv(null, $group); - $div->setCSSClasses(['centeredTable']); + $div = new htmlDiv(null, $group); + $div->setCSSClasses(['centeredTable']); - parseHtml(null, $div, [], false, 'user'); - ?> -
    -
    -
    -
    - + parseHtml(null, $div, [], false, 'user'); + ?> +
    +
    +
    +
    + -



    +



    - + diff --git a/lam/templates/config/mainmanage.php b/lam/templates/config/mainmanage.php index 327e584a5..debba03ac 100644 --- a/lam/templates/config/mainmanage.php +++ b/lam/templates/config/mainmanage.php @@ -1,31 +1,35 @@ checkPassword($_SESSION["mainconf_password"]))) { - require('mainlogin.php'); + require(__DIR__ . '/mainlogin.php'); exit(); } @@ -114,7 +123,8 @@ printHeaderContents(_("Edit general settings"), '../..'); - + menu   @@ -134,37 +144,57 @@ $errors = []; $messages = []; // check if submit button was pressed if (isset($_POST['submitFormData'])) { - if (extension_loaded('PDO')) { - // set database - $cfg->configDatabaseType = $_POST['configDatabaseType']; - $cfg->configDatabaseServer = $_POST['configDatabaseServer']; - $cfg->configDatabasePort = $_POST['configDatabasePort']; - $cfg->configDatabaseName = $_POST['configDatabaseName']; - $cfg->configDatabaseUser = $_POST['configDatabaseUser']; - $cfg->configDatabasePassword = $_POST['configDatabasePassword']; - if ($cfg->configDatabaseType === LAMCfgMain::DATABASE_MYSQL) { - if (empty($cfg->configDatabaseServer) || !get_preg($cfg->configDatabaseServer, 'hostname')) { - $errors[] = _('Please enter a valid database host name.'); - } - if (empty($cfg->configDatabaseName)) { - $errors[] = _('Please enter a valid database name.'); - } - if (empty($cfg->configDatabaseUser)) { - $errors[] = _('Please enter a valid database user.'); - } - if (empty($cfg->configDatabasePassword)) { - $errors[] = _('Please enter a valid database password.'); - } - } - } + if (extension_loaded('PDO')) { + // set database + $cfg->configDatabaseType = $_POST['configDatabaseType']; + $cfg->configDatabaseServer = $_POST['configDatabaseServer']; + $cfg->configDatabaseSSLCA = $_POST['configDatabaseSSLCA']; + $cfg->configDatabasePort = $_POST['configDatabasePort']; + $cfg->configDatabaseName = $_POST['configDatabaseName']; + $cfg->configDatabaseUser = $_POST['configDatabaseUser']; + $cfg->configDatabasePassword = $_POST['configDatabasePassword']; + if ($cfg->configDatabaseType === LAMCfgMain::DATABASE_MYSQL) { + $mySqlConfigOk = true; + if (empty($cfg->configDatabaseServer) || !get_preg($cfg->configDatabaseServer, 'hostname')) { + $errors[] = _('Please enter a valid database host name.'); + $mySqlConfigOk = false; + } + if (empty($cfg->configDatabaseName)) { + $errors[] = _('Please enter a valid database name.'); + $mySqlConfigOk = false; + } + if (empty($cfg->configDatabaseUser)) { + $errors[] = _('Please enter a valid database user.'); + $mySqlConfigOk = false; + } + if (empty($cfg->configDatabasePassword)) { + $errors[] = _('Please enter a valid database password.'); + $mySqlConfigOk = false; + } + if ($mySqlConfigOk) { + try { + $configurationDatabase = new ConfigurationDatabase($cfg); + $configurationDatabase->checkConnection(); + } + catch (Exception $e) { + logNewMessage(LOG_ERR, 'Unable to connect to configuration database: ' . $e->getMessage()); + $errors[] = _('Unable to connect to configuration database.'); + } + } + } + } // set master password - if (isset($_POST['masterpassword']) && ($_POST['masterpassword'] != "")) { - if ($_POST['masterpassword'] && $_POST['masterpassword2'] && ($_POST['masterpassword'] == $_POST['masterpassword2'])) { + if (!empty($_POST['masterpassword'])) { + if (($_POST['masterpassword'] !== $_POST['masterpassword2'])) { + $errors[] = _("Master passwords are different."); + } + elseif (!isValidConfigurationPassword($_POST['masterpassword'])) { + $errors[] = _('Please enter at least 8 characters including letters, a number and a symbol.'); + } + else { $cfg->setPassword($_POST['masterpassword']); $msg = _("New master password set successfully."); unset($_SESSION["mainconf_password"]); - } else { - $errors[] = _("Master passwords are different or empty!"); } } // set license @@ -176,19 +206,19 @@ if (isset($_POST['submitFormData'])) { $cfg->licenseEmailFrom = $_POST['licenseEmailFrom']; $cfg->licenseEmailTo = $_POST['licenseEmailTo']; if ((($cfg->licenseWarningType === LAMCfgMain::LICENSE_WARNING_EMAIL) || ($cfg->licenseWarningType === LAMCfgMain::LICENSE_WARNING_ALL)) - && !get_preg($cfg->licenseEmailFrom, 'email')) { - $errors[] = _('Licence') . ': ' . _('From address') . ' - ' . _('Please enter a valid email address!'); - } + && !get_preg($cfg->licenseEmailFrom, 'email')) { + $errors[] = _('Licence') . ': ' . _('From address') . ' - ' . _('Please enter a valid email address!'); + } if (($cfg->licenseWarningType === LAMCfgMain::LICENSE_WARNING_EMAIL) || ($cfg->licenseWarningType === LAMCfgMain::LICENSE_WARNING_ALL)) { - $toEmails = preg_split('/;[ ]*/', $cfg->licenseEmailTo); - if ($toEmails !== false) { + $toEmails = preg_split('/;[ ]*/', $cfg->licenseEmailTo); + if ($toEmails !== false) { foreach ($toEmails as $toEmail) { if (!get_preg($toEmail, 'email')) { - $errors[] = _('Licence') . ': ' . _('TO address') . ' - ' . _('Please enter a valid email address!'); + $errors[] = _('Licence') . ': ' . _('To address') . ' - ' . _('Please enter a valid email address!'); break; } } - } + } } } // set session timeout @@ -199,10 +229,10 @@ if (isset($_POST['submitFormData'])) { if (isset($_POST['allowedHosts'])) { $allowedHosts = $_POST['allowedHosts']; $allowedHostsList = explode("\n", $allowedHosts); - for ($i = 0; $i < sizeof($allowedHostsList); $i++) { + for ($i = 0; $i < count($allowedHostsList); $i++) { $allowedHostsList[$i] = trim($allowedHostsList[$i]); // ignore empty lines - if ($allowedHostsList[$i] == "") { + if ($allowedHostsList[$i] === "") { unset($allowedHostsList[$i]); continue; } @@ -213,31 +243,33 @@ if (isset($_POST['submitFormData'])) { } } $allowedHosts = implode(",", $allowedHostsList); - } else { + } + else { $allowedHosts = ""; } $cfg->allowedHosts = $allowedHosts; - // set allowed hosts for self service + // set allowed hosts for self-service if (isLAMProVersion()) { if (isset($_POST['allowedHostsSelfService'])) { $allowedHostsSelfService = $_POST['allowedHostsSelfService']; $allowedHostsSelfServiceList = explode("\r\n", $allowedHostsSelfService); - for ($i = 0; $i < sizeof($allowedHostsSelfServiceList); $i++) { + for ($i = 0; $i < count($allowedHostsSelfServiceList); $i++) { $allowedHostsSelfServiceList[$i] = trim($allowedHostsSelfServiceList[$i]); // ignore empty lines - if ($allowedHostsSelfServiceList[$i] == "") { + if ($allowedHostsSelfServiceList[$i] === "") { unset($allowedHostsSelfServiceList[$i]); continue; } // check each line $ipRegex = '/^[0-9a-f\\.:\\*]+$/i'; - if (!preg_match($ipRegex, $allowedHostsSelfServiceList[$i]) || (strlen($allowedHostsSelfServiceList[$i]) > 15)) { + if (!preg_match($ipRegex, $allowedHostsSelfServiceList[$i]) || (strlen($allowedHostsSelfServiceList[$i]) > 45)) { $errors[] = sprintf(_("The IP address %s is invalid!"), htmlspecialchars(str_replace('%', '%%', $allowedHostsSelfServiceList[$i]))); } } $allowedHostsSelfServiceList = array_unique($allowedHostsSelfServiceList); $allowedHostsSelfService = implode(",", $allowedHostsSelfServiceList); - } else { + } + else { $allowedHostsSelfService = ""; } $cfg->allowedHostsSelfService = $allowedHostsSelfService; @@ -247,34 +279,37 @@ if (isset($_POST['submitFormData'])) { // set log destination if ($_POST['logDestination'] == "none") { $cfg->logDestination = "NONE"; - } elseif ($_POST['logDestination'] == "syslog") { + } + elseif ($_POST['logDestination'] == "syslog") { $cfg->logDestination = "SYSLOG"; - } elseif ($_POST['logDestination'] == "remote") { + } + elseif ($_POST['logDestination'] == "remote") { $cfg->logDestination = "REMOTE:" . $_POST['logRemote']; $remoteParts = explode(':', $_POST['logRemote']); - if ((sizeof($remoteParts) !== 2) || !get_preg($remoteParts[0], 'DNSname') || !get_preg($remoteParts[1], 'digit')) { + if ((count($remoteParts) !== 2) || !get_preg($remoteParts[0], 'DNSname') || !get_preg($remoteParts[1], 'digit')) { $errors[] = _("Please enter a valid remote server in format \"server:port\"."); } - } else { - $isValidLogFile = isset($_POST['logFile']) && LAMCfgMain::isValidLogFilename($_POST['logFile']); + } + else { + $isValidLogFile = isset($_POST['logFile']) && LAMCfgMain::isValidLogFilename($_POST['logFile']); $blockedPrefixes = ['/usr', '/etc', '/dev', '/boot', '/lib', '/proc', '/root', '/run', '/sys', '/snap']; if (!empty($_SERVER['DOCUMENT_ROOT'])) { - $blockedPrefixes[] = $_SERVER['DOCUMENT_ROOT']; - } + $blockedPrefixes[] = $_SERVER['DOCUMENT_ROOT']; + } foreach ($blockedPrefixes as $blockedPrefix) { - if (!$isValidLogFile) { - break; - } - if (str_starts_with($_POST['logFile'], $blockedPrefix)) { - $isValidLogFile = false; - } - } + if (!$isValidLogFile) { + break; + } + if (str_starts_with($_POST['logFile'], $blockedPrefix)) { + $isValidLogFile = false; + } + } if ($isValidLogFile) { $cfg->logDestination = $_POST['logFile']; - } + } else { $errors[] = _("The log file is empty or contains invalid characters! Valid characters are: a-z, A-Z, 0-9, /, ., _ and -. The file must end with '.log' or '.txt'."); - } + } } // password policies $cfg->passwordMinLength = $_POST['passwordMinLength']; @@ -315,8 +350,8 @@ if (isset($_POST['submitFormData'])) { else { $messages[] = _('You might need to restart your webserver for changes to take effect.'); } - } - } + } + } } } if (isset($_POST['sslCaCertDelete'])) { @@ -325,9 +360,9 @@ if (isset($_POST['submitFormData'])) { } if (isset($_POST['sslCaCertImport'])) { $matches = []; - if (preg_match('/^ldaps:\\/\\/([a-zA-Z0-9_\\.-]+)(:([0-9]+))?$/', $_POST['serverurl'], $matches)) { + if (preg_match('/^ldaps:\/\/([a-zA-Z0-9_.-]+)(:(\d+))?$/', $_POST['serverurl'], $matches)) { $port = '636'; - if (isset($matches[3]) && !empty($matches[3])) { + if (!empty($matches[3])) { $port = $matches[3]; } $pemResult = getLDAPSSLCertificate($matches[1], $port); @@ -335,16 +370,18 @@ if (isset($_POST['submitFormData'])) { $messages[] = _('Imported certificate from server.'); $messages[] = _('You might need to restart your webserver for changes to take effect.'); $cfg->uploadSSLCaCert($pemResult); - } else { + } + else { $errors[] = _('Unable to import server certificate. Please use the upload function.'); } - } else { + } + else { $errors[] = _('Invalid server name. Please enter "server" or "server:port".'); } } - foreach ($_POST as $key => $value) { + foreach (array_keys($_POST) as $key) { if (str_starts_with($key, 'deleteCert_')) { - $index = substr($key, strlen('deleteCert_')); + $index = (int) substr($key, strlen('deleteCert_')); $cfg->deleteSSLCaCert($index); } } @@ -355,19 +392,19 @@ if (isset($_POST['submitFormData'])) { $cfg->mailEncryption = $_POST['mailEncryption']; $cfg->mailServer = $_POST['mailServer']; if (!empty($cfg->mailServer) && !get_preg($cfg->mailServer, 'hostAndPort')) { - $errors[] = _('Please enter the mail server with host name and port.'); - } + $errors[] = _('Please enter the mail server with host name and port.'); + } $mailAttribute = strtolower($_POST['mailAttribute']); $mailBackupAttribute = strtolower($_POST['mailBackupAttribute']); if (empty($mailAttribute)) { $cfg->mailAttribute = LAMCfgMain::MAIL_ATTRIBUTE_DEFAULT; - } - elseif (preg_match('/^[a-z0-9_-]+$/', $mailAttribute)) { - $cfg->mailAttribute = $mailAttribute; - } + } + elseif (preg_match('/^[a-z0-9_-]+$/', $mailAttribute)) { + $cfg->mailAttribute = $mailAttribute; + } else { - $errors[] = _('The mail attributes are invalid.'); - } + $errors[] = _('The mail attributes are invalid.'); + } if (empty($mailBackupAttribute)) { $cfg->mailBackupAttribute = LAMCfgMain::MAIL_BACKUP_ATTRIBUTE_DEFAULT; } @@ -378,23 +415,37 @@ if (isset($_POST['submitFormData'])) { $errors[] = _('The mail attributes are invalid.'); } } - $cfg->errorReporting = $_POST['errorReporting']; - // module settings - $allModules = getAllModules(); - $moduleSettings = $cfg->getModuleSettings(); - foreach ($allModules as $module) { - $module->checkGlobalConfigOptions($moduleSettings, $messages, $errors); + // SMS settings + if (isLAMProVersion()) { + $cfg->smsProvider = $_POST['smsProvider']; + $cfg->smsAttributes = $_POST['smsAttributes']; + $cfg->smsApiKey = $_POST['smsApiKey']; + $cfg->smsToken = $_POST['smsApiToken']; + $cfg->smsAccountId = $_POST['smsAccountId']; + $cfg->smsRegion = $_POST['smsRegion']; + $cfg->smsFrom = $_POST['smsFrom']; + $cfg->smsDefaultCountryPrefix = $_POST['smsDefaultCountryPrefix']; } - $cfg->setModuleSettings($moduleSettings); + $cfg->errorReporting = $_POST['errorReporting']; + // module settings + $allModules = getAllModules(); + $moduleSettings = $cfg->getModuleSettings(); + foreach ($allModules as $module) { + $module->checkGlobalConfigOptions($moduleSettings, $messages, $errors); + } + $cfg->setModuleSettings($moduleSettings); // save settings - if (isset($_POST['submit'])) { - $cfg->save(); - if (empty($errors)) { - $scriptTag = new htmlJavaScript('window.lam.dialog.showSuccessMessageAndRedirect("' . _("Your settings were successfully saved.") . '", "", "' . _('Ok') . '", "../login.php")'); - parseHtml(null, $scriptTag, [], false, null); - echo ''; - exit(); - } + if (isset($_POST['submit']) && empty($errors)) { + try { + $cfg->save(); + $scriptTag = new htmlJavaScript('window.lam.dialog.showSuccessMessageAndRedirect("' . _("Your settings were successfully saved.") . '", "", "' . _('Ok') . '", "../login.php")'); + parseHtml(null, $scriptTag, [], false, null); + echo ''; + exit(); + } + catch (LAMException $e) { + $errors[] = $e->getTitle(); + } } } @@ -415,89 +466,91 @@ if (isset($_POST['submitFormData'])) { // check if config file is writable if (!$cfg->isWritable()) { - $row->add(new htmlStatusMessage('WARN', _('The config file is not writable.'), _('Your changes cannot be saved until you make the file writable for the webserver user.')), 12); + $row->add(new htmlStatusMessage('WARN', _('The config file is not writable.'), _('Your changes cannot be saved until you make the file writable for the webserver user.'))); } // database if (extension_loaded('PDO')) { - $row->add(new htmlSubTitle(_('Configuration storage')), 12); + $row->add(new htmlSubTitle(_('Configuration storage'))); $storageProviders = [ - _('Local file system') => LAMCfgMain::DATABASE_FILE_SYSTEM - ]; + _('Local file system') => LAMCfgMain::DATABASE_FILE_SYSTEM + ]; if (in_array('mysql', PDO::getAvailableDrivers())) { $storageProviders['MySQL'] = LAMCfgMain::DATABASE_MYSQL; } $storageProviderSelect = new htmlResponsiveSelect('configDatabaseType', $storageProviders, [$cfg->configDatabaseType], _('Database type'), '293'); $storageProviderSelect->setHasDescriptiveElements(true); $dbRowsToShow = [ - LAMCfgMain::DATABASE_FILE_SYSTEM => [], - LAMCfgMain::DATABASE_MYSQL => ['configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', 'configDatabasePassword'] - ]; + LAMCfgMain::DATABASE_FILE_SYSTEM => [], + LAMCfgMain::DATABASE_MYSQL => ['configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', 'configDatabasePassword', 'configDatabaseSSLCA'] + ]; $storageProviderSelect->setTableRowsToShow($dbRowsToShow); $dbRowsToHide = [ - LAMCfgMain::DATABASE_FILE_SYSTEM => ['configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', 'configDatabasePassword'], - LAMCfgMain::DATABASE_MYSQL => [] - ]; + LAMCfgMain::DATABASE_FILE_SYSTEM => ['configDatabaseServer', 'configDatabasePort', 'configDatabaseName', 'configDatabaseUser', 'configDatabasePassword', 'configDatabaseSSLCA'], + LAMCfgMain::DATABASE_MYSQL => [] + ]; $storageProviderSelect->setTableRowsToHide($dbRowsToHide); - $row->add($storageProviderSelect, 12); + $row->add($storageProviderSelect); $dbHost = new htmlResponsiveInputField(_('Database host'), 'configDatabaseServer', $cfg->configDatabaseServer, '273'); $dbHost->setRequired(true); - $row->add($dbHost, 12); + $row->add($dbHost); $dbPort = new htmlResponsiveInputField(_('Database port'), 'configDatabasePort', $cfg->configDatabasePort, '274'); - $row->add($dbPort, 12); + $row->add($dbPort); + $dbHostSSLCA = new htmlResponsiveInputField(_('CA certificate path'), 'configDatabaseSSLCA', $cfg->configDatabaseSSLCA, '277'); + $row->add($dbHostSSLCA); $dbName = new htmlResponsiveInputField(_('Database name'), 'configDatabaseName', $cfg->configDatabaseName, '276'); $dbName->setRequired(true); - $row->add($dbName, 12); + $row->add($dbName); $dbUser = new htmlResponsiveInputField(_('Database user'), 'configDatabaseUser', $cfg->configDatabaseUser, '275'); $dbUser->setRequired(true); - $row->add($dbUser, 12); + $row->add($dbUser); $dbPassword = new htmlResponsiveInputField(_('Database password'), 'configDatabasePassword', deobfuscateText($cfg->configDatabasePassword), '275'); $dbPassword->setRequired(true); $dbPassword->setIsPassword(true); - $row->add($dbPassword, 12); - } + $row->add($dbPassword); + } // license if (isLAMProVersion()) { - $row->add(new htmlSubTitle(_('Licence')), 12); - $row->add(new htmlResponsiveInputTextarea('license', implode("\n", $cfg->getLicenseLines()), '30', '10', _('Licence'), '287'), 12); + $row->add(new htmlSubTitle(_('Licence'))); + $row->add(new htmlResponsiveInputTextarea('license', implode("\n", $cfg->getLicenseLines()), 30, 10, _('Licence'), '287')); $warningOptions = [ - _('Screen') => LAMCfgMain::LICENSE_WARNING_SCREEN, - _('Email') => LAMCfgMain::LICENSE_WARNING_EMAIL, - _('Both') => LAMCfgMain::LICENSE_WARNING_ALL, - _('None') => LAMCfgMain::LICENSE_WARNING_NONE - ]; + _('Screen') => LAMCfgMain::LICENSE_WARNING_SCREEN, + _('Email') => LAMCfgMain::LICENSE_WARNING_EMAIL, + _('Both') => LAMCfgMain::LICENSE_WARNING_ALL, + _('None') => LAMCfgMain::LICENSE_WARNING_NONE + ]; $warningTypeSelect = new htmlResponsiveSelect('licenseWarningType', $warningOptions, [$cfg->getLicenseWarningType()], _('Expiration warning'), '288'); $warningTypeSelect->setHasDescriptiveElements(true); $warningTypeSelect->setSortElements(false); $warningTypeSelect->setTableRowsToHide([ - LAMCfgMain::LICENSE_WARNING_SCREEN => ['licenseEmailFrom', 'licenseEmailTo'], - LAMCfgMain::LICENSE_WARNING_NONE => ['licenseEmailFrom', 'licenseEmailTo'] - ]); + LAMCfgMain::LICENSE_WARNING_SCREEN => ['licenseEmailFrom', 'licenseEmailTo'], + LAMCfgMain::LICENSE_WARNING_NONE => ['licenseEmailFrom', 'licenseEmailTo'] + ]); $warningTypeSelect->setTableRowsToShow([ - LAMCfgMain::LICENSE_WARNING_EMAIL => ['licenseEmailFrom', 'licenseEmailTo'], - LAMCfgMain::LICENSE_WARNING_ALL => ['licenseEmailFrom', 'licenseEmailTo'] - ]); - $row->add($warningTypeSelect, 12); + LAMCfgMain::LICENSE_WARNING_EMAIL => ['licenseEmailFrom', 'licenseEmailTo'], + LAMCfgMain::LICENSE_WARNING_ALL => ['licenseEmailFrom', 'licenseEmailTo'] + ]); + $row->add($warningTypeSelect); $licenseFrom = new htmlResponsiveInputField(_('From address'), 'licenseEmailFrom', $cfg->licenseEmailFrom, '289'); $licenseFrom->setRequired(true); - $row->add($licenseFrom, 12); - $licenseTo = new htmlResponsiveInputField(_('TO address'), 'licenseEmailTo', $cfg->licenseEmailTo, '290'); + $row->add($licenseFrom); + $licenseTo = new htmlResponsiveInputField(_('To address'), 'licenseEmailTo', $cfg->licenseEmailTo, '290'); $licenseTo->setRequired(true); - $row->add($licenseTo, 12); + $row->add($licenseTo); - $row->add(new htmlSpacer(null, '1rem'), true); + $row->add(new htmlSpacer(null, '1rem')); } // security settings - $row->add(new htmlSubTitle(_("Security settings")), 12); + $row->add(new htmlSubTitle(_("Security settings"))); $options = [5, 10, 20, 30, 60, 90, 120, 240]; $row->add(new htmlResponsiveSelect('sessionTimeout', $options, [$cfg->sessionTimeout], _("Session timeout"), '238')); $hideLoginErrorDetails = ($cfg->hideLoginErrorDetails === 'true'); $row->add(new htmlResponsiveInputCheckbox('hideLoginErrorDetails', $hideLoginErrorDetails, _('Hide LDAP details on failed login'), '257')); - $row->add(new htmlResponsiveInputTextarea('allowedHosts', implode("\n", explode(",", $cfg->allowedHosts)), '30', '7', _("Allowed hosts"), '241')); + $row->add(new htmlResponsiveInputTextarea('allowedHosts', implode("\n", explode(",", $cfg->allowedHosts)), 30, 7, _("Allowed hosts"), '241')); if (isLAMProVersion()) { - $row->add(new htmlResponsiveInputTextarea('allowedHostsSelfService', implode("\n", explode(",", $cfg->allowedHostsSelfService)), '30', '7', _("Allowed hosts (self service)"), '241')); + $row->add(new htmlResponsiveInputTextarea('allowedHostsSelfService', implode("\n", explode(",", $cfg->allowedHostsSelfService)), 30, 7, _("Allowed hosts (self service)"), '241')); } // SSL certificate $row->addVerticalSpacer('1rem'); @@ -529,7 +582,7 @@ if (isset($_POST['submitFormData'])) { $sslUploadBtn->setTitle(_('Upload CA certificate in DER/PEM format.')); $row->addField($sslUploadBtn); if (function_exists('stream_socket_client') && function_exists('stream_context_get_params')) { - $sslImportServerUrl = !empty($_POST['serverurl']) ? $_POST['serverurl'] : 'ldaps://'; + $sslImportServerUrl = empty($_POST['serverurl']) ? 'ldaps://' : (string) $_POST['serverurl']; $serverUrlUpload = new htmlInputField('serverurl', $sslImportServerUrl); $row->addLabel($serverUrlUpload); $sslImportBtn = new htmlButton('sslCaCertImport', _('Import from server')); @@ -538,87 +591,89 @@ if (isset($_POST['submitFormData'])) { } $sslCerts = $cfg->getSSLCaCertificates(); - if (sizeof($sslCerts) > 0) { + if (count($sslCerts) > 0) { $certsTitles = [_('Common name'), _('Valid to'), _('Serial number'), _('Delete')]; $certsData = []; - for ($i = 0; $i < sizeof($sslCerts); $i++) { + for ($i = 0; $i < count($sslCerts); $i++) { $serial = $sslCerts[$i]['serialNumber'] ?? ''; $validTo = $sslCerts[$i]['validTo_time_t'] ?? ''; if (get_preg($validTo, 'digit')) { - $date = DateTime::createFromFormat('U', $validTo, new DateTimeZone('UTC')); - if ($date !== false) { + $date = DateTime::createFromFormat('U', $validTo, new DateTimeZone('UTC')); + if ($date !== false) { $validTo = $date->format('Y-m-d'); - } - } + } + } $cn = $sslCerts[$i]['subject']['CN'] ?? ''; $delBtn = new htmlButton('deleteCert_' . $i, 'del.svg', true); $certsData[] = [ - new htmlOutputText($cn), - new htmlDiv(null, new htmlOutputText($validTo), ['nowrap']), - new htmlOutputText($serial), - $delBtn - ]; + new htmlOutputText($cn), + new htmlDiv(null, new htmlOutputText($validTo), ['nowrap']), + new htmlOutputText($serial), + $delBtn + ]; } $certsTable = new htmlResponsiveTable($certsTitles, $certsData); $certsTable->setCSSClasses(['text-left']); - $row->add($certsTable, 12); + $row->add($certsTable); } // password policy - $row->add(new htmlSubTitle(_("Password policy")), 12); + $row->add(new htmlSubTitle(_("Password policy"))); $optionsPwdLength = []; for ($i = 0; $i <= 50; $i++) { $optionsPwdLength[] = $i; } $options4 = [0, 1, 2, 3, 4]; - $row->add(new htmlResponsiveSelect('passwordMinLength', $optionsPwdLength, [$cfg->passwordMinLength], _('Minimum password length'), '242'), 12); + $row->add(new htmlResponsiveSelect('passwordMinLength', $optionsPwdLength, [$cfg->passwordMinLength], _('Minimum password length'), '242')); $row->addVerticalSpacer('1rem'); - $row->add(new htmlResponsiveSelect('passwordMinLower', $optionsPwdLength, [$cfg->passwordMinLower], _('Minimum lowercase characters'), '242'), 12); - $row->add(new htmlResponsiveSelect('passwordMinUpper', $optionsPwdLength, [$cfg->passwordMinUpper], _('Minimum uppercase characters'), '242'), 12); - $row->add(new htmlResponsiveSelect('passwordMinNumeric', $optionsPwdLength, [$cfg->passwordMinNumeric], _('Minimum numeric characters'), '242'), 12); - $row->add(new htmlResponsiveSelect('passwordMinSymbol', $optionsPwdLength, [$cfg->passwordMinSymbol], _('Minimum symbolic characters'), '242'), 12); - $row->add(new htmlResponsiveSelect('passwordMinClasses', $options4, [$cfg->passwordMinClasses], _('Minimum character classes'), '242'), 12); + $row->add(new htmlResponsiveSelect('passwordMinLower', $optionsPwdLength, [$cfg->passwordMinLower], _('Minimum lowercase characters'), '242')); + $row->add(new htmlResponsiveSelect('passwordMinUpper', $optionsPwdLength, [$cfg->passwordMinUpper], _('Minimum uppercase characters'), '242')); + $row->add(new htmlResponsiveSelect('passwordMinNumeric', $optionsPwdLength, [$cfg->passwordMinNumeric], _('Minimum numeric characters'), '242')); + $row->add(new htmlResponsiveSelect('passwordMinSymbol', $optionsPwdLength, [$cfg->passwordMinSymbol], _('Minimum symbolic characters'), '242')); + $row->add(new htmlResponsiveSelect('passwordMinClasses', $options4, [$cfg->passwordMinClasses], _('Minimum character classes'), '242')); $row->addVerticalSpacer('1rem'); $rulesCountOptions = [_('all') => '-1', '3' => '3', '4' => '4']; $rulesCountSelect = new htmlResponsiveSelect('passwordRulesCount', $rulesCountOptions, [$cfg->checkedRulesCount], _('Number of rules that must match'), '246'); $rulesCountSelect->setHasDescriptiveElements(true); - $row->add($rulesCountSelect, 12); + $row->add($rulesCountSelect); $passwordMustNotContainUser = ($cfg->passwordMustNotContainUser === 'true'); - $row->add(new htmlResponsiveInputCheckbox('passwordMustNotContainUser', $passwordMustNotContainUser, _('Password must not contain user name'), '247'), 12); + $row->add(new htmlResponsiveInputCheckbox('passwordMustNotContainUser', $passwordMustNotContainUser, _('Password must not contain user name'), '247')); $passwordMustNotContain3Chars = ($cfg->passwordMustNotContain3Chars === 'true'); - $row->add(new htmlResponsiveInputCheckbox('passwordMustNotContain3Chars', $passwordMustNotContain3Chars, _('Password must not contain part of user/first/last name'), '248'), 12); + $row->add(new htmlResponsiveInputCheckbox('passwordMustNotContain3Chars', $passwordMustNotContain3Chars, _('Password must not contain part of user/first/last name'), '248')); if (function_exists('curl_init')) { $row->addVerticalSpacer('1rem'); - $row->add(new htmlResponsiveInputField(_('External password check'), 'externalPwdCheckUrl', $cfg->externalPwdCheckUrl, '249'), 12); + $row->add(new htmlResponsiveInputField(_('External password check'), 'externalPwdCheckUrl', $cfg->externalPwdCheckUrl, '249')); } // logging - $row->add(new htmlSubTitle(_("Logging")), 12); + $row->add(new htmlSubTitle(_("Logging"))); $levelOptions = [ - _("Debug") => LOG_DEBUG, - _("Notice") => LOG_NOTICE, - _("Warning") => LOG_WARNING, - _("Error") => LOG_ERR - ]; + _("Debug") => LOG_DEBUG, + _("Notice") => LOG_NOTICE, + _("Warning") => LOG_WARNING, + _("Error") => LOG_ERR + ]; $levelSelect = new htmlResponsiveSelect('logLevel', $levelOptions, [$cfg->logLevel], _("Log level"), '239'); $levelSelect->setHasDescriptiveElements(true); - $row->add($levelSelect, 12); + $row->add($levelSelect); $destinationOptions = [ - _("No logging") => "none", - _("System logging") => "syslog", - _("File") => 'file', - _("Remote") => 'remote' - ]; + _("No logging") => "none", + _("System logging") => "syslog", + _("File") => 'file', + _("Remote") => 'remote' + ]; $destinationSelected = 'file'; $destinationPath = $cfg->logDestination; $destinationRemote = ''; if ($cfg->logDestination == 'NONE') { $destinationSelected = 'none'; $destinationPath = ''; - } elseif ($cfg->logDestination == 'SYSLOG') { + } + elseif ($cfg->logDestination == 'SYSLOG') { $destinationSelected = 'syslog'; $destinationPath = ''; - } elseif (str_starts_with($cfg->logDestination, 'REMOTE')) { + } + elseif (str_starts_with($cfg->logDestination, 'REMOTE')) { $destinationSelected = 'remote'; $remoteParts = explode(':', $cfg->logDestination, 2); $destinationRemote = empty($remoteParts[1]) ? '' : $remoteParts[1]; @@ -626,31 +681,31 @@ if (isset($_POST['submitFormData'])) { } $logDestinationSelect = new htmlResponsiveSelect('logDestination', $destinationOptions, [$destinationSelected], _("Log destination"), '240'); $logDestinationSelect->setTableRowsToHide([ - 'none' => ['logFile', 'logRemote'], - 'syslog' => ['logFile', 'logRemote'], - 'remote' => ['logFile'], - 'file' => ['logRemote'] - ]); + 'none' => ['logFile', 'logRemote'], + 'syslog' => ['logFile', 'logRemote'], + 'remote' => ['logFile'], + 'file' => ['logRemote'] + ]); $logDestinationSelect->setTableRowsToShow([ - 'file' => ['logFile'], - 'remote' => ['logRemote'] - ]); + 'file' => ['logFile'], + 'remote' => ['logRemote'] + ]); $logDestinationSelect->setHasDescriptiveElements(true); - $row->add($logDestinationSelect, 12); - $row->add(new htmlResponsiveInputField(_('File'), 'logFile', $destinationPath), 12); - $row->add(new htmlResponsiveInputField(_('Remote server'), 'logRemote', $destinationRemote, '251'), 12); + $row->add($logDestinationSelect); + $row->add(new htmlResponsiveInputField(_('File'), 'logFile', $destinationPath)); + $row->add(new htmlResponsiveInputField(_('Remote server'), 'logRemote', $destinationRemote, '251')); $errorLogOptions = [ - _('PHP system setting') => LAMCfgMain::ERROR_REPORTING_SYSTEM, - _('default') => LAMCfgMain::ERROR_REPORTING_DEFAULT, - _('all') => LAMCfgMain::ERROR_REPORTING_ALL - ]; + _('PHP system setting') => LAMCfgMain::ERROR_REPORTING_SYSTEM, + _('default') => LAMCfgMain::ERROR_REPORTING_DEFAULT, + _('all') => LAMCfgMain::ERROR_REPORTING_ALL + ]; $errorLogSelect = new htmlResponsiveSelect('errorReporting', $errorLogOptions, [$cfg->errorReporting], _('PHP error reporting'), '244'); $errorLogSelect->setHasDescriptiveElements(true); $row->add($errorLogSelect); // mail options if (isLAMProVersion()) { - $row->add(new htmlSubTitle(_('Mail options')), 12); + $row->add(new htmlSubTitle(_('Mail options'))); $mailServer = new htmlResponsiveInputField(_("Mail server"), 'mailServer', $cfg->mailServer, '253'); $row->add($mailServer); $mailUser = new htmlResponsiveInputField(_("User name"), 'mailUser', $cfg->mailUser, '254'); @@ -659,10 +714,10 @@ if (isset($_POST['submitFormData'])) { $mailPassword->setIsPassword(true); $row->add($mailPassword); $mailEncryptionOptions = [ - 'TLS' => LAMCfgMain::SMTP_TLS, - 'SSL' => LAMCfgMain::SMTP_SSL, - _('None') => LAMCfgMain::SMTP_NONE - ]; + 'TLS' => LAMCfgMain::SMTP_TLS, + 'SSL' => LAMCfgMain::SMTP_SSL, + _('None') => LAMCfgMain::SMTP_NONE + ]; $selectedMailEncryption = empty($cfg->mailEncryption) ? LAMCfgMain::SMTP_TLS : $cfg->mailEncryption; $mailEncryptionSelect = new htmlResponsiveSelect('mailEncryption', $mailEncryptionOptions, [$selectedMailEncryption], _('Encryption protocol'), '256'); $mailEncryptionSelect->setHasDescriptiveElements(true); @@ -672,14 +727,99 @@ if (isset($_POST['submitFormData'])) { addSecurityTokenToSession(false); $mailTestButton = new htmlButton('testSmtp', _('Test settings')); $mailTestButton->setOnClick("window.lam.smtp.test(event, '" . getSecurityTokenName() - . "', '" . getSecurityTokenValue() . "', '" . _('Ok') . "')"); + . "', '" . getSecurityTokenValue() . "', '" . _('Ok') . "', '" . _('Cancel') . "', '" . _('Test settings') . "')"); $row->addLabel(new htmlOutputText(" ", false)); $row->addField($mailTestButton); + $testDialogDivContent = new htmlResponsiveRow(); + $fromAddressInput = new htmlResponsiveInputField(_('From address'), 'testSmtpFrom', null, null, true); + $fromAddressInput->setType('email'); + $testDialogDivContent->add($fromAddressInput); + $toAddressInput = new htmlResponsiveInputField(_('To address'), 'testSmtpTo', null, null, true); + $toAddressInput->setType('email'); + $testDialogDivContent->add($toAddressInput); + $testDialogDiv = new htmlDiv('smtpTestDialogDiv', $testDialogDivContent, ['hidden']); + $row->add($testDialogDiv); + } + + // SMS options + if (isLAMProVersion()) { + $row->add(new htmlSubTitle(_('SMS options'))); + $smsService = new SmsService(); + $smsProviders = $smsService->findProviders(); + $smsProviderOptions = [ + '-' => '', + ]; + $smsOptionsToHide = [ + '' => ['smsApiKey', 'smsApiToken', 'smsAccountId', 'smsRegion', 'smsFrom', 'smsAttributes', + 'smsDefaultCountryPrefix', 'btn_testSms'] + ]; + $smsOptionsToShow = []; + foreach ($smsProviders as $provider) { + $smsProviderOptions[$provider->getLabel()] = $provider->getId(); + $smsOptionsToShow[$provider->getId()][] = 'smsAttributes'; + $smsOptionsToShow[$provider->getId()][] = 'btn_testSms'; + if ($provider->usesApiToken()) { + $smsOptionsToShow[$provider->getId()][] = 'smsApiToken'; + } + else { + $smsOptionsToHide[$provider->getId()][] = 'smsApiToken'; + } + if ($provider->usesApiKey()) { + $smsOptionsToShow[$provider->getId()][] = 'smsApiKey'; + } + else { + $smsOptionsToHide[$provider->getId()][] = 'smsApiKey'; + } + if ($provider->usesAccountId()) { + $smsOptionsToShow[$provider->getId()][] = 'smsAccountId'; + } + else { + $smsOptionsToHide[$provider->getId()][] = 'smsAccountId'; + } + if ($provider->usesRegion()) { + $smsOptionsToShow[$provider->getId()][] = 'smsRegion'; + } + else { + $smsOptionsToHide[$provider->getId()][] = 'smsRegion'; + } + if ($provider->usesFrom()) { + $smsOptionsToShow[$provider->getId()][] = 'smsFrom'; + } + else { + $smsOptionsToHide[$provider->getId()][] = 'smsFrom'; + } + } + $selectedSmsProvider = empty($cfg->smsProvider) ? '' : $cfg->smsProvider; + $smsProviderSelect = new htmlResponsiveSelect('smsProvider', $smsProviderOptions, [$selectedSmsProvider], _('SMS provider'), '296'); + $smsProviderSelect->setHasDescriptiveElements(true); + $smsProviderSelect->setTableRowsToHide($smsOptionsToHide); + $smsProviderSelect->setTableRowsToShow($smsOptionsToShow); + $row->add($smsProviderSelect); + $row->add(new htmlResponsiveInputField(_('Region'), 'smsRegion', $cfg->smsRegion, '299c')); + $row->add(new htmlResponsiveInputField(_('Account id'), 'smsAccountId', $cfg->smsAccountId, '298a')); + $row->add(new htmlResponsiveInputField(_('API key'), 'smsApiKey', $cfg->smsApiKey, '297')); + $row->add(new htmlResponsiveInputField(_('Token'), 'smsApiToken', $cfg->smsToken, '298')); + $row->add(new htmlResponsiveInputField(_('From'), 'smsFrom', $cfg->smsFrom, '299b')); + $row->add(new htmlResponsiveInputField(_('Default country prefix'), 'smsDefaultCountryPrefix', $cfg->smsDefaultCountryPrefix, '299a')); + $row->add(new htmlResponsiveInputField(_("Mobile phone attributes"), 'smsAttributes', implode(';', $cfg->getSmsAttributes()), '299')); + $smsTestButtonRow = new htmlResponsiveRow(); + $smsTestButton = new htmlButton('testSms', _('Test settings')); + $smsTestButton->setOnClick("window.lam.sms.test(event, '" . getSecurityTokenName() + . "', '" . getSecurityTokenValue() . "', '" . _('Ok') . "', '" . _('Cancel') . "', '" . _('Test settings') . "')"); + $smsTestButtonRow->addLabel(new htmlOutputText(" ", false)); + $smsTestButtonRow->addField($smsTestButton); + $row->add($smsTestButtonRow); + $smsTestDialogDivContent = new htmlResponsiveRow(); + $smsTestNumber = new htmlResponsiveInputField(_('Mobile number'), 'testSmsNumber', null, null, true); + $smsTestNumber->setType('tel'); + $smsTestDialogDivContent->add($smsTestNumber); + $smsTestDialogDiv = new htmlDiv('smsTestDialogDiv', $smsTestDialogDivContent, ['hidden']); + $row->add($smsTestDialogDiv); } // webauthn management if (extension_loaded('PDO') - && in_array('sqlite', \PDO::getAvailableDrivers())) { + && in_array('sqlite', PDO::getAvailableDrivers())) { include_once __DIR__ . '/../../lib/webauthn.inc'; $webAuthnManager = new WebauthnManager(); try { @@ -687,7 +827,7 @@ if (isset($_POST['submitFormData'])) { if ($database->hasRegisteredCredentials()) { $row->add(new htmlSubTitle(_('WebAuthn devices'))); $webauthnSearchField = new htmlResponsiveInputField(_('User DN'), 'webauthn_searchTerm', null, '252'); - $row->add($webauthnSearchField, 12); + $row->add($webauthnSearchField); $row->addVerticalSpacer('0.5rem'); $row->add(new htmlButton('webauthn_search', _('Search')), 12, 12, 12, 'text-center'); $resultDiv = new htmlDiv('webauthn_results', new htmlOutputText(''), ['lam-webauthn-results', 'text-left']); @@ -699,48 +839,48 @@ if (isset($_POST['submitFormData'])) { } } catch (LAMException $e) { - logNewMessage(LOG_ERR, 'Webauthn error: ' . $e->getTitle() . ' ' . $e->getMessage()); - $row->add(new htmlStatusMessage('ERROR', $e->getTitle())); - } + logNewMessage(LOG_ERR, 'Webauthn error: ' . $e->getTitle() . ' ' . $e->getMessage()); + $row->add(new htmlStatusMessage('ERROR', $e->getTitle())); + } } - // module settings + // module settings $modules = getAllModules(); - $supportsGlobalCronJob = false; - foreach ($modules as $module) { - $supportsGlobalCronJob = $supportsGlobalCronJob || $module->supportsGlobalCronJob(); - $moduleOptions = $module->getGlobalConfigOptions($cfg->getModuleSettings()); - if (empty($moduleOptions)) { - continue; - } - $row->add(new htmlSubTitle($module->get_alias())); - foreach ($moduleOptions as $moduleOption) { - $row->add($moduleOption); - } + $supportsGlobalCronJob = false; + foreach ($modules as $module) { + $supportsGlobalCronJob = $supportsGlobalCronJob || $module->supportsGlobalCronJob(); + $moduleOptions = $module->getGlobalConfigOptions($cfg->getModuleSettings()); + if (empty($moduleOptions)) { + continue; + } + $row->add(new htmlSubTitle($module->get_alias())); + foreach ($moduleOptions as $moduleOption) { + $row->add($moduleOption); + } $row->addVerticalSpacer('3rem'); - } + } - // global cron job - if ($supportsGlobalCronJob) { + // global cron job + if ($supportsGlobalCronJob) { $row->add(new htmlSubTitle(_('Global cron job'))); - $cronCommand = dirname(__FILE__, 3) . '/lib/runCronJobs.sh all'; - $row->addLabel(new htmlOutputText('Cron command')); + $cronCommand = dirname(__FILE__, 3) . '/lib/runCronJobs.sh all'; + $row->addLabel(new htmlOutputText('Cron command')); $cmdGroup = new htmlGroup(); $cmdGroup->addElement(new htmlOutputText('0 0 * * * ' . $cronCommand)); $cmdGroup->addElement(new htmlSpacer('2rem', null)); $cmdGroup->addElement(new htmlHelpLink('294')); $row->addField($cmdGroup); - } + } // change master password $row->add(new htmlSubTitle(_("Change master password"))); $pwd1 = new htmlResponsiveInputField(_("New master password"), 'masterpassword', '', '235'); $pwd1->setIsPassword(true, false, true); - $row->add($pwd1, 12); + $row->add($pwd1); $pwd2 = new htmlResponsiveInputField(_("Reenter password"), 'masterpassword2', ''); $pwd2->setIsPassword(true, false, true); $pwd2->setSameValueFieldID('masterpassword'); - $row->add($pwd2, 12); + $row->add($pwd2); $row->addVerticalSpacer('3rem'); // buttons @@ -751,8 +891,8 @@ if (isset($_POST['submitFormData'])) { $buttonTable->addElement($saveButton); $buttonTable->addElement(new htmlSpacer('0.5rem', null)); $buttonTable->addElement(new htmlButton('cancel', _("Cancel"))); - $row->add($buttonTable, 12); - $row->add(new htmlHiddenInput('submitFormData', '1'), 12); + $row->add($buttonTable); + $row->add(new htmlHiddenInput('submitFormData', '1')); } $box = new htmlDiv(null, $row); diff --git a/lam/templates/config/moduleSettings.php b/lam/templates/config/moduleSettings.php index f2a29a3f8..93ac45345 100644 --- a/lam/templates/config/moduleSettings.php +++ b/lam/templates/config/moduleSettings.php @@ -1,16 +1,22 @@ \n"; @@ -112,7 +118,7 @@ printJsIncludes('../..'); printConfigurationPageHeaderBar($conf); // print error messages -for ($i = 0; $i < sizeof($errorsToDisplay); $i++) { +for ($i = 0; $i < count($errorsToDisplay); $i++) { call_user_func_array(StatusMessage(...), $errorsToDisplay[$i]); } @@ -121,21 +127,21 @@ echo "
    - - - - + + + getConfiguredTypes(); // get list of scopes of modules $scopes = []; foreach ($types as $type) { $mods = $conf->get_AccountModules($type->getId()); - for ($i = 0; $i < sizeof($mods); $i++) { + for ($i = 0; $i < count($mods); $i++) { $scopes[$mods[$i]][] = $type->getId(); } } @@ -149,26 +155,27 @@ $old_options = $conf->get_moduleSettings(); // display module boxes $modules = array_keys($options); $_SESSION['conf_types'] = []; -for ($i = 0; $i < sizeof($modules); $i++) { +for ($i = 0; $i < count($modules); $i++) { if (empty($options[$modules[$i]])) { continue; } $module = moduleCache::getModule($modules[$i], null); + if ($module === null) { + continue; + } $iconImage = $module->getIcon(); - if ($iconImage != null) { - if (!(str_starts_with($iconImage, 'http')) && !(str_starts_with($iconImage, '/'))) { - $iconImage = '../../graphics/' . $iconImage; - } + if (($iconImage != null) && !(str_starts_with($iconImage, 'http')) && !(str_starts_with($iconImage, '/'))) { + $iconImage = '../../graphics/' . $iconImage; } $row = new htmlResponsiveRow(); - $row->add(new htmlSubTitle(getModuleAlias($modules[$i], null), $iconImage, null, true), 12); + $row->add(new htmlSubTitle($module->get_alias(), $iconImage, null, true)); if (is_array($options[$modules[$i]])) { foreach ($options[$modules[$i]] as $option) { - $row->add($option, 12); + $row->add($option); } } else { - $row->add($options[$modules[$i]], 12); + $row->add($options[$modules[$i]]); } $configTypes = parseHtml($modules[$i], $row, $old_options, false, null); $_SESSION['conf_types'] = array_merge($configTypes, $_SESSION['conf_types']); @@ -190,7 +197,7 @@ $buttonContainer->addElement(new htmlSpacer(null, '10px'), true); if (empty($errorsToDisplay) && isset($_POST['scrollPositionTop']) && isset($_POST['scrollPositionLeft'])) { // scroll to last position - $buttonContainer->addElement(new htmlJavaScript('window.lam.utility.restoreScrollPosition(' . $_POST['scrollPositionTop'] .', ' . $_POST['scrollPositionLeft'] . ')')); + $buttonContainer->addElement(new htmlJavaScript('window.lam.utility.restoreScrollPosition(' . $_POST['scrollPositionTop'] . ', ' . $_POST['scrollPositionLeft'] . ')')); } parseHtml(null, $buttonContainer, [], false, null); @@ -210,7 +217,10 @@ function checkInput(): array { return []; } $conf = &$_SESSION['conf_config']; - $typeManager = new \LAM\TYPES\TypeManager($conf); + if (!($conf instanceof LAMConfig)) { + return []; + } + $typeManager = new TypeManager($conf); $types = $typeManager->getConfiguredTypes(); // check module options @@ -221,7 +231,7 @@ function checkInput(): array { $scopes = []; foreach ($types as $type) { $mods = $conf->get_AccountModules($type->getId()); - for ($i = 0; $i < sizeof($mods); $i++) { + for ($i = 0; $i < count($mods); $i++) { $scopes[$mods[$i]][] = $type->getId(); } } diff --git a/lam/templates/config/profmanage.php b/lam/templates/config/profmanage.php index 2f7ffe452..136f0276a 100644 --- a/lam/templates/config/profmanage.php +++ b/lam/templates/config/profmanage.php @@ -1,25 +1,24 @@ createProfileFromTemplate($_POST['addprofile'], $_POST['addTemplate'], $_POST['addpassword']); $_SESSION['conf_isAuthenticated'] = $_POST['addprofile']; @@ -88,12 +93,9 @@ if (isset($_POST['action'])) { metaRefresh('confmain.php'); exit; } catch (LAMException $e) { - $error = $e->getTitle(); + $error = $e->getTitle(); } } - else { - $error = _("Profile passwords are different or empty!"); - } } // rename profile elseif ($_POST['action'] == "rename") { @@ -114,7 +116,7 @@ if (isset($_POST['action'])) { // update default profile setting if needed if ($cfg->default == $_POST['delfilename']) { $filesNew = array_delete([$_POST['delfilename']], $files); - if (sizeof($filesNew) > 0) { + if (count($filesNew) > 0) { sort($filesNew); $cfg->default = $filesNew[0]; $cfg->save(); @@ -131,20 +133,23 @@ if (isset($_POST['action'])) { // set new profile password elseif ($_POST['action'] == "setpass") { if (preg_match("/^[a-z0-9_-]+$/i", (string) $_POST['setprofile'])) { - if ($_POST['setpassword'] && $_POST['setpassword2'] && ($_POST['setpassword'] == $_POST['setpassword2'])) { + if (empty($_POST['setpassword']) || ($_POST['setpassword'] !== $_POST['setpassword2'])) { + $error = _("Profile passwords are different or empty!"); + } + elseif (!isValidConfigurationPassword($_POST['setpassword'])) { + $error = _('Please enter at least 8 characters including letters, a number and a symbol.'); + } + else { try { $config = $serverProfilePersistenceManager->loadProfile($_POST['setprofile']); $config->set_Passwd($_POST['setpassword']); $serverProfilePersistenceManager->saveProfile($config, $_POST['setprofile']); $msg = _("New password set successfully."); } catch (LAMException $e) { - $error = $e->getTitle(); + $error = $e->getTitle(); } $config = null; } - else { - $error = _("Profile passwords are different or empty!"); - } } else { $error = _("Profile name is invalid!"); @@ -155,9 +160,14 @@ if (isset($_POST['action'])) { if (preg_match("/^[a-z0-9_-]+$/i", (string) $_POST['defaultfilename'])) { $configMain = new LAMCfgMain(); $configMain->default = $_POST['defaultfilename']; - $configMain->save(); - $configMain = null; - $msg = _("New default profile set successfully."); + try { + $configMain->save(); + $configMain = null; + $msg = _("New default profile set successfully."); + } + catch (LAMException $e) { + $error = $e->getTitle(); + } } else { $error = _("Profile name is invalid!"); @@ -211,19 +221,19 @@ $row = new htmlResponsiveRow(); // print messages if (isset($error)) { - $row->add(new htmlStatusMessage('ERROR', $error), 12); + $row->add(new htmlStatusMessage('ERROR', $error)); $row->addVerticalSpacer('1rem'); } if (isset($msg)) { - $row->add(new htmlStatusMessage('INFO', $msg), 12); + $row->add(new htmlStatusMessage('INFO', $msg)); $row->addVerticalSpacer('1rem'); } $box = new htmlResponsiveRow(); -$box->add(new htmlTitle(_("Profile management")), 12); +$box->add(new htmlTitle(_("Profile management"))); // new profile -$box->add(new htmlSubTitle(_("Add profile")), 12); +$box->add(new htmlSubTitle(_("Add profile"))); $newProfileInput = new htmlResponsiveInputField(_("Profile name"), 'addprofile', null, '230'); $box->add($newProfileInput); $profileNewPwd1 = new htmlResponsiveInputField(_("Profile password"), 'addpassword'); @@ -248,7 +258,7 @@ $templates = [ $addTemplateSelect = new htmlResponsiveSelect('addTemplate', $templates, ['unix.sample'], _('Template'), '267'); $addTemplateSelect->setContainsOptgroups(true); $addTemplateSelect->setHasDescriptiveElements(true); -$box->add($addTemplateSelect, 12); +$box->add($addTemplateSelect); $box->addVerticalSpacer('0.5rem'); $newProfileButton = new htmlButton('btnAddProfile', _('Add')); $newProfileButton->setCSSClasses(['lam-primary']); @@ -260,7 +270,7 @@ $box->add(new htmlOutputText(''), 0, 6); // rename profile $box->add(new htmlSubTitle(_("Rename profile"))); -$box->add(new htmlResponsiveSelect('oldfilename', $files, [], _('Profile name'), '231'), 12); +$box->add(new htmlResponsiveSelect('oldfilename', $files, [], _('Profile name'), '231')); $oldProfileInput = new htmlResponsiveInputField(_('New profile name'), 'renfilename'); $box->add($oldProfileInput); $box->addVerticalSpacer('0.5rem'); @@ -273,8 +283,8 @@ $box->addLabel($renameProfileButton); $box->add(new htmlOutputText(''), 0, 6); // delete profile -$box->add(new htmlSubTitle(_("Delete profile")), 12); -$box->add(new htmlResponsiveSelect('delfilename', $files, [], _('Profile name'), '232'), 12); +$box->add(new htmlSubTitle(_("Delete profile"))); +$box->add(new htmlResponsiveSelect('delfilename', $files, [], _('Profile name'), '232')); $box->addVerticalSpacer('0.5rem'); $deleteProfileButton = new htmlButton('btnDeleteProfile', _('Delete')); $deleteProfileButton->setCSSClasses(['lam-danger']); @@ -285,8 +295,8 @@ $box->addLabel($deleteProfileButton); $box->add(new htmlOutputText(''), 0, 6); // set password -$box->add(new htmlSubTitle(_("Set profile password")), 12); -$box->add(new htmlResponsiveSelect('setprofile', $files, [], _('Profile name'), '233'), 12); +$box->add(new htmlSubTitle(_("Set profile password"))); +$box->add(new htmlResponsiveSelect('setprofile', $files, [], _('Profile name'), '233')); $profileSetPwd1 = new htmlResponsiveInputField(_("Profile password"), 'setpassword'); $profileSetPwd1->setIsPassword(true); $box->add($profileSetPwd1); @@ -300,7 +310,7 @@ $setPasswordProfileButton->setCSSClasses(['lam-secondary']); $setPasswordProfileButton->setOnClick("document.getElementById('action').value = 'setpass';" . "window.lam.dialog.requestPasswordAndSendForm('" . _("Set profile password") . "', '" . _('Ok') . "', '" . _('Cancel') . "', '" . _('Master password') . "', 'passwd', 'profileForm');"); -$box->addLabel($setPasswordProfileButton, 12); +$box->addLabel($setPasswordProfileButton); $box->add(new htmlOutputText(''), 0, 6); @@ -308,7 +318,7 @@ $box->add(new htmlOutputText(''), 0, 6); $conf = new LAMCfgMain(); $defaultProfile = $conf->default; $box->add(new htmlSubTitle(_("Change default profile"))); -$box->add(new htmlResponsiveSelect('defaultfilename', $files, [$defaultProfile], _('Profile name'), '234'), 12); +$box->add(new htmlResponsiveSelect('defaultfilename', $files, [$defaultProfile], _('Profile name'), '234')); $box->addVerticalSpacer('0.5rem'); $defaultProfileButton = new htmlButton('btnDefaultProfile', _('Ok')); $defaultProfileButton->setCSSClasses(['lam-secondary']); diff --git a/lam/templates/delete.php b/lam/templates/delete.php index c1bbc58dc..d4336ea7b 100644 --- a/lam/templates/delete.php +++ b/lam/templates/delete.php @@ -1,18 +1,23 @@ $value) { } } -$typeManager = new \LAM\TYPES\TypeManager(); +$typeManager = new TypeManager(); if (isset($_POST['type']) && ($typeManager->getConfiguredType($_POST['type']) === null)) { logNewMessage(LOG_ERR, 'Invalid type: ' . $_POST['type']); @@ -109,42 +114,45 @@ if (isset($_GET['type']) && isset($_SESSION['delete_dn'])) { $users[] = substr($dn, $start, $end-$start); } - $sessionKey = $sessionAccountPrefix . (new \DateTime('now', getTimeZone()))->getTimestamp() . generateRandomText(); + $sessionKey = $sessionAccountPrefix . (new DateTime('now', getTimeZone()))->getTimestamp() . generateRandomText(); //load account - $_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey); + $_SESSION[$sessionKey] = new accountContainer($type, $sessionKey); // Show HTML Page - include '../lib/adminHeader.inc'; + include __DIR__ . '/../lib/adminHeader.inc'; echo "
    "; echo "
    \n"; echo "\n"; $container = new htmlResponsiveRow(); - $container->add(new htmlOutputText(_("Do you really want to remove the following accounts?")), 12); + $container->add(new htmlOutputText(_("Do you really want to remove the following accounts?"))); $container->addVerticalSpacer('2rem'); - $userCount = sizeof($users); + $userCount = count($users); for ($i = 0; $i < $userCount; $i++) { $container->addLabel(new htmlOutputText(_("Account name:"))); $container->addField(new htmlOutputText($users[$i])); $container->addLabel(new htmlOutputText(_('DN') . ':')); - $container->addField(new htmlOutputText($_SESSION['delete_dn'][$i])); + $container->addField(new htmlOutputText((string) $_SESSION['delete_dn'][$i])); $_SESSION[$sessionKey]->load_account($_SESSION['delete_dn'][$i]); if (!$_SESSION[$sessionKey]->hasOnlyVirtualChildren()) { $childCount = getChildCount($_SESSION['delete_dn'][$i]); if ($childCount > 0) { $container->addLabel(new htmlOutputText(_('Number of child entries') . ':')); - $container->addField(new htmlOutputText($childCount)); + $container->addField(new htmlOutputText((string) $childCount)); } } $container->addVerticalSpacer('0.5rem'); } addSecurityTokenToMetaHTML($container); - $container->add(new htmlHiddenInput('type', $type->getId()), 12); + $container->add(new htmlHiddenInput('type', $type->getId())); $container->addVerticalSpacer('1rem'); parseHtml(null, $container, [], false, $type->getScope()); // Print delete rows from modules $modules = $_SESSION['config']->get_AccountModules($type->getId()); $values = []; foreach ($modules as $module) { - $module = \moduleCache::getModule($module, $type->getScope()); + $module = moduleCache::getModule($module, $type->getScope()); + if ($module === null) { + continue; + } parseHtml($module::class, $module->display_html_delete(), $values, true, $type->getScope()); } $buttonContainer = new htmlResponsiveRow(); @@ -156,12 +164,12 @@ if (isset($_GET['type']) && isset($_SESSION['delete_dn'])) { $buttonGroup->addElement(new htmlSpacer('0.5rem', null)); $cancelButton = new htmlButton('cancel', _('Cancel')); $buttonGroup->addElement($cancelButton); - $buttonContainer->add($buttonGroup, 12); + $buttonContainer->add($buttonGroup); $buttonContainer->addVerticalSpacer('1rem'); parseHtml(null, $buttonContainer, [], false, $type->getScope()); echo "\n"; echo "
    \n"; - include '../lib/adminFooter.inc'; + include __DIR__ . '/../lib/adminFooter.inc'; } if (isset($_POST['cancel'])) { @@ -180,8 +188,8 @@ elseif (isset($_POST['cancelAllOk'])) { if (isset($_POST['delete'])) { $typeId = $_POST['type']; $type = $typeManager->getConfiguredType($typeId); - if (!checkIfDeleteEntriesIsAllowed($type->getId()) || !checkIfWriteAccessIsAllowed($type->getId())) { - logNewMessage(LOG_ERR, 'User tried to delete entries of forbidden type '. $type->getId()); + if (($type === null) || !checkIfDeleteEntriesIsAllowed($type->getId()) || !checkIfWriteAccessIsAllowed($type->getId())) { + logNewMessage(LOG_ERR, 'User tried to delete entries of forbidden type '. $typeId); die(); } // Show HTML Page @@ -190,15 +198,15 @@ if (isset($_POST['delete'])) { echo "

    \n"; $container = new htmlResponsiveRow(); addSecurityTokenToMetaHTML($container); - $container->add(new htmlHiddenInput('type', $type->getId()), 12); + $container->add(new htmlHiddenInput('type', $type->getId())); - $sessionKey = $sessionAccountPrefix . (new \DateTime('now', getTimeZone()))->getTimestamp() . generateRandomText(); - $_SESSION[$sessionKey] = new \accountContainer($type, $sessionKey); + $sessionKey = $sessionAccountPrefix . (new DateTime('now', getTimeZone()))->getTimestamp() . generateRandomText(); + $_SESSION[$sessionKey] = new accountContainer($type, $sessionKey); // Delete dns $allOk = true; $allErrors = []; foreach ($_SESSION['delete_dn'] as $deleteDN) { - // Set to true if an real error has happened + // Set to true if a real error has happened $stopProcessing = false; // First load DN. $_SESSION[$sessionKey]->load_account($deleteDN); @@ -313,22 +321,19 @@ if (isset($_POST['delete'])) { } } if (!$stopProcessing) { - $container->add(new htmlOutputText(sprintf(_('Deleted DN: %s'), $deleteDN)), 12); - foreach ($errors as $error) { - $container->add(htmlStatusMessage::fromParamArray($error), 12); - } + $container->add(new htmlOutputText(sprintf(_('Deleted DN: %s'), $deleteDN))); } else { - $container->add(new htmlOutputText(sprintf(_('Error while deleting DN: %s'), $deleteDN)), 12); - foreach ($errors as $error) { - $container->add(htmlStatusMessage::fromParamArray($error), 12); - } + $container->add(new htmlOutputText(sprintf(_('Error while deleting DN: %s'), $deleteDN))); + } + foreach ($errors as $error) { + $container->add(htmlStatusMessage::fromParamArray($error)); } $allErrors = [...$allErrors, ...$errors]; } $container->addVerticalSpacer('2rem'); $buttonName = $allOk ? 'cancelAllOk' : 'cancel'; - $container->add(new htmlButton($buttonName, _('Back to list')), 12); + $container->add(new htmlButton($buttonName, _('Back to list'))); $container->addVerticalSpacer('1rem'); if ($allOk) { $_SESSION['listRedirectMessages'] = $allErrors; @@ -349,5 +354,5 @@ if (isset($_POST['delete'])) { */ function getChildCount($dn) { $entries = searchLDAP($dn, '(objectClass=*)', ['dn']); - return (sizeof($entries) - 1); + return (count($entries) - 1); } diff --git a/lam/templates/help.php b/lam/templates/help.php index a76349b1a..0f58a696f 100644 --- a/lam/templates/help.php +++ b/lam/templates/help.php @@ -1,4 +1,5 @@ - - + + - - + +
    ' . _('Technical name') . ': ' . $helpEntry['attr'] . ''; } echo $format; - if(isset($helpEntry['SeeAlso']) && is_array($helpEntry['SeeAlso'])) { + if (isset($helpEntry['SeeAlso']) && is_array($helpEntry['SeeAlso'])) { echo '

    ' . _('See also') . ': ' . $helpEntry['SeeAlso']['text'] . '

    '; } echoHTMLFoot(); @@ -116,24 +117,19 @@ if (!isset($_GET['HelpNumber'])) { $helpEntry = []; // module help -if (isset($_GET['module']) && !($_GET['module'] == 'main') && !($_GET['module'] == '')) { +if (isset($_GET['module']) && ($_GET['module'] != 'main') && ($_GET['module'] != '')) { include_once(__DIR__ . "/../lib/modules.inc"); $moduleName = $_GET['module']; if (!ScopeAndModuleValidation::isValidModuleName($moduleName)) { - logNewMessage(LOG_ERR, 'Invalid module name: ' . $moduleName); - die(); - } - if (!empty($_GET['scope'])) { - $scope = $_GET['scope']; + logNewMessage(LOG_ERR, 'Invalid module name: ' . $moduleName); + die(); } - else { - $scope = 'user'; - } - if (!ScopeAndModuleValidation::isValidScopeName($scope)) { - logNewMessage(LOG_ERR, 'Invalid scope name: ' . $scope); - die(); - } - $helpEntry = getHelp($moduleName, $_GET['HelpNumber'], $scope); + $scope = empty($_GET['scope']) ? 'user' : $_GET['scope']; + if (!ScopeAndModuleValidation::isValidScopeName($scope)) { + logNewMessage(LOG_ERR, 'Invalid scope name: ' . $scope); + die(); + } + $helpEntry = getHelp($moduleName, $_GET['HelpNumber'], $scope); if (!$helpEntry) { $variables = [htmlspecialchars((string) $_GET['HelpNumber']), htmlspecialchars((string) $moduleName)]; $errorMessage = _("Sorry, the help id '%s' is not available for the module '%s'."); @@ -143,20 +139,17 @@ if (isset($_GET['module']) && !($_GET['module'] == 'main') && !($_GET['module'] exit; } } -// help entry in help.inc -else { +elseif (!array_key_exists($_GET['HelpNumber'], $helpArray)) { /* If submitted help number is not in help/help.inc print error message */ - if (!array_key_exists($_GET['HelpNumber'], $helpArray)) { - $variables = [htmlspecialchars((string) $_GET['HelpNumber'])]; - $errorMessage = _("Sorry, the help number %s is not available."); - echoHTMLHead(); - statusMessage("ERROR", "", $errorMessage, $variables); - echoHTMLFoot(); - exit; - } - else { - $helpEntry = $helpArray[$_GET['HelpNumber']]; - } + $variables = [htmlspecialchars((string) $_GET['HelpNumber'])]; + $errorMessage = _("Sorry, the help number %s is not available."); + echoHTMLHead(); + statusMessage("ERROR", "", $errorMessage, $variables); + echoHTMLFoot(); + exit; +} +else { + $helpEntry = $helpArray[$_GET['HelpNumber']]; } displayHelp($helpEntry); diff --git a/lam/templates/initsuff.php b/lam/templates/initsuff.php index 604af9f9c..7cded1848 100644 --- a/lam/templates/initsuff.php +++ b/lam/templates/initsuff.php @@ -75,7 +75,7 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { $name = explode("=", $tmp[0]); array_shift($tmp); $end = implode(",", $tmp); - if ($name[0] != "ou") { // add root entry + if ($name[0] !== "ou") { // add root entry $attr = []; $attr[$name[0]] = $name[1]; $attr['objectClass'] = 'organization'; @@ -97,10 +97,10 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { $dnParts = explode(",", $suff); $subsuffs = []; // make list of subsuffixes - $dnPartsCount = sizeof($dnParts); + $dnPartsCount = count($dnParts); for ($k = 0; $k < $dnPartsCount; $k++) { $part = explode("=", $dnParts[$k]); - if ($part[0] == "ou") { + if ($part[0] === "ou") { $subsuffs[] = implode(",", array_slice($dnParts, $k)); } else { @@ -109,7 +109,7 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { } } // create missing entries - $subsuffCount = sizeof($subsuffs); + $subsuffCount = count($subsuffs); for ($k = $subsuffCount - 1; $k >= 0; $k--) { // check if subsuffix is present $info = @ldap_read($_SESSION['ldap']->server(), $subsuffs[$k], "(objectclass=*)", ['dn'], 0, 0, 0, LDAP_DEREF_NEVER); @@ -120,7 +120,7 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { if (!$res) { $suffarray = explode(",", $subsuffs[$k]); $headarray = explode("=", $suffarray[0]); - if ($headarray[0] == "ou") { // add ou entry + if ($headarray[0] === "ou") { // add ou entry $attr = []; $attr['objectClass'] = 'organizationalunit'; $attr['ou'] = $headarray[1]; @@ -134,7 +134,7 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { $attr = []; $attr['objectClass'][] = 'organization'; $attr[$headarray[0]] = $headarray[1]; - if ($headarray[0] == "dc") { + if ($headarray[0] === "dc") { $attr['o'] = $headarray[1]; $attr['objectClass'][] = 'dcObject'; } @@ -154,26 +154,26 @@ if (isset($_POST['add_suff']) || isset($_POST['cancel'])) { } } } - include '../lib/adminHeader.inc'; + include __DIR__ . '/../lib/adminHeader.inc'; // print error/success messages if (isset($_POST['add_suff'])) { - if (sizeof($failedDNs) > 0) { + if ($failedDNs !== []) { // print error messages foreach ($failedDNs as $suffix => $error) { StatusMessage("ERROR", _("Failed to create entry!") . "
    " . htmlspecialchars($error), htmlspecialchars($suffix)); } - include '../lib/adminFooter.inc'; + include __DIR__ . '/../lib/adminFooter.inc'; } else { // print success message StatusMessage("INFO", "", _("All changes were successful.")); - include '../lib/adminFooter.inc'; + include __DIR__ . '/../lib/adminFooter.inc'; } } else { // no suffixes were created StatusMessage("INFO", "", _("No changes were made.")); - include '../lib/adminFooter.inc'; + include __DIR__ . '/../lib/adminFooter.inc'; } exit; } diff --git a/lam/templates/lib/100_jquery-3.7.1.js b/lam/templates/lib/100_jquery-3.7.1.js deleted file mode 100644 index 1a86433c2..000000000 --- a/lam/templates/lib/100_jquery-3.7.1.js +++ /dev/null @@ -1,10716 +0,0 @@ -/*! - * jQuery JavaScript Library v3.7.1 - * https://jquery.com/ - * - * Copyright OpenJS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2023-08-28T13:37Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket trac-14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 - // Plus for old WebKit, typeof returns "function" for HTML collections - // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) - return typeof obj === "function" && typeof obj.nodeType !== "number" && - typeof obj.item !== "function"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var version = "3.7.1", - - rhtmlSuffix = /HTML$/i, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - - // Retrieve the text value of an array of DOM nodes - text: function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += jQuery.text( node ); - } - } - if ( nodeType === 1 || nodeType === 11 ) { - return elem.textContent; - } - if ( nodeType === 9 ) { - return elem.documentElement.textContent; - } - if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - isXMLDoc: function( elem ) { - var namespace = elem && elem.namespaceURI, - docElem = elem && ( elem.ownerDocument || elem ).documentElement; - - // Assume HTML when documentElement doesn't yet exist, such as inside - // document fragments. - return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), - function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); - } ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -} -var pop = arr.pop; - - -var sort = arr.sort; - - -var splice = arr.splice; - - -var whitespace = "[\\x20\\t\\r\\n\\f]"; - - -var rtrimCSS = new RegExp( - "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", - "g" -); - - - - -// Note: an element does not contain itself -jQuery.contains = function( a, b ) { - var bup = b && b.parentNode; - - return a === bup || !!( bup && bup.nodeType === 1 && ( - - // Support: IE 9 - 11+ - // IE doesn't have `contains` on SVG. - a.contains ? - a.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); -}; - - - - -// CSS string/identifier serialization -// https://drafts.csswg.org/cssom/#common-serializing-idioms -var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; - -function fcssescape( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; -} - -jQuery.escapeSelector = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); -}; - - - - -var preferredDoc = document, - pushNative = push; - -( function() { - -var i, - Expr, - outermostContext, - sortInput, - hasDuplicate, - push = pushNative, - - // Local document vars - document, - documentElement, - documentIsHTML, - rbuggyQSA, - matches, - - // Instance-specific data - expando = jQuery.expando, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + - "loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + - whitespace + "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - ID: new RegExp( "^#(" + identifier + ")" ), - CLASS: new RegExp( "^\\.(" + identifier + ")" ), - TAG: new RegExp( "^(" + identifier + "|[*])" ), - ATTR: new RegExp( "^" + attributes ), - PSEUDO: new RegExp( "^" + pseudos ), - CHILD: new RegExp( - "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - bool: new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - needsContext: new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - if ( nonHex ) { - - // Strip the backslash prefix from a non-hex escape sequence - return nonHex; - } - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - return high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // Used for iframes; see `setDocument`. - // Support: IE 9 - 11+, Edge 12 - 18+ - // Removing the function wrapper causes a "Permission Denied" - // error in IE/Edge. - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && nodeName( elem, "fieldset" ); - }, - { dir: "parentNode", next: "legend" } - ); - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android <=4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { - apply: function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - }, - call: function( target ) { - pushNative.apply( target, slice.call( arguments, 1 ) ); - } - }; -} - -function find( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE 9 only - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - push.call( results, elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE 9 only - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - find.contains( context, elem ) && - elem.id === m ) { - - push.call( results, elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when - // strict-comparing two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( newContext != context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = jQuery.escapeSelector( nid ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties - // (see https://github.com/jquery/sizzle/issues/157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by jQuery selector module - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - return nodeName( elem, "input" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && - elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11+ - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a jQuery selector context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [node] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -function setDocument( node ) { - var subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - documentElement = document.documentElement; - documentIsHTML = !jQuery.isXMLDoc( document ); - - // Support: iOS 7 only, IE 9 - 11+ - // Older browsers didn't support unprefixed `matches`. - matches = documentElement.matches || - documentElement.webkitMatchesSelector || - documentElement.msMatchesSelector; - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors - // (see trac-13936). - // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, - // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. - if ( documentElement.msMatchesSelector && - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 9 - 11+, Edge 12 - 18+ - subWindow.addEventListener( "unload", unloadHandler ); - } - - // Support: IE <10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - documentElement.appendChild( el ).id = jQuery.expando; - return !document.getElementsByName || - !document.getElementsByName( jQuery.expando ).length; - } ); - - // Support: IE 9 only - // Check to see if it's possible to do matchesSelector - // on a disconnected node. - support.disconnectedMatch = assert( function( el ) { - return matches.call( el, "*" ); - } ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // IE/Edge don't support the :scope pseudo-class. - support.scope = assert( function() { - return document.querySelectorAll( ":scope" ); - } ); - - // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only - // Make sure the `:has()` argument is parsed unforgivingly. - // We include `*` in the test to detect buggy implementations that are - // _selectively_ forgiving (specifically when the list includes at least - // one valid selector). - // Note that we treat complete lack of support for `:has()` as if it were - // spec-compliant support, which is fine because use of `:has()` in such - // environments will fail in the qSA path and fall back to jQuery traversal - // anyway. - support.cssHas = assert( function() { - try { - document.querySelector( ":has(*,:jqfake)" ); - return false; - } catch ( e ) { - return true; - } - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter.ID = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find.ID = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter.ID = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find.ID = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find.TAG = function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else { - return context.querySelectorAll( tag ); - } - }; - - // Class - Expr.find.CLASS = function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - rbuggyQSA = []; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - documentElement.appendChild( el ).innerHTML = - "" + - ""; - - // Support: iOS <=7 - 8 only - // Boolean attributes and "value" are not treated correctly in some XML documents - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: iOS <=7 - 8 only - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: iOS 8 only - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE 9 - 11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - documentElement.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - } ); - - if ( !support.cssHas ) { - - // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ - // Our regular `try-catch` mechanism fails to detect natively-unsupported - // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) - // in browsers that parse the `:has()` argument as a forgiving selector list. - // https://drafts.csswg.org/selectors/#relational now requires the argument - // to be parsed unforgivingly, but browsers have not yet fully adjusted. - rbuggyQSA.push( ":has" ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { - - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a === document || a.ownerDocument == preferredDoc && - find.contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( b === document || b.ownerDocument == preferredDoc && - find.contains( preferredDoc, b ) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - }; - - return document; -} - -find.matches = function( expr, elements ) { - return find( expr, null, null, elements ); -}; - -find.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch ( e ) { - nonnativeSelectorCache( expr, true ); - } - } - - return find( expr, document, null, [ elem ] ).length > 0; -}; - -find.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return jQuery.contains( context, elem ); -}; - - -find.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( elem.ownerDocument || elem ) != document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - - // Don't get fooled by Object.prototype properties (see trac-13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - if ( val !== undefined ) { - return val; - } - - return elem.getAttribute( name ); -}; - -find.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -jQuery.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - // - // Support: Android <=4.0+ - // Testing for detecting duplicates is unpredictable so instead assume we can't - // depend on duplicate detection in all browsers without a stable sort. - hasDuplicate = !support.sortStable; - sortInput = !support.sortStable && slice.call( results, 0 ); - sort.call( results, sortOrder ); - - if ( hasDuplicate ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - splice.call( results, duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -jQuery.fn.uniqueSort = function() { - return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); -}; - -Expr = jQuery.expr = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - ATTR: function( match ) { - match[ 1 ] = match[ 1 ].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) - .replace( runescape, funescape ); - - if ( match[ 2 ] === "~=" ) { - match[ 3 ] = " " + match[ 3 ] + " "; - } - - return match.slice( 0, 4 ); - }, - - CHILD: function( match ) { - - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[ 1 ] = match[ 1 ].toLowerCase(); - - if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - - // nth-* requires argument - if ( !match[ 3 ] ) { - find.error( match[ 0 ] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[ 4 ] = +( match[ 4 ] ? - match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) - ); - match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - - // other types prohibit arguments - } else if ( match[ 3 ] ) { - find.error( match[ 0 ] ); - } - - return match; - }, - - PSEUDO: function( match ) { - var excess, - unquoted = !match[ 6 ] && match[ 2 ]; - - if ( matchExpr.CHILD.test( match[ 0 ] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[ 3 ] ) { - match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - - // Get excess from tokenize (recursively) - ( excess = tokenize( unquoted, true ) ) && - - // advance to the next closing parenthesis - ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { - - // excess is a negative index - match[ 0 ] = match[ 0 ].slice( 0, excess ); - match[ 2 ] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - TAG: function( nodeNameSelector ) { - var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { - return true; - } : - function( elem ) { - return nodeName( elem, expectedNodeName ); - }; - }, - - CLASS: function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - ( pattern = new RegExp( "(^|" + whitespace + ")" + className + - "(" + whitespace + "|$)" ) ) && - classCache( className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); - } ); - }, - - ATTR: function( name, operator, check ) { - return function( elem ) { - var result = find.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - if ( operator === "=" ) { - return result === check; - } - if ( operator === "!=" ) { - return result !== check; - } - if ( operator === "^=" ) { - return check && result.indexOf( check ) === 0; - } - if ( operator === "*=" ) { - return check && result.indexOf( check ) > -1; - } - if ( operator === "$=" ) { - return check && result.slice( -check.length ) === check; - } - if ( operator === "~=" ) { - return ( " " + result.replace( rwhitespace, " " ) + " " ) - .indexOf( check ) > -1; - } - if ( operator === "|=" ) { - return result === check || result.slice( 0, check.length + 1 ) === check + "-"; - } - - return false; - }; - }, - - CHILD: function( type, what, _argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, _context, xml ) { - var cache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( ( node = node[ dir ] ) ) { - if ( ofType ? - nodeName( node, name ) : - node.nodeType === 1 ) { - - return false; - } - } - - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || ( parent[ expando ] = {} ); - cache = outerCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( ( node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - - // Use previously-cached element index if available - if ( useCache ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - cache = outerCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - - // Use the same loop as above to seek `elem` from the start - while ( ( node = ++nodeIndex && node && node[ dir ] || - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - if ( ( ofType ? - nodeName( node, name ) : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || - ( node[ expando ] = {} ); - outerCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - PSEUDO: function( pseudo, argument ) { - - // pseudo-class names are case-insensitive - // https://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - find.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as jQuery does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction( function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[ i ] ); - seed[ idx ] = !( matches[ idx ] = matched[ i ] ); - } - } ) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - - // Potentially complex pseudos - not: markFunction( function( selector ) { - - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrimCSS, "$1" ) ); - - return matcher[ expando ] ? - markFunction( function( seed, matches, _context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( ( elem = unmatched[ i ] ) ) { - seed[ i ] = !( matches[ i ] = elem ); - } - } - } ) : - function( elem, _context, xml ) { - input[ 0 ] = elem; - matcher( input, null, xml, results ); - - // Don't keep the element - // (see https://github.com/jquery/sizzle/issues/299) - input[ 0 ] = null; - return !results.pop(); - }; - } ), - - has: markFunction( function( selector ) { - return function( elem ) { - return find( selector, elem ).length > 0; - }; - } ), - - contains: markFunction( function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; - }; - } ), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // https://www.w3.org/TR/selectors/#lang-pseudo - lang: markFunction( function( lang ) { - - // lang value must be a valid identifier - if ( !ridentifier.test( lang || "" ) ) { - find.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( ( elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); - return false; - }; - } ), - - // Miscellaneous - target: function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - root: function( elem ) { - return elem === documentElement; - }, - - focus: function( elem ) { - return elem === safeActiveElement() && - document.hasFocus() && - !!( elem.type || elem.href || ~elem.tabIndex ); - }, - - // Boolean properties - enabled: createDisabledPseudo( false ), - disabled: createDisabledPseudo( true ), - - checked: function( elem ) { - - // In CSS3, :checked should return both checked and selected elements - // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - return ( nodeName( elem, "input" ) && !!elem.checked ) || - ( nodeName( elem, "option" ) && !!elem.selected ); - }, - - selected: function( elem ) { - - // Support: IE <=11+ - // Accessing the selectedIndex property - // forces the browser to treat the default option as - // selected when in an optgroup. - if ( elem.parentNode ) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - empty: function( elem ) { - - // https://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - parent: function( elem ) { - return !Expr.pseudos.empty( elem ); - }, - - // Element/input types - header: function( elem ) { - return rheader.test( elem.nodeName ); - }, - - input: function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - button: function( elem ) { - return nodeName( elem, "input" ) && elem.type === "button" || - nodeName( elem, "button" ); - }, - - text: function( elem ) { - var attr; - return nodeName( elem, "input" ) && elem.type === "text" && - - // Support: IE <10 only - // New HTML5 attribute values (e.g., "search") appear - // with elem.type === "text" - ( ( attr = elem.getAttribute( "type" ) ) == null || - attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - first: createPositionalPseudo( function() { - return [ 0 ]; - } ), - - last: createPositionalPseudo( function( _matchIndexes, length ) { - return [ length - 1 ]; - } ), - - eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - } ), - - even: createPositionalPseudo( function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - odd: createPositionalPseudo( function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - lt: createPositionalPseudo( function( matchIndexes, length, argument ) { - var i; - - if ( argument < 0 ) { - i = argument + length; - } else if ( argument > length ) { - i = length; - } else { - i = argument; - } - - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - gt: createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ) - } -}; - -Expr.pseudos.nth = Expr.pseudos.eq; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || ( match = rcomma.exec( soFar ) ) ) { - if ( match ) { - - // Don't consume trailing commas as valid - soFar = soFar.slice( match[ 0 ].length ) || soFar; - } - groups.push( ( tokens = [] ) ); - } - - matched = false; - - // Combinators - if ( ( match = rleadingCombinator.exec( soFar ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - - // Cast descendant combinators to space - type: match[ 0 ].replace( rtrimCSS, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || - ( match = preFilters[ type ]( match ) ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - if ( parseOnly ) { - return soFar.length; - } - - return soFar ? - find.error( selector ) : - - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[ i ].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - - if ( skip && nodeName( elem, skip ) ) { - elem = elem[ dir ] || elem; - } else if ( ( oldCache = outerCache[ key ] ) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return ( newCache[ 2 ] = oldCache[ 2 ] ); - } else { - - // Reuse newcache so results back-propagate to previous elements - outerCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[ i ]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[ 0 ]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - find( selector, contexts[ i ], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( ( elem = unmatched[ i ] ) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, matcherOut, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || - multipleContexts( selector || "*", - context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems; - - if ( matcher ) { - - // If we have a postFinder, or filtered seed, or non-seed postFilter - // or preexisting results, - matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results; - - // Find primary matches - matcher( matcherIn, matcherOut, context, xml ); - } else { - matcherOut = matcherIn; - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( ( elem = temp[ i ] ) ) { - matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) ) { - - // Restore matcherIn since elem is not yet a final match - temp.push( ( matcherIn[ i ] = elem ) ); - } - } - postFinder( null, ( matcherOut = [] ), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { - - seed[ temp ] = !( results[ temp ] = elem ); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - } ); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[ 0 ].type ], - implicitRelative = leadingRelative || Expr.relative[ " " ], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( - ( checkContext = context ).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - - // Avoid hanging onto element - // (see https://github.com/jquery/sizzle/issues/299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { - matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; - } else { - matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[ j ].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrimCSS, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find.TAG( "*", outermost ), - - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), - len = elems.length; - - if ( outermost ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: iOS <=7 - 9 only - // Tolerate NodeList properties (IE: "length"; Safari: ) matching - // elements by id. (see trac-14142) - for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( !context && elem.ownerDocument != document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( ( matcher = elementMatchers[ j++ ] ) ) { - if ( matcher( elem, context || document, xml ) ) { - push.call( results, elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - - // They will have gone through all possible matchers - if ( ( elem = !matcher && elem ) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( ( matcher = setMatchers[ j++ ] ) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !( unmatched[ i ] || setMatched[ i ] ) ) { - setMatched[ i ] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - jQuery.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -function compile( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[ i ] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -} - -/** - * A low-level selection function that works with jQuery's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with jQuery selector compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( ( selector = compiled.selector || selector ) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[ 0 ] = match[ 0 ].slice( 0 ); - if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - - context = ( Expr.find.ID( - token.matches[ 0 ].replace( runescape, funescape ), - context - ) || [] )[ 0 ]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[ i ]; - - // Abort if we hit a combinator - if ( Expr.relative[ ( type = token.type ) ] ) { - break; - } - if ( ( find = Expr.find[ type ] ) ) { - - // Search, expanding context for leading sibling combinators - if ( ( seed = find( - token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && - testContext( context.parentNode ) || context - ) ) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -} - -// One-time assignments - -// Support: Android <=4.0 - 4.1+ -// Sort stability -support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; - -// Initialize against the default document -setDocument(); - -// Support: Android <=4.0 - 4.1+ -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert( function( el ) { - - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; -} ); - -jQuery.find = find; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.unique = jQuery.uniqueSort; - -// These have always been private, but they used to be documented as part of -// Sizzle so let's maintain them for now for backwards compatibility purposes. -find.compile = compile; -find.select = select; -find.setDocument = setDocument; -find.tokenize = tokenize; - -find.escape = jQuery.escapeSelector; -find.getText = jQuery.text; -find.isXML = jQuery.isXMLDoc; -find.selectors = jQuery.expr; -find.support = jQuery.support; -find.uniqueSort = jQuery.uniqueSort; - - /* eslint-enable */ - -} )(); - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (trac-9521) - // Strict HTML recognition (trac-11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to jQuery#find - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, _i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, _i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, _i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( _i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.error ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the error, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getErrorHook ) { - process.error = jQuery.Deferred.getErrorHook(); - - // The deprecated alias of the above. While the name suggests - // returning the stack, not an error instance, jQuery just passes - // it directly to `console.warn` so both will work; an instance - // just better cooperates with source maps. - } else if ( jQuery.Deferred.getStackHook ) { - process.error = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the primary Deferred - primary = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - primary.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( primary.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return primary.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); - } - - return primary.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error -// captured before the async barrier to get the original error cause -// which may otherwise be hidden. -jQuery.Deferred.exceptionHook = function( error, asyncError ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, - error.stack, asyncError ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See trac-6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, _key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (trac-9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see trac-8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (trac-14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (trac-11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (trac-14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (trac-13200) -var wrapMap = { - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
    " ], - col: [ 2, "", "
    " ], - tr: [ 2, "", "
    " ], - td: [ 3, "", "
    " ], - - _default: [ 0, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (trac-12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = Object.create( null ); - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (trac-13208) - // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (trac-13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", true ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, isSetup ) { - - // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add - if ( !isSetup ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - if ( !saved ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - this[ type ](); - result = dataPriv.get( this, type ); - dataPriv.set( this, type, false ); - - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - - return result; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering - // the native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved ) { - - // ...and capture the result - dataPriv.set( this, type, jQuery.event.trigger( - saved[ 0 ], - saved.slice( 1 ), - this - ) ); - - // Abort handling of the native event by all jQuery handlers while allowing - // native handlers on the same element to run. On target, this is achieved - // by stopping immediate propagation just on the jQuery event. However, - // the native event is re-wrapped by a jQuery one on each level of the - // propagation so the only way to stop it for jQuery is to stop it for - // everyone via native `stopPropagation()`. This is not a problem for - // focus/blur which don't bubble, but it does also stop click on checkboxes - // and radios. We accept this limitation. - event.stopPropagation(); - event.isImmediatePropagationStopped = returnTrue; - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (trac-504, trac-13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - which: true -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - - function focusMappedHandler( nativeEvent ) { - if ( document.documentMode ) { - - // Support: IE 11+ - // Attach a single focusin/focusout handler on the document while someone wants - // focus/blur. This is because the former are synchronous in IE while the latter - // are async. In other browsers, all those handlers are invoked synchronously. - - // `handle` from private data would already wrap the event, but we need - // to change the `type` here. - var handle = dataPriv.get( this, "handle" ), - event = jQuery.event.fix( nativeEvent ); - event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; - event.isSimulated = true; - - // First, handle focusin/focusout - handle( nativeEvent ); - - // ...then, handle focus/blur - // - // focus/blur don't bubble while focusin/focusout do; simulate the former by only - // invoking the handler at the lower level. - if ( event.target === event.currentTarget ) { - - // The setup part calls `leverageNative`, which, in turn, calls - // `jQuery.event.add`, so event handle will already have been set - // by this point. - handle( event ); - } - } else { - - // For non-IE browsers, attach a single capturing handler on the document - // while someone wants focusin/focusout. - jQuery.event.simulate( delegateType, nativeEvent.target, - jQuery.event.fix( nativeEvent ) ); - } - } - - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - var attaches; - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, true ); - - if ( document.documentMode ) { - - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - attaches = dataPriv.get( this, delegateType ); - if ( !attaches ) { - this.addEventListener( delegateType, focusMappedHandler ); - } - dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); - } else { - - // Return false to allow normal processing in the caller - return false; - } - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - teardown: function() { - var attaches; - - if ( document.documentMode ) { - attaches = dataPriv.get( this, delegateType ) - 1; - if ( !attaches ) { - this.removeEventListener( delegateType, focusMappedHandler ); - dataPriv.remove( this, delegateType ); - } else { - dataPriv.set( this, delegateType, attaches ); - } - } else { - - // Return false to indicate standard teardown should be applied - return false; - } - }, - - // Suppress native focus or blur if we're currently inside - // a leveraged native-event stack - _default: function( event ) { - return dataPriv.get( event.target, type ); - }, - - delegateType: delegateType - }; - - // Support: Firefox <=44 - // Firefox doesn't have focus(in | out) events - // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 - // - // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 - // focus(in | out) events fire after focus & blur events, - // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order - // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 - // - // Support: IE 9 - 11+ - // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, - // attach a single handler for both events in IE. - jQuery.event.special[ delegateType ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get( dataHolder, delegateType ); - - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - if ( !attaches ) { - if ( document.documentMode ) { - this.addEventListener( delegateType, focusMappedHandler ); - } else { - doc.addEventListener( type, focusMappedHandler, true ); - } - } - dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get( dataHolder, delegateType ) - 1; - - if ( !attaches ) { - if ( document.documentMode ) { - this.removeEventListener( delegateType, focusMappedHandler ); - } else { - doc.removeEventListener( type, focusMappedHandler, true ); - } - dataPriv.remove( dataHolder, delegateType ); - } else { - dataPriv.set( dataHolder, delegateType, attaches ); - } - } - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle events" ); - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (trac-8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Re-enable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - - // Unwrap a CDATA section containing script contents. This shouldn't be - // needed as in XML documents they're already not visible when - // inspecting element contents and in HTML documents they have no - // meaning but we're preserving that logic for backwards compatibility. - // This will be removed completely in 4.0. See gh-4904. - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew jQuery#find here for performance reasons: - // https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var rcustomProp = /^--/; - - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var swap = function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (trac-8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - // - // Support: Firefox 70+ - // Only Firefox includes border widths - // in computed dimensions. (gh-4529) - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "box-sizing:content-box;border:1px solid"; - - // Support: Chrome 86+ - // Height set through cssText does not get applied. - // Computed height then comes back as 0. - tr.style.height = "1px"; - trChild.style.height = "9px"; - - // Support: Android 8 Chrome 86+ - // In our bodyBackground.html iframe, - // display for all div elements is set to "inline", - // which causes a problem only in Android 8 Chrome 86. - // Ensuring the div is `display: block` - // gets around this issue. - trChild.style.display = "block"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + - parseInt( trStyle.borderTopWidth, 10 ) + - parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - isCustomProp = rcustomProp.test( name ), - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, trac-12537) - // .css('--customProperty) (gh-3144) - if ( computed ) { - - // Support: IE <=9 - 11+ - // IE only supports `"float"` in `getPropertyValue`; in computed styles - // it's only available as `"cssFloat"`. We no longer modify properties - // sent to `.css()` apart from camelCasing, so we need to check both. - // Normally, this would create difference in behavior: if - // `getPropertyValue` returns an empty string, the value returned - // by `.css()` would be `undefined`. This is usually the case for - // disconnected elements. However, in IE even disconnected elements - // with no styles return `"none"` for `getPropertyValue( "float" )` - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( isCustomProp && ret ) { - - // Support: Firefox 105+, Chrome <=105+ - // Spec requires trimming whitespace for custom properties (gh-4926). - // Firefox only trims leading whitespace. Chrome just collapses - // both leading & trailing whitespace to a single space. - // - // Fall back to `undefined` if empty string returned. - // This collapses a missing definition with property defined - // and set to an empty string but there's no standard API - // allowing us to differentiate them without a performance penalty - // and returning `undefined` aligns with older jQuery. - // - // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED - // as whitespace while CSS does not, but this is not a problem - // because CSS preprocessing replaces them with U+000A LINE FEED - // (which *is* CSS whitespace) - // https://www.w3.org/TR/css-syntax-3/#input-preprocessing - ret = ret.replace( rtrimCSS, "$1" ) || undefined; - } - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( _elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0, - marginDelta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - // Count margin delta separately to only add it after scroll gutter adjustment. - // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). - if ( box === "margin" ) { - marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta + marginDelta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - animationIterationCount: true, - aspectRatio: true, - borderImageSlice: true, - columnCount: true, - flexGrow: true, - flexShrink: true, - fontWeight: true, - gridArea: true, - gridColumn: true, - gridColumnEnd: true, - gridColumnStart: true, - gridRow: true, - gridRowEnd: true, - gridRowStart: true, - lineHeight: true, - opacity: true, - order: true, - orphans: true, - scale: true, - widows: true, - zIndex: true, - zoom: true, - - // SVG-related - fillOpacity: true, - floodOpacity: true, - stopOpacity: true, - strokeMiterlimit: true, - strokeOpacity: true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (trac-7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug trac-9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (trac-7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( _i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // Use proper attribute retrieval (trac-12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classNames, cur, curValue, className, i, finalValue; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classNames = classesToArray( value ); - - if ( classNames.length ) { - return this.each( function() { - curValue = getClass( this ); - cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - if ( cur.indexOf( " " + className + " " ) < 0 ) { - cur += className + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - this.setAttribute( "class", finalValue ); - } - } - } ); - } - - return this; - }, - - removeClass: function( value ) { - var classNames, cur, curValue, className, i, finalValue; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classNames = classesToArray( value ); - - if ( classNames.length ) { - return this.each( function() { - curValue = getClass( this ); - - // This expression is here for better compressibility (see addClass) - cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - - // Remove *all* instances - while ( cur.indexOf( " " + className + " " ) > -1 ) { - cur = cur.replace( " " + className + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - this.setAttribute( "class", finalValue ); - } - } - } ); - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var classNames, className, i, self, - type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - classNames = classesToArray( value ); - - return this.each( function() { - if ( isValidValue ) { - - // Toggle individual class names - self = jQuery( this ); - - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (trac-14686, trac-14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (trac-2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml, parserErrorElem; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) {} - - parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; - if ( !xml || parserErrorElem ) { - jQuery.error( "Invalid XML: " + ( - parserErrorElem ? - jQuery.map( parserErrorElem.childNodes, function( el ) { - return el.textContent; - } ).join( "\n" ) : - data - ) ); - } - return xml; -}; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (trac-9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (trac-6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ).filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ).map( function( _i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // trac-7653, trac-8125, trac-8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - -originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes trac-9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (trac-10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket trac-12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // trac-9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + - uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Use a noop converter for missing script but not if jsonp - if ( !isSuccess && - jQuery.inArray( "script", s.dataTypes ) > -1 && - jQuery.inArray( "json", s.dataTypes ) < 0 ) { - s.converters[ "text script" ] = function() {}; - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( _i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - -jQuery.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (trac-11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // trac-1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see trac-8605, trac-14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // trac-14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( "'; +echo ''; +echo ''; +echo ''; echo '
    '; $roots = TreeViewTool::getRootDns(); @@ -72,12 +74,12 @@ function showTree(): void { $initialDn = base64_decode($_GET['dn']); $roots = TreeViewTool::getRootDns(); foreach ($roots as $rootDn) { - if ((strlen($initialDn) > strlen($rootDn)) && substr($initialDn, -1 * strlen($rootDn)) === $rootDn) { + if ((strlen($initialDn) > strlen($rootDn)) && str_ends_with($initialDn, $rootDn)) { $extraDnPart = substr($initialDn, 0, (-1 * strlen($rootDn)) - 1); $dnParts = ldap_explode_dn($extraDnPart, 0); if ($dnParts !== false) { unset($dnParts['count']); - $dnPartsCount = sizeof($dnParts); + $dnPartsCount = count($dnParts); for ($i = 0; $i < $dnPartsCount; $i++) { $currentParts = array_slice($dnParts, $dnPartsCount - ($i + 1)); $openInitial[] = '"' . base64_encode(implode(',', $currentParts) . ',' . $rootDn) . '"'; @@ -89,57 +91,77 @@ function showTree(): void { $openInitialJsArray = '[' . implode(', ', $openInitial) . ']'; $row = new htmlResponsiveRow(); $row->setCSSClasses(['maxrow']); - $row->add(new htmlDiv('ldap_tree', new htmlOutputText(''), ['tree-view--tree']), 12, 5, 5, 'tree-left-area'); - $row->add(new htmlDiv('ldap_actionarea', new htmlOutputText(''), ['tree-view--actionarea']), 12, 7, 7, 'tree-right-area'); + $row->add(new htmlDiv('ldap_tree', new htmlOutputText(''), ['tree-view--tree']), 12, 4, 4, 'tree-left-area'); + $row->add(new htmlDiv('ldap_actionarea', new htmlOutputText(''), ['tree-view--actionarea']), 12, 8, 8, 'tree-right-area'); $treeScript = new htmlJavaScript(' window.lam.utility.documentReady(function() { + window.sessionStorage.removeItem("LAM_COPY_PASTE_ACTION"); + window.sessionStorage.removeItem("LAM_COPY_PASTE_DN"); var maxHeight = document.documentElement.scrollHeight - (document.querySelector("#ldap_tree").getBoundingClientRect().top - window.scrollY) - 50; document.getElementById("ldap_tree").style.maxHeight = maxHeight; document.getElementById("ldap_actionarea").style.maxHeight = maxHeight; - jQuery(\'#ldap_tree\').jstree({ - "plugins": [ - "changed" - ], - "core": { - "worker": false, - "strings": { - "Loading ...": "' . _('Loading') . '" - }, - "data": function(node, callback) { - window.lam.treeview.getNodes("' . getSecurityTokenName() . '", "' . getSecurityTokenValue() . '", node, callback); + const tree = new mar10.Wunderbaum({ + element: document.getElementById("ldap_tree"), + id: "ldap_tree", + strings: { + loading: "' . addslashes(_('Loading')) . '", + loadError: "' . addslashes(_('Error')) . '", + noData: "' . addslashes(_('No objects found!')) . '" + }, + debugLevel: 2, + source: "../misc/ajax.php?function=treeview&command=getRootNodes", + init: (e) => { + tree.expandAll(true, {depth: 1, }); + window.lam.treeview.openInitial(tree, ' . $openInitialJsArray . '); + }, + lazyLoad: function(e) { + return {url: "../misc/ajax.php?function=treeview&command=getNodes&dn=" + e.node.key}; + }, + iconBadge: (e) => { + if (e.node.data.badge) { + const badgeSpan = document.createElement("span"); + badgeSpan.className = "tree-badge"; + const badgeImg = document.createElement("img"); + badgeImg.src = e.node.data.badge; + badgeSpan.appendChild(badgeImg); + return badgeSpan; } + }, + activate: function(e) { + const node = e.node; + window.lam.treeview.getNodeContent("' . getSecurityTokenName() . '", "' . getSecurityTokenValue() . '", node.key); } - }) - .on("changed.jstree", function (e, data) { - if (data && data.action && (data.action == "select_node")) { - var node = data.node; - window.lam.treeview.getNodeContent("' . getSecurityTokenName() . '", "' . getSecurityTokenValue() . '", node.id); - } - }) - .on("ready.jstree", function (e, data) { - var tree = jQuery.jstree.reference("#ldap_tree"); - window.lam.treeview.openInitial(tree, ' . $openInitialJsArray . '); - }); + }); }); '); - $row->add($treeScript, 12); + $row->add($treeScript); $deleteDialogContent = new htmlResponsiveRow(); - $deleteDialogContent->add(new htmlOutputText(_('Do you really want to delete this entry?')), 12); + $deleteDialogContent->add(new htmlOutputText(_('Do you really want to delete this entry?'))); $deleteDialogContent->addVerticalSpacer('0.5rem'); $deleteDialogEntryText = new htmlOutputText(''); $deleteDialogEntryText->setCSSClasses(['treeview-delete-entry']); - $deleteDialogContent->add($deleteDialogEntryText, 12); + $deleteDialogContent->add($deleteDialogEntryText); $deleteDialogDiv = new htmlDiv('treeview_delete_dlg', $deleteDialogContent, ['hidden']); $row->add($deleteDialogDiv); + $restoreDialogContent = new htmlResponsiveRow(); + $restoreDialogContent->add(new htmlOutputText(_('Do you really want to restore this entry?'))); + $restoreDialogContent->addVerticalSpacer('0.5rem'); + $restoreDialogEntryText = new htmlOutputText(''); + $restoreDialogEntryText->setCSSClasses(['treeview-restore-entry']); + $restoreDialogContent->add($restoreDialogEntryText); + $restoreDialogDiv = new htmlDiv('treeview_restore_dlg', $restoreDialogContent, ['hidden']); + $row->add($restoreDialogDiv); + $errorDialogContent = new htmlResponsiveRow(); $errorDialogEntryTitle = new htmlOutputText(''); $errorDialogEntryTitle->setCSSClasses(['treeview-error-title']); - $errorDialogContent->add($errorDialogEntryTitle, 12); + $errorDialogContent->add($errorDialogEntryTitle); + $errorDialogContent->addVerticalSpacer('0.5rem'); $errorDialogEntryText = new htmlOutputText(''); $errorDialogEntryText->setCSSClasses(['treeview-error-text']); - $errorDialogContent->add($errorDialogEntryText, 12); + $errorDialogContent->add($errorDialogEntryText); $errorDialogDiv = new htmlDiv('treeview_error_dlg', $errorDialogContent, ['hidden']); $row->add($errorDialogDiv); diff --git a/lam/templates/tools/webauthn.php b/lam/templates/tools/webauthn.php index bcf958e6c..9dbdc1808 100644 --- a/lam/templates/tools/webauthn.php +++ b/lam/templates/tools/webauthn.php @@ -17,7 +17,7 @@ use Webauthn\PublicKeyCredentialCreationOptions; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2020 - 2023 Roland Gruber + Copyright (C) 2020 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -120,7 +120,7 @@ else { $saveButton->addDataAttribute('dn', $result['dn']); $saveButton->addDataAttribute('nameelement', 'deviceName_' . $id); $saveButton->setOnClick('window.lam.webauthn.updateOwnDeviceName(event);'); - $nameField = new htmlInputField('deviceName_' . $id, $result['name']); + $nameField = new htmlInputField('deviceName_' . $id, (string) $result['name']); $nameFieldClasses = ['maxwidth20']; if (!empty($_GET['updated']) && ($_GET['updated'] === $credentialId)) { $nameFieldClasses[] = 'markPass'; @@ -164,7 +164,7 @@ function addNewDevice(htmlResponsiveRow $container, WebauthnManager $webauthnMan return; } $registrationData = base64_decode($_POST['registrationData']); - $registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']); + $registrationObject = PublicKeyCredentialCreationOptions::createFromString((string) $_SESSION['webauthn_registration']); $success = $webauthnManager->storeNewRegistration($registrationObject, $registrationData); if ($success) { $container->add(new htmlStatusMessage('INFO', _('The device was registered.')), 12); diff --git a/lam/templates/upload/massBuildAccounts.php b/lam/templates/upload/massBuildAccounts.php index 58ba9e08c..03bc2ae2a 100644 --- a/lam/templates/upload/massBuildAccounts.php +++ b/lam/templates/upload/massBuildAccounts.php @@ -1,19 +1,18 @@ getConfiguredType($typeId); +if ($type === null) { + logNewMessage(LOG_ERR, 'User tried to access invalid upload type: ' . $typeId); + die(); +} // check if account type is ok if ($type->isHidden()) { @@ -133,15 +138,15 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { $uploadColumns = getUploadColumns($type, $selectedModules); // read input file logNewMessage(LOG_DEBUG, 'Reading CSV file'); - $handle = fopen ($_FILES['inputfile']['tmp_name'], "r"); + $handle = fopen($_FILES['inputfile']['tmp_name'], "r"); if ($handle !== false) { - $head = fgetcsv($handle, 2000); + $head = fgetcsv($handle, 2000, escape: ''); if ($head !== false ) { // head row foreach ($head as $i => $headItem) { $ids[$headItem] = $i; } } - while (($line = fgetcsv($handle, 2000)) !== false ) { // account rows + while (($line = fgetcsv($handle, 2000, escape: '')) !== false ) { // account rows $data[] = $line; } fclose($handle); @@ -153,7 +158,7 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { $checkcolumns = []; $columns = []; foreach ($uploadColumns as $uploadColumn) { - $columns = array_merge($columns, $uploadColumns); + $columns = array_merge($columns, $uploadColumn); } foreach ($columns as $column) { if (isset($column['required']) && ($column['required'] === true)) { @@ -196,7 +201,7 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { $values_given[] = $dataRow[$colNumber]; } $values_unique = array_unique($values_given); - if (sizeof($values_given) != sizeof($values_unique)) { + if (count($values_given) !== count($values_unique)) { $duplicates = []; foreach ($values_given as $key => $value) { if (!isset($values_unique[$key]) && ($value !== null)) { @@ -211,9 +216,9 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { logNewMessage(LOG_DEBUG, 'End of generic checks'); // if input data is invalid just display error messages (max 50) - if (sizeof($errors) > 0) { + if ($errors !== []) { foreach ($errors as $error) { - $container->add(new htmlStatusMessage("ERROR", $error[0], $error[1]), 12); + $container->add(new htmlStatusMessage("ERROR", $error[0], $error[1])); } $container->addVerticalSpacer('2rem'); massPrintBackButton($type->getId(), $selectedModules, $container); @@ -237,12 +242,7 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { $rdnValue = $rdnValue[0]; } $account_dn = $data[$i][$ids['dn_rdn']] . "=" . ldap_escape($rdnValue, '', LDAP_ESCAPE_DN) . ","; - if ($data[$i][$ids['dn_suffix']] == "") { - $account_dn = $account_dn . $suffix; - } - else { - $account_dn = $account_dn . $data[$i][$ids['dn_suffix']]; - } + $account_dn = ($data[$i][$ids['dn_suffix']] == "") ? $account_dn . $suffix : $account_dn . $data[$i][$ids['dn_suffix']]; $accounts[$i]['dn'] = $account_dn; } // set overwrite @@ -251,9 +251,9 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { } } // print errors if DN could not be built - if (sizeof($errors) > 0) { + if ($errors !== []) { foreach ($errors as $error) { - $container->add(new htmlStatusMessage("ERROR", $error[0], $error[1], $error[2]), 12); + $container->add(new htmlStatusMessage("ERROR", $error[0], $error[1], $error[2])); } } else { @@ -281,7 +281,7 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { } // show links for upload and LDIF export $container->addVerticalSpacer('2rem'); - $container->add(new htmlOutputText(_("LAM has checked your input and is now ready to create the accounts.")), 12); + $container->add(new htmlOutputText(_("LAM has checked your input and is now ready to create the accounts."))); $container->addVerticalSpacer('3rem'); $formRow = new htmlResponsiveRow(); $uploadButton = new htmlButton('upload', _("Upload accounts to LDAP")); @@ -304,7 +304,7 @@ if ($_FILES['inputfile'] && ($_FILES['inputfile']['size'] > 0)) { } } else { - $container->add(new htmlStatusMessage('ERROR', _('Please provide a file to upload.')), 12); + $container->add(new htmlStatusMessage('ERROR', _('Please provide a file to upload.'))); $container->addVerticalSpacer('2rem'); massPrintBackButton($type->getId(), $selectedModules, $container); } @@ -321,19 +321,19 @@ include __DIR__ . '/../../lib/adminFooter.inc'; * @param string[] $selectedModules selected modules for upload * @param htmlResponsiveRow $container table container */ -function massPrintBackButton(string $typeId, array $selectedModules, htmlResponsiveRow &$container): void { +function massPrintBackButton(string $typeId, array $selectedModules, htmlResponsiveRow $container): void { $row = new htmlResponsiveRow(); $backButton = new htmlButton('submit', _('Back')); - $row->add($backButton, 12); - $row->add(new htmlHiddenInput('type', $typeId), 12); - $createPDF = 0; + $row->add($backButton); + $row->add(new htmlHiddenInput('type', $typeId)); + $createPDF = '0'; if (isset($_POST['createPDF']) && ($_POST['createPDF'] == 'on')) { - $createPDF = 1; + $createPDF = '1'; } - $row->add(new htmlHiddenInput('createPDF', $createPDF), 12); - $row->add(new htmlHiddenInput('pdfStructure', $_POST['pdfStructure']), 12); + $row->add(new htmlHiddenInput('createPDF', $createPDF)); + $row->add(new htmlHiddenInput('pdfStructure', $_POST['pdfStructure'])); foreach ($selectedModules as $selectedModule) { - $row->add(new htmlHiddenInput($typeId . '___' . $selectedModule, 'on'), 12); + $row->add(new htmlHiddenInput($typeId . '___' . $selectedModule, 'on')); } addSecurityTokenToMetaHTML($row); $container->add(new htmlForm('backform', 'masscreate.php', $row)); diff --git a/lam/templates/upload/massDoUpload.php b/lam/templates/upload/massDoUpload.php index 912d5665d..c7a4884ec 100644 --- a/lam/templates/upload/massDoUpload.php +++ b/lam/templates/upload/massDoUpload.php @@ -3,7 +3,7 @@ namespace LAM\UPLOAD; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2004 - 2024 Roland Gruber + Copyright (C) 2004 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ namespace LAM\UPLOAD; use htmlDiv; use htmlJavaScript; use htmlResponsiveRow; +use LAM\TYPES\TypeManager; /** * Creates LDAP accounts for file upload. @@ -54,7 +55,9 @@ enforceUserIsLoggedIn(); checkIfToolIsActive('toolFileUpload'); // die if no write access -if (!checkIfWriteAccessIsAllowed()) die(); +if (!checkIfWriteAccessIsAllowed()) { + die(); +} // Redirect to startpage if user is not logged in if (!isLoggedIn()) { @@ -67,8 +70,12 @@ setlanguage(); include __DIR__ . '/../../lib/adminHeader.inc'; $typeId = htmlspecialchars($_SESSION['mass_typeId']); -$typeManager = new \LAM\TYPES\TypeManager(); +$typeManager = new TypeManager(); $type = $typeManager->getConfiguredType($typeId); +if ($type === null) { + logNewMessage(LOG_ERR, 'User tried to access invalid upload type: ' . $typeId); + die(); +} // check if account type is ok if ($type->isHidden()) { diff --git a/lam/templates/upload/masscreate.php b/lam/templates/upload/masscreate.php index 03fda066e..90043d67f 100644 --- a/lam/templates/upload/masscreate.php +++ b/lam/templates/upload/masscreate.php @@ -1,5 +1,7 @@ getConfiguredTypes(); -$count = sizeof($types); +$count = count($types); for ($i = 0; $i < $count; $i++) { $myType = $types[$i]; if (!$myType->getBaseType()->supportsFileUpload() || $myType->isHidden() - || !checkIfNewEntriesAreAllowed($myType->getId()) || !checkIfWriteAccessIsAllowed($myType->getId())) { + || !checkIfNewEntriesAreAllowed($myType->getId()) || !checkIfWriteAccessIsAllowed($myType->getId())) { unset($types[$i]); } } @@ -117,6 +122,10 @@ if (isset($_POST['type'])) { // get selected type $typeId = htmlspecialchars((string) $_POST['type']); $type = $typeManager->getConfiguredType($typeId); + if ($type === null) { + logNewMessage(LOG_ERR, 'Invalid type: ' . $typeId); + die(); + } // get selected modules $selectedModules = []; $checkedBoxes = array_keys($_POST, 'on'); @@ -127,11 +136,11 @@ if (isset($_POST['type'])) { } $deps = getModulesDependencies($type->getScope()); $depErrors = check_module_depends($selectedModules, $deps); - if (is_array($depErrors) && (sizeof($depErrors) > 0)) { + if (is_array($depErrors) && ($depErrors !== [])) { foreach ($depErrors as $depError) { StatusMessage('ERROR', _("Unsolved dependency:") . ' ' . - getModuleAlias($depError[0], $type->getScope()) . " (" . - getModuleAlias($depError[1], $type->getScope()) . ")"); + getModuleAlias($depError[0], $type->getScope()) . " (" . + getModuleAlias($depError[1], $type->getScope()) . ")"); } } else { @@ -184,6 +193,9 @@ foreach ($types as $type) { foreach ($modules as $moduleName) { $moduleGroup = new htmlGroup(); $module = moduleCache::getModule($moduleName, $type->getScope()); + if ($module === null) { + continue; + } $iconImage = $module->getIcon(); if (!(str_starts_with($iconImage, 'http')) && !(str_starts_with($iconImage, '/'))) { $iconImage = '../../graphics/' . $iconImage; @@ -211,17 +223,17 @@ foreach ($types as $type) { $boxGroup->addElement(new htmlHiddenInput($type->getId() . '___' . $moduleName, 'on')); $moduleGroup->addElement($boxGroup); } - $moduleGroup->addElement(new htmlLabel($type->getId() . '___' . $moduleName, getModuleAlias($moduleName, $type->getScope()))); + $moduleGroup->addElement(new htmlLabel($type->getId() . '___' . $moduleName, $module->get_alias())); $innerRow->add($moduleGroup, 12, 6, 4); } - $moduleCount = sizeof($modules); - if ($moduleCount%3 == 2) { + $moduleCount = count($modules); + if ($moduleCount % 3 == 2) { $innerRow->add(new htmlOutputText(' ', false), 0, 0, 4); } - if ($moduleCount%3 == 1) { + if ($moduleCount % 3 == 1) { $innerRow->add(new htmlOutputText(' ', false), 0, 0, 4); } - if ($moduleCount%2 == 1) { + if ($moduleCount % 2 == 1) { $innerRow->add(new htmlOutputText(' ', false), 0, 6, 0); } $typeDiv = new htmlDiv($type->getId(), $innerRow); @@ -232,8 +244,8 @@ foreach ($types as $type) { // ok button $row->addVerticalSpacer('3rem'); if (!empty($types)) { - $okButton = new htmlButton('submit', _('Ok')); - $okButton->setCSSClasses(['lam-primary']); + $okButton = new htmlButton('submit', _('Ok')); + $okButton->setCSSClasses(['lam-primary']); $row->add($okButton); } @@ -246,11 +258,11 @@ echo '
    '; include __DIR__ . '/../../lib/adminFooter.inc'; /** -* Displays the account type specific main page of the upload. -* -* @param \LAM\TYPES\ConfiguredType $type account type -* @param string[] $selectedModules list of selected account modules -*/ + * Displays the account type specific main page of the upload. + * + * @param \LAM\TYPES\ConfiguredType $type account type + * @param string[] $selectedModules list of selected account modules + */ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): void { $scope = $type->getScope(); echo '
    '; @@ -278,9 +290,9 @@ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): $saveLink->setCSSClasses(['icon']); $row->addField($saveLink); $row->addVerticalSpacer('3rem'); - $row->add(new htmlResponsiveInputFileUpload('inputfile', _("CSV file"), null, true), 12); + $row->add(new htmlResponsiveInputFileUpload('inputfile', _("CSV file"), null, true)); $row->add(new htmlHiddenInput('typeId', $type->getId()), 12); - $row->add(new htmlHiddenInput('selectedModules', implode(',', $selectedModules)), 12); + $row->add(new htmlHiddenInput('selectedModules', implode(',', $selectedModules))); // PDF $pdfStructurePersistenceManager = new PdfStructurePersistenceManager(); @@ -297,7 +309,7 @@ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): if (isset($_POST['pdfStructure'])) { $pdfSelected = [$_POST['pdfStructure']]; } - else if (in_array('default', $pdfStructures)) { + elseif (in_array('default', $pdfStructures)) { $pdfSelected = ['default']; } $row->add(new htmlResponsiveSelect('pdfStructure', $pdfStructures, $pdfSelected, _('PDF structure'))); @@ -386,17 +398,20 @@ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): // module options foreach ($modules as $moduleName) { // skip modules without upload columns - if (sizeof($columns[$moduleName]) < 1) { + if (count($columns[$moduleName]) < 1) { continue; } $data = []; $row->addVerticalSpacer('2rem'); $module = moduleCache::getModule($moduleName, $scope); + if ($module === null) { + continue; + } $icon = $module->getIcon(); if (!(str_starts_with($icon, 'http')) && !(str_starts_with($icon, '/'))) { $icon = '../../graphics/' . $icon; } - $moduleTitle = new htmlSubTitle(getModuleAlias($moduleName, $scope), $icon); + $moduleTitle = new htmlSubTitle($module->get_alias(), $icon); $moduleTitle->colspan = 20; $row->add($moduleTitle, 12); foreach ($columns[$moduleName] as $column) { @@ -423,18 +438,8 @@ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): $example = $column['example']; } $rowCells[] = new htmlOutputText($example); - if (isset($column['default'])) { - $rowCells[] = new htmlOutputText($column['default']); - } - else { - $rowCells[] = new htmlOutputText(''); - } - if (isset($column['values'])) { - $rowCells[] = new htmlOutputText($column['values']); - } - else { - $rowCells[] = new htmlOutputText(''); - } + $rowCells[] = isset($column['default']) ? new htmlOutputText($column['default']) : new htmlOutputText(''); + $rowCells[] = isset($column['values']) ? new htmlOutputText($column['values']) : new htmlOutputText(''); $data[] = $rowCells; } $table = new htmlResponsiveTable($titles, $data); @@ -450,38 +455,33 @@ function showMainPage(\LAM\TYPES\ConfiguredType $type, array $selectedModules): // build sample CSV $sampleCSV_head = []; $sampleCSV_row = []; - // DN attributes - $sampleCSV_head[] = "\"dn_suffix\""; - $sampleCSV_head[] = "\"dn_rdn\""; - $sampleCSV_head[] = "\"overwrite\""; - // module attributes - foreach ($modules as $moduleName) { - if (sizeof($columns[$moduleName]) < 1) { - continue; - } - foreach ($columns[$moduleName] as $column) { - $sampleCSV_head[] = "\"" . $column['name'] . "\""; - } + // DN attributes + $sampleCSV_head[] = "\"dn_suffix\""; + $sampleCSV_head[] = "\"dn_rdn\""; + $sampleCSV_head[] = "\"overwrite\""; + // module attributes + foreach ($modules as $moduleName) { + if (count($columns[$moduleName]) < 1) { + continue; } - $RDNs = getRDNAttributes($type->getId(), $selectedModules); - // DN attributes - $sampleCSV_row[] = "\"" . $type->getSuffix() . "\""; - $sampleCSV_row[] = "\"" . $RDNs[0] . "\""; - $sampleCSV_row[] = "\"false\""; - // module attributes - foreach ($modules as $moduleName) { - if (sizeof($columns[$moduleName]) < 1) { - continue; - } - foreach ($columns[$moduleName] as $column) { - if (isset($column['example'])) { - $sampleCSV_row[] = '"' . $column['example'] . '"'; - } - else { - $sampleCSV_row[] = '""'; - } - } + foreach ($columns[$moduleName] as $column) { + $sampleCSV_head[] = "\"" . $column['name'] . "\""; } + } + $RDNs = getRDNAttributes($type->getId(), $selectedModules); + // DN attributes + $sampleCSV_row[] = "\"" . $type->getSuffix() . "\""; + $sampleCSV_row[] = "\"" . $RDNs[0] . "\""; + $sampleCSV_row[] = "\"false\""; + // module attributes + foreach ($modules as $moduleName) { + if (count($columns[$moduleName]) < 1) { + continue; + } + foreach ($columns[$moduleName] as $column) { + $sampleCSV_row[] = isset($column['example']) ? '"' . $column['example'] . '"' : '""'; + } + } $sampleCSV = implode(",", $sampleCSV_head) . "\n" . implode(",", $sampleCSV_row) . "\n"; $_SESSION['mass_csv'] = $sampleCSV; diff --git a/lam/tests/lib/2factorTest.php b/lam/tests/lib/2factorTest.php index 325063e5a..65f699e93 100644 --- a/lam/tests/lib/2factorTest.php +++ b/lam/tests/lib/2factorTest.php @@ -24,9 +24,9 @@ use PHPUnit\Framework\TestCase; */ -include_once 'lam/tests/utils/configuration.inc'; -include_once 'lam/tests/utils/2factorUtils.inc'; -require_once 'lam/lib/2factor.inc'; +include_once __DIR__ . '/../../tests/utils/configuration.inc'; +include_once __DIR__ . '/../../tests/utils/2factorUtils.inc'; +require_once __DIR__ . '/../../lib/2factor.inc'; /** * Checks code in 2factor.inc. diff --git a/lam/tests/lib/AccountTest.php b/lam/tests/lib/AccountTest.php index d5544e1bb..ac1a95d5d 100644 --- a/lam/tests/lib/AccountTest.php +++ b/lam/tests/lib/AccountTest.php @@ -2,7 +2,7 @@ use PHPUnit\Framework\TestCase; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2018 - 2024 Roland Gruber + Copyright (C) 2018 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -252,4 +252,86 @@ class AccountTest extends TestCase { $this->assertEquals(20, strlen(generateRandomText(20))); } + function testGetPreg() { + $this->assertTrue(get_preg('abc123', 'password')); + $this->assertTrue(get_preg('abc ^|#*,.;:_+!%&/?{}()[]$§°@=-123', 'password')); + $this->assertFalse(get_preg('abc\\123', 'password')); + + $this->assertTrue(get_preg('abc123', 'username')); + $this->assertTrue(get_preg('abc%#@. _$-123', 'username')); + $this->assertFalse(get_preg('abc?123', 'username')); + + $this->assertTrue(get_preg('abc123', 'krbUserName')); + $this->assertTrue(get_preg('abc#@. _$-123', 'krbUserName')); + $this->assertFalse(get_preg('abc?123', 'krbUserName')); + + $this->assertTrue(get_preg('abc123', 'hostObject')); + $this->assertTrue(get_preg('!abc123', 'hostObject')); + $this->assertTrue(get_preg('abc@. _$:*-123', 'hostObject')); + $this->assertFalse(get_preg('abc!123', 'hostObject')); + + $this->assertTrue(get_preg('abc123', 'usernameList')); + $this->assertTrue(get_preg('abc123,def456', 'usernameList')); + $this->assertTrue(get_preg('abc123,def456,ghi789', 'usernameList')); + $this->assertTrue(get_preg('abc%#@. _-123,def%#@. _-456,ghi%#@. _-789', 'usernameList')); + $this->assertFalse(get_preg('abc!123', 'usernameList')); + $this->assertFalse(get_preg('abcdef,abc!123', 'usernameList')); + + $this->assertTrue(get_preg('abc123', 'cn')); + $this->assertTrue(get_preg('abc123$', 'cn')); + $this->assertTrue(get_preg('abc#@. _-123', 'cn')); + $this->assertFalse(get_preg('abc\123', 'cn')); + $this->assertFalse(get_preg('abc<123', 'cn')); + $this->assertFalse(get_preg('abc>123', 'cn')); + $this->assertFalse(get_preg('abc=123', 'cn')); + $this->assertFalse(get_preg('abc$123', 'cn')); + $this->assertFalse(get_preg('abc?123', 'cn')); + + $this->assertTrue(get_preg('abc123ABC', 'telephone')); + $this->assertTrue(get_preg('abc -.(123)12/3', 'telephone')); + $this->assertFalse(get_preg('abc?123', 'telephone')); + + $this->assertTrue(get_preg('abc@abc123.com', 'email')); + $this->assertTrue(get_preg('ab!~#+*%$/._-c@abc123.com', 'email')); + $this->assertFalse(get_preg('abc?abc123.com', 'email')); + $this->assertFalse(get_preg('abc@abc~123.com', 'email')); + $this->assertFalse(get_preg('abc', 'email')); + + $this->assertTrue(get_preg('abc abc ', 'emailWithName')); + $this->assertTrue(get_preg('abc \'!~#+*%$()_- abc ', 'emailWithName')); + $this->assertFalse(get_preg('abc ', 'emailWithName')); + $this->assertFalse(get_preg('abc ', 'emailWithName')); + $this->assertFalse(get_preg('abc ', 'emailWithName')); + $this->assertFalse(get_preg('a?bc ', 'emailWithName')); + + $this->assertTrue(get_preg('31-12-2012', 'date')); + $this->assertTrue(get_preg('01-02-2012', 'date')); + $this->assertTrue(get_preg('1-2-2012', 'date')); + $this->assertFalse(get_preg('42-20-9999', 'date')); + $this->assertFalse(get_preg('10-10-12345', 'date')); + + $this->assertTrue(get_preg('2012-12-31 10:11:30', 'dateTime')); + $this->assertTrue(get_preg('2012-01-02 10:11:30', 'dateTime')); + $this->assertTrue(get_preg('2012-02-01 10:11:30', 'dateTime')); + $this->assertFalse(get_preg('2012-2-1 10:11:30', 'dateTime')); + $this->assertFalse(get_preg('9999-20-41 10:11:30', 'dateTime')); + $this->assertFalse(get_preg('12345-10-10 10:11:30', 'dateTime')); + $this->assertFalse(get_preg('1234-10-10 99:11:30', 'dateTime')); + + $this->assertTrue(get_preg('abc.123:6567', 'hostAndPort')); + $this->assertTrue(get_preg('ab_-c.123:132', 'hostAndPort')); + $this->assertFalse(get_preg('abc', 'hostAndPort')); + $this->assertFalse(get_preg('abc:abc', 'hostAndPort')); + $this->assertFalse(get_preg('ab?c:80', 'hostAndPort')); + } + + function testAreArrayContentsEqual() { + $this->assertTrue(areArrayContentsEqual([], [])); + $this->assertFalse(areArrayContentsEqual(['1'], [])); + $this->assertFalse(areArrayContentsEqual([], ['1'])); + $this->assertTrue(areArrayContentsEqual(['a', 'b', 'c'], ['c', 'b', 'a'])); + $this->assertFalse(areArrayContentsEqual(['a', 'b', 'c'], ['a', 'c', 'd'])); + $this->assertFalse(areArrayContentsEqual(['a', 'b', 'c'], ['a', 'c'])); + } + } diff --git a/lam/tests/lib/BaseModuleTest.php b/lam/tests/lib/BaseModuleTest.php index 365bd6230..73b9c5020 100644 --- a/lam/tests/lib/BaseModuleTest.php +++ b/lam/tests/lib/BaseModuleTest.php @@ -189,6 +189,33 @@ class BaseModuleTest extends TestCase { $this->assertEquals([['ERROR', 'errorCMP']], $errors); } + function test_check_profileOptions_cmpGreater_minMissing() { + $meta = []; + $module = new baseModuleDummy('user'); + + $meta['profile_checks']['test_val1'] = [ + 'type' => 'ext_preg', + 'regex' => 'digit', + 'error_message' => ['ERROR', 'error1']]; + $meta['profile_checks']['test_val2'] = [ + 'type' => 'ext_preg', + 'regex' => 'digit', + 'error_message' => ['ERROR', 'error2']]; + $meta['profile_checks']['test_cmp'] = [ + 'type' => 'int_greater', + 'cmp_name1' => 'test_val2', + 'cmp_name2' => 'test_val1', + 'error_message' => ['ERROR', 'errorCMP']]; + + $module->setMeta($meta); + + $options = [ + 'test_val2' => ['20'], + ]; + $errors = $module->check_profileOptions($options, 'user1'); + $this->assertEmpty($errors, print_r($errors, true)); + } + function test_check_profileOptions_cmpEqual_greater() { $meta = []; $module = new baseModuleDummy('user'); diff --git a/lam/tests/lib/ImporterTest.php b/lam/tests/lib/ImporterTest.php index d42b407a1..dd2ecc07f 100644 --- a/lam/tests/lib/ImporterTest.php +++ b/lam/tests/lib/ImporterTest.php @@ -29,7 +29,7 @@ use PHPUnit\Framework\TestCase; */ -require_once 'lam/lib/import.inc'; +require_once __DIR__ . '/../../lib/import.inc'; /** * Checks the LDIF importer. @@ -127,7 +127,7 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); } /** @@ -162,7 +162,7 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(AddEntryTask::class, $task::class); } @@ -219,7 +219,7 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(RenameEntryTask::class, $task::class); } @@ -255,7 +255,7 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(DeleteEntryTask::class, $task::class); } @@ -314,17 +314,17 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(MultiTask::class, $task::class); $subtasks = $task->getTasks(); - $this->assertEquals(1, sizeof($subtasks)); + $this->assertEquals(1, count($subtasks)); $subTask = $subtasks[0]; $this->assertEquals(AddAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); $attributes = $subTask->getAttributes(); - $this->assertEquals(1, sizeof($attributes)); - $this->assertEquals(2, sizeof($attributes['uid'])); + $this->assertEquals(1, count($attributes)); + $this->assertEquals(2, count($attributes['uid'])); $this->assertTrue(in_array('uid1', $attributes['uid'])); $this->assertTrue(in_array('uid2', $attributes['uid'])); } @@ -349,25 +349,25 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(MultiTask::class, $task::class); $subtasks = $task->getTasks(); - $this->assertEquals(2, sizeof($subtasks)); + $this->assertEquals(2, count($subtasks)); $subTask = $subtasks[0]; $this->assertEquals(AddAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); $attributes = $subTask->getAttributes(); - $this->assertEquals(1, sizeof($attributes)); - $this->assertEquals(2, sizeof($attributes['uid'])); + $this->assertEquals(1, count($attributes)); + $this->assertEquals(2, count($attributes['uid'])); $this->assertTrue(in_array('uid1', $attributes['uid'])); $this->assertTrue(in_array('uid2', $attributes['uid'])); $subTask = $subtasks[1]; $this->assertEquals(AddAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); $attributes = $subTask->getAttributes(); - $this->assertEquals(1, sizeof($attributes)); - $this->assertEquals(2, sizeof($attributes['gn'])); + $this->assertEquals(1, count($attributes)); + $this->assertEquals(2, count($attributes['gn'])); $this->assertTrue(in_array('name1', $attributes['gn'])); $this->assertTrue(in_array('name2', $attributes['gn'])); } @@ -388,17 +388,17 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(MultiTask::class, $task::class); $subtasks = $task->getTasks(); - $this->assertEquals(1, sizeof($subtasks)); + $this->assertEquals(1, count($subtasks)); $subTask = $subtasks[0]; $this->assertEquals(DeleteAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); $attributes = $subTask->getAttributes(); - $this->assertEquals(1, sizeof($attributes)); - $this->assertEquals(2, sizeof($attributes['uid'])); + $this->assertEquals(1, count($attributes)); + $this->assertEquals(2, count($attributes['uid'])); $this->assertTrue(in_array('uid1', $attributes['uid'])); $this->assertTrue(in_array('uid2', $attributes['uid'])); } @@ -417,11 +417,11 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(MultiTask::class, $task::class); $subtasks = $task->getTasks(); - $this->assertEquals(1, sizeof($subtasks)); + $this->assertEquals(1, count($subtasks)); $subTask = $subtasks[0]; $this->assertEquals(DeleteAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); @@ -445,17 +445,17 @@ class ImporterTest extends TestCase { $importer = new Importer(); $tasks = $importer->getTasks($lines); - $this->assertEquals(1, sizeof($tasks)); + $this->assertEquals(1, count($tasks)); $task = $tasks[0]; $this->assertEquals(MultiTask::class, $task::class); $subtasks = $task->getTasks(); - $this->assertEquals(1, sizeof($subtasks)); + $this->assertEquals(1, count($subtasks)); $subTask = $subtasks[0]; $this->assertEquals(ReplaceAttributesTask::class, $subTask::class); $this->assertEquals($subTask->getDn(), 'uid=test,dc=example,dc=com'); $attributes = $subTask->getAttributes(); - $this->assertEquals(1, sizeof($attributes)); - $this->assertEquals(2, sizeof($attributes['uid'])); + $this->assertEquals(1, count($attributes)); + $this->assertEquals(2, count($attributes['uid'])); $this->assertTrue(in_array('uid1', $attributes['uid'])); $this->assertTrue(in_array('uid2', $attributes['uid'])); } diff --git a/lam/tests/lib/LAMCfgMainTest.php b/lam/tests/lib/LAMCfgMainTest.php index a25832a2a..ebf0550ae 100644 --- a/lam/tests/lib/LAMCfgMainTest.php +++ b/lam/tests/lib/LAMCfgMainTest.php @@ -3,7 +3,7 @@ use PHPUnit\Framework\TestCase; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2020 - 2023 Roland Gruber + Copyright (C) 2020 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ use PHPUnit\Framework\TestCase; */ include_once __DIR__ . '/../../lib/config.inc'; +include_once __DIR__ . '/../../lib/plugins/sms/SmsService.inc'; /** * LAMConfig test case. @@ -56,6 +57,7 @@ class LAMCfgMainTest extends TestCase { /** * Mail related settings + * @throws LAMException error saving config */ public function testMail() { $this->assertEquals(LAMCfgMain::MAIL_ATTRIBUTE_DEFAULT, $this->conf->getMailAttribute()); @@ -79,8 +81,38 @@ class LAMCfgMainTest extends TestCase { $this->assertEquals('test2', $this->conf->getMailBackupAttribute()); } + /** + * SMS related settings + * @throws LAMException error saving config + */ + public function testSms() { + $this->assertEquals(explode(';', LAMCfgMain::SMS_ATTRIBUTES_DEFAULT), $this->conf->getSmsAttributes()); + + $this->conf->smsAttributes = 'mobile;pager'; + $this->conf->smsProvider = 'twilio'; + $this->conf->smsToken = 'token'; + $this->conf->smsApiKey = 'key'; + $this->conf->smsAccountId = 'id'; + $this->conf->smsRegion = 'eu'; + $this->conf->smsFrom = '+491234567890'; + $this->conf->smsDefaultCountryPrefix = '+49'; + + $this->conf->save(); + $this->conf = new LAMCfgMain($this->file); + + $this->assertEquals('twilio', $this->conf->smsProvider); + $this->assertEquals('token', $this->conf->smsToken); + $this->assertEquals('key', $this->conf->smsApiKey); + $this->assertEquals('id', $this->conf->smsAccountId); + $this->assertEquals('eu', $this->conf->smsRegion); + $this->assertEquals('+491234567890', $this->conf->smsFrom); + $this->assertEquals('+49', $this->conf->smsDefaultCountryPrefix); + $this->assertEquals(['mobile', 'pager'], $this->conf->getSmsAttributes()); + } + /** * License related settings. + * @throws LAMException error saving config */ public function testLicense() { $timestamp = '12345'; diff --git a/lam/tests/lib/LAMConfigTest.php b/lam/tests/lib/LAMConfigTest.php index 74b0d63e0..648a5326f 100644 --- a/lam/tests/lib/LAMConfigTest.php +++ b/lam/tests/lib/LAMConfigTest.php @@ -156,6 +156,17 @@ class LAMConfigTest extends TestCase { $this->assertEquals($val, $this->lAMConfig->getPagedResults()); } + /** + * Tests LAMConfig->getAdShowDeleted() and LAMConfig->setAdShowDeleted() + */ + public function testAdShowDeleted() { + $val = 'yes'; + $this->lAMConfig->setAdShowDeleted($val); + $this->assertEquals($val, $this->lAMConfig->getAdShowDeleted()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getAdShowDeleted()); + } + /** * Tests LAMConfig->getReferentialIntegrityOverlay() and LAMConfig->setReferentialIntegrityOverlay() */ @@ -302,10 +313,10 @@ class LAMConfigTest extends TestCase { $val = 'server1;server2:label2;server3:label3:/prefix'; $this->assertTrue($this->lAMConfig->set_scriptServers($val)); $servers = $this->lAMConfig->getConfiguredScriptServers(); - $this->assertEquals(3, sizeof($servers)); + $this->assertEquals(3, count($servers)); $this->doSave(); $servers = $this->lAMConfig->getConfiguredScriptServers(); - $this->assertEquals(3, sizeof($servers)); + $this->assertEquals(3, count($servers)); $this->assertEquals('server1', $servers[0]->getServer()); $this->assertEquals('server2', $servers[1]->getServer()); $this->assertEquals('server3', $servers[2]->getServer()); @@ -366,32 +377,18 @@ class LAMConfigTest extends TestCase { * Tests LAMConfig->get_searchLimit() and LAMConfig->set_searchLimit() */ public function testsearchLimit() { - $this->assertFalse($this->lAMConfig->set_searchLimit('abc')); - $val = '1024'; + $this->assertFalse($this->lAMConfig->set_searchLimit(-100)); + $val = 1024; $this->lAMConfig->set_searchLimit($val); $this->assertEquals($val, $this->lAMConfig->get_searchLimit()); $this->doSave(); $this->assertEquals($val, $this->lAMConfig->get_searchLimit()); } - /** - * Tests LAMConfig->get_AccountModules() and LAMConfig->set_AccountModules() - */ - public function testAccountModules() { - $scope = 'user'; - $this->assertFalse($this->lAMConfig->set_AccountModules('abc', $scope)); - $val = ['posixAccount', 'shadowAccount']; - $this->lAMConfig->set_AccountModules($val, $scope); - $this->assertEquals($val, $this->lAMConfig->get_AccountModules($scope)); - $this->doSave(); - $this->assertEquals($val, $this->lAMConfig->get_AccountModules($scope)); - } - /** * Tests LAMConfig->set_moduleSettings() and LAMConfig->get_moduleSettings() */ public function testmoduleSettings() { - $this->assertFalse($this->lAMConfig->set_moduleSettings('abc')); $val = ['posixAccount_123' => ['123'], 'shadowAccount_123' => ['123']]; $this->lAMConfig->set_moduleSettings($val); $this->assertTrue(array_key_exists('posixAccount_123', $this->lAMConfig->get_moduleSettings())); @@ -416,7 +413,6 @@ class LAMConfigTest extends TestCase { * Tests LAMConfig->set_typeSettings() and LAMConfig->get_typeSettings() */ public function testtypeSettings() { - $this->assertFalse($this->lAMConfig->set_typeSettings('abc')); $val = ['posixAccount_123' => '123', 'shadowAccount_123' => '123']; $this->lAMConfig->set_typeSettings($val); $this->assertTrue(array_key_exists('posixAccount_123', $this->lAMConfig->get_typeSettings())); @@ -430,7 +426,6 @@ class LAMConfigTest extends TestCase { * Tests LAMConfig->getToolSettings() and LAMConfig->setToolSettings() */ public function testGetToolSettings() { - $this->assertFalse($this->lAMConfig->setToolSettings('abc')); $val = ['user_123' => '123', 'group_123' => '123']; $this->lAMConfig->setToolSettings($val); $this->assertTrue(array_key_exists('user_123', $this->lAMConfig->getToolSettings())); @@ -816,6 +811,17 @@ class LAMConfigTest extends TestCase { $this->assertEquals($val, $this->lAMConfig->getJobsDBPort()); } + /** + * Tests LAMConfig->getJobsDBCaPath() and LAMConfig->setJobsDBCaPath() + */ + public function testJobsCaPath() { + $val = '/tmp/test.pem'; + $this->lAMConfig->setJobsDBCaPath($val); + $this->assertEquals($val, $this->lAMConfig->getJobsDBCaPath()); + $this->doSave(); + $this->assertEquals($val, $this->lAMConfig->getJobsDBCaPath()); + } + /** * Tests LAMConfig->getJobsDBUser() and LAMConfig->setJobsDBUser() */ @@ -920,14 +926,14 @@ class LAMConfigTest extends TestCase { * Checks that number of settings stays constant over multiple saves. */ public function testMultiSave() { - $sizeModSettings = sizeof($this->lAMConfig->get_moduleSettings()); - $sizeTypeSettings = sizeof($this->lAMConfig->get_typeSettings()); + $sizeModSettings = count($this->lAMConfig->get_moduleSettings()); + $sizeTypeSettings = count($this->lAMConfig->get_typeSettings()); $this->doSave(); - $this->assertEquals($sizeModSettings, sizeof($this->lAMConfig->get_moduleSettings())); - $this->assertEquals($sizeTypeSettings, sizeof($this->lAMConfig->get_typeSettings())); + $this->assertEquals($sizeModSettings, count($this->lAMConfig->get_moduleSettings())); + $this->assertEquals($sizeTypeSettings, count($this->lAMConfig->get_typeSettings())); $this->doSave(); - $this->assertEquals($sizeModSettings, sizeof($this->lAMConfig->get_moduleSettings())); - $this->assertEquals($sizeTypeSettings, sizeof($this->lAMConfig->get_typeSettings())); + $this->assertEquals($sizeModSettings, count($this->lAMConfig->get_moduleSettings())); + $this->assertEquals($sizeTypeSettings, count($this->lAMConfig->get_typeSettings())); } /** diff --git a/lam/tests/lib/PdfStructTest.php b/lam/tests/lib/PdfStructTest.php index f6f16b198..53c7e166e 100644 --- a/lam/tests/lib/PdfStructTest.php +++ b/lam/tests/lib/PdfStructTest.php @@ -50,13 +50,13 @@ class PdfStructTest extends TestCase { $this->assertEquals('User information', $structure->getTitle()); $this->assertEquals(PDFStructure::FOLDING_STANDARD, $structure->getFoldingMarks()); $sections = $structure->getSections(); - $this->assertEquals(4, sizeof($sections)); + $this->assertEquals(4, count($sections)); // check first section $this->assertInstanceOf(PDFEntrySection::class, $sections[0]); $this->assertFalse($sections[0]->isAttributeTitle()); $this->assertEquals('Personal user information', $sections[0]->getTitle()); $entries = $sections[0]->getEntries(); - $this->assertEquals(3, sizeof($entries)); + $this->assertEquals(3, count($entries)); $this->assertEquals('inetOrgPerson_givenName', $entries[0]->getKey()); $this->assertEquals('inetOrgPerson_sn', $entries[1]->getKey()); $this->assertEquals('inetOrgPerson_street', $entries[2]->getKey()); @@ -68,7 +68,7 @@ class PdfStructTest extends TestCase { $this->assertTrue($sections[2]->isAttributeTitle()); $this->assertEquals('posixAccount_uid', $sections[2]->getPdfKey()); $entries = $sections[2]->getEntries(); - $this->assertEquals(2, sizeof($entries)); + $this->assertEquals(2, count($entries)); $this->assertEquals('posixAccount_homeDirectory', $entries[0]->getKey()); $this->assertEquals('posixAccount_loginShell', $entries[1]->getKey()); // check fourth section @@ -76,7 +76,7 @@ class PdfStructTest extends TestCase { $this->assertFalse($sections[3]->isAttributeTitle()); $this->assertEquals('No entries', $sections[3]->getTitle()); $entries = $sections[3]->getEntries(); - $this->assertEquals(0, sizeof($entries)); + $this->assertEquals(0, count($entries)); } /** @@ -190,7 +190,7 @@ class PdfStructTest extends TestCase { $this->assertEquals('mytitle', $section->getTitle()); $entries = $section->getEntries(); - $this->assertEquals(2, sizeof($entries)); + $this->assertEquals(2, count($entries)); $this->assertEquals('e1', ($entries[0]->getKey())); $this->assertEquals('e2', ($entries[1]->getKey())); } @@ -225,12 +225,12 @@ class PdfStructTest extends TestCase { $this->assertEquals(PDFStructure::FOLDING_STANDARD, $structure->getFoldingMarks()); $this->assertEquals('logo', $structure->getLogo()); $sections = $structure->getSections(); - $this->assertEquals(2, sizeof($sections)); + $this->assertEquals(2, count($sections)); $this->assertTrue($sections[0] instanceof PDFTextSection); $this->assertEquals('textvalue', $sections[0]->getText()); $this->assertTrue($sections[1] instanceof PDFEntrySection); $entries = $sections[1]->getEntries(); - $this->assertEquals(2, sizeof($entries)); + $this->assertEquals(2, count($entries)); $this->assertEquals('e1', $entries[0]->getKey()); $this->assertEquals('e2', $entries[1]->getKey()); } diff --git a/lam/tests/lib/PublicKeyCredentialSourceRepositorySQLiteTest.php b/lam/tests/lib/PublicKeyCredentialSourceRepositorySQLiteTest.php index 7b4cbb09b..b55aa94b7 100644 --- a/lam/tests/lib/PublicKeyCredentialSourceRepositorySQLiteTest.php +++ b/lam/tests/lib/PublicKeyCredentialSourceRepositorySQLiteTest.php @@ -109,10 +109,10 @@ class PublicKeyCredentialSourceRepositorySQLiteTest extends TestCase { $this->assertNotNull($this->database->findOneByCredentialId("id1")); $this->assertNotNull($this->database->findOneByCredentialId("id2")); $this->assertNotNull($this->database->findOneByCredentialId("id3")); - $this->assertEquals(2, sizeof( + $this->assertEquals(2, count( $this->database->findAllForUserDn("cn=user1") )); - $this->assertEquals(1, sizeof( + $this->assertEquals(1, count( $this->database->findAllForUserDn("cn=user2") )); } diff --git a/lam/tests/lib/SecurityTest.php b/lam/tests/lib/SecurityTest.php index 2dfe2fc2a..835eb766c 100644 --- a/lam/tests/lib/SecurityTest.php +++ b/lam/tests/lib/SecurityTest.php @@ -23,8 +23,8 @@ use PHPUnit\Framework\TestCase; $_SERVER ['REMOTE_ADDR'] = '127.0.0.1'; -include_once 'lam/tests/utils/configuration.inc'; -include_once 'lam/lib/security.inc'; +include_once __DIR__ . '/../../tests/utils/configuration.inc'; +include_once __DIR__ . '/../../lib/security.inc'; /** * Checks password checking functions. diff --git a/lam/tests/lib/TypesTest.php b/lam/tests/lib/TypesTest.php index 3ffedf0cf..dfa1d1ef8 100644 --- a/lam/tests/lib/TypesTest.php +++ b/lam/tests/lib/TypesTest.php @@ -6,7 +6,7 @@ use user; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2016 - 2023 Roland Gruber + Copyright (C) 2016 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ use user; */ -require_once 'lam/lib/types.inc'; +require_once __DIR__ . '/../../lib/types.inc'; /** * Checks code in types.inc. @@ -37,7 +37,10 @@ class TypesTest extends TestCase { private $type; protected function setUp(): void { - $this->type = $this->getMockBuilder('ConfiguredType')->setMethods(['getBaseType', 'getModules'])->getMock(); + $typeManager = new TypeManager(null); + $this->type = $this->getMockBuilder('LAM\TYPES\ConfiguredType') + ->setConstructorArgs([$typeManager, 'user', 'user']) + ->setMethods(['getBaseType', 'getModules'])->getMock(); $scope = new user($this->type); $this->type->method('getBaseType')->willReturn($scope); $this->type->method('getModules')->willReturn(['posixAccount']); diff --git a/lam/tests/lib/modules/BindDLZTest.php b/lam/tests/lib/modules/BindDLZTest.php index 24be1ab54..b280115c8 100644 --- a/lam/tests/lib/modules/BindDLZTest.php +++ b/lam/tests/lib/modules/BindDLZTest.php @@ -5,11 +5,11 @@ use PHPUnit\Framework\TestCase; Copyright (C) 2018 - 2019 Roland Gruber */ -if (is_readable('lam/lib/modules/bindDLZ.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/bindDLZ.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules.inc'; - include_once 'lam/lib/modules/bindDLZ.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules.inc'; + include_once __DIR__ . '/../../../lib/modules/bindDLZ.inc'; /** * Checks the bindDLZ module. diff --git a/lam/tests/lib/modules/CustomFieldsTest.php b/lam/tests/lib/modules/CustomFieldsTest.php index 2ac068016..7430109ed 100644 --- a/lam/tests/lib/modules/CustomFieldsTest.php +++ b/lam/tests/lib/modules/CustomFieldsTest.php @@ -5,11 +5,11 @@ use PHPUnit\Framework\TestCase; Copyright (C) 2017 - 2023 Roland Gruber */ -if (is_readable('lam/lib/modules/customFields.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/customFields.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules.inc'; - include_once 'lam/lib/modules/customFields.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules.inc'; + include_once __DIR__ . '/../../../lib/modules/customFields.inc'; /** * Checks the ppolicy expire job. diff --git a/lam/tests/lib/modules/CustomScriptsTest.php b/lam/tests/lib/modules/CustomScriptsTest.php index 4a70fc4fc..d0b95566d 100644 --- a/lam/tests/lib/modules/CustomScriptsTest.php +++ b/lam/tests/lib/modules/CustomScriptsTest.php @@ -9,7 +9,7 @@ use PHPUnit\Framework\TestCase; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2024 Roland Gruber + Copyright (C) 2024 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,11 +27,11 @@ use PHPUnit\Framework\TestCase; */ -if (is_readable('lam/lib/modules/customScripts.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/customScripts.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules.inc'; - include_once 'lam/lib/modules/customScripts.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules.inc'; + include_once __DIR__ . '/../../../lib/modules/customScripts.inc'; /** * Checks the custom scripts. @@ -51,16 +51,13 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { 'LAM_TEXT_COMMENT: Comment=no comment', 'LAM_TEXT_AMOUNT:Amount', 'LAM_GROUP: Group 1', - 'user manual LAMLABEL="echo uid" echo $uid$', + 'manual LAMLABEL="echo uid" echo $uid$', 'LAM_GROUP: Group 2', - 'user manual echo $description$', - 'user postModify echo $dn$', - 'gon preModify echo NEW $member$ OLD $ORIG.member$', + 'manual echo $description$', + 'postModify echo $dn$', '', ' ', - 'group:group_3 manual echo group3', - 'group:group_3 postCreate echo group3', - 'group preCreate echo group', + 'preCreate echo user', ]; $this->configLinesSelfService = [ 'postModify echo $dn$', @@ -70,17 +67,12 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { public function testCustomScriptParser() { $parser = new \CustomScriptParser(); - $scripts = $parser->parse($this->configLines, false); + $scripts = $parser->parse($this->configLines); $this->assertNotEmpty($scripts); - $this->assertEquals(7, count($scripts)); - $typeManager = new TypeManager(); + $this->assertEquals(4, count($scripts)); $script = $scripts[0]; - $configuredType = new ConfiguredType($typeManager, 'user', 'user'); - $configuredWrongType = new ConfiguredType($typeManager, 'group', 'group_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); $this->assertTrue($script->isManual()); $this->assertEquals('echo $uid$', $script->getCommand()); $this->assertEquals('manual', $script->getType()); @@ -88,10 +80,6 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { $this->assertEquals('Group 1', $script->getGroupLabel()); $script = $scripts[1]; - $configuredType = new ConfiguredType($typeManager, 'user', 'user'); - $configuredWrongType = new ConfiguredType($typeManager, 'group', 'group_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); $this->assertTrue($script->isManual()); $this->assertEquals('echo $description$', $script->getCommand()); $this->assertEquals('manual', $script->getType()); @@ -99,10 +87,6 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { $this->assertEquals('Group 2', $script->getGroupLabel()); $script = $scripts[2]; - $configuredType = new ConfiguredType($typeManager, 'user', 'user'); - $configuredWrongType = new ConfiguredType($typeManager, 'group', 'group_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); $this->assertFalse($script->isManual()); $this->assertEquals('echo $dn$', $script->getCommand()); $this->assertEquals('postModify', $script->getType()); @@ -110,49 +94,13 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { $this->assertEquals(_('Post-modify'), $script->getTypeLabel()); $script = $scripts[3]; - $configuredType = new ConfiguredType($typeManager, 'gon', 'gon_1'); - $configuredWrongType = new ConfiguredType($typeManager, 'group', 'group_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); $this->assertFalse($script->isManual()); - $this->assertEquals('echo NEW $member$ OLD $ORIG.member$', $script->getCommand()); - $this->assertEquals('preModify', $script->getType()); - $this->assertNull($script->getLabel()); - $this->assertEquals(_('Pre-modify'), $script->getTypeLabel()); - - $script = $scripts[4]; - $configuredType = new ConfiguredType($typeManager, 'group', 'group_3'); - $configuredWrongType = new ConfiguredType($typeManager, 'group', 'group_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); - $this->assertTrue($script->isManual()); - $this->assertEquals('echo group3', $script->getCommand()); - $this->assertEquals('manual', $script->getType()); - $this->assertNull($script->getLabel()); - - $script = $scripts[5]; - $configuredType = new ConfiguredType($typeManager, 'group', 'group_3'); - $configuredWrongType = new ConfiguredType($typeManager, 'gon', 'gon_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); - $this->assertFalse($script->isManual()); - $this->assertEquals('echo group3', $script->getCommand()); - $this->assertEquals('postCreate', $script->getType()); - $this->assertNull($script->getLabel()); - $this->assertEquals(_('Post-create'), $script->getTypeLabel()); - - $script = $scripts[6]; - $configuredType = new ConfiguredType($typeManager, 'group', 'group_3'); - $configuredWrongType = new ConfiguredType($typeManager, 'gon', 'gon_1'); - $this->assertTrue($script->matchesConfiguredType($configuredType)); - $this->assertFalse($script->matchesConfiguredType($configuredWrongType)); - $this->assertFalse($script->isManual()); - $this->assertEquals('echo group', $script->getCommand()); + $this->assertEquals('echo user', $script->getCommand()); $this->assertEquals('preCreate', $script->getType()); $this->assertNull($script->getLabel()); $this->assertEquals(_('Pre-create'), $script->getTypeLabel()); - $this->assertEquals(4, sizeof($parser->getManualOptions())); + $this->assertEquals(4, count($parser->getManualOptions())); $this->assertEquals('select', $parser->getManualOptions()[0]['type']); $this->assertEquals('select', $parser->getManualOptions()[1]['type']); $this->assertEquals('LAM_SELECTION_ENV', $parser->getManualOptions()[0]['name']); @@ -174,7 +122,7 @@ if (is_readable('lam/lib/modules/customScripts.inc')) { public function testCustomScriptParserSelfService() { $parser = new \CustomScriptParser(); - $scripts = $parser->parse($this->configLinesSelfService, true); + $scripts = $parser->parse($this->configLinesSelfService); $this->assertNotEmpty($scripts); $this->assertEquals(2, count($scripts)); diff --git a/lam/tests/lib/modules/PPolicyUserPasswordNotifyJobTest.php b/lam/tests/lib/modules/PPolicyUserPasswordNotifyJobTest.php index 9ac4038e6..3d9394bc1 100644 --- a/lam/tests/lib/modules/PPolicyUserPasswordNotifyJobTest.php +++ b/lam/tests/lib/modules/PPolicyUserPasswordNotifyJobTest.php @@ -5,7 +5,7 @@ use PHPUnit\Framework\TestCase; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2016 - 2023 Roland Gruber + Copyright (C) 2016 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,12 +23,12 @@ use PHPUnit\Framework\TestCase; */ -if (is_readable('lam/lib/modules/ppolicyUser.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/ppolicyUser.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules.inc'; - include_once 'lam/lib/passwordExpirationJob.inc'; - include_once 'lam/lib/modules/ppolicyUser.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules.inc'; + include_once __DIR__ . '/../../../lib/passwordExpirationJob.inc'; + include_once __DIR__ . '/../../../lib/modules/ppolicyUser.inc'; /** * Checks the ppolicy expire job. @@ -130,7 +130,7 @@ if (is_readable('lam/lib/modules/ppolicyUser.inc')) { public function testWarningNotReached() { $now = new DateTime('now', getTimeZone()); - $lastChangeNow = floor($now->format('U')/3600/24); + $lastChangeNow = (string) floor($now->format('U')/3600/24); $this->job->method('getDBLastPwdChangeTime')->willReturn($lastChangeNow); $date = new DateTime('now', new DateTimeZone('UTC')); $this->job->method('findUsers')->willReturn([[ diff --git a/lam/tests/lib/modules/RequestAccessTest.php b/lam/tests/lib/modules/RequestAccessTest.php index 78c1e0d1b..c321a9439 100644 --- a/lam/tests/lib/modules/RequestAccessTest.php +++ b/lam/tests/lib/modules/RequestAccessTest.php @@ -21,10 +21,10 @@ use PHPUnit\Framework\TestCase; */ -if (is_readable('lam/lib/modules/requestAccess.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/requestAccess.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules/requestAccess.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules/requestAccess.inc'; /** * Checks sudo role functions. diff --git a/lam/tests/lib/modules/SambaSamAccountTest.php b/lam/tests/lib/modules/SambaSamAccountTest.php index f6ea43081..164bcc496 100644 --- a/lam/tests/lib/modules/SambaSamAccountTest.php +++ b/lam/tests/lib/modules/SambaSamAccountTest.php @@ -21,9 +21,9 @@ use PHPUnit\Framework\TestCase; */ -include_once 'lam/lib/baseModule.inc'; -include_once 'lam/lib/modules.inc'; -include_once 'lam/lib/modules/sambaSamAccount.inc'; +include_once __DIR__ . '/../../../lib/baseModule.inc'; +include_once __DIR__ . '/../../../lib/modules.inc'; +include_once __DIR__ . '/../../../lib/modules/sambaSamAccount.inc'; /** * Checks the shadow expire job. diff --git a/lam/tests/lib/modules/ShadowAccountPasswordNotifyJobTest.php b/lam/tests/lib/modules/ShadowAccountPasswordNotifyJobTest.php index db11e918b..caa8f1088 100644 --- a/lam/tests/lib/modules/ShadowAccountPasswordNotifyJobTest.php +++ b/lam/tests/lib/modules/ShadowAccountPasswordNotifyJobTest.php @@ -5,7 +5,7 @@ use PHPUnit\Framework\TestCase; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2016 - 2023 Roland Gruber + Copyright (C) 2016 - 2025 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,14 +23,14 @@ use PHPUnit\Framework\TestCase; */ -include_once 'lam/lib/baseModule.inc'; -include_once 'lam/lib/modules.inc'; -if (is_readable('lam/lib/passwordExpirationJob.inc')) { - include_once 'lam/lib/passwordExpirationJob.inc'; +include_once __DIR__ . '/../../../lib/baseModule.inc'; +include_once __DIR__ . '/../../../lib/modules.inc'; +if (is_readable(__DIR__ . '/../../../lib/passwordExpirationJob.inc')) { + include_once __DIR__ . '/../../../lib/passwordExpirationJob.inc'; } -include_once 'lam/lib/modules/shadowAccount.inc'; +include_once __DIR__ . '/../../../lib/modules/shadowAccount.inc'; -if (is_readable('lam/lib/passwordExpirationJob.inc')) { +if (is_readable(__DIR__ . '/../../../lib/passwordExpirationJob.inc')) { /** * Checks the shadow expire job. @@ -101,7 +101,7 @@ if (is_readable('lam/lib/passwordExpirationJob.inc')) { public function testWarningNotReached() { $now = new DateTime('now', getTimeZone()); - $lastChangeNow = floor($now->format('U')/3600/24); + $lastChangeNow = (string) floor($now->format('U')/3600/24); $this->job->method('getDBLastPwdChangeTime')->willReturn($lastChangeNow); $this->job->method('findUsers')->willReturn([[ 'dn' => 'cn=some,dc=dn', @@ -119,7 +119,7 @@ if (is_readable('lam/lib/passwordExpirationJob.inc')) { public function testAlreadyWarned() { $now = new DateTime('now', getTimeZone()); - $lastChangeNow = floor($now->format('U')/3600/24); + $lastChangeNow = (string) floor($now->format('U')/3600/24); $this->job->method('getDBLastPwdChangeTime')->willReturn($lastChangeNow); $this->job->method('findUsers')->willReturn([[ 'dn' => 'cn=some,dc=dn', diff --git a/lam/tests/lib/modules/ShadowAccountTest.php b/lam/tests/lib/modules/ShadowAccountTest.php index 31d266f18..69454644f 100644 --- a/lam/tests/lib/modules/ShadowAccountTest.php +++ b/lam/tests/lib/modules/ShadowAccountTest.php @@ -23,12 +23,12 @@ use PHPUnit\Framework\TestCase; */ - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules.inc'; - if (is_readable('lam/lib/passwordExpirationJob.inc')) { - include_once 'lam/lib/passwordExpirationJob.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules.inc'; + if (is_readable(__DIR__ . '/../../../lib/passwordExpirationJob.inc')) { + include_once __DIR__ . '/../../../lib/passwordExpirationJob.inc'; } - include_once 'lam/lib/modules/shadowAccount.inc'; + include_once __DIR__ . '/../../../lib/modules/shadowAccount.inc'; /** * Checks the shadowAccount class. diff --git a/lam/tests/lib/modules/SudoRoleTest.php b/lam/tests/lib/modules/SudoRoleTest.php index 2d09d0f2c..106fb846d 100644 --- a/lam/tests/lib/modules/SudoRoleTest.php +++ b/lam/tests/lib/modules/SudoRoleTest.php @@ -21,10 +21,10 @@ use PHPUnit\Framework\TestCase; */ -if (is_readable('lam/lib/modules/sudoRole.inc')) { +if (is_readable(__DIR__ . '/../../../lib/modules/sudoRole.inc')) { - include_once 'lam/lib/baseModule.inc'; - include_once 'lam/lib/modules/sudoRole.inc'; + include_once __DIR__ . '/../../../lib/baseModule.inc'; + include_once __DIR__ . '/../../../lib/modules/sudoRole.inc'; /** * Checks sudo role functions. diff --git a/lam/tests/utils/configuration.inc b/lam/tests/utils/configuration.inc index d980ccef4..ab189b60d 100644 --- a/lam/tests/utils/configuration.inc +++ b/lam/tests/utils/configuration.inc @@ -36,6 +36,9 @@ function testCreateDefaultConfig() { unlink($cfgPath); } touch($cfgPath); + $fileHandle = fopen($cfgPath, 'w'); + fwrite($fileHandle, '{}'); + fclose($fileHandle); $serverProfilePersistenceManager = new ServerProfilePersistenceManager(); $config = $serverProfilePersistenceManager->loadProfile(LAMConfigTest::FILE_NAME); $_SESSION['config'] = $config; diff --git a/phpstan.neon b/phpstan.neon index 970f5a3fe..b920f9bfe 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 9 + level: 5 scanDirectories: - lam/lib - lam/templates @@ -8,37 +8,56 @@ parameters: - lam/templates fileExtensions: - php + - inc excludePaths: - analyseAndScan: + analyse: - */3rdParty/* + # phpstan cannot ignore unknown class errors, skip these files + - lam/lib/persistence.inc + - lam/lib/modules/freeRadius.inc + - lam/lib/modules/shadowAccount.inc + - lam/lib/modules/windowsUser.inc + analyseAndScan: + - lam/templates/config/job*.php (?) + - lam/templates/lists/changePassword.php (?) + - lam/templates/selfService/*.php (?) + - lam/lib/cron.inc (?) + - lam/lib/database.inc (?) + - lam/lib/env.inc (?) + - lam/lib/jobs.inc (?) + - lam/lib/passwordExpirationJob.inc (?) + - lam/lib/modules/groupOfMembers.inc (?) + - lam/lib/modules/groupOfNames.inc (?) + - lam/lib/modules/groupOfNamesUser.inc (?) + - lam/lib/modules/groupOfUniqueNames.inc (?) + - lam/lib/modules/guacamole.inc (?) + - lam/lib/modules/heimdalKerberos.inc (?) + - lam/lib/modules/mitKerberos.inc (?) + - lam/lib/modules/mitKerberosStructural.inc (?) + - lam/lib/modules/qmailUser.inc (?) + - lam/lib/modules/passwordSelfReset.inc (?) + - lam/lib/modules/ppolicyUser.inc (?) + - lam/lib/modules/lastBind.inc (?) + - lam/lib/modules/locking389ds.inc (?) + - lam/lib/modules/rfc2307bisPosixGroup.inc (?) + - lam/lib/plugins/extendedInvalidCredentials/Locking389DsExtraInvalidCredentialsProvider.inc (?) + - lam/lib/plugins/extendedInvalidCredentials/MitKerberosExtraInvalidCredentialsProvider.inc (?) ignoreErrors: - - '#.* on an unknown class .*#' - - '#.* has invalid type .*#' - - '#Function [a-zA-Z0-9\\_-]+ not found.#' - - '#Class [a-zA-Z0-9\\_-]+ not found.#' - - '#Instantiated class [a-zA-Z0-9\\_-]+ not found.#' - - '#Caught class [a-zA-Z0-9\\_-]+ not found.#' - - '#Used function [a-zA-Z0-9\\_-]+ not found.#' - '#Variable \$helpArray might not be defined.#' - - '#Function [a-zA-Z0-9\(\)\\_-]+ has invalid return type [a-zA-Z0-9\\_-]+.#' - - '#PHPDoc tag @throws with type LAMException is not subtype of Throwable#' - - '#Throwing object of an unknown class [a-zA-Z0-9\\_-]+.#' - - '#Parameter \#[0-9] \$[a-zA-Z_]+ of function [a-zA-Z_]+ expects [(]?callable.*#' - - '#Call to an undefined method object::.*#' - - '#Parameter \#2 \$string of function explode expects string, array\|string given.#' - - '#Parameter \#2 \$result of function ldap_.* expects LDAP\\Result, array\|LDAP\\Result given.#' - - '#Cannot assign new offset to array\|string.#' - - '#Cannot access offset .* on mixed.#' - - '#Cannot access offset .* on array\|int.#' - - '#Cannot access an offset on array\|Countable.#' - - '#Parameter \#1 \$haystack of function str_starts_with expects string, int\|string given.#' - - '#Parameter \#3 \$length of function substr expects int\|null, int<0, max>\|false given.#' - - '#Parameter \#1 \$string of function htmlspecialchars expects string, array\|string given.#' - - '#Parameter \#1 \$name of function LAM\\ACCOUNTLIST\\search_username expects string, array\|string given.#' - - '#Parameter \#1 \$array of function array_keys expects array, mixed given.#' - - '#Argument of an invalid type mixed supplied for foreach, only iterables are supported.#' - - '#Parameter \#2 \$args of function call_user_func_array expects array, mixed given.#' - - '#Parameter \#1 \$input of static method LAM\\AJAX\\Ajax::managePasswordChange\(\) expects array, mixed given.#' - - '#Parameter \#1 \$input of method LAM\\AJAX\\Ajax::checkPasswordStrength\(\) expects array, mixed given.#' - - '#Cannot access offset non-falsy-string on array\|object.#' - - '#Unable to resolve the template type T in call to function array_values#' + - '#Offset .preferred_username. does not exist on.*#' + - '#Strict comparison using !== between non-empty-list.*will always evaluate to true.*#' + - '#Strict comparison using !== between non-empty-array.*will always evaluate to true.*#' + - '#.*class LAM\\JOB\\.* not found.*#' + - '#.*class LAM\\ENV\\.* not found.*#' + - '#.*class LAM\\DB\\CronDatabase.* not found.*#' + - '#Call to .*method .* on an unknown class LAM\\ENV\\.*#' + - '#Call to .*method .* on an unknown class LAM\\JOB\\.*#' + - '#Call to .*method .* on an unknown class LAM\\DB\\CronDatabase.*#' + - '#.* has invalid type LAM\\ENV\\.*#' + - '#.* has invalid type LAM\\DB\\.*#' + - '#.* has invalid return type LAM\\JOB\\.*#' + - '#Call to an undefined method baseModule::getBackupEmail\(\).#' + - '#Call to an undefined method baseModule::getMembers\(\).#' + - '#Call to an undefined method baseModule::getNextGIDs\(\).#' + - '#Call to an undefined method baseModule::setExpirationDate\(\).#' + - '#.*accountContainer::getAccountModule\(\) expects class-string\, string given.*#' diff --git a/rector.php b/rector.php index 2133b7e77..17c6b5293 100644 --- a/rector.php +++ b/rector.php @@ -1,6 +1,13 @@ withParallel(240, 4) ->withPaths([ __DIR__ . '/lam/help', __DIR__ . '/lam/lib', @@ -19,7 +28,8 @@ return RectorConfig::configure() ]) ->withSets([ SetList::DEAD_CODE, - LevelSetList::UP_TO_PHP_81 + LevelSetList::UP_TO_PHP_81, + SetList::CODE_QUALITY, ]) ->withSkip([ __DIR__ . '/lam/lib/3rdParty', @@ -29,8 +39,17 @@ return RectorConfig::configure() StaticCallOnNonStaticToInstanceCallRector::class, StringifyStrNeedlesRector::class, RestoreDefaultNullToNullableTypePropertyRector::class, + ForRepeatedCountToOwnVariableRector::class, + SimplifyEmptyCheckOnEmptyArrayRector::class, + DisallowedEmptyRuleFixerRector::class, + FlipTypeControlToUseExclusiveTypeRector::class, + InlineArrayReturnAssignRector::class, + // TODO unreliable, recheck with newer rector version + ExplicitReturnNullRector::class, + RemoveParentCallWithoutParentRector::class, + RemoveAlwaysTrueIfConditionRector::class, ]) ->withFileExtensions([ 'php', -// 'inc' + 'inc' ]);